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 0 : static bool net_vfs_make_session_info(struct auth_session_info **session_info)
77 : {
78 : NTSTATUS status;
79 :
80 0 : if (non_root_mode()) {
81 0 : struct passwd *p = NULL;
82 :
83 0 : p = getpwuid(geteuid());
84 0 : if (p == NULL) {
85 0 : fprintf(stderr, "getpwuid(%d) failed\n", geteuid());
86 0 : return false;
87 : }
88 :
89 0 : status = make_session_info_from_username(state.mem_ctx,
90 0 : p->pw_name,
91 : false,
92 : session_info);
93 0 : if (!NT_STATUS_IS_OK(status)) {
94 0 : fprintf(stderr, "session_info from username failed\n");
95 0 : return false;
96 : }
97 :
98 0 : 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 0 : static int net_vfs_init(struct net_context *c, int argc, const char **argv)
117 : {
118 0 : const struct loadparm_substitution *lp_sub =
119 0 : loadparm_s3_global_substitution();
120 0 : const char *service = NULL;
121 0 : char *share_root = NULL;
122 : int snum;
123 : NTSTATUS status;
124 : bool ok;
125 0 : int rc = 1;
126 :
127 0 : state = (struct net_vfs_state) {
128 : .c = c,
129 : .mem_ctx = c,
130 : };
131 :
132 0 : if (argc < 1) {
133 0 : net_vfs_usage();
134 0 : goto done;
135 : }
136 :
137 0 : 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 0 : smb_init_locale();
143 0 : umask(0);
144 0 : sec_init();
145 0 : setup_logging("net", DEBUG_STDOUT);
146 0 : lp_set_cmdline("log level", "0");
147 :
148 0 : ok = lp_load_with_registry_shares(get_dyn_CONFIGFILE());
149 0 : if (!ok) {
150 0 : fprintf(stderr, "lp_load_with_registry_shares failed\n");
151 0 : goto done;
152 : }
153 :
154 0 : ok = locking_init();
155 0 : if (!ok) {
156 0 : fprintf(stderr, "locking init failed\n");
157 0 : goto done;
158 : }
159 :
160 0 : ok = net_vfs_make_session_info(&state.session_info);
161 0 : if (!ok) {
162 0 : goto done;
163 : }
164 :
165 0 : service = argv[0];
166 0 : snum = lp_servicenumber(service);
167 0 : if (snum == -1) {
168 0 : fprintf(stderr, "unknown service: %s\n", service);
169 0 : goto done;
170 : }
171 :
172 0 : share_root = lp_path(state.mem_ctx, lp_sub, snum);
173 0 : 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 0 : status = create_conn_struct_tos_cwd(global_messaging_context(),
180 : snum,
181 : share_root,
182 0 : state.session_info,
183 : &state.conn_tos);
184 0 : if (!NT_STATUS_IS_OK(status)) {
185 0 : goto done;
186 : }
187 :
188 0 : state.conn_tos->conn->share_access = FILE_GENERIC_ALL;
189 0 : state.conn_tos->conn->read_only = false;
190 0 : file_init(state.conn_tos->conn->sconn);
191 :
192 0 : ok = become_user_without_service_by_session(state.conn_tos->conn,
193 0 : state.session_info);
194 0 : if (!ok) {
195 0 : fprintf(stderr,
196 : "become_user_without_service_by_session failed\n");
197 0 : goto done;
198 : }
199 :
200 0 : rc = 0;
201 0 : done:
202 0 : 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 : NTSTATUS status;
214 : 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 : fsp,
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 : if (fsp != NULL) {
300 0 : status = close_file_free(NULL, &fsp, NORMAL_CLOSE);
301 0 : if (!NT_STATUS_IS_OK(status)) {
302 0 : DBG_ERR("close_file_free() [%s] failed: %s\n",
303 : smb_fname_str_dbg(smb_fname),
304 : nt_errstr(status));
305 0 : rc = 1;
306 : }
307 : }
308 0 : return rc;
309 : }
310 :
311 0 : static bool do_unfruit(const char *path)
312 : {
313 0 : struct smb_filename *smb_fname = NULL;
314 0 : char *p = NULL;
315 : bool converted;
316 : int ret;
317 : bool ok;
318 :
319 0 : p = strrchr_m(path, '/');
320 0 : if (p != NULL) {
321 0 : if (p[1] == '.' && p[2] == '_') {
322 0 : return true;
323 : }
324 : }
325 :
326 0 : smb_fname = synthetic_smb_fname(state.mem_ctx,
327 : path,
328 : NULL,
329 : NULL,
330 : 0,
331 : 0);
332 0 : if (smb_fname == NULL) {
333 0 : return false;
334 : }
335 :
336 0 : ret = SMB_VFS_STAT(state.conn_tos->conn, smb_fname);
337 0 : if (ret != 0) {
338 0 : fprintf(stderr, "%s: %s\n", path, strerror(errno));
339 0 : if (state.c->opt_continue_on_error) {
340 0 : return true;
341 : }
342 0 : return false;
343 : }
344 :
345 0 : ok = ad_unconvert(state.mem_ctx,
346 0 : state.conn_tos->conn->vfs_handles,
347 : macos_string_replace_map,
348 : smb_fname,
349 : &converted);
350 0 : if (!ok) {
351 0 : fprintf(stderr, "Converting failed: %s\n", path);
352 0 : if (state.c->opt_continue_on_error) {
353 0 : return true;
354 : }
355 0 : return false;
356 : }
357 :
358 0 : if (converted) {
359 0 : fprintf(stdout, "Converted: %s\n", path);
360 0 : } else if (state.c->opt_verbose) {
361 0 : fprintf(stdout, "%s\n", path);
362 : }
363 0 : return true;
364 : }
365 :
366 0 : static int nftw_cb(const char *path,
367 : const struct stat *sb,
368 : int typeflag,
369 : struct FTW *ftwbuf)
370 : {
371 : bool ok;
372 :
373 0 : if (typeflag == FTW_SL) {
374 0 : if (state.c->opt_verbose) {
375 0 : fprintf(stdout, "Ignoring symlink: %s\n", path);
376 : }
377 0 : return 0;
378 : }
379 :
380 0 : ok = do_unfruit(path);
381 0 : if (!ok) {
382 0 : return -1;
383 : }
384 :
385 0 : return 0;
386 : }
387 :
388 0 : static int net_vfs_stream_to_appledouble(struct net_context *net,
389 : int argc,
390 : const char **argv)
391 : {
392 : int i;
393 : int ret;
394 : bool ok;
395 0 : int rc = 1;
396 :
397 0 : if (argc < 2 || net->display_usage) {
398 0 : net_vfs_stream_to_appledouble_usage();
399 0 : goto done;
400 : }
401 :
402 0 : ret = net_vfs_init(net, argc, argv);
403 0 : if (ret != 0) {
404 0 : goto done;
405 : }
406 :
407 0 : for (i = 1; i < argc; i++) {
408 0 : const char *path = argv[i];
409 :
410 0 : if (path[0] == '/') {
411 0 : fprintf(stderr, "ignoring absolute path: %s\n", path);
412 0 : if (state.c->opt_continue_on_error) {
413 0 : continue;
414 : }
415 0 : goto done;
416 : }
417 :
418 0 : if (!state.c->opt_recursive) {
419 0 : ok = do_unfruit(path);
420 0 : if (!ok) {
421 0 : if (!state.c->opt_continue_on_error) {
422 0 : goto done;
423 : }
424 : }
425 0 : continue;
426 : }
427 :
428 0 : ret = nftw(path,
429 : nftw_cb,
430 : 256,
431 0 : state.c->opt_follow_symlink ? 0 : FTW_PHYS);
432 0 : if (ret != 0) {
433 0 : fprintf(stderr, "%s: %s\n", path, strerror(errno));
434 0 : if (!state.c->opt_continue_on_error) {
435 0 : goto done;
436 : }
437 : }
438 : }
439 :
440 0 : rc = 0;
441 :
442 0 : done:
443 0 : return rc;
444 : }
445 :
446 : static struct functable func[] = {
447 : {
448 : "getntacl",
449 : net_vfs_get_ntacl,
450 : NET_TRANSPORT_LOCAL,
451 : N_("Display security descriptor of a file or directory"),
452 : N_("net vfs getntacl <share> <path> [<path> ...]")
453 : },
454 : {
455 : NET_VFS_CMD_STREAM_TO_ADOUBLE,
456 : net_vfs_stream_to_appledouble,
457 : NET_TRANSPORT_LOCAL,
458 : N_("Convert streams to AppleDouble files"),
459 : N_("net vfs " NET_VFS_CMD_STREAM_TO_ADOUBLE " [OPTIONS] <share> <path> [<path> ...]")
460 : },
461 : {NULL, NULL, 0, NULL, NULL}
462 : };
463 :
464 0 : int net_vfs(struct net_context *c, int argc, const char **argv)
465 : {
466 0 : return net_run_function(c, argc, argv, "net vfs", func);
467 : }
|