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