]> git.proxmox.com Git - mirror_zfs.git/blame - lib/libshare/smb.c
cstyle: Resolve C style issues
[mirror_zfs.git] / lib / libshare / smb.c
CommitLineData
645fb9cc
TF
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 http://www.opensolaris.org/os/licensing.
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 *
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.
d1d7e268 29 *
645fb9cc
TF
30 * TESTING
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).
34 *
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'):
38 *
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
43 *
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).
46 */
47
48#include <time.h>
49#include <stdlib.h>
50#include <stdio.h>
51#include <strings.h>
52#include <fcntl.h>
53#include <sys/wait.h>
54#include <unistd.h>
55#include <dirent.h>
56#include <sys/types.h>
57#include <sys/stat.h>
58#include <libzfs.h>
59#include <libshare.h>
60#include "libshare_impl.h"
61#include "smb.h"
62
63static boolean_t smb_available(void);
64
65static sa_fstype_t *smb_fstype;
66
d1d7e268 67/*
645fb9cc
TF
68 * Retrieve the list of SMB shares.
69 */
70static int
71smb_retrieve_shares(void)
72{
73 int rc = SA_OK;
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;
77 DIR *shares_dir;
78 FILE *share_file_fp = NULL;
79 struct dirent *directory;
80 struct stat eStat;
81 smb_share_t *shares, *new_shares = NULL;
82
83 /* opendir(), stat() */
84 shares_dir = opendir(SHARE_DIR);
85 if (shares_dir == NULL)
d1d7e268 86 return (SA_SYSTEM_ERR);
645fb9cc
TF
87
88 /* Go through the directory, looking for shares */
89 while ((directory = readdir(shares_dir))) {
90 if (directory->d_name[0] == '.')
91 continue;
92
93 snprintf(file_path, sizeof (file_path),
d1d7e268 94 "%s/%s", SHARE_DIR, directory->d_name);
645fb9cc
TF
95
96 if (stat(file_path, &eStat) == -1) {
97 rc = SA_SYSTEM_ERR;
98 goto out;
99 }
100
101 if (!S_ISREG(eStat.st_mode))
102 continue;
103
104 if ((share_file_fp = fopen(file_path, "r")) == NULL) {
105 rc = SA_SYSTEM_ERR;
106 goto out;
107 }
108
109 name = strdup(directory->d_name);
110 if (name == NULL) {
d1d7e268
MK
111 rc = SA_NO_MEMORY;
112 goto out;
645fb9cc
TF
113 }
114
d1d7e268 115 while (fgets(line, sizeof (line), share_file_fp)) {
645fb9cc
TF
116 if (line[0] == '#')
117 continue;
118
119 /* Trim trailing new-line character(s). */
120 while (line[strlen(line) - 1] == '\r' ||
d1d7e268 121 line[strlen(line) - 1] == '\n')
645fb9cc
TF
122 line[strlen(line) - 1] = '\0';
123
124 /* Split the line in two, separated by '=' */
125 token = strchr(line, '=');
126 if (token == NULL)
127 continue;
128
129 key = line;
130 value = token + 1;
131 *token = '\0';
132
133 dup_value = strdup(value);
134 if (dup_value == NULL) {
135 rc = SA_NO_MEMORY;
136 goto out;
137 }
138
139 if (strcmp(key, "path") == 0)
140 path = dup_value;
141 if (strcmp(key, "comment") == 0)
142 comment = dup_value;
143 if (strcmp(key, "guest_ok") == 0)
144 guest_ok = dup_value;
145
146 if (path == NULL || comment == NULL || guest_ok == NULL)
147 continue; /* Incomplete share definition */
148 else {
149 shares = (smb_share_t *)
150 malloc(sizeof (smb_share_t));
151 if (shares == NULL) {
152 rc = SA_NO_MEMORY;
153 goto out;
154 }
155
156 strncpy(shares->name, name,
157 sizeof (shares->name));
d1d7e268 158 shares->name [sizeof (shares->name) - 1] = '\0';
645fb9cc
TF
159
160 strncpy(shares->path, path,
d1d7e268
MK
161 sizeof (shares->path));
162 shares->path [sizeof (shares->path) - 1] = '\0';
645fb9cc
TF
163
164 strncpy(shares->comment, comment,
d1d7e268
MK
165 sizeof (shares->comment));
166 shares->comment[sizeof (shares->comment)-1] =
167 '\0';
645fb9cc
TF
168
169 shares->guest_ok = atoi(guest_ok);
170
171 shares->next = new_shares;
172 new_shares = shares;
173
d1d7e268
MK
174 name = NULL;
175 path = NULL;
176 comment = NULL;
645fb9cc
TF
177 guest_ok = NULL;
178 }
179 }
180
181out:
182 if (share_file_fp != NULL)
183 fclose(share_file_fp);
184
185 free(name);
186 free(path);
187 free(comment);
188 free(guest_ok);
189 }
190 closedir(shares_dir);
191
192 smb_shares = new_shares;
193
d1d7e268 194 return (rc);
645fb9cc
TF
195}
196
d1d7e268 197/*
645fb9cc
TF
198 * Used internally by smb_enable_share to enable sharing for a single host.
199 */
200static int
201smb_enable_share_one(const char *sharename, const char *sharepath)
202{
203 char *argv[10], *pos;
204 char name[SMB_NAME_MAX], comment[SMB_COMMENT_MAX];
205 int rc;
206
207 /* Support ZFS share name regexp '[[:alnum:]_-.: ]' */
d1d7e268
MK
208 strncpy(name, sharename, sizeof (name));
209 name [sizeof (name)-1] = '\0';
645fb9cc
TF
210
211 pos = name;
212 while (*pos != '\0') {
213 switch (*pos) {
214 case '/':
215 case '-':
216 case ':':
217 case ' ':
218 *pos = '_';
219 }
220
221 ++pos;
222 }
223
d1d7e268
MK
224 /*
225 * CMD: net -S NET_CMD_ARG_HOST usershare add Test1 /share/Test1 \
226 * "Comment" "Everyone:F"
227 */
228 snprintf(comment, sizeof (comment), "Comment: %s", sharepath);
229
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;
645fb9cc
TF
238 argv[8] = "Everyone:F";
239 argv[9] = NULL;
240
241 rc = libzfs_run_process(argv[0], argv, 0);
242 if (rc < 0)
d1d7e268 243 return (SA_SYSTEM_ERR);
645fb9cc
TF
244
245 /* Reload the share file */
246 (void) smb_retrieve_shares();
247
d1d7e268 248 return (SA_OK);
645fb9cc
TF
249}
250
d1d7e268 251/*
645fb9cc
TF
252 * Enables SMB sharing for the specified share.
253 */
254static int
255smb_enable_share(sa_share_impl_t impl_share)
256{
257 char *shareopts;
258
259 if (!smb_available())
d1d7e268 260 return (SA_SYSTEM_ERR);
645fb9cc
TF
261
262 shareopts = FSINFO(impl_share, smb_fstype)->shareopts;
263 if (shareopts == NULL) /* on/off */
d1d7e268 264 return (SA_SYSTEM_ERR);
645fb9cc
TF
265
266 if (strcmp(shareopts, "off") == 0)
d1d7e268 267 return (SA_OK);
645fb9cc
TF
268
269 /* Magic: Enable (i.e., 'create new') share */
d1d7e268
MK
270 return (smb_enable_share_one(impl_share->dataset,
271 impl_share->sharepath));
645fb9cc
TF
272}
273
d1d7e268 274/*
645fb9cc
TF
275 * Used internally by smb_disable_share to disable sharing for a single host.
276 */
277static int
278smb_disable_share_one(const char *sharename)
279{
280 int rc;
281 char *argv[7];
282
283 /* CMD: net -S NET_CMD_ARG_HOST usershare delete Test1 */
284 argv[0] = NET_CMD_PATH;
d1d7e268 285 argv[1] = (char *)"-S";
645fb9cc 286 argv[2] = NET_CMD_ARG_HOST;
d1d7e268
MK
287 argv[3] = (char *)"usershare";
288 argv[4] = (char *)"delete";
645fb9cc
TF
289 argv[5] = strdup(sharename);
290 argv[6] = NULL;
291
292 rc = libzfs_run_process(argv[0], argv, 0);
293 if (rc < 0)
d1d7e268 294 return (SA_SYSTEM_ERR);
645fb9cc 295 else
d1d7e268 296 return (SA_OK);
645fb9cc
TF
297}
298
d1d7e268 299/*
645fb9cc
TF
300 * Disables SMB sharing for the specified share.
301 */
302static int
303smb_disable_share(sa_share_impl_t impl_share)
304{
305 smb_share_t *shares = smb_shares;
306
307 if (!smb_available()) {
308 /*
309 * The share can't possibly be active, so nothing
310 * needs to be done to disable it.
311 */
d1d7e268 312 return (SA_OK);
645fb9cc
TF
313 }
314
315 while (shares != NULL) {
316 if (strcmp(impl_share->sharepath, shares->path) == 0)
d1d7e268 317 return (smb_disable_share_one(shares->name));
645fb9cc
TF
318
319 shares = shares->next;
320 }
321
d1d7e268 322 return (SA_OK);
645fb9cc
TF
323}
324
d1d7e268 325/*
645fb9cc
TF
326 * Checks whether the specified SMB share options are syntactically correct.
327 */
328static int
329smb_validate_shareopts(const char *shareopts)
330{
331 /* TODO: Accept 'name' and sec/acl (?) */
332 if ((strcmp(shareopts, "off") == 0) || (strcmp(shareopts, "on") == 0))
d1d7e268 333 return (SA_OK);
645fb9cc 334
d1d7e268 335 return (SA_SYNTAX_ERR);
645fb9cc
TF
336}
337
d1d7e268 338/*
645fb9cc
TF
339 * Checks whether a share is currently active.
340 */
341static boolean_t
342smb_is_share_active(sa_share_impl_t impl_share)
343{
344 if (!smb_available())
d1d7e268 345 return (B_FALSE);
645fb9cc
TF
346
347 /* Retrieve the list of (possible) active shares */
348 smb_retrieve_shares();
349
350 while (smb_shares != NULL) {
351 if (strcmp(impl_share->sharepath, smb_shares->path) == 0)
d1d7e268 352 return (B_TRUE);
645fb9cc
TF
353
354 smb_shares = smb_shares->next;
355 }
356
d1d7e268 357 return (B_FALSE);
645fb9cc
TF
358}
359
d1d7e268 360/*
645fb9cc
TF
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.
365 */
366static int
367smb_update_shareopts(sa_share_impl_t impl_share, const char *resource,
368 const char *shareopts)
369{
370 char *shareopts_dup;
371 boolean_t needs_reshare = B_FALSE;
372 char *old_shareopts;
373
d1d7e268
MK
374 if (!impl_share)
375 return (SA_SYSTEM_ERR);
645fb9cc
TF
376
377 FSINFO(impl_share, smb_fstype)->active =
378 smb_is_share_active(impl_share);
379
380 old_shareopts = FSINFO(impl_share, smb_fstype)->shareopts;
381
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);
386 }
387
388 shareopts_dup = strdup(shareopts);
389
390 if (shareopts_dup == NULL)
d1d7e268 391 return (SA_NO_MEMORY);
645fb9cc
TF
392
393 if (old_shareopts != NULL)
394 free(old_shareopts);
395
396 FSINFO(impl_share, smb_fstype)->shareopts = shareopts_dup;
397
398 if (needs_reshare)
399 smb_enable_share(impl_share);
400
d1d7e268 401 return (SA_OK);
645fb9cc
TF
402}
403
d1d7e268 404/*
645fb9cc
TF
405 * Clears a share's SMB options. Used by libshare to
406 * clean up shares that are about to be free()'d.
407 */
408static void
409smb_clear_shareopts(sa_share_impl_t impl_share)
410{
411 free(FSINFO(impl_share, smb_fstype)->shareopts);
412 FSINFO(impl_share, smb_fstype)->shareopts = NULL;
413}
414
415static const sa_share_ops_t smb_shareops = {
416 .enable_share = smb_enable_share,
417 .disable_share = smb_disable_share,
418
419 .validate_shareopts = smb_validate_shareopts,
420 .update_shareopts = smb_update_shareopts,
421 .clear_shareopts = smb_clear_shareopts,
422};
423
424/*
425 * Provides a convenient wrapper for determining SMB availability
426 */
427static boolean_t
428smb_available(void)
429{
be8bc8c0
TF
430 struct stat statbuf;
431
432 if (lstat(SHARE_DIR, &statbuf) != 0 ||
433 !S_ISDIR(statbuf.st_mode))
d1d7e268 434 return (B_FALSE);
be8bc8c0
TF
435
436 if (access(NET_CMD_PATH, F_OK) != 0)
d1d7e268 437 return (B_FALSE);
be8bc8c0 438
d1d7e268 439 return (B_TRUE);
645fb9cc
TF
440}
441
d1d7e268 442/*
645fb9cc
TF
443 * Initializes the SMB functionality of libshare.
444 */
445void
446libshare_smb_init(void)
447{
448 smb_fstype = register_fstype("smb", &smb_shareops);
449}