s3:utils: Call gfree_all() before exit in sharesec
[samba.git] / source3 / utils / net_vfs.c
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 static void net_vfs_usage(void)
50 {
51         fprintf(stderr,
52                 "Usage:\n"
53                 "net vfs [OPTIONS] <share> ....\n");
54 }
55
56 static void net_vfs_getntacl_usage(void)
57 {
58         fprintf(stderr,
59                 "Usage:\n"
60                 "net vfs getntacl <share> <path>\n");
61 }
62
63 static void net_vfs_stream_to_appledouble_usage(void)
64 {
65         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 }
75
76 static bool net_vfs_make_session_info(struct auth_session_info **session_info)
77 {
78         NTSTATUS status;
79
80         if (non_root_mode()) {
81                 struct passwd *p = NULL;
82
83                 p = getpwuid(geteuid());
84                 if (p == NULL) {
85                         fprintf(stderr, "getpwuid(%d) failed\n", geteuid());
86                         return false;
87                 }
88
89                 status = make_session_info_from_username(state.mem_ctx,
90                                                          p->pw_name,
91                                                          false,
92                                                          session_info);
93                 if (!NT_STATUS_IS_OK(status)) {
94                         fprintf(stderr, "session_info from username failed\n");
95                         return false;
96                 }
97
98                 return true;
99         }
100
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");
104                 return false;
105         }
106
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");
110                 return false;
111         }
112
113         return true;
114 }
115
116 static int net_vfs_init(struct net_context *c, int argc, const char **argv)
117 {
118         const struct loadparm_substitution *lp_sub =
119                 loadparm_s3_global_substitution();
120         const char *service = NULL;
121         char *share_root = NULL;
122         int snum;
123         NTSTATUS status;
124         bool ok;
125         int rc = 1;
126
127         state = (struct net_vfs_state) {
128                 .c = c,
129                 .mem_ctx = c,
130         };
131
132         if (argc < 1) {
133                 net_vfs_usage();
134                 goto done;
135         }
136
137         if (geteuid() != 0 && !uid_wrapper_enabled()) {
138                 fprintf(stderr, "'net vfs' must be run as root.\n");
139                 goto done;
140         }
141
142         smb_init_locale();
143         umask(0);
144         sec_init();
145         setup_logging("net", DEBUG_STDOUT);
146         lpcfg_set_cmdline(c->lp_ctx, "log level", "0");
147
148         ok = lp_load_with_registry_shares(get_dyn_CONFIGFILE());
149         if (!ok) {
150                 fprintf(stderr, "lp_load_with_registry_shares failed\n");
151                 goto done;
152         }
153
154         ok = locking_init();
155         if (!ok) {
156                 fprintf(stderr, "locking init failed\n");
157                 goto done;
158         }
159
160         ok = net_vfs_make_session_info(&state.session_info);
161         if (!ok) {
162                 goto done;
163         }
164
165         service = argv[0];
166         snum = lp_servicenumber(service);
167         if (snum == -1) {
168                 fprintf(stderr, "unknown service: %s\n", service);
169                 goto done;
170         }
171
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",
175                         service);
176                 goto done;
177         }
178
179         status = create_conn_struct_tos_cwd(global_messaging_context(),
180                                             snum,
181                                             share_root,
182                                             state.session_info,
183                                             &state.conn_tos);
184         if (!NT_STATUS_IS_OK(status)) {
185                 goto done;
186         }
187
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);
191
192         ok = become_user_without_service_by_session(state.conn_tos->conn,
193                                                     state.session_info);
194         if (!ok) {
195                 fprintf(stderr,
196                         "become_user_without_service_by_session failed\n");
197                 goto done;
198         }
199
200         rc = 0;
201 done:
202         return rc;
203 }
204
205 static int net_vfs_get_ntacl(struct net_context *net,
206                              int argc,
207                              const char **argv)
208 {
209         const char *path = NULL;
210         struct smb_filename *smb_fname = NULL;
211         files_struct *fsp = NULL;
212         struct security_descriptor *sd = NULL;
213         NTSTATUS status;
214         int ret;
215         int rc = 1;
216
217         if (argc < 2 || net->display_usage) {
218                 net_vfs_getntacl_usage();
219                 goto done;
220         }
221
222         ret = net_vfs_init(net, argc, argv);
223         if (ret != 0) {
224                 goto done;
225         }
226
227         path = argv[1];
228         smb_fname = synthetic_smb_fname(state.mem_ctx,
229                                         path,
230                                         NULL,
231                                         NULL,
232                                         0,
233                                         0);
234         if (smb_fname == NULL) {
235                 goto done;
236         }
237
238         ret = SMB_VFS_STAT(state.conn_tos->conn, smb_fname);
239         if (ret != 0) {
240                 fprintf(stderr, "stat [%s] failed: %s\n",
241                         smb_fname_str_dbg(smb_fname), strerror(errno));
242                 goto done;
243         }
244
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));
249                 goto done;
250         }
251
252         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         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));
274                 goto done;
275         }
276
277         status = SMB_VFS_FGET_NT_ACL(fsp,
278                                      SECINFO_OWNER|SECINFO_GROUP|SECINFO_DACL,
279                                      talloc_tos(),
280                                      &sd);
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));
284                 goto done;
285         }
286
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),
291                         nt_errstr(status));
292                 goto done;
293         }
294
295         sec_desc_print(NULL, stdout, sd, true);
296
297         rc = 0;
298 done:
299         TALLOC_FREE(sd);
300
301         if (fsp != NULL) {
302                 status = close_file_free(NULL, &fsp, NORMAL_CLOSE);
303                 if (!NT_STATUS_IS_OK(status)) {
304                         DBG_ERR("close_file_free() [%s] failed: %s\n",
305                                 smb_fname_str_dbg(smb_fname),
306                                 nt_errstr(status));
307                         rc = 1;
308                 }
309         }
310         return rc;
311 }
312
313 static bool do_unfruit(const char *path)
314 {
315         struct smb_filename *smb_fname = NULL;
316         char *p = NULL;
317         bool converted;
318         int ret;
319         bool ok;
320
321         p = strrchr_m(path, '/');
322         if (p != NULL) {
323                 if (p[1] == '.' && p[2] == '_') {
324                         return true;
325                 }
326         }
327
328         smb_fname = synthetic_smb_fname(state.mem_ctx,
329                                         path,
330                                         NULL,
331                                         NULL,
332                                         0,
333                                         0);
334         if (smb_fname == NULL) {
335                 return false;
336         }
337
338         ret = SMB_VFS_STAT(state.conn_tos->conn, smb_fname);
339         if (ret != 0) {
340                 fprintf(stderr, "%s: %s\n", path, strerror(errno));
341                 if (state.c->opt_continue_on_error) {
342                         return true;
343                 }
344                 return false;
345         }
346
347         ok = ad_unconvert(state.mem_ctx,
348                           state.conn_tos->conn->vfs_handles,
349                           macos_string_replace_map,
350                           smb_fname,
351                           &converted);
352         if (!ok) {
353                 fprintf(stderr, "Converting failed: %s\n", path);
354                 if (state.c->opt_continue_on_error) {
355                         return true;
356                 }
357                 return false;
358         }
359
360         if (converted) {
361                 fprintf(stdout, "Converted: %s\n", path);
362         } else if (state.c->opt_verbose) {
363                 fprintf(stdout, "%s\n", path);
364         }
365         return true;
366 }
367
368 static int nftw_cb(const char *path,
369                    const struct stat *sb,
370                    int typeflag,
371                    struct FTW *ftwbuf)
372 {
373         bool ok;
374
375         if (typeflag == FTW_SL) {
376                 if (state.c->opt_verbose) {
377                         fprintf(stdout, "Ignoring symlink: %s\n", path);
378                 }
379                 return 0;
380         }
381
382         ok = do_unfruit(path);
383         if (!ok) {
384                 return -1;
385         }
386
387         return 0;
388 }
389
390 static int net_vfs_stream_to_appledouble(struct net_context *net,
391                                          int argc,
392                                          const char **argv)
393 {
394         int i;
395         int ret;
396         bool ok;
397         int rc = 1;
398
399         if (argc < 2 || net->display_usage) {
400                 net_vfs_stream_to_appledouble_usage();
401                 goto done;
402         }
403
404         ret = net_vfs_init(net, argc, argv);
405         if (ret != 0) {
406                 goto done;
407         }
408
409         for (i = 1; i < argc; i++) {
410                 const char *path = argv[i];
411
412                 if (path[0] == '/') {
413                         fprintf(stderr, "ignoring absolute path: %s\n", path);
414                         if (state.c->opt_continue_on_error) {
415                                 continue;
416                         }
417                         goto done;
418                 }
419
420                 if (!state.c->opt_recursive) {
421                         ok = do_unfruit(path);
422                         if (!ok) {
423                                 if (!state.c->opt_continue_on_error) {
424                                         goto done;
425                                 }
426                         }
427                         continue;
428                 }
429
430                 ret = nftw(path,
431                            nftw_cb,
432                            256,
433                            state.c->opt_follow_symlink ? 0 : FTW_PHYS);
434                 if (ret != 0) {
435                         fprintf(stderr, "%s: %s\n", path, strerror(errno));
436                         if (!state.c->opt_continue_on_error) {
437                                 goto done;
438                         }
439                 }
440         }
441
442         rc = 0;
443
444 done:
445         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 int net_vfs(struct net_context *c, int argc, const char **argv)
467 {
468         return net_run_function(c, argc, argv, "net vfs", func);
469 }