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

Generated by: LCOV version 1.14