Line data Source code
1 : /*
2 : * Samba Unix/Linux SMB client library
3 : * Distributed SMB/CIFS Server Management Utility
4 : * Copyright (C) 2019 Ralph Boehme <slow@samba.org>
5 : *
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.
10 : *
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.
15 : *
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/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include <talloc.h>
22 : #include <tevent.h>
23 : #include <ftw.h>
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"
32 : #include "auth.h"
33 : #include "client.h"
34 : #include "util_sd.h"
35 : #include "lib/adouble.h"
36 : #include "lib/string_replace.h"
37 : #include "utils/net.h"
38 : #include "lib/global_contexts.h"
39 :
40 : #define NET_VFS_CMD_STREAM_TO_ADOUBLE "stream2adouble"
41 :
42 : static struct net_vfs_state {
43 : TALLOC_CTX *mem_ctx;
44 : struct net_context *c;
45 : struct auth_session_info *session_info;
46 : struct conn_struct_tos *conn_tos;
47 : } state;
48 :
49 0 : static void net_vfs_usage(void)
50 : {
51 0 : fprintf(stderr,
52 : "Usage:\n"
53 : "net vfs [OPTIONS] <share> ....\n");
54 0 : }
55 :
56 0 : static void net_vfs_getntacl_usage(void)
57 : {
58 0 : fprintf(stderr,
59 : "Usage:\n"
60 : "net vfs getntacl <share> <path>\n");
61 0 : }
62 :
63 0 : static void net_vfs_stream_to_appledouble_usage(void)
64 : {
65 0 : fprintf(stderr,
66 : "Usage:\n"
67 : "net vfs " NET_VFS_CMD_STREAM_TO_ADOUBLE
68 : " [OPTIONS] <share> <path> [<path> ...]\n"
69 : "Options:\n"
70 : " --verbose verbose output\n"
71 : " --continue continue on error\n"
72 : " --recursive traverse directory hierarchy\n"
73 : " --follow-symlinks follow symlinks\n");
74 0 : }
75 :
76 6 : static bool net_vfs_make_session_info(struct auth_session_info **session_info)
77 : {
78 0 : NTSTATUS status;
79 :
80 6 : if (non_root_mode()) {
81 6 : struct passwd *p = NULL;
82 :
83 6 : p = getpwuid(geteuid());
84 6 : if (p == NULL) {
85 0 : fprintf(stderr, "getpwuid(%d) failed\n", geteuid());
86 0 : return false;
87 : }
88 :
89 6 : status = make_session_info_from_username(state.mem_ctx,
90 6 : p->pw_name,
91 : false,
92 : session_info);
93 6 : if (!NT_STATUS_IS_OK(status)) {
94 0 : fprintf(stderr, "session_info from username failed\n");
95 0 : return false;
96 : }
97 :
98 6 : return true;
99 : }
100 :
101 0 : status = init_system_session_info(state.mem_ctx);
102 0 : if (!NT_STATUS_IS_OK(status)) {
103 0 : fprintf(stderr, "init_system_session_info failed\n");
104 0 : return false;
105 : }
106 :
107 0 : status = make_session_info_system(state.mem_ctx, session_info);
108 0 : if (!NT_STATUS_IS_OK(status)) {
109 0 : fprintf(stderr, "make_session_info_system failed\n");
110 0 : return false;
111 : }
112 :
113 0 : return true;
114 : }
115 :
116 6 : static int net_vfs_init(struct net_context *c, int argc, const char **argv)
117 : {
118 0 : const struct loadparm_substitution *lp_sub =
119 6 : loadparm_s3_global_substitution();
120 6 : const char *service = NULL;
121 6 : char *share_root = NULL;
122 0 : int snum;
123 0 : NTSTATUS status;
124 0 : bool ok;
125 6 : int rc = 1;
126 :
127 6 : state = (struct net_vfs_state) {
128 : .c = c,
129 : .mem_ctx = c,
130 : };
131 :
132 6 : if (argc < 1) {
133 0 : net_vfs_usage();
134 0 : goto done;
135 : }
136 :
137 6 : if (geteuid() != 0 && !uid_wrapper_enabled()) {
138 0 : fprintf(stderr, "'net vfs' must be run as root.\n");
139 0 : goto done;
140 : }
141 :
142 6 : smb_init_locale();
143 6 : umask(0);
144 6 : sec_init();
145 6 : setup_logging("net", DEBUG_STDOUT);
146 6 : lpcfg_set_cmdline(c->lp_ctx, "log level", "0");
147 :
148 6 : ok = lp_load_with_registry_shares(get_dyn_CONFIGFILE());
149 6 : if (!ok) {
150 0 : fprintf(stderr, "lp_load_with_registry_shares failed\n");
151 0 : goto done;
152 : }
153 :
154 6 : ok = locking_init();
155 6 : if (!ok) {
156 0 : fprintf(stderr, "locking init failed\n");
157 0 : goto done;
158 : }
159 :
160 6 : ok = net_vfs_make_session_info(&state.session_info);
161 6 : if (!ok) {
162 0 : goto done;
163 : }
164 :
165 6 : service = argv[0];
166 6 : snum = lp_servicenumber(service);
167 6 : if (snum == -1) {
168 0 : fprintf(stderr, "unknown service: %s\n", service);
169 0 : goto done;
170 : }
171 :
172 6 : share_root = lp_path(state.mem_ctx, lp_sub, snum);
173 6 : if (share_root == NULL) {
174 0 : fprintf(stderr, "Failed to find share root for service: %s\n",
175 : service);
176 0 : goto done;
177 : }
178 :
179 6 : status = create_conn_struct_tos_cwd(global_messaging_context(),
180 : snum,
181 : share_root,
182 6 : state.session_info,
183 : &state.conn_tos);
184 6 : if (!NT_STATUS_IS_OK(status)) {
185 0 : goto done;
186 : }
187 :
188 6 : state.conn_tos->conn->share_access = FILE_GENERIC_ALL;
189 6 : state.conn_tos->conn->read_only = false;
190 6 : file_init(state.conn_tos->conn->sconn);
191 :
192 6 : ok = become_user_without_service_by_session(state.conn_tos->conn,
193 6 : state.session_info);
194 6 : if (!ok) {
195 0 : fprintf(stderr,
196 : "become_user_without_service_by_session failed\n");
197 0 : goto done;
198 : }
199 :
200 6 : rc = 0;
201 6 : done:
202 6 : return rc;
203 : }
204 :
205 0 : static int net_vfs_get_ntacl(struct net_context *net,
206 : int argc,
207 : const char **argv)
208 : {
209 0 : const char *path = NULL;
210 0 : struct smb_filename *smb_fname = NULL;
211 0 : files_struct *fsp = NULL;
212 0 : struct security_descriptor *sd = NULL;
213 0 : NTSTATUS status;
214 0 : int ret;
215 0 : int rc = 1;
216 :
217 0 : if (argc < 2 || net->display_usage) {
218 0 : net_vfs_getntacl_usage();
219 0 : goto done;
220 : }
221 :
222 0 : ret = net_vfs_init(net, argc, argv);
223 0 : if (ret != 0) {
224 0 : goto done;
225 : }
226 :
227 0 : path = argv[1];
228 0 : smb_fname = synthetic_smb_fname(state.mem_ctx,
229 : path,
230 : NULL,
231 : NULL,
232 : 0,
233 : 0);
234 0 : if (smb_fname == NULL) {
235 0 : goto done;
236 : }
237 :
238 0 : ret = SMB_VFS_STAT(state.conn_tos->conn, smb_fname);
239 0 : if (ret != 0) {
240 0 : fprintf(stderr, "stat [%s] failed: %s\n",
241 0 : smb_fname_str_dbg(smb_fname), strerror(errno));
242 0 : goto done;
243 : }
244 :
245 0 : status = openat_pathref_fsp(state.conn_tos->conn->cwd_fsp, smb_fname);
246 0 : if (!NT_STATUS_IS_OK(status)) {
247 0 : DBG_ERR("openat_pathref_fsp [%s] failed: %s\n",
248 : smb_fname_str_dbg(smb_fname), nt_errstr(status));
249 0 : goto done;
250 : }
251 :
252 0 : status = SMB_VFS_CREATE_FILE(
253 : state.conn_tos->conn,
254 : NULL, /* req */
255 : NULL,
256 : smb_fname,
257 : FILE_READ_ATTRIBUTES|READ_CONTROL_ACCESS,
258 : FILE_SHARE_READ|FILE_SHARE_WRITE,
259 : FILE_OPEN,
260 : 0, /* create_options */
261 : 0, /* file_attributes */
262 : INTERNAL_OPEN_ONLY, /* oplock_request */
263 : NULL, /* lease */
264 : 0, /* allocation_size */
265 : 0, /* private_flags */
266 : NULL, /* sd */
267 : NULL, /* ea_list */
268 : &fsp,
269 : NULL, /* info */
270 : NULL, NULL); /* create context */
271 0 : if (!NT_STATUS_IS_OK(status)) {
272 0 : DBG_ERR("SMB_VFS_CREATE_FILE [%s] failed: %s\n",
273 : smb_fname_str_dbg(smb_fname), nt_errstr(status));
274 0 : goto done;
275 : }
276 :
277 0 : status = SMB_VFS_FGET_NT_ACL(fsp,
278 : SECINFO_OWNER|SECINFO_GROUP|SECINFO_DACL,
279 : talloc_tos(),
280 : &sd);
281 0 : if (!NT_STATUS_IS_OK(status)) {
282 0 : DBG_ERR("SMB_VFS_FGET_NT_ACL [%s] failed: %s\n",
283 : smb_fname_str_dbg(smb_fname), nt_errstr(status));
284 0 : goto done;
285 : }
286 :
287 0 : status = close_file_free(NULL, &fsp, NORMAL_CLOSE);
288 0 : if (!NT_STATUS_IS_OK(status)) {
289 0 : DBG_ERR("close_file [%s] failed: %s\n",
290 : smb_fname_str_dbg(smb_fname),
291 : nt_errstr(status));
292 0 : goto done;
293 : }
294 :
295 0 : sec_desc_print(NULL, stdout, sd, true);
296 :
297 0 : rc = 0;
298 0 : done:
299 0 : TALLOC_FREE(sd);
300 :
301 0 : if (fsp != NULL) {
302 0 : status = close_file_free(NULL, &fsp, NORMAL_CLOSE);
303 0 : if (!NT_STATUS_IS_OK(status)) {
304 0 : DBG_ERR("close_file_free() [%s] failed: %s\n",
305 : smb_fname_str_dbg(smb_fname),
306 : nt_errstr(status));
307 0 : rc = 1;
308 : }
309 : }
310 0 : return rc;
311 : }
312 :
313 16 : static bool do_unfruit(const char *path)
314 : {
315 16 : struct smb_filename *smb_fname = NULL;
316 16 : char *p = NULL;
317 0 : bool converted;
318 0 : int ret;
319 0 : bool ok;
320 :
321 16 : p = strrchr_m(path, '/');
322 16 : if (p != NULL) {
323 10 : if (p[1] == '.' && p[2] == '_') {
324 4 : return true;
325 : }
326 : }
327 :
328 12 : smb_fname = synthetic_smb_fname(state.mem_ctx,
329 : path,
330 : NULL,
331 : NULL,
332 : 0,
333 : 0);
334 12 : if (smb_fname == NULL) {
335 0 : return false;
336 : }
337 :
338 12 : ret = SMB_VFS_STAT(state.conn_tos->conn, smb_fname);
339 12 : if (ret != 0) {
340 0 : fprintf(stderr, "%s: %s\n", path, strerror(errno));
341 0 : if (state.c->opt_continue_on_error) {
342 0 : return true;
343 : }
344 0 : return false;
345 : }
346 :
347 12 : ok = ad_unconvert(state.mem_ctx,
348 12 : state.conn_tos->conn->vfs_handles,
349 : macos_string_replace_map,
350 : smb_fname,
351 : &converted);
352 12 : if (!ok) {
353 0 : fprintf(stderr, "Converting failed: %s\n", path);
354 0 : if (state.c->opt_continue_on_error) {
355 0 : return true;
356 : }
357 0 : return false;
358 : }
359 :
360 12 : if (converted) {
361 6 : fprintf(stdout, "Converted: %s\n", path);
362 6 : } else if (state.c->opt_verbose) {
363 0 : fprintf(stdout, "%s\n", path);
364 : }
365 12 : return true;
366 : }
367 :
368 16 : static int nftw_cb(const char *path,
369 : const struct stat *sb,
370 : int typeflag,
371 : struct FTW *ftwbuf)
372 : {
373 0 : bool ok;
374 :
375 16 : if (typeflag == FTW_SL) {
376 0 : if (state.c->opt_verbose) {
377 0 : fprintf(stdout, "Ignoring symlink: %s\n", path);
378 : }
379 0 : return 0;
380 : }
381 :
382 16 : ok = do_unfruit(path);
383 16 : if (!ok) {
384 0 : return -1;
385 : }
386 :
387 16 : return 0;
388 : }
389 :
390 6 : static int net_vfs_stream_to_appledouble(struct net_context *net,
391 : int argc,
392 : const char **argv)
393 : {
394 0 : int i;
395 0 : int ret;
396 0 : bool ok;
397 6 : int rc = 1;
398 :
399 6 : if (argc < 2 || net->display_usage) {
400 0 : net_vfs_stream_to_appledouble_usage();
401 0 : goto done;
402 : }
403 :
404 6 : ret = net_vfs_init(net, argc, argv);
405 6 : if (ret != 0) {
406 0 : goto done;
407 : }
408 :
409 12 : for (i = 1; i < argc; i++) {
410 6 : const char *path = argv[i];
411 :
412 6 : if (path[0] == '/') {
413 0 : fprintf(stderr, "ignoring absolute path: %s\n", path);
414 0 : if (state.c->opt_continue_on_error) {
415 0 : continue;
416 : }
417 0 : goto done;
418 : }
419 :
420 6 : if (!state.c->opt_recursive) {
421 0 : ok = do_unfruit(path);
422 0 : if (!ok) {
423 0 : if (!state.c->opt_continue_on_error) {
424 0 : goto done;
425 : }
426 : }
427 0 : continue;
428 : }
429 :
430 6 : ret = nftw(path,
431 : nftw_cb,
432 : 256,
433 6 : state.c->opt_follow_symlink ? 0 : FTW_PHYS);
434 6 : if (ret != 0) {
435 0 : fprintf(stderr, "%s: %s\n", path, strerror(errno));
436 0 : if (!state.c->opt_continue_on_error) {
437 0 : goto done;
438 : }
439 : }
440 : }
441 :
442 6 : rc = 0;
443 :
444 6 : done:
445 6 : return rc;
446 : }
447 :
448 : static struct functable func[] = {
449 : {
450 : "getntacl",
451 : net_vfs_get_ntacl,
452 : NET_TRANSPORT_LOCAL,
453 : N_("Display security descriptor of a file or directory"),
454 : N_("net vfs getntacl <share> <path> [<path> ...]")
455 : },
456 : {
457 : NET_VFS_CMD_STREAM_TO_ADOUBLE,
458 : net_vfs_stream_to_appledouble,
459 : NET_TRANSPORT_LOCAL,
460 : N_("Convert streams to AppleDouble files"),
461 : N_("net vfs " NET_VFS_CMD_STREAM_TO_ADOUBLE " [OPTIONS] <share> <path> [<path> ...]")
462 : },
463 : {NULL, NULL, 0, NULL, NULL}
464 : };
465 :
466 6 : int net_vfs(struct net_context *c, int argc, const char **argv)
467 : {
468 6 : return net_run_function(c, argc, argv, "net vfs", func);
469 : }
|