LCOV - code coverage report
Current view: top level - source3/utils - net_usershare.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 207 590 35.1 %
Date: 2024-02-28 12:06:22 Functions: 9 16 56.2 %

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

Generated by: LCOV version 1.14