r13502: Fix error messages for usershares when smbd is not
[nivanova/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 2 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, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
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         static pstring out;
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         slprintf(out, sizeof(out), "Usershare error code (0x%x)", (unsigned int)us_err);
56         return out;
57 }
58
59 /* The help subsystem for the USERSHARE subcommand */
60
61 static int net_usershare_add_usage(int argc, const char **argv)
62 {
63         char c = *lp_winbind_separator();
64         d_printf(
65                 "net usershare add [-l|--long] <sharename> <path> [<comment>] [<acl>]\n"
66                 "\tAdds the specified share name for this user.\n"
67                 "\t<sharename> is the new share name.\n"
68                 "\t<path> is the path on the filesystem to export.\n"
69                 "\t<comment> is the optional comment for the new share.\n"
70                 "\t<acl> is an optional share acl in the format \"DOMAIN%cname:X,DOMAIN%cname:X,....\"\n"
71                 "\t\t\"X\" represents a permission and can be any one of the characters f, r or d\n"
72                 "\t\twhere \"f\" means full control, \"r\" means read-only, \"d\" means deny access.\n"
73                 "\t\tname may be a domain user or group. For local users use the local server name "
74                 "instead of \"DOMAIN\"\n"
75                 "\t\tThe default acl is \"Everyone:r\" which allows everyone read-only access.\n"
76                 "\tAdd -l or --long to print the info on the newly added share.\n",
77                 c, c );
78         return -1;
79 }
80
81 static int net_usershare_delete_usage(int argc, const char **argv)
82 {
83         d_printf(
84                 "net usershare delete <sharename>\n"\
85                 "\tdeletes the specified share name for this user.\n");
86         return -1;
87 }
88
89 static int net_usershare_info_usage(int argc, const char **argv)
90 {
91         d_printf(
92                 "net usershare info [-l|--long] [wildcard sharename]\n"\
93                 "\tPrints out the path, comment and acl elements of shares that match the wildcard.\n"
94                 "\tBy default only gives info on shares owned by the current user\n"
95                 "\tAdd -l or --long to apply this to all shares\n"
96                 "\tOmit the sharename or use a wildcard of '*' to see all shares\n");
97         return -1;
98 }
99
100 static int net_usershare_list_usage(int argc, const char **argv)
101 {
102         d_printf(
103                 "net usershare list [-l|--long] [wildcard sharename]\n"\
104                 "\tLists the names of all shares that match the wildcard.\n"
105                 "\tBy default only lists shares owned by the current user\n"
106                 "\tAdd -l or --long to apply this to all shares\n"
107                 "\tOmit the sharename or use a wildcard of '*' to see all shares\n");
108         return -1;
109 }
110
111 int net_usershare_usage(int argc, const char **argv)
112 {
113         d_printf("net usershare add <sharename> <path> [<comment>] [<acl>] to add or change a user defined share.\n"
114                 "net usershare delete <sharename> to delete a user defined share.\n"
115                 "net usershare info [-l|--long] [wildcard sharename] to print info about a user defined share.\n"
116                 "net usershare list [-l|--long] [wildcard sharename] to list user defined shares.\n"
117                 "net usershare help\n"\
118                 "\nType \"net usershare help <option>\" to get more information on that option\n\n");
119
120         net_common_flags_usage(argc, argv);
121         return -1;
122 }
123
124 /***************************************************************************
125 ***************************************************************************/
126
127 static void get_basepath(pstring basepath)
128 {
129         pstrcpy(basepath, lp_usershare_path());
130         if (basepath[strlen(basepath)-1] == '/') {
131                 basepath[strlen(basepath)-1] = '\0';
132         }
133 }
134
135 /***************************************************************************
136  Delete a single userlevel share.
137 ***************************************************************************/
138
139 static int net_usershare_delete(int argc, const char **argv)
140 {
141         pstring us_path;
142         char *sharename;
143
144         if (argc != 1) {
145                 return net_usershare_delete_usage(argc, argv);
146         }
147
148         sharename = strdup_lower(argv[0]);
149
150         if (!validate_net_name(sharename, INVALID_SHARENAME_CHARS, strlen(sharename))) {
151                 d_fprintf(stderr, "net usershare delete: share name %s contains "
152                         "invalid characters (any of %s)\n",
153                         sharename, INVALID_SHARENAME_CHARS);
154                 SAFE_FREE(sharename);
155                 return -1;
156         }
157
158         pstrcpy(us_path, lp_usershare_path());
159         pstrcat(us_path, "/");
160         pstrcat(us_path, sharename);
161
162         if (unlink(us_path) != 0) {
163                 d_fprintf(stderr, "net usershare delete: unable to remove usershare %s. "
164                         "Error was %s\n",
165                         us_path, strerror(errno));
166                 SAFE_FREE(sharename);
167                 return -1;
168         }
169         SAFE_FREE(sharename);
170         return 0;
171 }
172
173 /***************************************************************************
174  Data structures to handle a list of usershare files.
175 ***************************************************************************/
176
177 struct file_list {
178         struct file_list *next, *prev;
179         const char *pathname;
180 };
181
182 static struct file_list *flist;
183
184 /***************************************************************************
185 ***************************************************************************/
186
187 static int get_share_list(TALLOC_CTX *ctx, const char *wcard, BOOL only_ours)
188 {
189         SMB_STRUCT_DIR *dp;
190         SMB_STRUCT_DIRENT *de;
191         uid_t myuid = geteuid();
192         struct file_list *fl = NULL;
193         pstring basepath;
194
195         get_basepath(basepath);
196         dp = sys_opendir(basepath);
197         if (!dp) {
198                 d_fprintf(stderr, "get_share_list: cannot open usershare directory %s. Error %s\n",
199                         basepath, strerror(errno) );
200                 return -1;
201         }
202
203         while((de = sys_readdir(dp)) != 0) {
204                 SMB_STRUCT_STAT sbuf;
205                 pstring path;
206                 const char *n = de->d_name;
207
208                 /* Ignore . and .. */
209                 if (*n == '.') {
210                         if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
211                                 continue;
212                         }
213                 }
214
215                 if (!validate_net_name(n, INVALID_SHARENAME_CHARS, strlen(n))) {
216                         d_fprintf(stderr, "get_share_list: ignoring bad share name %s\n",n);
217                         continue;
218                 }
219                 pstrcpy(path, basepath);
220                 pstrcat(path, "/");
221                 pstrcat(path, n);
222
223                 if (sys_lstat(path, &sbuf) != 0) {
224                         d_fprintf(stderr, "get_share_list: can't lstat file %s. Error was %s\n",
225                                 path, strerror(errno) );
226                         continue;
227                 }
228
229                 if (!S_ISREG(sbuf.st_mode)) {
230                         d_fprintf(stderr, "get_share_list: file %s is not a regular file. Ignoring.\n",
231                                 path );
232                         continue;
233                 }
234
235                 if (only_ours && sbuf.st_uid != myuid) {
236                         continue;
237                 }
238
239                 if (!unix_wild_match(wcard, n)) {
240                         continue;
241                 }
242
243                 /* (Finally) - add to list. */ 
244                 fl = TALLOC_P(ctx, struct file_list);
245                 if (!fl) {
246                         return -1;
247                 }
248                 fl->pathname = talloc_strdup(ctx, n);
249                 if (!fl->pathname) {
250                         return -1;
251                 }
252
253                 DLIST_ADD(flist, fl);
254         }
255
256         sys_closedir(dp);
257         return 0;
258 }
259
260 enum priv_op { US_LIST_OP, US_INFO_OP};
261
262 struct priv_info {
263         TALLOC_CTX *ctx;
264         enum priv_op op;
265 };
266
267 /***************************************************************************
268  Call a function for every share on the list.
269 ***************************************************************************/
270
271 static int process_share_list(int (*fn)(struct file_list *, void *), void *priv)
272 {
273         struct file_list *fl;
274         int ret = 0;
275
276         for (fl = flist; fl; fl = fl->next) {
277                 ret = (*fn)(fl, priv);
278         }
279
280         return ret;
281 }
282
283 /***************************************************************************
284  Info function.
285 ***************************************************************************/
286
287 static int info_fn(struct file_list *fl, void *priv)
288 {
289         SMB_STRUCT_STAT sbuf;
290         char **lines = NULL;
291         struct priv_info *pi = (struct priv_info *)priv;
292         TALLOC_CTX *ctx = pi->ctx;
293         int fd = -1;
294         int numlines = 0;
295         SEC_DESC *psd = NULL;
296         pstring basepath;
297         pstring sharepath;
298         pstring comment;
299         pstring acl_str;
300         int num_aces;
301         char sep_str[2];
302         enum usershare_err us_err;
303
304         sep_str[0] = *lp_winbind_separator();
305         sep_str[1] = '\0';
306
307         get_basepath(basepath);
308         pstrcat(basepath, "/");
309         pstrcat(basepath, fl->pathname);
310
311 #ifdef O_NOFOLLOW
312         fd = sys_open(basepath, O_RDONLY|O_NOFOLLOW, 0);
313 #else
314         fd = sys_open(basepath, O_RDONLY, 0);
315 #endif
316
317         if (fd == -1) {
318                 d_fprintf(stderr, "info_fn: unable to open %s. %s\n",
319                         basepath, strerror(errno) );
320                 return -1;
321         }
322
323         /* Paranoia... */
324         if (sys_fstat(fd, &sbuf) != 0) {
325                 d_fprintf(stderr, "info_fn: can't fstat file %s. Error was %s\n",
326                         basepath, strerror(errno) );
327                 close(fd);
328                 return -1;
329         }
330
331         if (!S_ISREG(sbuf.st_mode)) {
332                 d_fprintf(stderr, "info_fn: file %s is not a regular file. Ignoring.\n",
333                         basepath );
334                 close(fd);
335                 return -1;
336         }
337
338         lines = fd_lines_load(fd, &numlines, 10240);
339         close(fd);
340
341         if (lines == NULL) {
342                 return -1;
343         }
344
345         /* Ensure it's well formed. */
346         us_err = parse_usershare_file(ctx, &sbuf, fl->pathname, -1, lines, numlines,
347                                 sharepath,
348                                 comment,
349                                 &psd);
350
351         if (us_err != USERSHARE_OK) {
352                 d_fprintf(stderr, "info_fn: file %s is not a well formed usershare file.\n",
353                         basepath );
354                 d_fprintf(stderr, "info_fn: Error was %s.\n",
355                         get_us_error_code(us_err) );
356                 return -1;
357         }
358
359         pstrcpy(acl_str, "usershare_acl=");
360
361         for (num_aces = 0; num_aces < psd->dacl->num_aces; num_aces++) {
362                 char access_str[2];
363                 const char *domain;
364                 const char *name;
365                 NTSTATUS ntstatus;
366
367                 access_str[1] = '\0';
368
369                 ntstatus = net_lookup_name_from_sid(ctx, &psd->dacl->ace[num_aces].trustee, &domain, &name);
370
371                 if (!NT_STATUS_IS_OK(ntstatus)) {
372                         if (*domain) {
373                                 pstrcat(acl_str, domain);
374                                 pstrcat(acl_str, sep_str);
375                         }
376                         pstrcat(acl_str,name);
377                 } else {
378                         fstring sidstr;
379                         sid_to_string(sidstr, &psd->dacl->ace[num_aces].trustee);
380                         pstrcat(acl_str,sidstr);
381                 }
382                 pstrcat(acl_str, ":");
383
384                 if (psd->dacl->ace[num_aces].type == SEC_ACE_TYPE_ACCESS_DENIED) {
385                         pstrcat(acl_str, "D,");
386                 } else {
387                         if (psd->dacl->ace[num_aces].info.mask & GENERIC_ALL_ACCESS) {
388                                 pstrcat(acl_str, "F,");
389                         } else {
390                                 pstrcat(acl_str, "R,");
391                         }
392                 }
393         }
394
395         acl_str[strlen(acl_str)-1] = '\0';
396
397         if (pi->op == US_INFO_OP) {
398                 d_printf("[%s]\n", fl->pathname );
399                 d_printf("path=%s\n", sharepath );
400                 d_printf("comment=%s\n", comment);
401                 d_printf("%s\n\n", acl_str);
402         } else if (pi->op == US_LIST_OP) {
403                 d_printf("%s\n", fl->pathname);
404         }
405
406         return 0;
407 }
408
409 /***************************************************************************
410  Print out info (internal detail) on userlevel shares.
411 ***************************************************************************/
412
413 static int net_usershare_info(int argc, const char **argv)
414 {
415         fstring wcard;
416         BOOL only_ours = True;
417         int ret = -1;
418         struct priv_info pi;
419         TALLOC_CTX *ctx;
420
421         fstrcpy(wcard, "*");
422
423         if (opt_long_list_entries) {
424                 only_ours = False;
425         }
426
427         switch (argc) {
428                 case 0:
429                         break;
430                 case 1:
431                         fstrcpy(wcard, argv[0]);
432                         break;
433                 default:
434                         return net_usershare_info_usage(argc, argv);
435         }
436
437         strlower_m(wcard);
438
439         ctx = talloc_init("share_info");
440         ret = get_share_list(ctx, wcard, only_ours);
441         if (ret) {
442                 return ret;
443         }
444
445         pi.ctx = ctx;
446         pi.op = US_INFO_OP;
447
448         ret = process_share_list(info_fn, &pi);
449         talloc_destroy(ctx);
450         return ret;
451 }
452
453 /***************************************************************************
454  Add a single userlevel share.
455 ***************************************************************************/
456
457 static int net_usershare_add(int argc, const char **argv)
458 {
459         TALLOC_CTX *ctx = NULL;
460         SMB_STRUCT_STAT sbuf;
461         SMB_STRUCT_STAT lsbuf;
462         char *sharename;
463         pstring full_path;
464         pstring full_path_tmp;
465         const char *us_path;
466         const char *us_comment;
467         const char *arg_acl;
468         char *us_acl;
469         char *file_img;
470         int num_aces = 0;
471         int i;
472         int tmpfd;
473         const char *pacl;
474         size_t to_write;
475         uid_t myeuid = geteuid();
476
477         us_comment = "";
478         arg_acl = "S-1-1-0:R";
479
480         switch (argc) {
481                 case 0:
482                 case 1:
483                 default:
484                         return net_usershare_add_usage(argc, argv);
485                 case 2:
486                         sharename = strdup_lower(argv[0]);
487                         us_path = argv[1];
488                         break;
489                 case 3:
490                         sharename = strdup_lower(argv[0]);
491                         us_path = argv[1];
492                         us_comment = argv[2];
493                         break;
494                 case 4:
495                         sharename = strdup_lower(argv[0]);
496                         us_path = argv[1];
497                         us_comment = argv[2];
498                         arg_acl = argv[3];
499                         break;
500         }
501
502         if (!validate_net_name(sharename, INVALID_SHARENAME_CHARS, strlen(sharename))) {
503                 d_fprintf(stderr, "net usershare add: share name %s contains "
504                         "invalid characters (any of %s)\n",
505                         sharename, INVALID_SHARENAME_CHARS);
506                 SAFE_FREE(sharename);
507                 return -1;
508         }
509
510         /* Disallow shares the same as users. */
511         if (getpwnam(sharename)) {
512                 d_fprintf(stderr, "net usershare add: share name %s is already a valid system user name\n",
513                         sharename );
514                 SAFE_FREE(sharename);
515                 return -1;
516         }
517
518         /* Construct the full path for the usershare file. */
519         get_basepath(full_path);
520         pstrcat(full_path, "/");
521         pstrcpy(full_path_tmp, full_path);
522         pstrcat(full_path, sharename);
523         pstrcat(full_path_tmp, ":tmpXXXXXX");
524
525         /* The path *must* be absolute. */
526         if (us_path[0] != '/') {
527                 d_fprintf(stderr,"net usershare add: path %s is not an absolute path.\n",
528                         us_path);
529                 SAFE_FREE(sharename);
530                 return -1;
531         }
532
533         /* Check the directory to be shared exists. */
534         if (sys_stat(us_path, &sbuf) != 0) {
535                 d_fprintf(stderr, "net usershare add: cannot stat path %s to ensure "
536                         "this is a directory. Error was %s\n",
537                         us_path, strerror(errno) );
538                 SAFE_FREE(sharename);
539                 return -1;
540         }
541
542         if (!S_ISDIR(sbuf.st_mode)) {
543                 d_fprintf(stderr, "net usershare add: path %s is not a directory.\n",
544                         us_path );
545                 SAFE_FREE(sharename);
546                 return -1;
547         }
548
549         /* If we're not root, check if we're restricted to sharing out directories
550            that we own only. */
551
552         if ((myeuid != 0) && lp_usershare_owner_only() && (myeuid != sbuf.st_uid)) {
553                 d_fprintf(stderr, "net usershare add: cannot share path %s as "
554                         "we are restricted to only sharing directories we own.\n"
555                         "\tAsk the administrator to add the line \"usershare owner only = False\" \n"
556                         "\tto the [global] section of the smb.conf to allow this.\n",
557                         us_path );
558                 SAFE_FREE(sharename);
559                 return -1;
560         }
561
562         /* No validation needed on comment. Now go through and validate the
563            acl string. Convert names to SID's as needed. Then run it through
564            parse_usershare_acl to ensure it's valid. */
565
566         ctx = talloc_init("share_info");
567
568         /* Start off the string we'll append to. */
569         us_acl = talloc_strdup(ctx, "");
570
571         pacl = arg_acl;
572         num_aces = 1;
573
574         /* Add the number of ',' characters to get the number of aces. */
575         num_aces += count_chars(pacl,',');
576
577         for (i = 0; i < num_aces; i++) {
578                 DOM_SID sid;
579                 const char *pcolon = strchr_m(pacl, ':');
580                 const char *name;
581
582                 if (pcolon == NULL) {
583                         d_fprintf(stderr, "net usershare add: malformed acl %s (missing ':').\n",
584                                 pacl );
585                         talloc_destroy(ctx);
586                         SAFE_FREE(sharename);
587                         return -1;
588                 }
589
590                 switch(pcolon[1]) {
591                         case 'f':
592                         case 'F':
593                         case 'd':
594                         case 'r':
595                         case 'R':
596                                 break;
597                         default:
598                                 d_fprintf(stderr, "net usershare add: malformed acl %s "
599                                         "(access control must be 'r', 'f', or 'd')\n",
600                                         pacl );
601                                 talloc_destroy(ctx);
602                                 SAFE_FREE(sharename);
603                                 return -1;
604                 }
605
606                 if (pcolon[2] != ',' && pcolon[2] != '\0') {
607                         d_fprintf(stderr, "net usershare add: malformed terminating character for acl %s\n",
608                                 pacl );
609                         talloc_destroy(ctx);
610                         SAFE_FREE(sharename);
611                         return -1;
612                 }
613
614                 /* Get the name */
615                 name = talloc_strndup(ctx, pacl, pcolon - pacl);
616                 if (!string_to_sid(&sid, name)) {
617                         /* Convert to a SID */
618                         NTSTATUS ntstatus = net_lookup_sid_from_name(ctx, name, &sid);
619                         if (!NT_STATUS_IS_OK(ntstatus)) {
620                                 d_fprintf(stderr, "net usershare add: cannot convert name \"%s\" to a SID. %s.",
621                                         name, get_friendly_nt_error_msg(ntstatus) );
622                                 if (NT_STATUS_EQUAL(ntstatus, NT_STATUS_CONNECTION_REFUSED)) {
623                                         d_fprintf(stderr,  " Maybe smbd is not running.\n");
624                                 } else {
625                                         d_fprintf(stderr, "\n");
626                                 }
627                                 talloc_destroy(ctx);
628                                 SAFE_FREE(sharename);
629                                 return -1;
630                         }
631                 }
632                 us_acl = talloc_asprintf_append(us_acl, "%s:%c,", sid_string_static(&sid), pcolon[1]);
633
634                 /* Move to the next ACL entry. */
635                 if (pcolon[2] == ',') {
636                         pacl = &pcolon[3];
637                 }
638         }
639
640         /* Remove the last ',' */
641         us_acl[strlen(us_acl)-1] = '\0';
642
643         /* Create a temporary filename for this share. */
644         tmpfd = smb_mkstemp(full_path_tmp);
645
646         if (tmpfd == -1) {
647                 d_fprintf(stderr, "net usershare add: cannot create tmp file %s\n",
648                                 full_path_tmp );
649                 talloc_destroy(ctx);
650                 SAFE_FREE(sharename);
651                 return -1;
652         }
653
654         /* Ensure we opened the file we thought we did. */
655         if (sys_lstat(full_path_tmp, &lsbuf) != 0) {
656                 d_fprintf(stderr, "net usershare add: cannot lstat tmp file %s\n",
657                                 full_path_tmp );
658                 talloc_destroy(ctx);
659                 SAFE_FREE(sharename);
660                 return -1;
661         }
662
663         /* Check this is the same as the file we opened. */
664         if (sys_fstat(tmpfd, &sbuf) != 0) {
665                 d_fprintf(stderr, "net usershare add: cannot fstat tmp file %s\n",
666                                 full_path_tmp );
667                 talloc_destroy(ctx);
668                 SAFE_FREE(sharename);
669                 return -1;
670         }
671
672         if (!S_ISREG(sbuf.st_mode) || sbuf.st_dev != lsbuf.st_dev || sbuf.st_ino != lsbuf.st_ino) {
673                 d_fprintf(stderr, "net usershare add: tmp file %s is not a regular file ?\n",
674                                 full_path_tmp );
675                 talloc_destroy(ctx);
676                 SAFE_FREE(sharename);
677                 return -1;
678         }
679         
680         if (fchmod(tmpfd, 0644) == -1) {
681                 d_fprintf(stderr, "net usershare add: failed to fchmod tmp file %s to 0644n",
682                                 full_path_tmp );
683                 talloc_destroy(ctx);
684                 SAFE_FREE(sharename);
685                 return -1;
686         }
687
688         /* Create the in-memory image of the file. */
689         file_img = talloc_strdup(ctx, "#VERSION 1\npath=");
690         file_img = talloc_asprintf_append(file_img, "%s\ncomment=%s\nusershare_acl=%s\n",
691                         us_path, us_comment, us_acl );
692
693         to_write = strlen(file_img);
694
695         if (write(tmpfd, file_img, to_write) != to_write) {
696                 d_fprintf(stderr, "net usershare add: failed to write %u bytes to file %s. Error was %s\n",
697                         (unsigned int)to_write, full_path_tmp, strerror(errno));
698                 unlink(full_path_tmp);
699                 talloc_destroy(ctx);
700                 SAFE_FREE(sharename);
701                 return -1;
702         }
703
704         /* Attempt to replace any existing share by this name. */
705         if (rename(full_path_tmp, full_path) != 0) {
706                 unlink(full_path_tmp);
707                 d_fprintf(stderr, "net usershare add: failed to add share %s. Error was %s\n",
708                         sharename, strerror(errno));
709                 talloc_destroy(ctx);
710                 close(tmpfd);
711                 SAFE_FREE(sharename);
712                 return -1;
713         }
714
715         close(tmpfd);
716         talloc_destroy(ctx);
717
718         if (opt_long_list_entries) {
719                 const char *my_argv[2];
720                 my_argv[0] = sharename;
721                 my_argv[1] = NULL;
722                 net_usershare_info(1, argv);
723         }
724
725         SAFE_FREE(sharename);
726         return 0;
727 }
728
729 #if 0
730 /***************************************************************************
731  List function.
732 ***************************************************************************/
733
734 static int list_fn(struct file_list *fl, void *priv)
735 {
736         d_printf("%s\n", fl->pathname);
737         return 0;
738 }
739 #endif
740
741 /***************************************************************************
742  List userlevel shares.
743 ***************************************************************************/
744
745 static int net_usershare_list(int argc, const char **argv)
746 {
747         fstring wcard;
748         BOOL only_ours = True;
749         int ret = -1;
750         struct priv_info pi;
751         TALLOC_CTX *ctx;
752
753         fstrcpy(wcard, "*");
754
755         if (opt_long_list_entries) {
756                 only_ours = False;
757         }
758
759         switch (argc) {
760                 case 0:
761                         break;
762                 case 1:
763                         fstrcpy(wcard, argv[0]);
764                         break;
765                 default:
766                         return net_usershare_list_usage(argc, argv);
767         }
768
769         strlower_m(wcard);
770
771         ctx = talloc_init("share_list");
772         ret = get_share_list(ctx, wcard, only_ours);
773         if (ret) {
774                 return ret;
775         }
776
777         pi.ctx = ctx;
778         pi.op = US_LIST_OP;
779
780         ret = process_share_list(info_fn, &pi);
781         talloc_destroy(ctx);
782         return ret;
783 }
784
785 /***************************************************************************
786  Handle "net usershare help *" subcommands.
787 ***************************************************************************/
788
789 int net_usershare_help(int argc, const char **argv)
790 {
791         struct functable func[] = {
792                 {"ADD", net_usershare_add_usage},
793                 {"DELETE", net_usershare_delete_usage},
794                 {"INFO", net_usershare_info_usage},
795                 {"LIST", net_usershare_list_usage},
796                 {NULL, NULL}};
797
798         return net_run_function(argc, argv, func, net_usershare_usage);
799 }
800
801 /***************************************************************************
802  Entry-point for all the USERSHARE functions.
803 ***************************************************************************/
804
805 int net_usershare(int argc, const char **argv)
806 {
807         SMB_STRUCT_DIR *dp;
808
809         struct functable func[] = {
810                 {"ADD", net_usershare_add},
811                 {"DELETE", net_usershare_delete},
812                 {"INFO", net_usershare_info},
813                 {"LIST", net_usershare_list},
814                 {"HELP", net_usershare_help},
815                 {NULL, NULL}
816         };
817         
818         if (lp_usershare_max_shares() == 0) {
819                 d_fprintf(stderr, "net usershare: usershares are currently disabled\n");
820                 return -1;
821         }
822
823         dp = sys_opendir(lp_usershare_path());
824         if (!dp) {
825                 int err = errno;
826                 d_fprintf(stderr, "net usershare: cannot open usershare directory %s. Error %s\n",
827                         lp_usershare_path(), strerror(err) );
828                 if (err == EACCES) {
829                         d_fprintf(stderr, "You do not have permission to create a usershare. Ask your "
830                                 "administrator to grant you permissions to create a share.\n");
831                 } else if (err == ENOENT) {
832                         d_fprintf(stderr, "Please ask your system administrator to "
833                                 "enable user sharing.\n");
834                 }
835                 return -1;
836         }
837         sys_closedir(dp);
838
839         return net_run_function(argc, argv, func, net_usershare_usage);
840 }