The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/openzfs/lib/libshare/os/linux/smb.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * CDDL HEADER START
    3  *
    4  * The contents of this file are subject to the terms of the
    5  * Common Development and Distribution License (the "License").
    6  * You may not use this file except in compliance with the License.
    7  *
    8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
    9  * or https://opensource.org/licenses/CDDL-1.0.
   10  * See the License for the specific language governing permissions
   11  * and limitations under the License.
   12  *
   13  * When distributing Covered Code, include this CDDL HEADER in each
   14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
   15  * If applicable, add the following below this CDDL HEADER, with the
   16  * fields enclosed by brackets "[]" replaced with your own identifying
   17  * information: Portions Copyright [yyyy] [name of copyright owner]
   18  *
   19  * CDDL HEADER END
   20  */
   21 
   22 /*
   23  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
   24  * Copyright (c) 2011,2012 Turbo Fredriksson <turbo@bayour.com>, based on nfs.c
   25  *                         by Gunnar Beutner
   26  * Copyright (c) 2019, 2020 by Delphix. All rights reserved.
   27  *
   28  * This is an addition to the zfs device driver to add, modify and remove SMB
   29  * shares using the 'net share' command that comes with Samba.
   30  *
   31  * TESTING
   32  * Make sure that samba listens to 'localhost' (127.0.0.1) and that the options
   33  * 'usershare max shares' and 'usershare owner only' have been reviewed/set
   34  * accordingly (see zfs(8) for information).
   35  *
   36  * Once configuration in samba have been done, test that this
   37  * works with the following three commands (in this case, my ZFS
   38  * filesystem is called 'share/Test1'):
   39  *
   40  *      (root)# net -U root -S 127.0.0.1 usershare add Test1 /share/Test1 \
   41  *              "Comment: /share/Test1" "Everyone:F"
   42  *      (root)# net usershare list | grep -i test
   43  *      (root)# net -U root -S 127.0.0.1 usershare delete Test1
   44  *
   45  * The first command will create a user share that gives everyone full access.
   46  * To limit the access below that, use normal UNIX commands (chmod, chown etc).
   47  */
   48 
   49 #include <time.h>
   50 #include <stdlib.h>
   51 #include <stdio.h>
   52 #include <string.h>
   53 #include <fcntl.h>
   54 #include <sys/wait.h>
   55 #include <unistd.h>
   56 #include <dirent.h>
   57 #include <sys/types.h>
   58 #include <sys/stat.h>
   59 #include <libzfs.h>
   60 #include <libshare.h>
   61 #include "libshare_impl.h"
   62 #include "smb.h"
   63 
   64 static boolean_t smb_available(void);
   65 
   66 static smb_share_t *smb_shares;
   67 static int smb_disable_share(sa_share_impl_t impl_share);
   68 static boolean_t smb_is_share_active(sa_share_impl_t impl_share);
   69 
   70 /*
   71  * Retrieve the list of SMB shares.
   72  */
   73 static int
   74 smb_retrieve_shares(void)
   75 {
   76         int rc = SA_OK;
   77         char file_path[PATH_MAX], line[512], *token, *key, *value;
   78         char *dup_value = NULL, *path = NULL, *comment = NULL, *name = NULL;
   79         char *guest_ok = NULL;
   80         DIR *shares_dir;
   81         FILE *share_file_fp = NULL;
   82         struct dirent *directory;
   83         struct stat eStat;
   84         smb_share_t *shares, *new_shares = NULL;
   85 
   86         /* opendir(), stat() */
   87         shares_dir = opendir(SHARE_DIR);
   88         if (shares_dir == NULL)
   89                 return (SA_SYSTEM_ERR);
   90 
   91         /* Go through the directory, looking for shares */
   92         while ((directory = readdir(shares_dir))) {
   93                 int fd;
   94 
   95                 if (directory->d_name[0] == '.')
   96                         continue;
   97 
   98                 snprintf(file_path, sizeof (file_path),
   99                     "%s/%s", SHARE_DIR, directory->d_name);
  100 
  101                 if ((fd = open(file_path, O_RDONLY | O_CLOEXEC)) == -1) {
  102                         rc = SA_SYSTEM_ERR;
  103                         goto out;
  104                 }
  105 
  106                 if (fstat(fd, &eStat) == -1) {
  107                         close(fd);
  108                         rc = SA_SYSTEM_ERR;
  109                         goto out;
  110                 }
  111 
  112                 if (!S_ISREG(eStat.st_mode)) {
  113                         close(fd);
  114                         continue;
  115                 }
  116 
  117                 if ((share_file_fp = fdopen(fd, "r")) == NULL) {
  118                         close(fd);
  119                         rc = SA_SYSTEM_ERR;
  120                         goto out;
  121                 }
  122 
  123                 name = strdup(directory->d_name);
  124                 if (name == NULL) {
  125                         rc = SA_NO_MEMORY;
  126                         goto out;
  127                 }
  128 
  129                 while (fgets(line, sizeof (line), share_file_fp)) {
  130                         if (line[0] == '#')
  131                                 continue;
  132 
  133                         /* Trim trailing new-line character(s). */
  134                         while (line[strlen(line) - 1] == '\r' ||
  135                             line[strlen(line) - 1] == '\n')
  136                                 line[strlen(line) - 1] = '\0';
  137 
  138                         /* Split the line in two, separated by '=' */
  139                         token = strchr(line, '=');
  140                         if (token == NULL)
  141                                 continue;
  142 
  143                         key = line;
  144                         value = token + 1;
  145                         *token = '\0';
  146 
  147                         dup_value = strdup(value);
  148                         if (dup_value == NULL) {
  149                                 rc = SA_NO_MEMORY;
  150                                 goto out;
  151                         }
  152 
  153                         if (strcmp(key, "path") == 0) {
  154                                 free(path);
  155                                 path = dup_value;
  156                         } else if (strcmp(key, "comment") == 0) {
  157                                 free(comment);
  158                                 comment = dup_value;
  159                         } else if (strcmp(key, "guest_ok") == 0) {
  160                                 free(guest_ok);
  161                                 guest_ok = dup_value;
  162                         } else
  163                                 free(dup_value);
  164 
  165                         dup_value = NULL;
  166 
  167                         if (path == NULL || comment == NULL || guest_ok == NULL)
  168                                 continue; /* Incomplete share definition */
  169                         else {
  170                                 shares = (smb_share_t *)
  171                                     malloc(sizeof (smb_share_t));
  172                                 if (shares == NULL) {
  173                                         rc = SA_NO_MEMORY;
  174                                         goto out;
  175                                 }
  176 
  177                                 (void) strlcpy(shares->name, name,
  178                                     sizeof (shares->name));
  179 
  180                                 (void) strlcpy(shares->path, path,
  181                                     sizeof (shares->path));
  182 
  183                                 (void) strlcpy(shares->comment, comment,
  184                                     sizeof (shares->comment));
  185 
  186                                 shares->guest_ok = atoi(guest_ok);
  187 
  188                                 shares->next = new_shares;
  189                                 new_shares = shares;
  190 
  191                                 free(path);
  192                                 free(comment);
  193                                 free(guest_ok);
  194 
  195                                 path = NULL;
  196                                 comment = NULL;
  197                                 guest_ok = NULL;
  198                         }
  199                 }
  200 
  201 out:
  202                 if (share_file_fp != NULL) {
  203                         fclose(share_file_fp);
  204                         share_file_fp = NULL;
  205                 }
  206 
  207                 free(name);
  208                 free(path);
  209                 free(comment);
  210                 free(guest_ok);
  211 
  212                 name = NULL;
  213                 path = NULL;
  214                 comment = NULL;
  215                 guest_ok = NULL;
  216         }
  217         closedir(shares_dir);
  218 
  219         smb_shares = new_shares;
  220 
  221         return (rc);
  222 }
  223 
  224 /*
  225  * Used internally by smb_enable_share to enable sharing for a single host.
  226  */
  227 static int
  228 smb_enable_share_one(const char *sharename, const char *sharepath)
  229 {
  230         char name[SMB_NAME_MAX], comment[SMB_COMMENT_MAX];
  231 
  232         /* Support ZFS share name regexp '[[:alnum:]_-.: ]' */
  233         strlcpy(name, sharename, sizeof (name));
  234         for (char *itr = name; *itr != '\0'; ++itr)
  235                 switch (*itr) {
  236                 case '/':
  237                 case '-':
  238                 case ':':
  239                 case ' ':
  240                         *itr = '_';
  241                 }
  242 
  243         /*
  244          * CMD: net -S NET_CMD_ARG_HOST usershare add Test1 /share/Test1 \
  245          *      "Comment" "Everyone:F"
  246          */
  247         snprintf(comment, sizeof (comment), "Comment: %s", sharepath);
  248 
  249         char *argv[] = {
  250                 (char *)NET_CMD_PATH,
  251                 (char *)"-S",
  252                 (char *)NET_CMD_ARG_HOST,
  253                 (char *)"usershare",
  254                 (char *)"add",
  255                 name,
  256                 (char *)sharepath,
  257                 comment,
  258                 (char *)"Everyone:F",
  259                 NULL,
  260         };
  261 
  262         if (libzfs_run_process(argv[0], argv, 0) != 0)
  263                 return (SA_SYSTEM_ERR);
  264 
  265         /* Reload the share file */
  266         (void) smb_retrieve_shares();
  267 
  268         return (SA_OK);
  269 }
  270 
  271 /*
  272  * Enables SMB sharing for the specified share.
  273  */
  274 static int
  275 smb_enable_share(sa_share_impl_t impl_share)
  276 {
  277         if (!smb_available())
  278                 return (SA_SYSTEM_ERR);
  279 
  280         if (smb_is_share_active(impl_share))
  281                 smb_disable_share(impl_share);
  282 
  283         if (impl_share->sa_shareopts == NULL) /* on/off */
  284                 return (SA_SYSTEM_ERR);
  285 
  286         if (strcmp(impl_share->sa_shareopts, "off") == 0)
  287                 return (SA_OK);
  288 
  289         /* Magic: Enable (i.e., 'create new') share */
  290         return (smb_enable_share_one(impl_share->sa_zfsname,
  291             impl_share->sa_mountpoint));
  292 }
  293 
  294 /*
  295  * Used internally by smb_disable_share to disable sharing for a single host.
  296  */
  297 static int
  298 smb_disable_share_one(const char *sharename)
  299 {
  300         /* CMD: net -S NET_CMD_ARG_HOST usershare delete Test1 */
  301         char *argv[] = {
  302                 (char *)NET_CMD_PATH,
  303                 (char *)"-S",
  304                 (char *)NET_CMD_ARG_HOST,
  305                 (char *)"usershare",
  306                 (char *)"delete",
  307                 (char *)sharename,
  308                 NULL,
  309         };
  310 
  311         if (libzfs_run_process(argv[0], argv, 0) != 0)
  312                 return (SA_SYSTEM_ERR);
  313         else
  314                 return (SA_OK);
  315 }
  316 
  317 /*
  318  * Disables SMB sharing for the specified share.
  319  */
  320 static int
  321 smb_disable_share(sa_share_impl_t impl_share)
  322 {
  323         if (!smb_available()) {
  324                 /*
  325                  * The share can't possibly be active, so nothing
  326                  * needs to be done to disable it.
  327                  */
  328                 return (SA_OK);
  329         }
  330 
  331         for (const smb_share_t *i = smb_shares; i != NULL; i = i->next)
  332                 if (strcmp(impl_share->sa_mountpoint, i->path) == 0)
  333                         return (smb_disable_share_one(i->name));
  334 
  335         return (SA_OK);
  336 }
  337 
  338 /*
  339  * Checks whether the specified SMB share options are syntactically correct.
  340  */
  341 static int
  342 smb_validate_shareopts(const char *shareopts)
  343 {
  344         /* TODO: Accept 'name' and sec/acl (?) */
  345         if ((strcmp(shareopts, "off") == 0) || (strcmp(shareopts, "on") == 0))
  346                 return (SA_OK);
  347 
  348         return (SA_SYNTAX_ERR);
  349 }
  350 
  351 /*
  352  * Checks whether a share is currently active.
  353  */
  354 static boolean_t
  355 smb_is_share_active(sa_share_impl_t impl_share)
  356 {
  357         if (!smb_available())
  358                 return (B_FALSE);
  359 
  360         /* Retrieve the list of (possible) active shares */
  361         smb_retrieve_shares();
  362 
  363         for (const smb_share_t *i = smb_shares; i != NULL; i = i->next)
  364                 if (strcmp(impl_share->sa_mountpoint, i->path) == 0)
  365                         return (B_TRUE);
  366 
  367         return (B_FALSE);
  368 }
  369 
  370 static int
  371 smb_update_shares(void)
  372 {
  373         /* Not implemented */
  374         return (0);
  375 }
  376 
  377 const sa_fstype_t libshare_smb_type = {
  378         .enable_share = smb_enable_share,
  379         .disable_share = smb_disable_share,
  380         .is_shared = smb_is_share_active,
  381 
  382         .validate_shareopts = smb_validate_shareopts,
  383         .commit_shares = smb_update_shares,
  384 };
  385 
  386 /*
  387  * Provides a convenient wrapper for determining SMB availability
  388  */
  389 static boolean_t
  390 smb_available(void)
  391 {
  392         static int avail;
  393 
  394         if (!avail) {
  395                 struct stat statbuf;
  396 
  397                 if (access(NET_CMD_PATH, F_OK) != 0 ||
  398                     lstat(SHARE_DIR, &statbuf) != 0 ||
  399                     !S_ISDIR(statbuf.st_mode))
  400                         avail = -1;
  401                 else
  402                         avail = 1;
  403         }
  404 
  405         return (avail == 1);
  406 }

Cache object: 19e5fdb8a7ae1d18409dc0f2e47342ad


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.