2 * Samba Unix/Linux SMB client library
3 * Distributed SMB/CIFS Server Management Utility
4 * Copyright (C) 2019 Ralph Boehme <slow@samba.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "system/filesys.h"
25 #include "system/passwd.h"
26 #include "lib/param/loadparm.h"
27 #include "lib/param/param.h"
28 #include "libcli/security/security.h"
29 #include "smbd/proto.h"
30 #include "locking/share_mode_lock.h"
31 #include "locking/proto.h"
35 #include "lib/adouble.h"
36 #include "lib/string_replace.h"
37 #include "utils/net.h"
38 #include "lib/global_contexts.h"
40 #define NET_VFS_CMD_STREAM_TO_ADOUBLE "stream2adouble"
42 static struct net_vfs_state
{
44 struct net_context
*c
;
45 struct auth_session_info
*session_info
;
46 struct conn_struct_tos
*conn_tos
;
49 static void net_vfs_usage(void)
53 "net vfs [OPTIONS] <share> ....\n");
56 static void net_vfs_getntacl_usage(void)
60 "net vfs getntacl <share> <path>\n");
63 static void net_vfs_stream_to_appledouble_usage(void)
67 "net vfs " NET_VFS_CMD_STREAM_TO_ADOUBLE
68 " [OPTIONS] <share> <path> [<path> ...]\n"
70 " --verbose verbose output\n"
71 " --continue continue on error\n"
72 " --recursive traverse directory hierarchy\n"
73 " --follow-symlinks follow symlinks\n");
76 static bool net_vfs_make_session_info(struct auth_session_info
**session_info
)
80 if (non_root_mode()) {
81 struct passwd
*p
= NULL
;
83 p
= getpwuid(geteuid());
85 fprintf(stderr
, "getpwuid(%d) failed\n", geteuid());
89 status
= make_session_info_from_username(state
.mem_ctx
,
93 if (!NT_STATUS_IS_OK(status
)) {
94 fprintf(stderr
, "session_info from username failed\n");
101 status
= init_system_session_info(state
.mem_ctx
);
102 if (!NT_STATUS_IS_OK(status
)) {
103 fprintf(stderr
, "init_system_session_info failed\n");
107 status
= make_session_info_system(state
.mem_ctx
, session_info
);
108 if (!NT_STATUS_IS_OK(status
)) {
109 fprintf(stderr
, "make_session_info_system failed\n");
116 static int net_vfs_init(struct net_context
*c
, int argc
, const char **argv
)
118 const struct loadparm_substitution
*lp_sub
=
119 loadparm_s3_global_substitution();
120 const char *service
= NULL
;
121 char *share_root
= NULL
;
127 state
= (struct net_vfs_state
) {
137 if (geteuid() != 0 && !uid_wrapper_enabled()) {
138 fprintf(stderr
, "'net vfs' must be run as root.\n");
145 setup_logging("net", DEBUG_STDOUT
);
146 lp_set_cmdline("log level", "0");
148 ok
= lp_load_with_registry_shares(get_dyn_CONFIGFILE());
150 fprintf(stderr
, "lp_load_with_registry_shares failed\n");
156 fprintf(stderr
, "locking init failed\n");
160 ok
= net_vfs_make_session_info(&state
.session_info
);
166 snum
= lp_servicenumber(service
);
168 fprintf(stderr
, "unknown service: %s\n", service
);
172 share_root
= lp_path(state
.mem_ctx
, lp_sub
, snum
);
173 if (share_root
== NULL
) {
174 fprintf(stderr
, "Failed to find share root for service: %s\n",
179 status
= create_conn_struct_tos_cwd(global_messaging_context(),
184 if (!NT_STATUS_IS_OK(status
)) {
188 state
.conn_tos
->conn
->share_access
= FILE_GENERIC_ALL
;
189 state
.conn_tos
->conn
->read_only
= false;
190 file_init(state
.conn_tos
->conn
->sconn
);
192 ok
= become_user_without_service_by_session(state
.conn_tos
->conn
,
196 "become_user_without_service_by_session failed\n");
205 static int net_vfs_get_ntacl(struct net_context
*net
,
209 const char *path
= NULL
;
210 struct smb_filename
*smb_fname
= NULL
;
211 files_struct
*fsp
= NULL
;
212 struct security_descriptor
*sd
= NULL
;
217 if (argc
< 2 || net
->display_usage
) {
218 net_vfs_getntacl_usage();
222 ret
= net_vfs_init(net
, argc
, argv
);
228 smb_fname
= synthetic_smb_fname(state
.mem_ctx
,
234 if (smb_fname
== NULL
) {
238 ret
= SMB_VFS_STAT(state
.conn_tos
->conn
, smb_fname
);
240 fprintf(stderr
, "stat [%s] failed: %s\n",
241 smb_fname_str_dbg(smb_fname
), strerror(errno
));
245 status
= openat_pathref_fsp(state
.conn_tos
->conn
->cwd_fsp
, smb_fname
);
246 if (!NT_STATUS_IS_OK(status
)) {
247 DBG_ERR("openat_pathref_fsp [%s] failed: %s\n",
248 smb_fname_str_dbg(smb_fname
), nt_errstr(status
));
252 status
= SMB_VFS_CREATE_FILE(
253 state
.conn_tos
->conn
,
257 FILE_READ_ATTRIBUTES
|READ_CONTROL_ACCESS
,
258 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
260 0, /* create_options */
261 0, /* file_attributes */
262 INTERNAL_OPEN_ONLY
, /* oplock_request */
264 0, /* allocation_size */
265 0, /* private_flags */
270 NULL
, NULL
); /* create context */
271 if (!NT_STATUS_IS_OK(status
)) {
272 DBG_ERR("SMB_VFS_CREATE_FILE [%s] failed: %s\n",
273 smb_fname_str_dbg(smb_fname
), nt_errstr(status
));
277 status
= SMB_VFS_FGET_NT_ACL(fsp
,
278 SECINFO_OWNER
|SECINFO_GROUP
|SECINFO_DACL
,
281 if (!NT_STATUS_IS_OK(status
)) {
282 DBG_ERR("SMB_VFS_FGET_NT_ACL [%s] failed: %s\n",
283 smb_fname_str_dbg(smb_fname
), nt_errstr(status
));
287 status
= close_file_free(NULL
, &fsp
, NORMAL_CLOSE
);
288 if (!NT_STATUS_IS_OK(status
)) {
289 DBG_ERR("close_file [%s] failed: %s\n",
290 smb_fname_str_dbg(smb_fname
),
295 sec_desc_print(NULL
, stdout
, sd
, true);
300 status
= close_file_free(NULL
, &fsp
, NORMAL_CLOSE
);
301 if (!NT_STATUS_IS_OK(status
)) {
302 DBG_ERR("close_file_free() [%s] failed: %s\n",
303 smb_fname_str_dbg(smb_fname
),
311 static bool do_unfruit(const char *path
)
313 struct smb_filename
*smb_fname
= NULL
;
319 p
= strrchr_m(path
, '/');
321 if (p
[1] == '.' && p
[2] == '_') {
326 smb_fname
= synthetic_smb_fname(state
.mem_ctx
,
332 if (smb_fname
== NULL
) {
336 ret
= SMB_VFS_STAT(state
.conn_tos
->conn
, smb_fname
);
338 fprintf(stderr
, "%s: %s\n", path
, strerror(errno
));
339 if (state
.c
->opt_continue_on_error
) {
345 ok
= ad_unconvert(state
.mem_ctx
,
346 state
.conn_tos
->conn
->vfs_handles
,
347 macos_string_replace_map
,
351 fprintf(stderr
, "Converting failed: %s\n", path
);
352 if (state
.c
->opt_continue_on_error
) {
359 fprintf(stdout
, "Converted: %s\n", path
);
360 } else if (state
.c
->opt_verbose
) {
361 fprintf(stdout
, "%s\n", path
);
366 static int nftw_cb(const char *path
,
367 const struct stat
*sb
,
373 if (typeflag
== FTW_SL
) {
374 if (state
.c
->opt_verbose
) {
375 fprintf(stdout
, "Ignoring symlink: %s\n", path
);
380 ok
= do_unfruit(path
);
388 static int net_vfs_stream_to_appledouble(struct net_context
*net
,
397 if (argc
< 2 || net
->display_usage
) {
398 net_vfs_stream_to_appledouble_usage();
402 ret
= net_vfs_init(net
, argc
, argv
);
407 for (i
= 1; i
< argc
; i
++) {
408 const char *path
= argv
[i
];
410 if (path
[0] == '/') {
411 fprintf(stderr
, "ignoring absolute path: %s\n", path
);
412 if (state
.c
->opt_continue_on_error
) {
418 if (!state
.c
->opt_recursive
) {
419 ok
= do_unfruit(path
);
421 if (!state
.c
->opt_continue_on_error
) {
431 state
.c
->opt_follow_symlink
? 0 : FTW_PHYS
);
433 fprintf(stderr
, "%s: %s\n", path
, strerror(errno
));
434 if (!state
.c
->opt_continue_on_error
) {
446 static struct functable func
[] = {
451 N_("Display security descriptor of a file or directory"),
452 N_("net vfs getntacl <share> <path> [<path> ...]")
455 NET_VFS_CMD_STREAM_TO_ADOUBLE
,
456 net_vfs_stream_to_appledouble
,
458 N_("Convert streams to AppleDouble files"),
459 N_("net vfs " NET_VFS_CMD_STREAM_TO_ADOUBLE
" [OPTIONS] <share> <path> [<path> ...]")
461 {NULL
, NULL
, 0, NULL
, NULL
}
464 int net_vfs(struct net_context
*c
, int argc
, const char **argv
)
466 return net_run_function(c
, argc
, argv
, "net vfs", func
);