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