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 "popt_common.h"
27 #include "lib/param/loadparm.h"
28 #include "lib/param/param.h"
29 #include "libcli/security/security.h"
30 #include "smbd/proto.h"
31 #include "locking/proto.h"
35 #include "lib/adouble.h"
36 #include "lib/string_replace.h"
37 #include "utils/net.h"
39 #define NET_VFS_CMD_STREAM_TO_ADOUBLE "stream2adouble"
41 static struct net_vfs_state {
43 struct net_context *c;
44 struct auth_session_info *session_info;
45 struct conn_struct_tos *conn_tos;
48 static void net_vfs_usage(void)
52 "net vfs [OPTIONS] <share> ....\n");
55 static void net_vfs_getntacl_usage(void)
59 "net vfs getntacl <share> <path>\n");
62 static void net_vfs_stream_to_appledouble_usage(void)
66 "net vfs " NET_VFS_CMD_STREAM_TO_ADOUBLE
67 " [OPTIONS] <share> <path> [<path> ...]\n"
69 " --verbose verbose output\n"
70 " --continue continue on error\n"
71 " --recursive traverse directory hierarchy\n"
72 " --follow-symlinks follow symlinks\n");
75 static bool net_vfs_make_session_info(struct auth_session_info **session_info)
79 if (non_root_mode()) {
80 struct passwd *p = NULL;
82 p = getpwuid(geteuid());
84 fprintf(stderr, "getpwuid(%d) failed\n", geteuid());
88 status = make_session_info_from_username(state.mem_ctx,
92 if (!NT_STATUS_IS_OK(status)) {
93 fprintf(stderr, "session_info from username failed\n");
100 status = init_system_session_info(state.mem_ctx);
101 if (!NT_STATUS_IS_OK(status)) {
102 fprintf(stderr, "init_system_session_info failed\n");
106 status = make_session_info_system(state.mem_ctx, session_info);
107 if (!NT_STATUS_IS_OK(status)) {
108 fprintf(stderr, "make_session_info_system failed\n");
115 static int net_vfs_init(struct net_context *c, int argc, const char **argv)
117 const struct loadparm_substitution *lp_sub =
118 loadparm_s3_global_substitution();
119 const char *service = NULL;
120 char *share_root = NULL;
126 state = (struct net_vfs_state) {
136 if (geteuid() != 0 && !uid_wrapper_enabled()) {
137 fprintf(stderr, "'net vfs' must be run as root.\n");
144 setup_logging("net", DEBUG_STDOUT);
145 lp_set_cmdline("log level", "0");
147 ok = lp_load_with_registry_shares(get_dyn_CONFIGFILE());
149 fprintf(stderr, "lp_load_with_registry_shares failed\n");
155 fprintf(stderr, "locking init failed\n");
159 ok = net_vfs_make_session_info(&state.session_info);
165 snum = lp_servicenumber(service);
167 fprintf(stderr, "unknown service: %s\n", service);
171 share_root = lp_path(state.mem_ctx, lp_sub, snum);
172 if (share_root == NULL) {
173 fprintf(stderr, "Failed to find share root for service: %s\n",
178 status = create_conn_struct_tos_cwd(global_messaging_context(),
183 if (!NT_STATUS_IS_OK(status)) {
187 state.conn_tos->conn->share_access = FILE_GENERIC_ALL;
188 state.conn_tos->conn->read_only = false;
189 file_init(state.conn_tos->conn->sconn);
191 ok = become_user_without_service_by_session(state.conn_tos->conn,
195 "become_user_without_service_by_session failed\n");
204 static int net_vfs_get_ntacl(struct net_context *net,
208 const char *path = NULL;
209 struct smb_filename *smb_fname = NULL;
210 files_struct *fsp = NULL;
211 struct security_descriptor *sd = NULL;
216 if (argc < 2 || net->display_usage) {
217 net_vfs_getntacl_usage();
221 ret = net_vfs_init(net, argc, argv);
227 smb_fname = synthetic_smb_fname(state.mem_ctx,
233 if (smb_fname == NULL) {
237 ret = SMB_VFS_STAT(state.conn_tos->conn, smb_fname);
239 fprintf(stderr, "stat [%s] failed: %s\n",
240 smb_fname_str_dbg(smb_fname), strerror(errno));
244 status = SMB_VFS_CREATE_FILE(
245 state.conn_tos->conn,
247 &state.conn_tos->conn->cwd_fsp,
249 FILE_READ_ATTRIBUTES|READ_CONTROL_ACCESS,
250 FILE_SHARE_READ|FILE_SHARE_WRITE,
252 0, /* create_options */
253 0, /* file_attributes */
254 INTERNAL_OPEN_ONLY, /* oplock_request */
256 0, /* allocation_size */
257 0, /* private_flags */
262 NULL, NULL); /* create context */
263 if (!NT_STATUS_IS_OK(status)) {
264 DBG_ERR("SMB_VFS_CREATE_FILE [%s] failed: %s\n",
265 smb_fname_str_dbg(smb_fname), nt_errstr(status));
269 status = SMB_VFS_FGET_NT_ACL(fsp,
270 SECINFO_OWNER|SECINFO_GROUP|SECINFO_DACL,
273 if (!NT_STATUS_IS_OK(status)) {
274 DBG_ERR("SMB_VFS_FGET_NT_ACL [%s] failed: %s\n",
275 smb_fname_str_dbg(smb_fname), nt_errstr(status));
279 status = close_file(NULL, fsp, NORMAL_CLOSE);
280 if (!NT_STATUS_IS_OK(status)) {
281 DBG_ERR("close_file [%s] failed: %s\n",
282 smb_fname_str_dbg(smb_fname),
288 sec_desc_print(NULL, stdout, sd, true);
293 status = close_file(NULL, fsp, NORMAL_CLOSE);
294 if (!NT_STATUS_IS_OK(status)) {
295 DBG_ERR("close_file [%s] failed: %s\n",
296 smb_fname_str_dbg(smb_fname),
304 static bool do_unfruit(const char *path)
306 struct smb_filename *smb_fname = NULL;
312 p = strrchr_m(path, '/');
314 if (p[1] == '.' && p[2] == '_') {
319 smb_fname = synthetic_smb_fname(state.mem_ctx,
325 if (smb_fname == NULL) {
329 ret = SMB_VFS_STAT(state.conn_tos->conn, smb_fname);
331 fprintf(stderr, "%s: %s\n", path, strerror(errno));
332 if (state.c->opt_continue_on_error) {
338 ok = ad_unconvert(state.mem_ctx,
339 state.conn_tos->conn->vfs_handles,
340 macos_string_replace_map,
344 fprintf(stderr, "Converting failed: %s\n", path);
345 if (state.c->opt_continue_on_error) {
352 fprintf(stdout, "Converted: %s\n", path);
353 } else if (state.c->opt_verbose) {
354 fprintf(stdout, "%s\n", path);
359 static int nftw_cb(const char *path,
360 const struct stat *sb,
366 if (typeflag == FTW_SL) {
367 if (state.c->opt_verbose) {
368 fprintf(stdout, "Ignoring symlink: %s\n", path);
373 ok = do_unfruit(path);
381 static int net_vfs_stream_to_appledouble(struct net_context *net,
390 if (argc < 2 || net->display_usage) {
391 net_vfs_stream_to_appledouble_usage();
395 ret = net_vfs_init(net, argc, argv);
400 for (i = 1; i < argc; i++) {
401 const char *path = argv[i];
403 if (path[0] == '/') {
404 fprintf(stderr, "ignoring absolute path: %s\n", path);
405 if (state.c->opt_continue_on_error) {
411 if (!state.c->opt_recursive) {
412 ok = do_unfruit(path);
414 if (!state.c->opt_continue_on_error) {
424 state.c->opt_follow_symlink ? 0 : FTW_PHYS);
426 fprintf(stderr, "%s: %s\n", path, strerror(errno));
427 if (!state.c->opt_continue_on_error) {
439 static struct functable func[] = {
444 N_("Display security descriptor of a file or directory"),
445 N_("net vfs getntacl <share> <path> [<path> ...]")
448 NET_VFS_CMD_STREAM_TO_ADOUBLE,
449 net_vfs_stream_to_appledouble,
451 N_("Convert streams to AppleDouble files"),
452 N_("net vfs " NET_VFS_CMD_STREAM_TO_ADOUBLE " [OPTIONS] <share> <path> [<path> ...]")
454 {NULL, NULL, 0, NULL, NULL}
457 int net_vfs(struct net_context *c, int argc, const char **argv)
459 return net_run_function(c, argc, argv, "net vfs", func);