s3-secdesc: remove "typedef struct security_descriptor SEC_DESC".
[samba.git] / source3 / utils / net_usershare.c
1 /*
2    Samba Unix/Linux SMB client library
3    Distributed SMB/CIFS Server Management Utility
4
5    Copyright (C) Jeremy Allison (jra@samba.org) 2005
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "utils/net.h"
23
24 struct {
25         const char *us_errstr;
26         enum usershare_err us_err;
27 } us_errs [] = {
28         {"",USERSHARE_OK},
29         {N_("Malformed usershare file"), USERSHARE_MALFORMED_FILE},
30         {N_("Bad version number"), USERSHARE_BAD_VERSION},
31         {N_("Malformed path entry"), USERSHARE_MALFORMED_PATH},
32         {N_("Malformed comment entryfile"), USERSHARE_MALFORMED_COMMENT_DEF},
33         {N_("Malformed acl definition"), USERSHARE_MALFORMED_ACL_DEF},
34         {N_("Acl parse error"), USERSHARE_ACL_ERR},
35         {N_("Path not absolute"), USERSHARE_PATH_NOT_ABSOLUTE},
36         {N_("Path is denied"), USERSHARE_PATH_IS_DENIED},
37         {N_("Path not allowed"), USERSHARE_PATH_NOT_ALLOWED},
38         {N_("Path is not a directory"), USERSHARE_PATH_NOT_DIRECTORY},
39         {N_("System error"), USERSHARE_POSIX_ERR},
40         {N_("Malformed sharename definition"), USERSHARE_MALFORMED_SHARENAME_DEF},
41         {N_("Bad sharename (doesn't match filename)"), USERSHARE_BAD_SHARENAME},
42         {NULL,(enum usershare_err)-1}
43 };
44
45 static const char *get_us_error_code(enum usershare_err us_err)
46 {
47         char *result;
48         int idx = 0;
49
50         while (us_errs[idx].us_errstr != NULL) {
51                 if (us_errs[idx].us_err == us_err) {
52                         return us_errs[idx].us_errstr;
53                 }
54                 idx++;
55         }
56
57         result = talloc_asprintf(talloc_tos(), _("Usershare error code (0x%x)"),
58                                  (unsigned int)us_err);
59         SMB_ASSERT(result != NULL);
60         return result;
61 }
62
63 /* The help subsystem for the USERSHARE subcommand */
64
65 static int net_usershare_add_usage(struct net_context *c, int argc, const char **argv)
66 {
67         char chr = *lp_winbind_separator();
68         d_printf(_(
69                 "net usershare add [-l|--long] <sharename> <path> [<comment>] [<acl>] [<guest_ok=[y|n]>]\n"
70                 "\tAdds the specified share name for this user.\n"
71                 "\t<sharename> is the new share name.\n"
72                 "\t<path> is the path on the filesystem to export.\n"
73                 "\t<comment> is the optional comment for the new share.\n"
74                 "\t<acl> is an optional share acl in the format \"DOMAIN%cname:X,DOMAIN%cname:X,....\"\n"
75                 "\t<guest_ok=y> if present sets \"guest ok = yes\" on this usershare.\n"
76                 "\t\t\"X\" represents a permission and can be any one of the characters f, r or d\n"
77                 "\t\twhere \"f\" means full control, \"r\" means read-only, \"d\" means deny access.\n"
78                 "\t\tname may be a domain user or group. For local users use the local server name "
79                 "instead of \"DOMAIN\"\n"
80                 "\t\tThe default acl is \"Everyone:r\" which allows everyone read-only access.\n"
81                 "\tAdd -l or --long to print the info on the newly added share.\n"),
82                 chr, chr );
83         return -1;
84 }
85
86 static int net_usershare_delete_usage(struct net_context *c, int argc, const char **argv)
87 {
88         d_printf(_(
89                 "net usershare delete <sharename>\n"
90                 "\tdeletes the specified share name for this user.\n"));
91         return -1;
92 }
93
94 static int net_usershare_info_usage(struct net_context *c, int argc, const char **argv)
95 {
96         d_printf(_(
97                 "net usershare info [-l|--long] [wildcard sharename]\n"
98                 "\tPrints out the path, comment and acl elements of shares that match the wildcard.\n"
99                 "\tBy default only gives info on shares owned by the current user\n"
100                 "\tAdd -l or --long to apply this to all shares\n"
101                 "\tOmit the sharename or use a wildcard of '*' to see all shares\n"));
102         return -1;
103 }
104
105 static int net_usershare_list_usage(struct net_context *c, int argc, const char **argv)
106 {
107         d_printf(_(
108                 "net usershare list [-l|--long] [wildcard sharename]\n"
109                 "\tLists the names of all shares that match the wildcard.\n"
110                 "\tBy default only lists shares owned by the current user\n"
111                 "\tAdd -l or --long to apply this to all shares\n"
112                 "\tOmit the sharename or use a wildcard of '*' to see all shares\n"));
113         return -1;
114 }
115
116 int net_usershare_usage(struct net_context *c, int argc, const char **argv)
117 {
118         d_printf(_("net usershare add <sharename> <path> [<comment>] [<acl>] [<guest_ok=[y|n]>] to "
119                                 "add or change a user defined share.\n"
120                 "net usershare delete <sharename> to delete a user defined share.\n"
121                 "net usershare info [-l|--long] [wildcard sharename] to print info about a user defined share.\n"
122                 "net usershare list [-l|--long] [wildcard sharename] to list user defined shares.\n"
123                 "net usershare help\n"
124                 "\nType \"net usershare help <option>\" to get more information on that option\n\n"));
125
126         net_common_flags_usage(c, argc, argv);
127         return -1;
128 }
129
130 /***************************************************************************
131 ***************************************************************************/
132
133 static char *get_basepath(TALLOC_CTX *ctx)
134 {
135         char *basepath = talloc_strdup(ctx, lp_usershare_path());
136
137         if (!basepath) {
138                 return NULL;
139         }
140         if ((basepath[0] != '\0') && (basepath[strlen(basepath)-1] == '/')) {
141                 basepath[strlen(basepath)-1] = '\0';
142         }
143         return basepath;
144 }
145
146 /***************************************************************************
147  Delete a single userlevel share.
148 ***************************************************************************/
149
150 static int net_usershare_delete(struct net_context *c, int argc, const char **argv)
151 {
152         char *us_path;
153         char *sharename;
154
155         if (argc != 1 || c->display_usage) {
156                 return net_usershare_delete_usage(c, argc, argv);
157         }
158
159         if ((sharename = strlower_talloc(talloc_tos(), argv[0])) == NULL) {
160                 d_fprintf(stderr, _("strlower_talloc failed\n"));
161                 return -1;
162         }
163
164         if (!validate_net_name(sharename, INVALID_SHARENAME_CHARS, strlen(sharename))) {
165                 d_fprintf(stderr, _("net usershare delete: share name %s contains "
166                         "invalid characters (any of %s)\n"),
167                         sharename, INVALID_SHARENAME_CHARS);
168                 TALLOC_FREE(sharename);
169                 return -1;
170         }
171
172         us_path = talloc_asprintf(talloc_tos(),
173                                 "%s/%s",
174                                 lp_usershare_path(),
175                                 sharename);
176         if (!us_path) {
177                 TALLOC_FREE(sharename);
178                 return -1;
179         }
180
181         if (unlink(us_path) != 0) {
182                 d_fprintf(stderr, _("net usershare delete: unable to remove usershare %s. "
183                         "Error was %s\n"),
184                         us_path, strerror(errno));
185                 TALLOC_FREE(sharename);
186                 return -1;
187         }
188         TALLOC_FREE(sharename);
189         return 0;
190 }
191
192 /***************************************************************************
193  Data structures to handle a list of usershare files.
194 ***************************************************************************/
195
196 struct file_list {
197         struct file_list *next, *prev;
198         const char *pathname;
199 };
200
201 static struct file_list *flist;
202
203 /***************************************************************************
204 ***************************************************************************/
205
206 static int get_share_list(TALLOC_CTX *ctx, const char *wcard, bool only_ours)
207 {
208         SMB_STRUCT_DIR *dp;
209         SMB_STRUCT_DIRENT *de;
210         uid_t myuid = geteuid();
211         struct file_list *fl = NULL;
212         char *basepath = get_basepath(ctx);
213
214         if (!basepath) {
215                 return -1;
216         }
217         dp = sys_opendir(basepath);
218         if (!dp) {
219                 d_fprintf(stderr,
220                         _("get_share_list: cannot open usershare directory %s. "
221                           "Error %s\n"),
222                         basepath, strerror(errno) );
223                 return -1;
224         }
225
226         while((de = sys_readdir(dp)) != 0) {
227                 SMB_STRUCT_STAT sbuf;
228                 char *path;
229                 const char *n = de->d_name;
230
231                 /* Ignore . and .. */
232                 if (*n == '.') {
233                         if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
234                                 continue;
235                         }
236                 }
237
238                 if (!validate_net_name(n, INVALID_SHARENAME_CHARS, strlen(n))) {
239                         d_fprintf(stderr,
240                                   _("get_share_list: ignoring bad share "
241                                     "name %s\n"), n);
242                         continue;
243                 }
244                 path = talloc_asprintf(ctx,
245                                         "%s/%s",
246                                         basepath,
247                                         n);
248                 if (!path) {
249                         sys_closedir(dp);
250                         return -1;
251                 }
252
253                 if (sys_lstat(path, &sbuf, false) != 0) {
254                         d_fprintf(stderr,
255                                 _("get_share_list: can't lstat file %s. Error "
256                                   "was %s\n"),
257                                 path, strerror(errno) );
258                         continue;
259                 }
260
261                 if (!S_ISREG(sbuf.st_ex_mode)) {
262                         d_fprintf(stderr,
263                                   _("get_share_list: file %s is not a regular "
264                                     "file. Ignoring.\n"),
265                                 path );
266                         continue;
267                 }
268
269                 if (only_ours && sbuf.st_ex_uid != myuid) {
270                         continue;
271                 }
272
273                 if (!unix_wild_match(wcard, n)) {
274                         continue;
275                 }
276
277                 /* (Finally) - add to list. */
278                 fl = TALLOC_P(ctx, struct file_list);
279                 if (!fl) {
280                         sys_closedir(dp);
281                         return -1;
282                 }
283                 fl->pathname = talloc_strdup(ctx, n);
284                 if (!fl->pathname) {
285                         sys_closedir(dp);
286                         return -1;
287                 }
288
289                 DLIST_ADD(flist, fl);
290         }
291
292         sys_closedir(dp);
293         return 0;
294 }
295
296 enum us_priv_op { US_LIST_OP, US_INFO_OP};
297
298 struct us_priv_info {
299         TALLOC_CTX *ctx;
300         enum us_priv_op op;
301         struct net_context *c;
302 };
303
304 /***************************************************************************
305  Call a function for every share on the list.
306 ***************************************************************************/
307
308 static int process_share_list(int (*fn)(struct file_list *, void *), void *priv)
309 {
310         struct file_list *fl;
311         int ret = 0;
312
313         for (fl = flist; fl; fl = fl->next) {
314                 ret = (*fn)(fl, priv);
315         }
316
317         return ret;
318 }
319
320 /***************************************************************************
321  Info function.
322 ***************************************************************************/
323
324 static int info_fn(struct file_list *fl, void *priv)
325 {
326         SMB_STRUCT_STAT sbuf;
327         char **lines = NULL;
328         struct us_priv_info *pi = (struct us_priv_info *)priv;
329         TALLOC_CTX *ctx = pi->ctx;
330         struct net_context *c = pi->c;
331         int fd = -1;
332         int numlines = 0;
333         struct security_descriptor *psd = NULL;
334         char *basepath;
335         char *sharepath = NULL;
336         char *comment = NULL;
337         char *cp_sharename = NULL;
338         char *acl_str;
339         int num_aces;
340         char sep_str[2];
341         enum usershare_err us_err;
342         bool guest_ok = false;
343
344         sep_str[0] = *lp_winbind_separator();
345         sep_str[1] = '\0';
346
347         basepath = get_basepath(ctx);
348         if (!basepath) {
349                 return -1;
350         }
351         basepath = talloc_asprintf_append(basepath,
352                         "/%s",
353                         fl->pathname);
354         if (!basepath) {
355                 return -1;
356         }
357
358 #ifdef O_NOFOLLOW
359         fd = sys_open(basepath, O_RDONLY|O_NOFOLLOW, 0);
360 #else
361         fd = sys_open(basepath, O_RDONLY, 0);
362 #endif
363
364         if (fd == -1) {
365                 d_fprintf(stderr, _("info_fn: unable to open %s. %s\n"),
366                         basepath, strerror(errno) );
367                 return -1;
368         }
369
370         /* Paranoia... */
371         if (sys_fstat(fd, &sbuf, false) != 0) {
372                 d_fprintf(stderr,
373                         _("info_fn: can't fstat file %s. Error was %s\n"),
374                         basepath, strerror(errno) );
375                 close(fd);
376                 return -1;
377         }
378
379         if (!S_ISREG(sbuf.st_ex_mode)) {
380                 d_fprintf(stderr,
381                         _("info_fn: file %s is not a regular file. Ignoring.\n"),
382                         basepath );
383                 close(fd);
384                 return -1;
385         }
386
387         lines = fd_lines_load(fd, &numlines, 10240, NULL);
388         close(fd);
389
390         if (lines == NULL) {
391                 return -1;
392         }
393
394         /* Ensure it's well formed. */
395         us_err = parse_usershare_file(ctx, &sbuf, fl->pathname, -1, lines, numlines,
396                                 &sharepath,
397                                 &comment,
398                                 &cp_sharename,
399                                 &psd,
400                                 &guest_ok);
401
402         TALLOC_FREE(lines);
403
404         if (us_err != USERSHARE_OK) {
405                 d_fprintf(stderr,
406                         _("info_fn: file %s is not a well formed usershare "
407                           "file.\n"),
408                         basepath );
409                 d_fprintf(stderr, _("info_fn: Error was %s.\n"),
410                         get_us_error_code(us_err) );
411                 return -1;
412         }
413
414         acl_str = talloc_strdup(ctx, "usershare_acl=");
415         if (!acl_str) {
416                 return -1;
417         }
418
419         for (num_aces = 0; num_aces < psd->dacl->num_aces; num_aces++) {
420                 const char *domain;
421                 const char *name;
422                 NTSTATUS ntstatus;
423
424                 ntstatus = net_lookup_name_from_sid(c, ctx,
425                                                     &psd->dacl->aces[num_aces].trustee,
426                                                     &domain, &name);
427
428                 if (NT_STATUS_IS_OK(ntstatus)) {
429                         if (domain && *domain) {
430                                 acl_str = talloc_asprintf_append(acl_str,
431                                                 "%s%s",
432                                                 domain,
433                                                 sep_str);
434                                 if (!acl_str) {
435                                         return -1;
436                                 }
437                         }
438                         acl_str = talloc_asprintf_append(acl_str,
439                                                 "%s",
440                                                 name);
441                         if (!acl_str) {
442                                 return -1;
443                         }
444
445                 } else {
446                         fstring sidstr;
447                         sid_to_fstring(sidstr,
448                                        &psd->dacl->aces[num_aces].trustee);
449                         acl_str = talloc_asprintf_append(acl_str,
450                                                 "%s",
451                                                 sidstr);
452                         if (!acl_str) {
453                                 return -1;
454                         }
455                 }
456                 acl_str = talloc_asprintf_append(acl_str, ":");
457                 if (!acl_str) {
458                         return -1;
459                 }
460
461                 if (psd->dacl->aces[num_aces].type == SEC_ACE_TYPE_ACCESS_DENIED) {
462                         acl_str = talloc_asprintf_append(acl_str, "D,");
463                         if (!acl_str) {
464                                 return -1;
465                         }
466                 } else {
467                         if (psd->dacl->aces[num_aces].access_mask & GENERIC_ALL_ACCESS) {
468                                 acl_str = talloc_asprintf_append(acl_str, "F,");
469                         } else {
470                                 acl_str = talloc_asprintf_append(acl_str, "R,");
471                         }
472                         if (!acl_str) {
473                                 return -1;
474                         }
475                 }
476         }
477
478         /* NOTE: This is smb.conf-like output. Do not translate. */
479         if (pi->op == US_INFO_OP) {
480                 d_printf("[%s]\n", cp_sharename );
481                 d_printf("path=%s\n", sharepath );
482                 d_printf("comment=%s\n", comment);
483                 d_printf("%s\n", acl_str);
484                 d_printf("guest_ok=%c\n\n", guest_ok ? 'y' : 'n');
485         } else if (pi->op == US_LIST_OP) {
486                 d_printf("%s\n", cp_sharename);
487         }
488
489         return 0;
490 }
491
492 /***************************************************************************
493  Print out info (internal detail) on userlevel shares.
494 ***************************************************************************/
495
496 static int net_usershare_info(struct net_context *c, int argc, const char **argv)
497 {
498         fstring wcard;
499         bool only_ours = true;
500         int ret = -1;
501         struct us_priv_info pi;
502         TALLOC_CTX *ctx;
503
504         fstrcpy(wcard, "*");
505
506         if (c->display_usage)
507                 return net_usershare_info_usage(c, argc, argv);
508
509         if (c->opt_long_list_entries) {
510                 only_ours = false;
511         }
512
513         switch (argc) {
514                 case 0:
515                         break;
516                 case 1:
517                         fstrcpy(wcard, argv[0]);
518                         break;
519                 default:
520                         return net_usershare_info_usage(c, argc, argv);
521         }
522
523         strlower_m(wcard);
524
525         ctx = talloc_init("share_info");
526         ret = get_share_list(ctx, wcard, only_ours);
527         if (ret) {
528                 return ret;
529         }
530
531         pi.ctx = ctx;
532         pi.op = US_INFO_OP;
533         pi.c = c;
534
535         ret = process_share_list(info_fn, &pi);
536         talloc_destroy(ctx);
537         return ret;
538 }
539
540 /***************************************************************************
541  Count the current total number of usershares.
542 ***************************************************************************/
543
544 static int count_num_usershares(void)
545 {
546         SMB_STRUCT_DIR *dp;
547         SMB_STRUCT_DIRENT *de;
548         int num_usershares = 0;
549         TALLOC_CTX *ctx = talloc_tos();
550         char *basepath = get_basepath(ctx);
551
552         if (!basepath) {
553                 return -1;
554         }
555
556         dp = sys_opendir(basepath);
557         if (!dp) {
558                 d_fprintf(stderr,
559                         _("count_num_usershares: cannot open usershare "
560                           "directory %s. Error %s\n"),
561                         basepath, strerror(errno) );
562                 return -1;
563         }
564
565         while((de = sys_readdir(dp)) != 0) {
566                 SMB_STRUCT_STAT sbuf;
567                 char *path;
568                 const char *n = de->d_name;
569
570                 /* Ignore . and .. */
571                 if (*n == '.') {
572                         if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
573                                 continue;
574                         }
575                 }
576
577                 if (!validate_net_name(n, INVALID_SHARENAME_CHARS, strlen(n))) {
578                         d_fprintf(stderr,
579                                   _("count_num_usershares: ignoring bad share "
580                                     "name %s\n"), n);
581                         continue;
582                 }
583                 path = talloc_asprintf(ctx,
584                                 "%s/%s",
585                                 basepath,
586                                 n);
587                 if (!path) {
588                         sys_closedir(dp);
589                         return -1;
590                 }
591
592                 if (sys_lstat(path, &sbuf, false) != 0) {
593                         d_fprintf(stderr,
594                                 _("count_num_usershares: can't lstat file %s. "
595                                   "Error was %s\n"),
596                                 path, strerror(errno) );
597                         continue;
598                 }
599
600                 if (!S_ISREG(sbuf.st_ex_mode)) {
601                         d_fprintf(stderr,
602                                 _("count_num_usershares: file %s is not a "
603                                   "regular file. Ignoring.\n"),
604                                 path );
605                         continue;
606                 }
607                 num_usershares++;
608         }
609
610         sys_closedir(dp);
611         return num_usershares;
612 }
613
614 /***************************************************************************
615  Add a single userlevel share.
616 ***************************************************************************/
617
618 static int net_usershare_add(struct net_context *c, int argc, const char **argv)
619 {
620         TALLOC_CTX *ctx = talloc_stackframe();
621         SMB_STRUCT_STAT sbuf;
622         SMB_STRUCT_STAT lsbuf;
623         char *sharename;
624         const char *cp_sharename;
625         char *full_path;
626         char *full_path_tmp;
627         const char *us_path;
628         const char *us_comment;
629         const char *arg_acl;
630         char *us_acl;
631         char *file_img;
632         int num_aces = 0;
633         int i;
634         int tmpfd;
635         const char *pacl;
636         size_t to_write;
637         uid_t myeuid = geteuid();
638         bool guest_ok = false;
639         int num_usershares;
640
641         us_comment = "";
642         arg_acl = "S-1-1-0:R";
643
644         if (c->display_usage)
645                 return net_usershare_add_usage(c, argc, argv);
646
647         switch (argc) {
648                 case 0:
649                 case 1:
650                 default:
651                         return net_usershare_add_usage(c, argc, argv);
652                 case 2:
653                         cp_sharename = argv[0];
654                         sharename = strlower_talloc(ctx, argv[0]);
655                         us_path = argv[1];
656                         break;
657                 case 3:
658                         cp_sharename = argv[0];
659                         sharename = strlower_talloc(ctx, argv[0]);
660                         us_path = argv[1];
661                         us_comment = argv[2];
662                         break;
663                 case 4:
664                         cp_sharename = argv[0];
665                         sharename = strlower_talloc(ctx, argv[0]);
666                         us_path = argv[1];
667                         us_comment = argv[2];
668                         arg_acl = argv[3];
669                         break;
670                 case 5:
671                         cp_sharename = argv[0];
672                         sharename = strlower_talloc(ctx, argv[0]);
673                         us_path = argv[1];
674                         us_comment = argv[2];
675                         arg_acl = argv[3];
676                         if (strlen(arg_acl) == 0) {
677                                 arg_acl = "S-1-1-0:R";
678                         }
679                         if (!strnequal(argv[4], "guest_ok=", 9)) {
680                                 TALLOC_FREE(ctx);
681                                 return net_usershare_add_usage(c, argc, argv);
682                         }
683                         switch (argv[4][9]) {
684                                 case 'y':
685                                 case 'Y':
686                                         guest_ok = true;
687                                         break;
688                                 case 'n':
689                                 case 'N':
690                                         guest_ok = false;
691                                         break;
692                                 default:
693                                         TALLOC_FREE(ctx);
694                                         return net_usershare_add_usage(c, argc, argv);
695                         }
696                         break;
697         }
698
699         /* Ensure we're under the "usershare max shares" number. Advisory only. */
700         num_usershares = count_num_usershares();
701         if (num_usershares >= lp_usershare_max_shares()) {
702                 d_fprintf(stderr,
703                         _("net usershare add: maximum number of allowed "
704                           "usershares (%d) reached\n"),
705                         lp_usershare_max_shares() );
706                 TALLOC_FREE(ctx);
707                 return -1;
708         }
709
710         if (!validate_net_name(sharename, INVALID_SHARENAME_CHARS, strlen(sharename))) {
711                 d_fprintf(stderr, _("net usershare add: share name %s contains "
712                         "invalid characters (any of %s)\n"),
713                         sharename, INVALID_SHARENAME_CHARS);
714                 TALLOC_FREE(ctx);
715                 return -1;
716         }
717
718         /* Disallow shares the same as users. */
719         if (getpwnam(sharename)) {
720                 d_fprintf(stderr,
721                         _("net usershare add: share name %s is already a valid "
722                           "system user name\n"),
723                         sharename );
724                 TALLOC_FREE(ctx);
725                 return -1;
726         }
727
728         /* Construct the full path for the usershare file. */
729         full_path = get_basepath(ctx);
730         if (!full_path) {
731                 TALLOC_FREE(ctx);
732                 return -1;
733         }
734         full_path_tmp = talloc_asprintf(ctx,
735                         "%s/:tmpXXXXXX",
736                         full_path);
737         if (!full_path_tmp) {
738                 TALLOC_FREE(ctx);
739                 return -1;
740         }
741
742         full_path = talloc_asprintf_append(full_path,
743                                         "/%s",
744                                         sharename);
745         if (!full_path) {
746                 TALLOC_FREE(ctx);
747                 return -1;
748         }
749
750         /* The path *must* be absolute. */
751         if (us_path[0] != '/') {
752                 d_fprintf(stderr,
753                         _("net usershare add: path %s is not an absolute "
754                           "path.\n"),
755                         us_path);
756                 TALLOC_FREE(ctx);
757                 return -1;
758         }
759
760         /* Check the directory to be shared exists. */
761         if (sys_stat(us_path, &sbuf, false) != 0) {
762                 d_fprintf(stderr,
763                         _("net usershare add: cannot stat path %s to ensure "
764                           "this is a directory. Error was %s\n"),
765                         us_path, strerror(errno) );
766                 TALLOC_FREE(ctx);
767                 return -1;
768         }
769
770         if (!S_ISDIR(sbuf.st_ex_mode)) {
771                 d_fprintf(stderr,
772                         _("net usershare add: path %s is not a directory.\n"),
773                         us_path );
774                 TALLOC_FREE(ctx);
775                 return -1;
776         }
777
778         /* If we're not root, check if we're restricted to sharing out directories
779            that we own only. */
780
781         if ((myeuid != 0) && lp_usershare_owner_only() && (myeuid != sbuf.st_ex_uid)) {
782                 d_fprintf(stderr, _("net usershare add: cannot share path %s as "
783                         "we are restricted to only sharing directories we own.\n"
784                         "\tAsk the administrator to add the line \"usershare owner only = false\" \n"
785                         "\tto the [global] section of the smb.conf to allow this.\n"),
786                         us_path );
787                 TALLOC_FREE(ctx);
788                 return -1;
789         }
790
791         /* No validation needed on comment. Now go through and validate the
792            acl string. Convert names to SID's as needed. Then run it through
793            parse_usershare_acl to ensure it's valid. */
794
795         /* Start off the string we'll append to. */
796         us_acl = talloc_strdup(ctx, "");
797         if (!us_acl) {
798                 TALLOC_FREE(ctx);
799                 return -1;
800         }
801
802         pacl = arg_acl;
803         num_aces = 1;
804
805         /* Add the number of ',' characters to get the number of aces. */
806         num_aces += count_chars(pacl,',');
807
808         for (i = 0; i < num_aces; i++) {
809                 DOM_SID sid;
810                 const char *pcolon = strchr_m(pacl, ':');
811                 const char *name;
812
813                 if (pcolon == NULL) {
814                         d_fprintf(stderr,
815                                 _("net usershare add: malformed acl %s "
816                                   "(missing ':').\n"),
817                                 pacl );
818                         TALLOC_FREE(ctx);
819                         return -1;
820                 }
821
822                 switch(pcolon[1]) {
823                         case 'f':
824                         case 'F':
825                         case 'd':
826                         case 'r':
827                         case 'R':
828                                 break;
829                         default:
830                                 d_fprintf(stderr,
831                                         _("net usershare add: malformed acl %s "
832                                           "(access control must be 'r', 'f', "
833                                           "or 'd')\n"),
834                                         pacl );
835                                 TALLOC_FREE(ctx);
836                                 return -1;
837                 }
838
839                 if (pcolon[2] != ',' && pcolon[2] != '\0') {
840                         d_fprintf(stderr,
841                                 _("net usershare add: malformed terminating "
842                                   "character for acl %s\n"),
843                                 pacl );
844                         TALLOC_FREE(ctx);
845                         return -1;
846                 }
847
848                 /* Get the name */
849                 if ((name = talloc_strndup(ctx, pacl, pcolon - pacl)) == NULL) {
850                         d_fprintf(stderr, _("talloc_strndup failed\n"));
851                         TALLOC_FREE(ctx);
852                         return -1;
853                 }
854                 if (!string_to_sid(&sid, name)) {
855                         /* Convert to a SID */
856                         NTSTATUS ntstatus = net_lookup_sid_from_name(c, ctx, name, &sid);
857                         if (!NT_STATUS_IS_OK(ntstatus)) {
858                                 d_fprintf(stderr,
859                                         _("net usershare add: cannot convert "
860                                           "name \"%s\" to a SID. %s."),
861                                         name, get_friendly_nt_error_msg(ntstatus) );
862                                 if (NT_STATUS_EQUAL(ntstatus, NT_STATUS_CONNECTION_REFUSED)) {
863                                         d_fprintf(stderr,
864                                             _(" Maybe smbd is not running.\n"));
865                                 } else {
866                                         d_fprintf(stderr, "\n");
867                                 }
868                                 TALLOC_FREE(ctx);
869                                 return -1;
870                         }
871                 }
872                 us_acl = talloc_asprintf_append(
873                         us_acl, "%s:%c,", sid_string_tos(&sid), pcolon[1]);
874
875                 /* Move to the next ACL entry. */
876                 if (pcolon[2] == ',') {
877                         pacl = &pcolon[3];
878                 }
879         }
880
881         /* Remove the last ',' */
882         us_acl[strlen(us_acl)-1] = '\0';
883
884         if (guest_ok && !lp_usershare_allow_guests()) {
885                 d_fprintf(stderr, _("net usershare add: guest_ok=y requested "
886                         "but the \"usershare allow guests\" parameter is not "
887                         "enabled by this server.\n"));
888                 TALLOC_FREE(ctx);
889                 return -1;
890         }
891
892         /* Create a temporary filename for this share. */
893         tmpfd = mkstemp(full_path_tmp);
894
895         if (tmpfd == -1) {
896                 d_fprintf(stderr,
897                           _("net usershare add: cannot create tmp file %s\n"),
898                           full_path_tmp );
899                 TALLOC_FREE(ctx);
900                 return -1;
901         }
902
903         /* Ensure we opened the file we thought we did. */
904         if (sys_lstat(full_path_tmp, &lsbuf, false) != 0) {
905                 d_fprintf(stderr,
906                           _("net usershare add: cannot lstat tmp file %s\n"),
907                           full_path_tmp );
908                 TALLOC_FREE(ctx);
909                 return -1;
910         }
911
912         /* Check this is the same as the file we opened. */
913         if (sys_fstat(tmpfd, &sbuf, false) != 0) {
914                 d_fprintf(stderr,
915                           _("net usershare add: cannot fstat tmp file %s\n"),
916                           full_path_tmp );
917                 TALLOC_FREE(ctx);
918                 return -1;
919         }
920
921         if (!S_ISREG(sbuf.st_ex_mode) || sbuf.st_ex_dev != lsbuf.st_ex_dev || sbuf.st_ex_ino != lsbuf.st_ex_ino) {
922                 d_fprintf(stderr,
923                           _("net usershare add: tmp file %s is not a regular "
924                             "file ?\n"),
925                           full_path_tmp );
926                 TALLOC_FREE(ctx);
927                 return -1;
928         }
929
930         if (fchmod(tmpfd, 0644) == -1) {
931                 d_fprintf(stderr,
932                           _("net usershare add: failed to fchmod tmp file %s "
933                             "to 0644n"),
934                           full_path_tmp );
935                 TALLOC_FREE(ctx);
936                 return -1;
937         }
938
939         /* Create the in-memory image of the file. */
940         file_img = talloc_strdup(ctx, "#VERSION 2\npath=");
941         file_img = talloc_asprintf_append(file_img,
942                         "%s\ncomment=%s\nusershare_acl=%s\n"
943                         "guest_ok=%c\nsharename=%s\n",
944                         us_path,
945                         us_comment,
946                         us_acl,
947                         guest_ok ? 'y' : 'n',
948                         cp_sharename);
949
950         to_write = strlen(file_img);
951
952         if (write(tmpfd, file_img, to_write) != to_write) {
953                 d_fprintf(stderr,
954                         _("net usershare add: failed to write %u bytes to "
955                           "file %s. Error was %s\n"),
956                         (unsigned int)to_write, full_path_tmp, strerror(errno));
957                 unlink(full_path_tmp);
958                 TALLOC_FREE(ctx);
959                 return -1;
960         }
961
962         /* Attempt to replace any existing share by this name. */
963         if (rename(full_path_tmp, full_path) != 0) {
964                 unlink(full_path_tmp);
965                 d_fprintf(stderr,
966                         _("net usershare add: failed to add share %s. Error "
967                           "was %s\n"),
968                         sharename, strerror(errno));
969                 TALLOC_FREE(ctx);
970                 close(tmpfd);
971                 return -1;
972         }
973
974         close(tmpfd);
975
976         if (c->opt_long_list_entries) {
977                 const char *my_argv[2];
978                 my_argv[0] = sharename;
979                 my_argv[1] = NULL;
980                 net_usershare_info(c, 1, my_argv);
981         }
982
983         TALLOC_FREE(ctx);
984         return 0;
985 }
986
987 #if 0
988 /***************************************************************************
989  List function.
990 ***************************************************************************/
991
992 static int list_fn(struct file_list *fl, void *priv)
993 {
994         d_printf("%s\n", fl->pathname);
995         return 0;
996 }
997 #endif
998
999 /***************************************************************************
1000  List userlevel shares.
1001 ***************************************************************************/
1002
1003 static int net_usershare_list(struct net_context *c, int argc,
1004                               const char **argv)
1005 {
1006         fstring wcard;
1007         bool only_ours = true;
1008         int ret = -1;
1009         struct us_priv_info pi;
1010         TALLOC_CTX *ctx;
1011
1012         fstrcpy(wcard, "*");
1013
1014         if (c->display_usage)
1015                 return net_usershare_list_usage(c, argc, argv);
1016
1017         if (c->opt_long_list_entries) {
1018                 only_ours = false;
1019         }
1020
1021         switch (argc) {
1022                 case 0:
1023                         break;
1024                 case 1:
1025                         fstrcpy(wcard, argv[0]);
1026                         break;
1027                 default:
1028                         return net_usershare_list_usage(c, argc, argv);
1029         }
1030
1031         strlower_m(wcard);
1032
1033         ctx = talloc_init("share_list");
1034         ret = get_share_list(ctx, wcard, only_ours);
1035         if (ret) {
1036                 return ret;
1037         }
1038
1039         pi.ctx = ctx;
1040         pi.op = US_LIST_OP;
1041         pi.c = c;
1042
1043         ret = process_share_list(info_fn, &pi);
1044         talloc_destroy(ctx);
1045         return ret;
1046 }
1047
1048 /***************************************************************************
1049  Entry-point for all the USERSHARE functions.
1050 ***************************************************************************/
1051
1052 int net_usershare(struct net_context *c, int argc, const char **argv)
1053 {
1054         SMB_STRUCT_DIR *dp;
1055
1056         struct functable func[] = {
1057                 {
1058                         "add",
1059                         net_usershare_add,
1060                         NET_TRANSPORT_LOCAL,
1061                         N_("Add/modify user defined share"),
1062                         N_("net usershare add\n"
1063                            "    Add/modify user defined share")
1064                 },
1065                 {
1066                         "delete",
1067                         net_usershare_delete,
1068                         NET_TRANSPORT_LOCAL,
1069                         N_("Delete user defined share"),
1070                         N_("net usershare delete\n"
1071                            "    Delete user defined share")
1072                 },
1073                 {
1074                         "info",
1075                         net_usershare_info,
1076                         NET_TRANSPORT_LOCAL,
1077                         N_("Display information about a user defined share"),
1078                         N_("net usershare info\n"
1079                            "    Display information about a user defined share")
1080                 },
1081                 {
1082                         "list",
1083                         net_usershare_list,
1084                         NET_TRANSPORT_LOCAL,
1085                         N_("List user defined shares"),
1086                         N_("net usershare list\n"
1087                            "    List user defined shares")
1088                 },
1089                 {NULL, NULL, 0, NULL, NULL}
1090         };
1091
1092         if (lp_usershare_max_shares() == 0) {
1093                 d_fprintf(stderr,
1094                           _("net usershare: usershares are currently "
1095                             "disabled\n"));
1096                 return -1;
1097         }
1098
1099         dp = sys_opendir(lp_usershare_path());
1100         if (!dp) {
1101                 int err = errno;
1102                 d_fprintf(stderr,
1103                         _("net usershare: cannot open usershare directory %s. "
1104                           "Error %s\n"),
1105                         lp_usershare_path(), strerror(err) );
1106                 if (err == EACCES) {
1107                         d_fprintf(stderr,
1108                                 _("You do not have permission to create a "
1109                                 "usershare. Ask your administrator to grant "
1110                                 "you permissions to create a share.\n"));
1111                 } else if (err == ENOENT) {
1112                         d_fprintf(stderr,
1113                                 _("Please ask your system administrator to "
1114                                   "enable user sharing.\n"));
1115                 }
1116                 return -1;
1117         }
1118         sys_closedir(dp);
1119
1120         return net_run_function(c, argc, argv, "net usershare", func);
1121 }