/* * 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 http://www.opensolaris.org/os/licensing. * 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 Gunnar Beutner * Copyright (c) 2018, 2020 by Delphix. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include "libzfs_impl.h" #include "libshare_impl.h" #include "nfs.h" #include "smb.h" static sa_share_impl_t alloc_share(const char *zfsname, const char *path); static void free_share(sa_share_impl_t share); static int fstypes_count; static sa_fstype_t *fstypes; sa_fstype_t * register_fstype(const char *name, const sa_share_ops_t *ops) { sa_fstype_t *fstype; fstype = calloc(1, sizeof (sa_fstype_t)); if (fstype == NULL) return (NULL); fstype->name = name; fstype->ops = ops; fstype->fsinfo_index = fstypes_count; fstypes_count++; fstype->next = fstypes; fstypes = fstype; return (fstype); } __attribute__((constructor)) static void libshare_init(void) { libshare_nfs_init(); libshare_smb_init(); } int sa_enable_share(const char *zfsname, const char *mountpoint, const char *shareopts, char *protocol) { int rc, ret = SA_OK; boolean_t found_protocol = B_FALSE; sa_fstype_t *fstype; sa_share_impl_t impl_share = alloc_share(zfsname, mountpoint); if (impl_share == NULL) return (SA_NO_MEMORY); fstype = fstypes; while (fstype != NULL) { if (strcmp(fstype->name, protocol) == 0) { rc = fstype->ops->update_shareopts(impl_share, shareopts); if (rc != SA_OK) break; rc = fstype->ops->enable_share(impl_share); if (rc != SA_OK) ret = rc; found_protocol = B_TRUE; } fstype = fstype->next; } free_share(impl_share); return (found_protocol ? ret : SA_INVALID_PROTOCOL); } int sa_disable_share(const char *mountpoint, char *protocol) { int rc, ret = SA_OK; boolean_t found_protocol = B_FALSE; sa_fstype_t *fstype; sa_share_impl_t impl_share = alloc_share(NULL, mountpoint); if (impl_share == NULL) return (SA_NO_MEMORY); fstype = fstypes; while (fstype != NULL) { if (strcmp(fstype->name, protocol) == 0) { rc = fstype->ops->disable_share(impl_share); if (rc != SA_OK) ret = rc; found_protocol = B_TRUE; } fstype = fstype->next; } free_share(impl_share); return (found_protocol ? ret : SA_INVALID_PROTOCOL); } boolean_t sa_is_shared(const char *mountpoint, char *protocol) { sa_fstype_t *fstype; boolean_t ret = B_FALSE; /* guid value is not used */ sa_share_impl_t impl_share = alloc_share(NULL, mountpoint); if (impl_share == NULL) return (B_FALSE); fstype = fstypes; while (fstype != NULL) { if (strcmp(fstype->name, protocol) == 0) { ret = fstype->ops->is_shared(impl_share); } fstype = fstype->next; } free_share(impl_share); return (ret); } void sa_commit_shares(const char *protocol) { sa_fstype_t *fstype = fstypes; while (fstype != NULL) { if (strcmp(fstype->name, protocol) == 0) fstype->ops->commit_shares(); fstype = fstype->next; } } /* * sa_errorstr(err) * * convert an error value to an error string */ char * sa_errorstr(int err) { static char errstr[32]; char *ret = NULL; switch (err) { case SA_OK: ret = dgettext(TEXT_DOMAIN, "ok"); break; case SA_NO_SUCH_PATH: ret = dgettext(TEXT_DOMAIN, "path doesn't exist"); break; case SA_NO_MEMORY: ret = dgettext(TEXT_DOMAIN, "no memory"); break; case SA_DUPLICATE_NAME: ret = dgettext(TEXT_DOMAIN, "name in use"); break; case SA_BAD_PATH: ret = dgettext(TEXT_DOMAIN, "bad path"); break; case SA_NO_SUCH_GROUP: ret = dgettext(TEXT_DOMAIN, "no such group"); break; case SA_CONFIG_ERR: ret = dgettext(TEXT_DOMAIN, "configuration error"); break; case SA_SYSTEM_ERR: ret = dgettext(TEXT_DOMAIN, "system error"); break; case SA_SYNTAX_ERR: ret = dgettext(TEXT_DOMAIN, "syntax error"); break; case SA_NO_PERMISSION: ret = dgettext(TEXT_DOMAIN, "no permission"); break; case SA_BUSY: ret = dgettext(TEXT_DOMAIN, "busy"); break; case SA_NO_SUCH_PROP: ret = dgettext(TEXT_DOMAIN, "no such property"); break; case SA_INVALID_NAME: ret = dgettext(TEXT_DOMAIN, "invalid name"); break; case SA_INVALID_PROTOCOL: ret = dgettext(TEXT_DOMAIN, "invalid protocol"); break; case SA_NOT_ALLOWED: ret = dgettext(TEXT_DOMAIN, "operation not allowed"); break; case SA_BAD_VALUE: ret = dgettext(TEXT_DOMAIN, "bad property value"); break; case SA_INVALID_SECURITY: ret = dgettext(TEXT_DOMAIN, "invalid security type"); break; case SA_NO_SUCH_SECURITY: ret = dgettext(TEXT_DOMAIN, "security type not found"); break; case SA_VALUE_CONFLICT: ret = dgettext(TEXT_DOMAIN, "property value conflict"); break; case SA_NOT_IMPLEMENTED: ret = dgettext(TEXT_DOMAIN, "not implemented"); break; case SA_INVALID_PATH: ret = dgettext(TEXT_DOMAIN, "invalid path"); break; case SA_NOT_SUPPORTED: ret = dgettext(TEXT_DOMAIN, "operation not supported"); break; case SA_PROP_SHARE_ONLY: ret = dgettext(TEXT_DOMAIN, "property not valid for group"); break; case SA_NOT_SHARED: ret = dgettext(TEXT_DOMAIN, "not shared"); break; case SA_NO_SUCH_RESOURCE: ret = dgettext(TEXT_DOMAIN, "no such resource"); break; case SA_RESOURCE_REQUIRED: ret = dgettext(TEXT_DOMAIN, "resource name required"); break; case SA_MULTIPLE_ERROR: ret = dgettext(TEXT_DOMAIN, "errors from multiple protocols"); break; case SA_PATH_IS_SUBDIR: ret = dgettext(TEXT_DOMAIN, "path is a subpath of share"); break; case SA_PATH_IS_PARENTDIR: ret = dgettext(TEXT_DOMAIN, "path is parent of a share"); break; case SA_NO_SECTION: ret = dgettext(TEXT_DOMAIN, "protocol requires a section"); break; case SA_NO_PROPERTIES: ret = dgettext(TEXT_DOMAIN, "properties not found"); break; case SA_NO_SUCH_SECTION: ret = dgettext(TEXT_DOMAIN, "section not found"); break; case SA_PASSWORD_ENC: ret = dgettext(TEXT_DOMAIN, "passwords must be encrypted"); break; case SA_SHARE_EXISTS: ret = dgettext(TEXT_DOMAIN, "path or file is already shared"); break; default: (void) snprintf(errstr, sizeof (errstr), dgettext(TEXT_DOMAIN, "unknown %d"), err); ret = errstr; } return (ret); } int sa_validate_shareopts(char *options, char *proto) { sa_fstype_t *fstype; fstype = fstypes; while (fstype != NULL) { if (strcmp(fstype->name, proto) != 0) { fstype = fstype->next; continue; } return (fstype->ops->validate_shareopts(options)); } return (SA_INVALID_PROTOCOL); } static sa_share_impl_t alloc_share(const char *zfsname, const char *mountpoint) { sa_share_impl_t impl_share; impl_share = calloc(1, sizeof (struct sa_share_impl)); if (impl_share == NULL) return (NULL); if (mountpoint != NULL && ((impl_share->sa_mountpoint = strdup(mountpoint)) == NULL)) { free(impl_share); return (NULL); } if (zfsname != NULL && ((impl_share->sa_zfsname = strdup(zfsname)) == NULL)) { free(impl_share->sa_mountpoint); free(impl_share); return (NULL); } impl_share->sa_fsinfo = calloc(fstypes_count, sizeof (sa_share_fsinfo_t)); if (impl_share->sa_fsinfo == NULL) { free(impl_share->sa_mountpoint); free(impl_share->sa_zfsname); free(impl_share); return (NULL); } return (impl_share); } static void free_share(sa_share_impl_t impl_share) { sa_fstype_t *fstype; fstype = fstypes; while (fstype != NULL) { fstype->ops->clear_shareopts(impl_share); fstype = fstype->next; } free(impl_share->sa_mountpoint); free(impl_share->sa_zfsname); free(impl_share->sa_fsinfo); free(impl_share); }