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.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
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]
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
27 * This is an addition to the zfs device driver to add, modify and remove SMB
28 * shares using the 'net share' command that comes with Samba.
31 * Make sure that samba listens to 'localhost' (127.0.0.1) and that the options
32 * 'usershare max shares' and 'usershare owner only' have been rewied/set
33 * accordingly (see zfs(8) for information).
35 * Once configuration in samba have been done, test that this
36 * works with the following three commands (in this case, my ZFS
37 * filesystem is called 'share/Test1'):
39 * (root)# net -U root -S 127.0.0.1 usershare add Test1 /share/Test1 \
40 * "Comment: /share/Test1" "Everyone:F"
41 * (root)# net usershare list | grep -i test
42 * (root)# net -U root -S 127.0.0.1 usershare delete Test1
44 * The first command will create a user share that gives everyone full access.
45 * To limit the access below that, use normal UNIX commands (chmod, chown etc).
56 #include <sys/types.h>
60 #include "libshare_impl.h"
63 static boolean_t smb_available(void);
65 static sa_fstype_t *smb_fstype;
68 * Retrieve the list of SMB shares.
71 smb_retrieve_shares(void)
74 char file_path[PATH_MAX], line[512], *token, *key, *value;
75 char *dup_value, *path = NULL, *comment = NULL, *name = NULL;
76 char *guest_ok = NULL;
78 FILE *share_file_fp = NULL;
79 struct dirent *directory;
81 smb_share_t *shares, *new_shares = NULL;
83 /* opendir(), stat() */
84 shares_dir = opendir(SHARE_DIR);
85 if (shares_dir == NULL)
88 /* Go through the directory, looking for shares */
89 while ((directory = readdir(shares_dir))) {
90 if (directory->d_name[0] == '.')
93 snprintf(file_path, sizeof (file_path),
94 "%s/%s", SHARE_DIR, directory->d_name);
96 if (stat(file_path, &eStat) == -1) {
101 if (!S_ISREG(eStat.st_mode))
104 if ((share_file_fp = fopen(file_path, "r")) == NULL) {
109 name = strdup(directory->d_name);
115 while (fgets(line, sizeof(line), share_file_fp)) {
119 /* Trim trailing new-line character(s). */
120 while (line[strlen(line) - 1] == '\r' ||
121 line[strlen(line) - 1] == '\n')
122 line[strlen(line) - 1] = '\0';
124 /* Split the line in two, separated by '=' */
125 token = strchr(line, '=');
133 dup_value = strdup(value);
134 if (dup_value == NULL) {
139 if (strcmp(key, "path") == 0)
141 if (strcmp(key, "comment") == 0)
143 if (strcmp(key, "guest_ok") == 0)
144 guest_ok = dup_value;
146 if (path == NULL || comment == NULL || guest_ok == NULL)
147 continue; /* Incomplete share definition */
149 shares = (smb_share_t *)
150 malloc(sizeof (smb_share_t));
151 if (shares == NULL) {
156 strncpy(shares->name, name,
157 sizeof (shares->name));
158 shares->name [sizeof(shares->name)-1] = '\0';
160 strncpy(shares->path, path,
161 sizeof (shares->path));
162 shares->path [sizeof(shares->path)-1] = '\0';
164 strncpy(shares->comment, comment,
165 sizeof (shares->comment));
166 shares->comment[sizeof(shares->comment)-1]='\0';
168 shares->guest_ok = atoi(guest_ok);
170 shares->next = new_shares;
181 if (share_file_fp != NULL)
182 fclose(share_file_fp);
189 closedir(shares_dir);
191 smb_shares = new_shares;
197 * Used internally by smb_enable_share to enable sharing for a single host.
200 smb_enable_share_one(const char *sharename, const char *sharepath)
202 char *argv[10], *pos;
203 char name[SMB_NAME_MAX], comment[SMB_COMMENT_MAX];
206 /* Support ZFS share name regexp '[[:alnum:]_-.: ]' */
207 strncpy(name, sharename, sizeof(name));
208 name [sizeof(name)-1] = '\0';
211 while (*pos != '\0') {
223 /* CMD: net -S NET_CMD_ARG_HOST usershare add Test1 /share/Test1 \
224 * "Comment" "Everyone:F" */
225 snprintf(comment, sizeof(comment), "Comment: %s", sharepath);
227 argv[0] = NET_CMD_PATH;
228 argv[1] = (char*)"-S";
229 argv[2] = NET_CMD_ARG_HOST;
230 argv[3] = (char*)"usershare";
231 argv[4] = (char*)"add";
232 argv[5] = (char*)name;
233 argv[6] = (char*)sharepath;
234 argv[7] = (char*)comment;
235 argv[8] = "Everyone:F";
238 rc = libzfs_run_process(argv[0], argv, 0);
240 return SA_SYSTEM_ERR;
242 /* Reload the share file */
243 (void) smb_retrieve_shares();
249 * Enables SMB sharing for the specified share.
252 smb_enable_share(sa_share_impl_t impl_share)
256 if (!smb_available())
257 return SA_SYSTEM_ERR;
259 shareopts = FSINFO(impl_share, smb_fstype)->shareopts;
260 if (shareopts == NULL) /* on/off */
261 return SA_SYSTEM_ERR;
263 if (strcmp(shareopts, "off") == 0)
266 /* Magic: Enable (i.e., 'create new') share */
267 return smb_enable_share_one(impl_share->dataset, impl_share->sharepath);
271 * Used internally by smb_disable_share to disable sharing for a single host.
274 smb_disable_share_one(const char *sharename)
279 /* CMD: net -S NET_CMD_ARG_HOST usershare delete Test1 */
280 argv[0] = NET_CMD_PATH;
281 argv[1] = (char*)"-S";
282 argv[2] = NET_CMD_ARG_HOST;
283 argv[3] = (char*)"usershare";
284 argv[4] = (char*)"delete";
285 argv[5] = strdup(sharename);
288 rc = libzfs_run_process(argv[0], argv, 0);
290 return SA_SYSTEM_ERR;
296 * Disables SMB sharing for the specified share.
299 smb_disable_share(sa_share_impl_t impl_share)
301 smb_share_t *shares = smb_shares;
303 if (!smb_available()) {
305 * The share can't possibly be active, so nothing
306 * needs to be done to disable it.
311 while (shares != NULL) {
312 if (strcmp(impl_share->sharepath, shares->path) == 0)
313 return smb_disable_share_one(shares->name);
315 shares = shares->next;
322 * Checks whether the specified SMB share options are syntactically correct.
325 smb_validate_shareopts(const char *shareopts)
327 /* TODO: Accept 'name' and sec/acl (?) */
328 if ((strcmp(shareopts, "off") == 0) || (strcmp(shareopts, "on") == 0))
331 return SA_SYNTAX_ERR;
335 * Checks whether a share is currently active.
338 smb_is_share_active(sa_share_impl_t impl_share)
340 if (!smb_available())
343 /* Retrieve the list of (possible) active shares */
344 smb_retrieve_shares();
346 while (smb_shares != NULL) {
347 if (strcmp(impl_share->sharepath, smb_shares->path) == 0)
350 smb_shares = smb_shares->next;
357 * Called to update a share's options. A share's options might be out of
358 * date if the share was loaded from disk and the "sharesmb" dataset
359 * property has changed in the meantime. This function also takes care
360 * of re-enabling the share if necessary.
363 smb_update_shareopts(sa_share_impl_t impl_share, const char *resource,
364 const char *shareopts)
367 boolean_t needs_reshare = B_FALSE;
371 return SA_SYSTEM_ERR;
373 FSINFO(impl_share, smb_fstype)->active =
374 smb_is_share_active(impl_share);
376 old_shareopts = FSINFO(impl_share, smb_fstype)->shareopts;
378 if (FSINFO(impl_share, smb_fstype)->active && old_shareopts != NULL &&
379 strcmp(old_shareopts, shareopts) != 0) {
380 needs_reshare = B_TRUE;
381 smb_disable_share(impl_share);
384 shareopts_dup = strdup(shareopts);
386 if (shareopts_dup == NULL)
389 if (old_shareopts != NULL)
392 FSINFO(impl_share, smb_fstype)->shareopts = shareopts_dup;
395 smb_enable_share(impl_share);
401 * Clears a share's SMB options. Used by libshare to
402 * clean up shares that are about to be free()'d.
405 smb_clear_shareopts(sa_share_impl_t impl_share)
407 free(FSINFO(impl_share, smb_fstype)->shareopts);
408 FSINFO(impl_share, smb_fstype)->shareopts = NULL;
411 static const sa_share_ops_t smb_shareops = {
412 .enable_share = smb_enable_share,
413 .disable_share = smb_disable_share,
415 .validate_shareopts = smb_validate_shareopts,
416 .update_shareopts = smb_update_shareopts,
417 .clear_shareopts = smb_clear_shareopts,
421 * Provides a convenient wrapper for determining SMB availability
426 /* TODO: Sanity check NET_CMD_PATH and SHARE_DIR */
431 * Initializes the SMB functionality of libshare.
434 libshare_smb_init(void)
436 smb_fstype = register_fstype("smb", &smb_shareops);