diff options
Diffstat (limited to 'lib/libshare/os/linux/smb.c')
-rw-r--r-- | lib/libshare/os/linux/smb.c | 407 |
1 files changed, 0 insertions, 407 deletions
diff --git a/lib/libshare/os/linux/smb.c b/lib/libshare/os/linux/smb.c deleted file mode 100644 index 40996ecc8f89..000000000000 --- a/lib/libshare/os/linux/smb.c +++ /dev/null @@ -1,407 +0,0 @@ -// SPDX-License-Identifier: CDDL-1.0 -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or https://opensource.org/licenses/CDDL-1.0. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ - -/* - * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011,2012 Turbo Fredriksson <turbo@bayour.com>, based on nfs.c - * by Gunnar Beutner - * Copyright (c) 2019, 2020 by Delphix. All rights reserved. - * - * This is an addition to the zfs device driver to add, modify and remove SMB - * shares using the 'net share' command that comes with Samba. - * - * TESTING - * Make sure that samba listens to 'localhost' (127.0.0.1) and that the options - * 'usershare max shares' and 'usershare owner only' have been reviewed/set - * accordingly (see zfs(8) for information). - * - * Once configuration in samba have been done, test that this - * works with the following three commands (in this case, my ZFS - * filesystem is called 'share/Test1'): - * - * (root)# net -U root -S 127.0.0.1 usershare add Test1 /share/Test1 \ - * "Comment: /share/Test1" "Everyone:F" - * (root)# net usershare list | grep -i test - * (root)# net -U root -S 127.0.0.1 usershare delete Test1 - * - * The first command will create a user share that gives everyone full access. - * To limit the access below that, use normal UNIX commands (chmod, chown etc). - */ - -#include <time.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <fcntl.h> -#include <sys/wait.h> -#include <unistd.h> -#include <dirent.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <libzfs.h> -#include <libshare.h> -#include "libshare_impl.h" -#include "smb.h" - -static boolean_t smb_available(void); - -static smb_share_t *smb_shares; -static int smb_disable_share(sa_share_impl_t impl_share); -static boolean_t smb_is_share_active(sa_share_impl_t impl_share); - -/* - * Retrieve the list of SMB shares. - */ -static int -smb_retrieve_shares(void) -{ - int rc = SA_OK; - char file_path[PATH_MAX], line[512], *token, *key, *value; - char *dup_value = NULL, *path = NULL, *comment = NULL, *name = NULL; - char *guest_ok = NULL; - DIR *shares_dir; - FILE *share_file_fp = NULL; - struct dirent *directory; - struct stat eStat; - smb_share_t *shares, *new_shares = NULL; - - /* opendir(), stat() */ - shares_dir = opendir(SHARE_DIR); - if (shares_dir == NULL) - return (SA_SYSTEM_ERR); - - /* Go through the directory, looking for shares */ - while ((directory = readdir(shares_dir))) { - int fd; - - if (directory->d_name[0] == '.') - continue; - - snprintf(file_path, sizeof (file_path), - "%s/%s", SHARE_DIR, directory->d_name); - - if ((fd = open(file_path, O_RDONLY | O_CLOEXEC)) == -1) { - rc = SA_SYSTEM_ERR; - goto out; - } - - if (fstat(fd, &eStat) == -1) { - close(fd); - rc = SA_SYSTEM_ERR; - goto out; - } - - if (!S_ISREG(eStat.st_mode)) { - close(fd); - continue; - } - - if ((share_file_fp = fdopen(fd, "r")) == NULL) { - close(fd); - rc = SA_SYSTEM_ERR; - goto out; - } - - name = strdup(directory->d_name); - if (name == NULL) { - rc = SA_NO_MEMORY; - goto out; - } - - while (fgets(line, sizeof (line), share_file_fp)) { - if (line[0] == '#') - continue; - - /* Trim trailing new-line character(s). */ - while (line[strlen(line) - 1] == '\r' || - line[strlen(line) - 1] == '\n') - line[strlen(line) - 1] = '\0'; - - /* Split the line in two, separated by '=' */ - token = strchr(line, '='); - if (token == NULL) - continue; - - key = line; - value = token + 1; - *token = '\0'; - - dup_value = strdup(value); - if (dup_value == NULL) { - rc = SA_NO_MEMORY; - goto out; - } - - if (strcmp(key, "path") == 0) { - free(path); - path = dup_value; - } else if (strcmp(key, "comment") == 0) { - free(comment); - comment = dup_value; - } else if (strcmp(key, "guest_ok") == 0) { - free(guest_ok); - guest_ok = dup_value; - } else - free(dup_value); - - dup_value = NULL; - - if (path == NULL || comment == NULL || guest_ok == NULL) - continue; /* Incomplete share definition */ - else { - shares = (smb_share_t *) - malloc(sizeof (smb_share_t)); - if (shares == NULL) { - rc = SA_NO_MEMORY; - goto out; - } - - (void) strlcpy(shares->name, name, - sizeof (shares->name)); - - (void) strlcpy(shares->path, path, - sizeof (shares->path)); - - (void) strlcpy(shares->comment, comment, - sizeof (shares->comment)); - - shares->guest_ok = atoi(guest_ok); - - shares->next = new_shares; - new_shares = shares; - - free(path); - free(comment); - free(guest_ok); - - path = NULL; - comment = NULL; - guest_ok = NULL; - } - } - -out: - if (share_file_fp != NULL) { - fclose(share_file_fp); - share_file_fp = NULL; - } - - free(name); - free(path); - free(comment); - free(guest_ok); - - name = NULL; - path = NULL; - comment = NULL; - guest_ok = NULL; - } - closedir(shares_dir); - - smb_shares = new_shares; - - return (rc); -} - -/* - * Used internally by smb_enable_share to enable sharing for a single host. - */ -static int -smb_enable_share_one(const char *sharename, const char *sharepath) -{ - char name[SMB_NAME_MAX], comment[SMB_COMMENT_MAX]; - - /* Support ZFS share name regexp '[[:alnum:]_-.: ]' */ - strlcpy(name, sharename, sizeof (name)); - for (char *itr = name; *itr != '\0'; ++itr) - switch (*itr) { - case '/': - case '-': - case ':': - case ' ': - *itr = '_'; - } - - /* - * CMD: net -S NET_CMD_ARG_HOST usershare add Test1 /share/Test1 \ - * "Comment" "Everyone:F" - */ - snprintf(comment, sizeof (comment), "Comment: %s", sharepath); - - char *argv[] = { - (char *)NET_CMD_PATH, - (char *)"-S", - (char *)NET_CMD_ARG_HOST, - (char *)"usershare", - (char *)"add", - name, - (char *)sharepath, - comment, - (char *)"Everyone:F", - NULL, - }; - - if (libzfs_run_process(argv[0], argv, 0) != 0) - return (SA_SYSTEM_ERR); - - /* Reload the share file */ - (void) smb_retrieve_shares(); - - return (SA_OK); -} - -/* - * Enables SMB sharing for the specified share. - */ -static int -smb_enable_share(sa_share_impl_t impl_share) -{ - if (!smb_available()) - return (SA_SYSTEM_ERR); - - if (smb_is_share_active(impl_share)) - smb_disable_share(impl_share); - - if (impl_share->sa_shareopts == NULL) /* on/off */ - return (SA_SYSTEM_ERR); - - if (strcmp(impl_share->sa_shareopts, "off") == 0) - return (SA_OK); - - /* Magic: Enable (i.e., 'create new') share */ - return (smb_enable_share_one(impl_share->sa_zfsname, - impl_share->sa_mountpoint)); -} - -/* - * Used internally by smb_disable_share to disable sharing for a single host. - */ -static int -smb_disable_share_one(const char *sharename) -{ - /* CMD: net -S NET_CMD_ARG_HOST usershare delete Test1 */ - char *argv[] = { - (char *)NET_CMD_PATH, - (char *)"-S", - (char *)NET_CMD_ARG_HOST, - (char *)"usershare", - (char *)"delete", - (char *)sharename, - NULL, - }; - - if (libzfs_run_process(argv[0], argv, 0) != 0) - return (SA_SYSTEM_ERR); - else - return (SA_OK); -} - -/* - * Disables SMB sharing for the specified share. - */ -static int -smb_disable_share(sa_share_impl_t impl_share) -{ - if (!smb_available()) { - /* - * The share can't possibly be active, so nothing - * needs to be done to disable it. - */ - return (SA_OK); - } - - for (const smb_share_t *i = smb_shares; i != NULL; i = i->next) - if (strcmp(impl_share->sa_mountpoint, i->path) == 0) - return (smb_disable_share_one(i->name)); - - return (SA_OK); -} - -/* - * Checks whether the specified SMB share options are syntactically correct. - */ -static int -smb_validate_shareopts(const char *shareopts) -{ - /* TODO: Accept 'name' and sec/acl (?) */ - if ((strcmp(shareopts, "off") == 0) || (strcmp(shareopts, "on") == 0)) - return (SA_OK); - - return (SA_SYNTAX_ERR); -} - -/* - * Checks whether a share is currently active. - */ -static boolean_t -smb_is_share_active(sa_share_impl_t impl_share) -{ - if (!smb_available()) - return (B_FALSE); - - /* Retrieve the list of (possible) active shares */ - smb_retrieve_shares(); - - for (const smb_share_t *i = smb_shares; i != NULL; i = i->next) - if (strcmp(impl_share->sa_mountpoint, i->path) == 0) - return (B_TRUE); - - return (B_FALSE); -} - -static int -smb_update_shares(void) -{ - /* Not implemented */ - return (0); -} - -const sa_fstype_t libshare_smb_type = { - .enable_share = smb_enable_share, - .disable_share = smb_disable_share, - .is_shared = smb_is_share_active, - - .validate_shareopts = smb_validate_shareopts, - .commit_shares = smb_update_shares, -}; - -/* - * Provides a convenient wrapper for determining SMB availability - */ -static boolean_t -smb_available(void) -{ - static int avail; - - if (!avail) { - struct stat statbuf; - - if (access(NET_CMD_PATH, F_OK) != 0 || - lstat(SHARE_DIR, &statbuf) != 0 || - !S_ISDIR(statbuf.st_mode)) - avail = -1; - else - avail = 1; - } - - return (avail == 1); -} |