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
)
86 return (SA_SYSTEM_ERR
);
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] =
169 shares
->guest_ok
= atoi(guest_ok
);
171 shares
->next
= new_shares
;
182 if (share_file_fp
!= NULL
)
183 fclose(share_file_fp
);
190 closedir(shares_dir
);
192 smb_shares
= new_shares
;
198 * Used internally by smb_enable_share to enable sharing for a single host.
201 smb_enable_share_one(const char *sharename
, const char *sharepath
)
203 char *argv
[10], *pos
;
204 char name
[SMB_NAME_MAX
], comment
[SMB_COMMENT_MAX
];
207 /* Support ZFS share name regexp '[[:alnum:]_-.: ]' */
208 strncpy(name
, sharename
, sizeof (name
));
209 name
[sizeof (name
)-1] = '\0';
212 while (*pos
!= '\0') {
225 * CMD: net -S NET_CMD_ARG_HOST usershare add Test1 /share/Test1 \
226 * "Comment" "Everyone:F"
228 snprintf(comment
, sizeof (comment
), "Comment: %s", sharepath
);
230 argv
[0] = NET_CMD_PATH
;
231 argv
[1] = (char *)"-S";
232 argv
[2] = NET_CMD_ARG_HOST
;
233 argv
[3] = (char *)"usershare";
234 argv
[4] = (char *)"add";
235 argv
[5] = (char *)name
;
236 argv
[6] = (char *)sharepath
;
237 argv
[7] = (char *)comment
;
238 argv
[8] = "Everyone:F";
241 rc
= libzfs_run_process(argv
[0], argv
, 0);
243 return (SA_SYSTEM_ERR
);
245 /* Reload the share file */
246 (void) smb_retrieve_shares();
252 * Enables SMB sharing for the specified share.
255 smb_enable_share(sa_share_impl_t impl_share
)
259 if (!smb_available())
260 return (SA_SYSTEM_ERR
);
262 shareopts
= FSINFO(impl_share
, smb_fstype
)->shareopts
;
263 if (shareopts
== NULL
) /* on/off */
264 return (SA_SYSTEM_ERR
);
266 if (strcmp(shareopts
, "off") == 0)
269 /* Magic: Enable (i.e., 'create new') share */
270 return (smb_enable_share_one(impl_share
->dataset
,
271 impl_share
->sharepath
));
275 * Used internally by smb_disable_share to disable sharing for a single host.
278 smb_disable_share_one(const char *sharename
)
283 /* CMD: net -S NET_CMD_ARG_HOST usershare delete Test1 */
284 argv
[0] = NET_CMD_PATH
;
285 argv
[1] = (char *)"-S";
286 argv
[2] = NET_CMD_ARG_HOST
;
287 argv
[3] = (char *)"usershare";
288 argv
[4] = (char *)"delete";
289 argv
[5] = strdup(sharename
);
292 rc
= libzfs_run_process(argv
[0], argv
, 0);
294 return (SA_SYSTEM_ERR
);
300 * Disables SMB sharing for the specified share.
303 smb_disable_share(sa_share_impl_t impl_share
)
305 smb_share_t
*shares
= smb_shares
;
307 if (!smb_available()) {
309 * The share can't possibly be active, so nothing
310 * needs to be done to disable it.
315 while (shares
!= NULL
) {
316 if (strcmp(impl_share
->sharepath
, shares
->path
) == 0)
317 return (smb_disable_share_one(shares
->name
));
319 shares
= shares
->next
;
326 * Checks whether the specified SMB share options are syntactically correct.
329 smb_validate_shareopts(const char *shareopts
)
331 /* TODO: Accept 'name' and sec/acl (?) */
332 if ((strcmp(shareopts
, "off") == 0) || (strcmp(shareopts
, "on") == 0))
335 return (SA_SYNTAX_ERR
);
339 * Checks whether a share is currently active.
342 smb_is_share_active(sa_share_impl_t impl_share
)
344 if (!smb_available())
347 /* Retrieve the list of (possible) active shares */
348 smb_retrieve_shares();
350 while (smb_shares
!= NULL
) {
351 if (strcmp(impl_share
->sharepath
, smb_shares
->path
) == 0)
354 smb_shares
= smb_shares
->next
;
361 * Called to update a share's options. A share's options might be out of
362 * date if the share was loaded from disk and the "sharesmb" dataset
363 * property has changed in the meantime. This function also takes care
364 * of re-enabling the share if necessary.
367 smb_update_shareopts(sa_share_impl_t impl_share
, const char *resource
,
368 const char *shareopts
)
371 boolean_t needs_reshare
= B_FALSE
;
375 return (SA_SYSTEM_ERR
);
377 FSINFO(impl_share
, smb_fstype
)->active
=
378 smb_is_share_active(impl_share
);
380 old_shareopts
= FSINFO(impl_share
, smb_fstype
)->shareopts
;
382 if (FSINFO(impl_share
, smb_fstype
)->active
&& old_shareopts
!= NULL
&&
383 strcmp(old_shareopts
, shareopts
) != 0) {
384 needs_reshare
= B_TRUE
;
385 smb_disable_share(impl_share
);
388 shareopts_dup
= strdup(shareopts
);
390 if (shareopts_dup
== NULL
)
391 return (SA_NO_MEMORY
);
393 if (old_shareopts
!= NULL
)
396 FSINFO(impl_share
, smb_fstype
)->shareopts
= shareopts_dup
;
399 smb_enable_share(impl_share
);
405 * Clears a share's SMB options. Used by libshare to
406 * clean up shares that are about to be free()'d.
409 smb_clear_shareopts(sa_share_impl_t impl_share
)
411 free(FSINFO(impl_share
, smb_fstype
)->shareopts
);
412 FSINFO(impl_share
, smb_fstype
)->shareopts
= NULL
;
415 static const sa_share_ops_t smb_shareops
= {
416 .enable_share
= smb_enable_share
,
417 .disable_share
= smb_disable_share
,
419 .validate_shareopts
= smb_validate_shareopts
,
420 .update_shareopts
= smb_update_shareopts
,
421 .clear_shareopts
= smb_clear_shareopts
,
425 * Provides a convenient wrapper for determining SMB availability
432 if (lstat(SHARE_DIR
, &statbuf
) != 0 ||
433 !S_ISDIR(statbuf
.st_mode
))
436 if (access(NET_CMD_PATH
, F_OK
) != 0)
443 * Initializes the SMB functionality of libshare.
446 libshare_smb_init(void)
448 smb_fstype
= register_fstype("smb", &smb_shareops
);