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