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) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
25 */
26
27 /*
28 * SMB specific functions
29 */
30 #include <stdio.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <zone.h>
36 #include <errno.h>
37 #include <locale.h>
38 #include <fcntl.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <syslog.h>
42 #include "libshare.h"
43 #include "libshare_impl.h"
44 #include <pwd.h>
45 #include <limits.h>
46 #include <libscf.h>
47 #include <libscf_priv.h>
48 #include <strings.h>
49 #include "libshare_smb.h"
50 #include <rpcsvc/daemon_utils.h>
51 #include <smbsrv/smb_share.h>
52 #include <smbsrv/smbinfo.h>
53 #include <smbsrv/libsmb.h>
54 #include <libdlpi.h>
55
56 #define SMB_CSC_BUFSZ 64
57
58 #define SMB_VALID_SUB_CHRS "UDhMLmIiSPu" /* substitution characters */
59
60 /* internal functions */
61 static int smb_share_init(void);
62 static void smb_share_fini(void);
63 static int smb_enable_share(sa_share_t);
64 static int smb_share_changed(sa_share_t);
65 static int smb_resource_changed(sa_resource_t);
66 static int smb_rename_resource(sa_handle_t, sa_resource_t, char *);
67 static int smb_disable_share(sa_share_t share, char *);
68 static int smb_validate_property(sa_handle_t, sa_property_t, sa_optionset_t);
69 static int smb_set_proto_prop(sa_property_t);
70 static sa_protocol_properties_t smb_get_proto_set(void);
71 static char *smb_get_status(void);
72 static int smb_parse_optstring(sa_group_t, char *);
73 static char *smb_format_options(sa_group_t, int);
74
75 static int smb_enable_service(void);
76
77 static int range_check_validator(int, char *);
78 static int range_check_validator_zero_ok(int, char *);
79 static int string_length_check_validator(int, char *);
80 static int print_enable_validator(int, char *);
81 static int true_false_validator(int, char *);
82 static int ipv4_validator(int, char *);
83 static int hostname_validator(int, char *);
84 static int path_validator(int, char *);
85 static int cmd_validator(int, char *);
86 static int disposition_validator(int, char *);
87 static int protocol_validator(int, char *);
88 static int require_validator(int, char *);
89
90 static int smb_enable_resource(sa_resource_t);
91 static int smb_disable_resource(sa_resource_t);
92 static uint64_t smb_share_features(void);
93 static int smb_list_transient(sa_handle_t);
94
95 static int smb_build_shareinfo(sa_share_t, sa_resource_t, smb_share_t *);
96 static void smb_csc_option(const char *, smb_share_t *);
97 static char *smb_csc_name(const smb_share_t *);
98 static sa_group_t smb_get_defaultgrp(sa_handle_t);
99 static int interface_validator(int, char *);
100 static int smb_update_optionset_props(sa_handle_t, sa_resource_t, nvlist_t *);
101
102 static boolean_t smb_saprop_getbool(sa_optionset_t, char *, boolean_t);
103 static boolean_t smb_saprop_getstr(sa_optionset_t, char *, char *, size_t);
104
105 static struct {
106 char *value;
107 uint32_t flag;
108 } cscopt[] = {
109 { "disabled", SMB_SHRF_CSC_DISABLED },
110 { "manual", SMB_SHRF_CSC_MANUAL },
111 { "auto", SMB_SHRF_CSC_AUTO },
112 { "vdo", SMB_SHRF_CSC_VDO }
113 };
114
115 /* size of basic format allocation */
116 #define OPT_CHUNK 1024
117
118 /* size of string for types - big enough to hold "dependency" */
119 #define SCFTYPE_LEN 32
120
121 /*
122 * Indexes of entries in smb_proto_options table.
123 * Changes to smb_proto_options table may require
124 * an update to these values.
125 */
126 #define PROTO_OPT_WINS1 6
127 #define PROTO_OPT_WINS_EXCLUDE 8
128
129 typedef struct smb_hostifs_walker {
130 const char *hiw_ifname;
131 boolean_t hiw_matchfound;
132 } smb_hostifs_walker_t;
133
134
135 /*
136 * ops vector that provides the protocol specific info and operations
137 * for share management.
138 */
139
140 struct sa_plugin_ops sa_plugin_ops = {
141 SA_PLUGIN_VERSION,
142 SMB_PROTOCOL_NAME,
143 smb_share_init,
144 smb_share_fini,
145 smb_enable_share,
146 smb_disable_share,
147 smb_validate_property,
148 NULL, /* valid_space */
149 NULL, /* security_prop */
150 smb_parse_optstring,
151 smb_format_options,
152 smb_set_proto_prop,
153 smb_get_proto_set,
154 smb_get_status,
155 NULL, /* space_alias */
156 NULL, /* update_legacy */
157 NULL, /* delete_legacy */
158 smb_share_changed,
159 smb_enable_resource,
160 smb_disable_resource,
161 smb_share_features,
162 smb_list_transient,
163 smb_resource_changed,
164 smb_rename_resource,
165 NULL, /* run_command */
166 NULL, /* command_help */
167 NULL /* delete_proto_section */
168 };
169
170 struct option_defs optdefs[] = {
171 { SHOPT_AD_CONTAINER, OPT_TYPE_STRING },
172 { SHOPT_ABE, OPT_TYPE_BOOLEAN },
173 { SHOPT_NAME, OPT_TYPE_NAME },
174 { SHOPT_RO, OPT_TYPE_ACCLIST },
175 { SHOPT_RW, OPT_TYPE_ACCLIST },
176 { SHOPT_NONE, OPT_TYPE_ACCLIST },
177 { SHOPT_CATIA, OPT_TYPE_BOOLEAN },
178 { SHOPT_CSC, OPT_TYPE_CSC },
179 { SHOPT_GUEST, OPT_TYPE_BOOLEAN },
180 { SHOPT_DFSROOT, OPT_TYPE_BOOLEAN },
181 { SHOPT_DESCRIPTION, OPT_TYPE_STRING },
182 { SHOPT_CA, OPT_TYPE_BOOLEAN },
183 { SHOPT_FSO, OPT_TYPE_BOOLEAN },
184 { SHOPT_QUOTAS, OPT_TYPE_BOOLEAN },
185 { SHOPT_ENCRYPT, OPT_TYPE_STRING },
186 { NULL, 0 }
187 };
188
189 /*
190 * findopt(name)
191 *
192 * Lookup option "name" in the option table and return the table
193 * index.
194 */
195 static int
196 findopt(char *name)
197 {
198 int i;
199 if (name != NULL) {
200 for (i = 0; optdefs[i].tag != NULL; i++) {
201 if (strcmp(optdefs[i].tag, name) == 0)
202 return (i);
203 }
204 }
205 return (-1);
206 }
207
208 /*
209 * is_a_number(number)
210 *
211 * is the string a number in one of the forms we want to use?
212 */
213 static boolean_t
214 is_a_number(char *number)
215 {
216 boolean_t isnum = B_TRUE;
217 boolean_t ishex = B_FALSE;
218
219 if (number == NULL || *number == '\0')
220 return (B_FALSE);
221
222 if (strncasecmp(number, "0x", 2) == 0) {
223 number += 2;
224 ishex = B_TRUE;
225 } else if (*number == '-') {
226 number++;
227 }
228
229 while (isnum && (*number != '\0')) {
230 isnum = (ishex) ? isxdigit(*number) : isdigit(*number);
231 number++;
232 }
233
234 return (isnum);
235 }
236
237 /*
238 * check ro vs rw values. Over time this may get beefed up.
239 * for now it just does simple checks.
240 */
241
242 static int
243 check_rorw(char *v1, char *v2)
244 {
245 int ret = SA_OK;
246 if (strcmp(v1, v2) == 0)
247 ret = SA_VALUE_CONFLICT;
248 return (ret);
249 }
250
251 /*
252 * validresource(name)
253 *
254 * Check that name only has valid characters in it. The current valid
255 * set are the printable characters but not including:
256 * " / \ [ ] : | < > + ; , ? * = \t
257 * Note that space is included and there is a maximum length.
258 */
259 static boolean_t
260 validresource(const char *name)
261 {
262 const char *cp;
263 size_t len;
264
265 if (name == NULL)
266 return (B_FALSE);
267
268 len = strlen(name);
269 if (len == 0 || len > SA_MAX_RESOURCE_NAME)
270 return (B_FALSE);
271
272 if (strpbrk(name, "\"/\\[]:|<>+;,?*=\t") != NULL) {
273 return (B_FALSE);
274 }
275
276 for (cp = name; *cp != '\0'; cp++)
277 if (iscntrl(*cp))
278 return (B_FALSE);
279
280 return (B_TRUE);
281 }
282
283 /*
284 * Check that the client-side caching (CSC) option value is valid.
285 */
286 static boolean_t
287 validcsc(const char *value)
288 {
289 int i;
290
291 for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
292 if (strcasecmp(value, cscopt[i].value) == 0)
293 return (B_TRUE);
294 }
295
296 return (B_FALSE);
297 }
298
299 /*
300 * smb_isonline()
301 *
302 * Determine if the SMF service instance is in the online state or
303 * not. A number of operations depend on this state.
304 */
305 static boolean_t
306 smb_isonline(void)
307 {
308 char *str;
309 boolean_t ret = B_FALSE;
310
311 if ((str = smf_get_state(SMBD_DEFAULT_INSTANCE_FMRI)) != NULL) {
312 ret = (strcmp(str, SCF_STATE_STRING_ONLINE) == 0);
313 free(str);
314 }
315 return (ret);
316 }
317
318 /*
319 * smb_isdisabled()
320 *
321 * Determine if the SMF service instance is in the disabled state or
322 * not. A number of operations depend on this state.
323 */
324 static boolean_t
325 smb_isdisabled(void)
326 {
327 char *str;
328 boolean_t ret = B_FALSE;
329
330 if ((str = smf_get_state(SMBD_DEFAULT_INSTANCE_FMRI)) != NULL) {
331 ret = (strcmp(str, SCF_STATE_STRING_DISABLED) == 0);
332 free(str);
333 }
334 return (ret);
335 }
336
337 /*
338 * smb_isautoenable()
339 *
340 * Determine if the SMF service instance auto_enabled set or not. A
341 * number of operations depend on this state. The property not being
342 * set or being set to true means autoenable. Only being set to false
343 * is not autoenabled.
344 */
345 static boolean_t
346 smb_isautoenable(void)
347 {
348 boolean_t ret = B_TRUE;
349 scf_simple_prop_t *prop;
350 uint8_t *retstr;
351
352 prop = scf_simple_prop_get(NULL, SMBD_DEFAULT_INSTANCE_FMRI,
353 "application", "auto_enable");
354 if (prop != NULL) {
355 retstr = scf_simple_prop_next_boolean(prop);
356 ret = *retstr != 0;
357 scf_simple_prop_free(prop);
358 }
359 return (ret);
360 }
361
362 /*
363 * smb_ismaint()
364 *
365 * Determine if the SMF service instance is in the disabled state or
366 * not. A number of operations depend on this state.
367 */
368 static boolean_t
369 smb_ismaint(void)
370 {
371 char *str;
372 boolean_t ret = B_FALSE;
373
374 if ((str = smf_get_state(SMBD_DEFAULT_INSTANCE_FMRI)) != NULL) {
375 ret = (strcmp(str, SCF_STATE_STRING_MAINT) == 0);
376 free(str);
377 }
378 return (ret);
379 }
380
381 /*
382 * smb_enable_share tells the implementation that it is to enable the share.
383 * This entails converting the path and options into the appropriate ioctl
384 * calls. It is assumed that all error checking of paths, etc. were
385 * done earlier.
386 */
387 static int
388 smb_enable_share(sa_share_t share)
389 {
390 char *path;
391 smb_share_t si;
392 sa_resource_t resource;
393 boolean_t iszfs;
394 boolean_t privileged;
395 int err = SA_OK;
396 priv_set_t *priv_effective;
397 boolean_t online;
398
399 /*
400 * Don't support Trusted Extensions.
401 */
402 if (is_system_labeled()) {
403 (void) printf(dgettext(TEXT_DOMAIN,
404 "SMB: service not supported with Trusted Extensions\n"));
405 return (SA_NOT_SUPPORTED);
406 }
407
408 priv_effective = priv_allocset();
409 (void) getppriv(PRIV_EFFECTIVE, priv_effective);
410 privileged = (priv_isfullset(priv_effective) == B_TRUE);
411 priv_freeset(priv_effective);
412
413 /* get the path since it is important in several places */
414 path = sa_get_share_attr(share, "path");
415 if (path == NULL)
416 return (SA_NO_SUCH_PATH);
417
418 /*
419 * If administratively disabled, don't try to start anything.
420 */
421 online = smb_isonline();
422 if (!online && !smb_isautoenable() && smb_isdisabled())
423 goto done;
424
425 iszfs = sa_path_is_zfs(path);
426
427 if (iszfs) {
428
429 if (privileged == B_FALSE && !online) {
430
431 if (!online) {
432 (void) printf(dgettext(TEXT_DOMAIN,
433 "SMB: Cannot share remove "
434 "file system: %s\n"), path);
435 (void) printf(dgettext(TEXT_DOMAIN,
436 "SMB: Service needs to be enabled "
437 "by a privileged user\n"));
438 err = SA_NO_PERMISSION;
439 errno = EPERM;
440 }
441 if (err) {
442 sa_free_attr_string(path);
443 return (err);
444 }
445
446 }
447 }
448
449 if (privileged == B_TRUE && !online) {
450 err = smb_enable_service();
451 if (err != SA_OK) {
452 (void) printf(dgettext(TEXT_DOMAIN,
453 "SMB: Unable to enable service\n"));
454 } else {
455 online = B_TRUE;
456 }
457 }
458
459 /*
460 * Don't bother trying to start shares if the service isn't
461 * running.
462 */
463 if (!online)
464 goto done;
465
466 /* Each share can have multiple resources */
467 for (resource = sa_get_share_resource(share, NULL);
468 resource != NULL;
469 resource = sa_get_next_resource(resource)) {
470 err = smb_build_shareinfo(share, resource, &si);
471 if (err != SA_OK) {
472 sa_free_attr_string(path);
473 return (err);
474 }
475
476 if (!iszfs) {
477 err = smb_share_create(&si);
478 } else {
479 share_t sh;
480
481 (void) sa_sharetab_fill_zfs(share, &sh, "smb");
482 err = sa_share_zfs(share, resource, (char *)path, &sh,
483 &si, ZFS_SHARE_SMB);
484 if (err != SA_OK) {
485 errno = err;
486 err = -1;
487 }
488 sa_emptyshare(&sh);
489 }
490 }
491 if (!iszfs)
492 (void) sa_update_sharetab(share, "smb");
493 done:
494 sa_free_attr_string(path);
495
496 return (err == NERR_DuplicateShare ? 0 : err);
497 }
498
499 /*
500 * This is the share for CIFS all shares have resource names.
501 * Enable tells the smb server to update its hash. If it fails
502 * because smb server is down, we just ignore as smb server loads
503 * the resources from sharemanager at startup.
504 */
505
506 static int
507 smb_enable_resource(sa_resource_t resource)
508 {
509 sa_share_t share;
510 smb_share_t si;
511 int ret = SA_OK;
512 int err;
513 boolean_t isonline;
514
515 share = sa_get_resource_parent(resource);
516 if (share == NULL)
517 return (SA_NO_SUCH_PATH);
518
519 /*
520 * If administratively disabled, don't try to start anything.
521 */
522 isonline = smb_isonline();
523 if (!isonline && !smb_isautoenable() && smb_isdisabled())
524 return (SA_OK);
525
526 if (!isonline) {
527 (void) smb_enable_service();
528
529 if (!smb_isonline())
530 return (SA_OK);
531 }
532
533 if ((ret = smb_build_shareinfo(share, resource, &si)) != SA_OK)
534 return (ret);
535
536 /*
537 * Attempt to add the share. Any error that occurs if it was
538 * online is an error but don't count NERR_DuplicateName if
539 * smb/server had to be brought online since bringing the
540 * service up will enable the share that was just added prior
541 * to the attempt to enable.
542 */
543 err = smb_share_create(&si);
544 if (err == NERR_Success || !(!isonline && err == NERR_DuplicateName))
545 (void) sa_update_sharetab(share, "smb");
546 else
547 return (SA_NOT_SHARED);
548
549 return (SA_OK);
550 }
551
552 /*
553 * Remove it from smb server hash.
554 */
555 static int
556 smb_disable_resource(sa_resource_t resource)
557 {
558 char *rname;
559 uint32_t res;
560 sa_share_t share;
561
562 rname = sa_get_resource_attr(resource, "name");
563 if (rname == NULL)
564 return (SA_NO_SUCH_RESOURCE);
565
566 if (smb_isonline()) {
567 res = smb_share_delete(rname);
568 if (res != NERR_Success &&
569 res != NERR_NetNameNotFound) {
570 sa_free_attr_string(rname);
571 return (SA_CONFIG_ERR);
572 }
573 }
574
575 sa_free_attr_string(rname);
576
577 share = sa_get_resource_parent(resource);
578 if (share != NULL) {
579 rname = sa_get_share_attr(share, "path");
580 if (rname != NULL) {
581 sa_handle_t handle;
582
583 handle = sa_find_group_handle((sa_group_t)resource);
584 (void) sa_delete_sharetab(handle, rname, "smb");
585 sa_free_attr_string(rname);
586 }
587 }
588 /*
589 * Always return OK as smb/server may be down and
590 * Shares will be picked up when loaded.
591 */
592 return (SA_OK);
593 }
594
595 /*
596 * smb_share_changed(sa_share_t share)
597 *
598 * The specified share has changed.
599 */
600 static int
601 smb_share_changed(sa_share_t share)
602 {
603 char *path;
604 sa_resource_t resource;
605
606 if (!smb_isonline())
607 return (SA_OK);
608
609 /* get the path since it is important in several places */
610 path = sa_get_share_attr(share, "path");
611 if (path == NULL)
612 return (SA_NO_SUCH_PATH);
613
614 for (resource = sa_get_share_resource(share, NULL);
615 resource != NULL;
616 resource = sa_get_next_resource(resource))
617 (void) smb_resource_changed(resource);
618
619 sa_free_attr_string(path);
620
621 return (SA_OK);
622 }
623
624 /*
625 * smb_resource_changed(sa_resource_t resource)
626 *
627 * The specified resource has changed.
628 */
629 static int
630 smb_resource_changed(sa_resource_t resource)
631 {
632 uint32_t res;
633 sa_share_t share;
634 smb_share_t si;
635
636 if (!smb_isonline())
637 return (SA_OK);
638
639 if ((share = sa_get_resource_parent(resource)) == NULL)
640 return (SA_CONFIG_ERR);
641
642 if ((res = smb_build_shareinfo(share, resource, &si)) != SA_OK)
643 return (res);
644
645 res = smb_share_modify(&si);
646
647 if (res != NERR_Success)
648 return (SA_CONFIG_ERR);
649
650 return (smb_enable_service());
651 }
652
653 /*
654 * smb_disable_share(sa_share_t share, char *path)
655 *
656 * Unshare the specified share. Note that "path" is the same
657 * path as what is in the "share" object. It is passed in to avoid an
658 * additional lookup. A missing "path" value makes this a no-op
659 * function.
660 */
661 static int
662 smb_disable_share(sa_share_t share, char *path)
663 {
664 char *rname;
665 sa_resource_t resource;
666 sa_group_t parent;
667 boolean_t iszfs;
668 int err = SA_OK;
669 int ret = SA_OK;
670 sa_handle_t handle;
671 boolean_t first = B_TRUE; /* work around sharetab issue */
672
673 if (path == NULL)
674 return (ret);
675
676 /*
677 * If the share is in a ZFS group we need to handle it
678 * differently. Just being on a ZFS file system isn't
679 * enough since we may be in a legacy share case.
680 */
681 parent = sa_get_parent_group(share);
682 iszfs = sa_group_is_zfs(parent);
683
684 if (!smb_isonline())
685 goto done;
686
687 for (resource = sa_get_share_resource(share, NULL);
688 resource != NULL;
689 resource = sa_get_next_resource(resource)) {
690 rname = sa_get_resource_attr(resource, "name");
691 if (rname == NULL) {
692 continue;
693 }
694 if (!iszfs) {
695 err = smb_share_delete(rname);
696 switch (err) {
697 case NERR_NetNameNotFound:
698 case NERR_Success:
699 err = SA_OK;
700 break;
701 default:
702 err = SA_CONFIG_ERR;
703 break;
704 }
705 } else {
706 share_t sh;
707
708 (void) sa_sharetab_fill_zfs(share, &sh, "smb");
709 err = sa_share_zfs(share, resource, (char *)path, &sh,
710 rname, ZFS_UNSHARE_SMB);
711 if (err != SA_OK) {
712 switch (err) {
713 case EINVAL:
714 case ENOENT:
715 err = SA_OK;
716 break;
717 default:
718 /*
719 * If we are no longer the first case,
720 * we don't care about the sa_share_zfs
721 * err if it is -1. This works around
722 * a problem in sharefs and should be
723 * removed when sharefs supports
724 * multiple entries per path.
725 */
726 if (!first)
727 err = SA_OK;
728 else
729 err = SA_SYSTEM_ERR;
730 break;
731 }
732 }
733
734 first = B_FALSE;
735
736 sa_emptyshare(&sh);
737 }
738
739 if (err != SA_OK)
740 ret = err;
741 sa_free_attr_string(rname);
742 }
743 done:
744 if (!iszfs) {
745 handle = sa_find_group_handle((sa_group_t)share);
746 if (handle != NULL)
747 (void) sa_delete_sharetab(handle, path, "smb");
748 else
749 ret = SA_SYSTEM_ERR;
750 }
751 return (ret);
752 }
753
754 /*
755 * smb_validate_property(handle, property, parent)
756 *
757 * Check that the property has a legitimate value for its type.
758 * Handle isn't currently used but may need to be in the future.
759 */
760
761 /*ARGSUSED*/
762 static int
763 smb_validate_property(sa_handle_t handle, sa_property_t property,
764 sa_optionset_t parent)
765 {
766 int ret = SA_OK;
767 char *propname;
768 int optindex;
769 sa_group_t parent_group;
770 char *value;
771 char *other;
772
773 propname = sa_get_property_attr(property, "type");
774
775 if ((optindex = findopt(propname)) < 0)
776 ret = SA_NO_SUCH_PROP;
777
778 /* need to validate value range here as well */
779 if (ret == SA_OK) {
780 parent_group = sa_get_parent_group((sa_share_t)parent);
781 if (optdefs[optindex].share && !sa_is_share(parent_group))
782 ret = SA_PROP_SHARE_ONLY;
783 }
784 if (ret != SA_OK) {
785 if (propname != NULL)
786 sa_free_attr_string(propname);
787 return (ret);
788 }
789
790 value = sa_get_property_attr(property, "value");
791 if (value != NULL) {
792 /* first basic type checking */
793 switch (optdefs[optindex].type) {
794 case OPT_TYPE_NUMBER:
795 /* check that the value is all digits */
796 if (!is_a_number(value))
797 ret = SA_BAD_VALUE;
798 break;
799 case OPT_TYPE_BOOLEAN:
800 ret = true_false_validator(0, value);
801 break;
802 case OPT_TYPE_NAME:
803 /*
804 * Make sure no invalid characters
805 */
806 if (!validresource(value))
807 ret = SA_BAD_VALUE;
808 break;
809 case OPT_TYPE_STRING:
810 /* whatever is here should be ok */
811 break;
812 case OPT_TYPE_CSC:
813 if (!validcsc(value))
814 ret = SA_BAD_VALUE;
815 break;
816 case OPT_TYPE_ACCLIST: {
817 sa_property_t oprop;
818 char *ovalue;
819 /*
820 * access list handling. Should eventually
821 * validate that all the values make sense.
822 * Also, ro and rw may have cross value
823 * conflicts.
824 */
825 if (parent == NULL)
826 break;
827 if (strcmp(propname, SHOPT_RO) == 0)
828 other = SHOPT_RW;
829 else if (strcmp(propname, SHOPT_RW) == 0)
830 other = SHOPT_RO;
831 else
832 other = NULL;
833 if (other == NULL)
834 break;
835
836 /* compare rw(ro) with ro(rw) */
837 oprop = sa_get_property(parent, other);
838 if (oprop == NULL)
839 break;
840 /*
841 * only potential
842 * confusion if other
843 * exists
844 */
845 ovalue = sa_get_property_attr(oprop, "value");
846 if (ovalue != NULL) {
847 ret = check_rorw(value, ovalue);
848 sa_free_attr_string(ovalue);
849 }
850 break;
851 }
852 default:
853 break;
854 }
855 }
856
857 if (value != NULL)
858 sa_free_attr_string(value);
859 if (ret == SA_OK && optdefs[optindex].check != NULL)
860 /* do the property specific check */
861 ret = optdefs[optindex].check(property);
862
863 if (propname != NULL)
864 sa_free_attr_string(propname);
865 return (ret);
866 }
867
868 /*
869 * Protocol management functions
870 *
871 * properties defined in the default files are defined in
872 * proto_option_defs for parsing and validation.
873 */
874
875 struct smb_proto_option_defs {
876 int smb_index;
877 int32_t minval;
878 int32_t maxval; /* In case of length of string this should be max */
879 int (*validator)(int, char *);
880 int32_t refresh;
881 } smb_proto_options[] = {
882 { SMB_CI_SYS_CMNT, 0, MAX_VALUE_BUFLEN,
883 string_length_check_validator, SMB_REFRESH_REFRESH },
884 { SMB_CI_MAX_WORKERS, SMB_PI_MAX_WORKERS_MIN, SMB_PI_MAX_WORKERS_MAX,
885 range_check_validator, SMB_REFRESH_REFRESH },
886 { SMB_CI_NETBIOS_ENABLE, 0, 0, true_false_validator,
887 SMB_REFRESH_REFRESH },
888 { SMB_CI_NBSCOPE, 0, MAX_VALUE_BUFLEN,
889 string_length_check_validator, 0 },
890 { SMB_CI_LM_LEVEL, 2, 5, range_check_validator, 0 },
891 { SMB_CI_KEEPALIVE, 20, 5400, range_check_validator_zero_ok,
892 SMB_REFRESH_REFRESH },
893 { SMB_CI_WINS_SRV1, 0, MAX_VALUE_BUFLEN,
894 ipv4_validator, SMB_REFRESH_REFRESH },
895 { SMB_CI_WINS_SRV2, 0, MAX_VALUE_BUFLEN,
896 ipv4_validator, SMB_REFRESH_REFRESH },
897 { SMB_CI_WINS_EXCL, 0, MAX_VALUE_BUFLEN,
898 interface_validator, SMB_REFRESH_REFRESH },
899 { SMB_CI_SIGNING_ENABLE, 0, 0, true_false_validator,
900 SMB_REFRESH_REFRESH },
901 { SMB_CI_SIGNING_REQD, 0, 0, true_false_validator,
902 SMB_REFRESH_REFRESH },
903 { SMB_CI_RESTRICT_ANON, 0, 0, true_false_validator,
904 SMB_REFRESH_REFRESH },
905 { SMB_CI_DOMAIN_SRV, 0, MAX_VALUE_BUFLEN,
906 hostname_validator, SMB_REFRESH_REFRESH },
907 { SMB_CI_ADS_SITE, 0, MAX_VALUE_BUFLEN,
908 string_length_check_validator, SMB_REFRESH_REFRESH },
909 { SMB_CI_DYNDNS_ENABLE, 0, 0, true_false_validator, 0 },
910 { SMB_CI_AUTOHOME_MAP, 0, MAX_VALUE_BUFLEN, path_validator, 0 },
911 { SMB_CI_IPV6_ENABLE, 0, 0, true_false_validator,
912 SMB_REFRESH_REFRESH },
913 { SMB_CI_PRINT_ENABLE, 0, 0, print_enable_validator,
914 SMB_REFRESH_REFRESH },
915 { SMB_CI_TRAVERSE_MOUNTS, 0, 0, true_false_validator,
916 SMB_REFRESH_REFRESH },
917 { SMB_CI_MAP, 0, MAX_VALUE_BUFLEN, cmd_validator, SMB_REFRESH_REFRESH },
918 { SMB_CI_UNMAP, 0, MAX_VALUE_BUFLEN, cmd_validator,
919 SMB_REFRESH_REFRESH },
920 { SMB_CI_DISPOSITION, 0, MAX_VALUE_BUFLEN,
921 disposition_validator, SMB_REFRESH_REFRESH },
922 { SMB_CI_MAX_PROTOCOL, 0, MAX_VALUE_BUFLEN, protocol_validator,
923 SMB_REFRESH_REFRESH },
924 { SMB_CI_ENCRYPT, 0, MAX_VALUE_BUFLEN, require_validator,
925 SMB_REFRESH_REFRESH },
926 { SMB_CI_MIN_PROTOCOL, 0, MAX_VALUE_BUFLEN, protocol_validator,
927 SMB_REFRESH_REFRESH },
928 { SMB_CI_BYPASS_TRAVERSE_CHECKING, 0, 0, true_false_validator,
929 SMB_REFRESH_REFRESH },
930 { SMB_CI_OPLOCK_ENABLE, 0, 0, true_false_validator,
931 SMB_REFRESH_REFRESH },
932 };
933
934 #define SMB_OPT_NUM \
935 (sizeof (smb_proto_options) / sizeof (smb_proto_options[0]))
936
937 static int
938 require_validator(int index, char *value)
939 {
940 if (string_length_check_validator(index, value) != SA_OK)
941 return (SA_BAD_VALUE);
942
943 if (strcmp(value, "required") == 0)
944 return (SA_OK);
945
946 if (strcmp(value, "disabled") == 0)
947 return (SA_OK);
948
949 if (strcmp(value, "enabled") == 0)
950 return (SA_OK);
951
952 return (SA_BAD_VALUE);
953 }
954
955 /*
956 * Check the range of value as int range.
957 */
958 static int
959 range_check_validator(int index, char *value)
960 {
961 int ret = SA_OK;
962
963 if (!is_a_number(value)) {
964 ret = SA_BAD_VALUE;
965 } else {
966 int val;
967 val = strtoul(value, NULL, 0);
968 if (val < smb_proto_options[index].minval ||
969 val > smb_proto_options[index].maxval)
970 ret = SA_BAD_VALUE;
971 }
972 return (ret);
973 }
974
975 /*
976 * Check the range of value as int range.
977 */
978 static int
979 range_check_validator_zero_ok(int index, char *value)
980 {
981 int ret = SA_OK;
982
983 if (!is_a_number(value)) {
984 ret = SA_BAD_VALUE;
985 } else {
986 int val;
987 val = strtoul(value, NULL, 0);
988 if (val == 0)
989 ret = SA_OK;
990 else {
991 if (val < smb_proto_options[index].minval ||
992 val > smb_proto_options[index].maxval)
993 ret = SA_BAD_VALUE;
994 }
995 }
996 return (ret);
997 }
998
999 /*
1000 * Check the length of the string
1001 */
1002 static int
1003 string_length_check_validator(int index, char *value)
1004 {
1005 int ret = SA_OK;
1006
1007 if (value == NULL)
1008 return (SA_BAD_VALUE);
1009 if (strlen(value) > smb_proto_options[index].maxval)
1010 ret = SA_BAD_VALUE;
1011 return (ret);
1012 }
1013
1014 /*
1015 * Check yes/no
1016 */
1017 /*ARGSUSED*/
1018 static int
1019 true_false_validator(int index, char *value)
1020 {
1021 if (value == NULL)
1022 return (SA_BAD_VALUE);
1023 if ((strcasecmp(value, "true") == 0) ||
1024 (strcasecmp(value, "false") == 0))
1025 return (SA_OK);
1026 return (SA_BAD_VALUE);
1027 }
1028
1029 /*
1030 * If printing support is compiled in, this is the same as:
1031 * true_false_validator. Otherwise, only allow false.
1032 */
1033 /*ARGSUSED*/
1034 static int
1035 print_enable_validator(int index, char *value)
1036 {
1037 if (value == NULL)
1038 return (SA_BAD_VALUE);
1039
1040 #ifdef HAVE_CUPS
1041 if (strcasecmp(value, "true") == 0)
1042 return (SA_OK);
1043 #endif
1044 if (strcasecmp(value, "false") == 0)
1045 return (SA_OK);
1046
1047 return (SA_BAD_VALUE);
1048 }
1049
1050 /*
1051 * Check IP v4 address.
1052 */
1053 /*ARGSUSED*/
1054 static int
1055 ipv4_validator(int index, char *value)
1056 {
1057 char sbytes[16];
1058
1059 if (value == NULL)
1060 return (SA_OK);
1061
1062 if (strlen(value) == 0)
1063 return (SA_OK);
1064
1065 if (inet_pton(AF_INET, value, (void *)sbytes) != 1)
1066 return (SA_BAD_VALUE);
1067
1068 return (SA_OK);
1069 }
1070
1071 /*
1072 * Check that the specified name is an IP address (v4 or v6) or a hostname.
1073 * Per RFC 1035 and 1123, names may contain alphanumeric characters, hyphens
1074 * and dots. The first and last character of a label must be alphanumeric.
1075 * Interior characters may be alphanumeric or hypens.
1076 *
1077 * Domain names should not contain underscores but we allow them because
1078 * Windows names are often in non-compliance with this rule.
1079 */
1080 /*ARGSUSED*/
1081 static int
1082 hostname_validator(int index, char *value)
1083 {
1084 char sbytes[INET6_ADDRSTRLEN];
1085 boolean_t new_label = B_TRUE;
1086 char *p;
1087 char label_terminator;
1088 int len;
1089
1090 if (value == NULL)
1091 return (SA_OK);
1092
1093 if ((len = strlen(value)) == 0)
1094 return (SA_OK);
1095
1096 if (inet_pton(AF_INET, value, (void *)sbytes) == 1)
1097 return (SA_OK);
1098
1099 if (inet_pton(AF_INET6, value, (void *)sbytes) == 1)
1100 return (SA_OK);
1101
1102 if (len >= MAXHOSTNAMELEN)
1103 return (SA_BAD_VALUE);
1104
1105 if (strspn(value, "0123456789.") == len)
1106 return (SA_BAD_VALUE);
1107
1108 label_terminator = *value;
1109
1110 for (p = value; *p != '\0'; ++p) {
1111 if (new_label) {
1112 if (!isalnum(*p))
1113 return (SA_BAD_VALUE);
1114 new_label = B_FALSE;
1115 label_terminator = *p;
1116 continue;
1117 }
1118
1119 if (*p == '.') {
1120 if (!isalnum(label_terminator))
1121 return (SA_BAD_VALUE);
1122 new_label = B_TRUE;
1123 label_terminator = *p;
1124 continue;
1125 }
1126
1127 label_terminator = *p;
1128
1129 if (isalnum(*p) || *p == '-' || *p == '_')
1130 continue;
1131
1132 return (SA_BAD_VALUE);
1133 }
1134
1135 if (!isalnum(label_terminator))
1136 return (SA_BAD_VALUE);
1137
1138 return (SA_OK);
1139 }
1140
1141 /*
1142 * Call back function for dlpi_walk.
1143 * Returns TRUE if interface name exists on the host.
1144 */
1145 static boolean_t
1146 smb_get_interface(const char *ifname, void *arg)
1147 {
1148 smb_hostifs_walker_t *iterp = arg;
1149
1150 iterp->hiw_matchfound = (strcmp(ifname, iterp->hiw_ifname) == 0);
1151
1152 return (iterp->hiw_matchfound);
1153 }
1154
1155 /*
1156 * Checks to see if the input interface exists on the host.
1157 * Returns B_TRUE if the match is found, B_FALSE otherwise.
1158 */
1159 static boolean_t
1160 smb_validate_interface(const char *ifname)
1161 {
1162 smb_hostifs_walker_t iter;
1163
1164 if ((ifname == NULL) || (*ifname == '\0'))
1165 return (B_FALSE);
1166
1167 iter.hiw_ifname = ifname;
1168 iter.hiw_matchfound = B_FALSE;
1169 dlpi_walk(smb_get_interface, &iter, 0);
1170
1171 return (iter.hiw_matchfound);
1172 }
1173
1174 /*
1175 * Check valid interfaces. Interface names value can be NULL or empty.
1176 * Returns SA_BAD_VALUE if interface cannot be found on the host.
1177 */
1178 /*ARGSUSED*/
1179 static int
1180 interface_validator(int index, char *value)
1181 {
1182 char buf[16];
1183 int ret = SA_OK;
1184 char *ifname, *tmp, *p;
1185
1186 if (value == NULL || *value == '\0')
1187 return (ret);
1188
1189 if (strlen(value) > MAX_VALUE_BUFLEN)
1190 return (SA_BAD_VALUE);
1191
1192 if ((p = strdup(value)) == NULL)
1193 return (SA_NO_MEMORY);
1194
1195 tmp = p;
1196 while ((ifname = strsep(&tmp, ",")) != NULL) {
1197 if (*ifname == '\0') {
1198 ret = SA_BAD_VALUE;
1199 break;
1200 }
1201
1202 if (!smb_validate_interface(ifname)) {
1203 if (inet_pton(AF_INET, ifname, (void *)buf) == 0) {
1204 ret = SA_BAD_VALUE;
1205 break;
1206 }
1207 }
1208 }
1209
1210 free(p);
1211 return (ret);
1212 }
1213
1214 /*
1215 * Check path
1216 */
1217 /*ARGSUSED*/
1218 static int
1219 path_validator(int index, char *path)
1220 {
1221 struct stat buffer;
1222 int fd, status;
1223
1224 if (path == NULL)
1225 return (SA_BAD_VALUE);
1226
1227 fd = open(path, O_RDONLY);
1228 if (fd < 0)
1229 return (SA_BAD_VALUE);
1230
1231 status = fstat(fd, &buffer);
1232 (void) close(fd);
1233
1234 if (status < 0)
1235 return (SA_BAD_VALUE);
1236
1237 if (buffer.st_mode & S_IFDIR)
1238 return (SA_OK);
1239 return (SA_BAD_VALUE);
1240 }
1241
1242 /*
1243 * the protoset holds the defined options so we don't have to read
1244 * them multiple times
1245 */
1246 static sa_protocol_properties_t protoset;
1247
1248 static int
1249 findprotoopt(char *name)
1250 {
1251 int i;
1252 char *sc_name;
1253
1254 for (i = 0; i < SMB_OPT_NUM; i++) {
1255 sc_name = smb_config_getname(smb_proto_options[i].smb_index);
1256 if (strcasecmp(sc_name, name) == 0)
1257 return (i);
1258 }
1259
1260 return (-1);
1261 }
1262
1263 /*
1264 * smb_load_proto_properties()
1265 *
1266 * read the smb config values from SMF.
1267 */
1268
1269 static int
1270 smb_load_proto_properties()
1271 {
1272 sa_property_t prop;
1273 char value[MAX_VALUE_BUFLEN];
1274 char *name;
1275 int index;
1276 int ret = SA_OK;
1277 int rc;
1278
1279 protoset = sa_create_protocol_properties(SMB_PROTOCOL_NAME);
1280 if (protoset == NULL)
1281 return (SA_NO_MEMORY);
1282
1283 for (index = 0; index < SMB_OPT_NUM && ret == SA_OK; index++) {
1284 rc = smb_config_get(smb_proto_options[index].smb_index,
1285 value, sizeof (value));
1286 if (rc != SMBD_SMF_OK)
1287 continue;
1288 name = smb_config_getname(smb_proto_options[index].smb_index);
1289 prop = sa_create_property(name, value);
1290 if (prop != NULL)
1291 ret = sa_add_protocol_property(protoset, prop);
1292 else
1293 ret = SA_NO_MEMORY;
1294 }
1295 return (ret);
1296 }
1297
1298 /*
1299 * smb_share_init()
1300 *
1301 * Initialize the smb plugin.
1302 */
1303
1304 static int
1305 smb_share_init(void)
1306 {
1307 if (sa_plugin_ops.sa_init != smb_share_init)
1308 return (SA_SYSTEM_ERR);
1309
1310 smb_share_door_clnt_init();
1311 return (smb_load_proto_properties());
1312 }
1313
1314 /*
1315 * smb_share_fini()
1316 *
1317 */
1318 static void
1319 smb_share_fini(void)
1320 {
1321 xmlFreeNode(protoset);
1322 protoset = NULL;
1323
1324 smb_share_door_clnt_fini();
1325 }
1326
1327 /*
1328 * smb_get_proto_set()
1329 *
1330 * Return an optionset with all the protocol specific properties in
1331 * it.
1332 */
1333 static sa_protocol_properties_t
1334 smb_get_proto_set(void)
1335 {
1336 return (protoset);
1337 }
1338
1339 /*
1340 * smb_enable_dependencies()
1341 *
1342 * SMBD_DEFAULT_INSTANCE_FMRI may have some dependencies that aren't
1343 * enabled. This will attempt to enable all of them.
1344 */
1345 static void
1346 smb_enable_dependencies(const char *fmri)
1347 {
1348 scf_handle_t *handle;
1349 scf_service_t *service;
1350 scf_instance_t *inst = NULL;
1351 scf_iter_t *iter;
1352 scf_property_t *prop;
1353 scf_value_t *value;
1354 scf_propertygroup_t *pg;
1355 scf_scope_t *scope;
1356 char type[SCFTYPE_LEN];
1357 char *dependency;
1358 char *servname;
1359 int maxlen;
1360
1361 /*
1362 * Get all required handles and storage.
1363 */
1364 handle = scf_handle_create(SCF_VERSION);
1365 if (handle == NULL)
1366 return;
1367
1368 if (scf_handle_bind(handle) != 0) {
1369 scf_handle_destroy(handle);
1370 return;
1371 }
1372
1373 maxlen = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
1374 if (maxlen == (ssize_t)-1)
1375 maxlen = MAXPATHLEN;
1376
1377 dependency = malloc(maxlen);
1378
1379 service = scf_service_create(handle);
1380
1381 iter = scf_iter_create(handle);
1382
1383 pg = scf_pg_create(handle);
1384
1385 prop = scf_property_create(handle);
1386
1387 value = scf_value_create(handle);
1388
1389 scope = scf_scope_create(handle);
1390
1391 if (service == NULL || iter == NULL || pg == NULL || prop == NULL ||
1392 value == NULL || scope == NULL || dependency == NULL)
1393 goto done;
1394
1395 /*
1396 * We passed in the FMRI for the default instance but for
1397 * some things we need the simple form so construct it. Since
1398 * we reuse the storage that dependency points to, we need to
1399 * use the servname early.
1400 */
1401 (void) snprintf(dependency, maxlen, "%s", fmri + sizeof ("svc:"));
1402 servname = strrchr(dependency, ':');
1403 if (servname == NULL)
1404 goto done;
1405 *servname = '\0';
1406 servname = dependency;
1407
1408 /*
1409 * Setup to iterate over the service property groups, only
1410 * looking at those that are "dependency" types. The "entity"
1411 * property will have the FMRI of the service we are dependent
1412 * on.
1413 */
1414 if (scf_handle_get_scope(handle, SCF_SCOPE_LOCAL, scope) != 0)
1415 goto done;
1416
1417 if (scf_scope_get_service(scope, servname, service) != 0)
1418 goto done;
1419
1420 if (scf_iter_service_pgs(iter, service) != 0)
1421 goto done;
1422
1423 while (scf_iter_next_pg(iter, pg) > 0) {
1424 char *services[2];
1425 /*
1426 * Have a property group for the service. See if it is
1427 * a dependency pg and only do operations on those.
1428 */
1429 if (scf_pg_get_type(pg, type, SCFTYPE_LEN) <= 0)
1430 continue;
1431
1432 if (strncmp(type, SCF_GROUP_DEPENDENCY, SCFTYPE_LEN) != 0)
1433 continue;
1434 /*
1435 * Have a dependency. Attempt to enable it.
1436 */
1437 if (scf_pg_get_property(pg, SCF_PROPERTY_ENTITIES, prop) != 0)
1438 continue;
1439
1440 if (scf_property_get_value(prop, value) != 0)
1441 continue;
1442
1443 services[1] = NULL;
1444
1445 if (scf_value_get_as_string(value, dependency, maxlen) > 0) {
1446 services[0] = dependency;
1447 _check_services(services);
1448 }
1449 }
1450
1451 done:
1452 if (dependency != NULL)
1453 free(dependency);
1454 if (value != NULL)
1455 scf_value_destroy(value);
1456 if (prop != NULL)
1457 scf_property_destroy(prop);
1458 if (pg != NULL)
1459 scf_pg_destroy(pg);
1460 if (iter != NULL)
1461 scf_iter_destroy(iter);
1462 if (scope != NULL)
1463 scf_scope_destroy(scope);
1464 if (inst != NULL)
1465 scf_instance_destroy(inst);
1466 if (service != NULL)
1467 scf_service_destroy(service);
1468
1469 (void) scf_handle_unbind(handle);
1470 scf_handle_destroy(handle);
1471 }
1472
1473 /*
1474 * How long to wait for service to come online
1475 */
1476 #define WAIT_FOR_SERVICE 15
1477
1478 /*
1479 * smb_enable_service()
1480 *
1481 */
1482 static int
1483 smb_enable_service(void)
1484 {
1485 int i;
1486 int ret = SA_OK;
1487 char *service[] = { SMBD_DEFAULT_INSTANCE_FMRI, NULL };
1488
1489 if (!smb_isonline()) {
1490 /*
1491 * Attempt to start the idmap, and other dependent
1492 * services, first. If it fails, the SMB service will
1493 * ultimately fail so we use that as the error. If we
1494 * don't try to enable idmap, smb won't start the
1495 * first time unless the admin has done it
1496 * manually. The service could be administratively
1497 * disabled so we won't always get started.
1498 */
1499 smb_enable_dependencies(SMBD_DEFAULT_INSTANCE_FMRI);
1500 _check_services(service);
1501
1502 /* Wait for service to come online */
1503 for (i = 0; i < WAIT_FOR_SERVICE; i++) {
1504 if (smb_isonline()) {
1505 ret = SA_OK;
1506 break;
1507 } else if (smb_ismaint()) {
1508 /* maintenance requires help */
1509 ret = SA_SYSTEM_ERR;
1510 break;
1511 } else {
1512 /* try another time */
1513 ret = SA_BUSY;
1514 (void) sleep(1);
1515 }
1516 }
1517 }
1518 return (ret);
1519 }
1520
1521 /*
1522 * smb_validate_proto_prop(index, name, value)
1523 *
1524 * Verify that the property specified by name can take the new
1525 * value. This is a sanity check to prevent bad values getting into
1526 * the default files.
1527 */
1528 static int
1529 smb_validate_proto_prop(int index, char *name, char *value)
1530 {
1531 if ((name == NULL) || (index < 0))
1532 return (SA_BAD_VALUE);
1533
1534 if (smb_proto_options[index].validator == NULL)
1535 return (SA_OK);
1536
1537 if (smb_proto_options[index].validator(index, value) == SA_OK)
1538 return (SA_OK);
1539 return (SA_BAD_VALUE);
1540 }
1541
1542 /*
1543 * smb_set_proto_prop(prop)
1544 *
1545 * check that prop is valid.
1546 */
1547 /*ARGSUSED*/
1548 static int
1549 smb_set_proto_prop(sa_property_t prop)
1550 {
1551 int ret = SA_OK;
1552 char *name;
1553 char *value;
1554 int index = -1;
1555 struct smb_proto_option_defs *opt;
1556
1557 name = sa_get_property_attr(prop, "type");
1558 value = sa_get_property_attr(prop, "value");
1559 if (name != NULL && value != NULL) {
1560 index = findprotoopt(name);
1561 if (index >= 0) {
1562 /* should test for valid value */
1563 ret = smb_validate_proto_prop(index, name, value);
1564 if (ret == SA_OK) {
1565 opt = &smb_proto_options[index];
1566
1567 /* Save to SMF */
1568 if (smb_config_set(opt->smb_index,
1569 value) != 0) {
1570 ret = SA_BAD_VALUE;
1571 goto out;
1572 }
1573 /*
1574 * Specialized refresh mechanisms can
1575 * be flagged in the proto_options and
1576 * processed here.
1577 */
1578 if (opt->refresh & SMB_REFRESH_REFRESH)
1579 (void) smf_refresh_instance(
1580 SMBD_DEFAULT_INSTANCE_FMRI);
1581 else if (opt->refresh & SMB_REFRESH_RESTART)
1582 (void) smf_restart_instance(
1583 SMBD_DEFAULT_INSTANCE_FMRI);
1584 }
1585 }
1586 }
1587
1588 out:
1589 if (name != NULL)
1590 sa_free_attr_string(name);
1591 if (value != NULL)
1592 sa_free_attr_string(value);
1593
1594 return (ret);
1595 }
1596
1597 /*
1598 * smb_get_status()
1599 *
1600 * What is the current status of the smbd? We use the SMF state here.
1601 * Caller must free the returned value.
1602 */
1603
1604 static char *
1605 smb_get_status(void)
1606 {
1607 return (smf_get_state(SMBD_DEFAULT_INSTANCE_FMRI));
1608 }
1609
1610 /*
1611 * This protocol plugin require resource names
1612 */
1613 static uint64_t
1614 smb_share_features(void)
1615 {
1616 return (SA_FEATURE_RESOURCE | SA_FEATURE_ALLOWSUBDIRS |
1617 SA_FEATURE_ALLOWPARDIRS | SA_FEATURE_SERVER);
1618 }
1619
1620 /*
1621 * This should be used to convert smb_share_t to sa_resource_t
1622 * Should only be needed to build transient shares/resources to be
1623 * supplied to sharemgr to display.
1624 */
1625 static int
1626 smb_add_transient(sa_handle_t handle, smb_share_t *si)
1627 {
1628 int err;
1629 sa_share_t share;
1630 sa_group_t group;
1631 sa_resource_t resource;
1632 nvlist_t *nvl;
1633 char *opt;
1634
1635 if (si == NULL)
1636 return (SA_INVALID_NAME);
1637
1638 if ((share = sa_find_share(handle, si->shr_path)) == NULL) {
1639 if ((group = smb_get_defaultgrp(handle)) == NULL)
1640 return (SA_NO_SUCH_GROUP);
1641
1642 share = sa_get_share(group, si->shr_path);
1643 if (share == NULL) {
1644 share = sa_add_share(group, si->shr_path,
1645 SA_SHARE_TRANSIENT, &err);
1646 if (share == NULL)
1647 return (SA_NO_SUCH_PATH);
1648 }
1649 }
1650
1651 /*
1652 * Now handle the resource. Make sure that the resource is
1653 * transient and added to the share.
1654 */
1655 resource = sa_get_share_resource(share, si->shr_name);
1656 if (resource == NULL) {
1657 resource = sa_add_resource(share,
1658 si->shr_name, SA_SHARE_TRANSIENT, &err);
1659 if (resource == NULL)
1660 return (SA_NO_SUCH_RESOURCE);
1661 }
1662
1663 if (si->shr_cmnt[0] != '\0')
1664 (void) sa_set_resource_description(resource, si->shr_cmnt);
1665
1666 if (si->shr_container[0] != '\0')
1667 (void) sa_set_resource_attr(resource, SHOPT_AD_CONTAINER,
1668 si->shr_container);
1669
1670 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
1671 return (SA_NO_MEMORY);
1672
1673 if ((opt = smb_csc_name(si)) != NULL)
1674 err |= nvlist_add_string(nvl, SHOPT_CSC, opt);
1675
1676 opt = (si->shr_flags & SMB_SHRF_ABE) ? "true" : "false";
1677 err |= nvlist_add_string(nvl, SHOPT_ABE, opt);
1678
1679 if ((si->shr_flags & SMB_SHRF_AUTOHOME) == 0) {
1680 opt = (si->shr_flags & SMB_SHRF_GUEST_OK) ? "true" : "false";
1681 err |= nvlist_add_string(nvl, SHOPT_GUEST, opt);
1682 }
1683
1684 if (si->shr_access_ro[0] != '\0')
1685 err |= nvlist_add_string(nvl, SHOPT_RO, si->shr_access_ro);
1686
1687 if (si->shr_access_rw[0] != '\0')
1688 err |= nvlist_add_string(nvl, SHOPT_RW, si->shr_access_rw);
1689
1690 if (si->shr_access_none[0] != '\0')
1691 err |= nvlist_add_string(nvl, SHOPT_NONE, si->shr_access_none);
1692
1693 if (err) {
1694 nvlist_free(nvl);
1695 return (SA_CONFIG_ERR);
1696 }
1697
1698 err = smb_update_optionset_props(handle, resource, nvl);
1699
1700 nvlist_free(nvl);
1701 return (err);
1702 }
1703
1704 /*
1705 * Return smb transient shares.
1706 */
1707 static int
1708 smb_list_transient(sa_handle_t handle)
1709 {
1710 int i, offset;
1711 smb_shrlist_t list;
1712 int res;
1713
1714 if (smb_share_count() <= 0)
1715 return (SA_OK);
1716
1717 offset = 0;
1718 while (smb_share_list(offset, &list) == NERR_Success) {
1719 if (list.sl_cnt == 0)
1720 break;
1721
1722 for (i = 0; i < list.sl_cnt; i++) {
1723 res = smb_add_transient(handle, &(list.sl_shares[i]));
1724 if (res != SA_OK)
1725 return (res);
1726 }
1727 offset += list.sl_cnt;
1728 }
1729
1730 return (SA_OK);
1731 }
1732
1733 /*
1734 * fix_resource_name(share, name, prefix)
1735 *
1736 * Construct a name where the ZFS dataset has the prefix replaced with "name".
1737 */
1738 static char *
1739 fix_resource_name(sa_share_t share, char *name, char *prefix)
1740 {
1741 char buf[SA_MAX_RESOURCE_NAME + 1];
1742 char *dataset;
1743 size_t bufsz = SA_MAX_RESOURCE_NAME + 1;
1744 size_t prelen;
1745
1746 if (prefix == NULL)
1747 return (strdup(name));
1748
1749 dataset = sa_get_share_attr(share, "dataset");
1750 if (dataset == NULL)
1751 return (strdup(name));
1752
1753 (void) strlcpy(buf, name, bufsz);
1754 prelen = strlen(prefix);
1755
1756 if (strncmp(dataset, prefix, prelen) == 0)
1757 (void) strlcat(buf, dataset + prelen, bufsz);
1758
1759 sa_free_attr_string(dataset);
1760 sa_fix_resource_name(buf);
1761 return (strdup(buf));
1762 }
1763
1764 /*
1765 * smb_parse_optstring(group, options)
1766 *
1767 * parse a compact option string into individual options. This allows
1768 * ZFS sharesmb and sharemgr "share" command to work. group can be a
1769 * group, a share or a resource.
1770 */
1771 static int
1772 smb_parse_optstring(sa_group_t group, char *options)
1773 {
1774 char *dup;
1775 char *base;
1776 char *lasts;
1777 char *token;
1778 sa_optionset_t optionset;
1779 sa_group_t parent = NULL;
1780 sa_resource_t resource = NULL;
1781 int iszfs = 0;
1782 int persist = 0;
1783 int need_optionset = 0;
1784 int ret = SA_OK;
1785 sa_property_t prop;
1786
1787 /*
1788 * In order to not attempt to change ZFS properties unless
1789 * absolutely necessary, we never do it in the legacy parsing
1790 * so we need to keep track of this.
1791 */
1792 if (sa_is_share(group)) {
1793 char *zfs;
1794
1795 parent = sa_get_parent_group(group);
1796 if (parent != NULL) {
1797 zfs = sa_get_group_attr(parent, "zfs");
1798 if (zfs != NULL) {
1799 sa_free_attr_string(zfs);
1800 iszfs = 1;
1801 }
1802 }
1803 } else {
1804 iszfs = sa_group_is_zfs(group);
1805 /*
1806 * If a ZFS group, then we need to see if a resource
1807 * name is being set. If so, bail with
1808 * SA_PROP_SHARE_ONLY, so we come back in with a share
1809 * instead of a group.
1810 */
1811 if (iszfs ||
1812 strncmp(options, "name=", sizeof ("name=") - 1) == 0 ||
1813 strstr(options, ",name=") != NULL) {
1814 return (SA_PROP_SHARE_ONLY);
1815 }
1816 }
1817
1818 /* do we have an existing optionset? */
1819 optionset = sa_get_optionset(group, "smb");
1820 if (optionset == NULL) {
1821 /* didn't find existing optionset so create one */
1822 optionset = sa_create_optionset(group, "smb");
1823 if (optionset == NULL)
1824 return (SA_NO_MEMORY);
1825 } else {
1826 /*
1827 * If an optionset already exists, we've come through
1828 * twice so ignore the second time.
1829 */
1830 return (ret);
1831 }
1832
1833 /* We need a copy of options for the next part. */
1834 dup = strdup(options);
1835 if (dup == NULL)
1836 return (SA_NO_MEMORY);
1837
1838 /*
1839 * SMB properties are straightforward and are strings,
1840 * integers or booleans. Properties are separated by
1841 * commas. It will be necessary to parse quotes due to some
1842 * strings not having a restricted characters set.
1843 *
1844 * Note that names will create a resource. For now, if there
1845 * is a set of properties "before" the first name="", those
1846 * properties will be placed on the group.
1847 */
1848 persist = sa_is_persistent(group);
1849 base = dup;
1850 token = dup;
1851 lasts = NULL;
1852 while (token != NULL && ret == SA_OK) {
1853 ret = SA_OK;
1854 token = strtok_r(base, ",", &lasts);
1855 base = NULL;
1856 if (token != NULL) {
1857 char *value;
1858 /*
1859 * All SMB properties have values so there
1860 * MUST be an '=' character. If it doesn't,
1861 * it is a syntax error.
1862 */
1863 value = strchr(token, '=');
1864 if (value != NULL) {
1865 *value++ = '\0';
1866 } else {
1867 ret = SA_SYNTAX_ERR;
1868 break;
1869 }
1870 /*
1871 * We may need to handle a "name" property
1872 * that is a ZFS imposed resource name. Each
1873 * name would trigger getting a new "resource"
1874 * to put properties on. For now, assume no
1875 * "name" property for special handling.
1876 */
1877
1878 if (strcmp(token, SHOPT_NAME) == 0) {
1879 char *prefix;
1880 char *name = NULL;
1881 /*
1882 * We have a name, so now work on the
1883 * resource level. We have a "share"
1884 * in "group" due to the caller having
1885 * added it. If we are called with a
1886 * group, the check for group/share
1887 * at the beginning of this function
1888 * will bail out the parse if there is a
1889 * "name" but no share.
1890 */
1891 if (!iszfs) {
1892 ret = SA_SYNTAX_ERR;
1893 break;
1894 }
1895 /*
1896 * Make sure the parent group has the
1897 * "prefix" property since we will
1898 * need to use this for constructing
1899 * inherited name= values.
1900 */
1901 prefix = sa_get_group_attr(parent, "prefix");
1902 if (prefix == NULL) {
1903 prefix = sa_get_group_attr(parent,
1904 "name");
1905 if (prefix != NULL) {
1906 (void) sa_set_group_attr(parent,
1907 "prefix", prefix);
1908 }
1909 }
1910 name = fix_resource_name((sa_share_t)group,
1911 value, prefix);
1912 if (name != NULL) {
1913 resource = sa_add_resource(
1914 (sa_share_t)group, name,
1915 SA_SHARE_TRANSIENT, &ret);
1916 sa_free_attr_string(name);
1917 } else {
1918 ret = SA_NO_MEMORY;
1919 }
1920 if (prefix != NULL)
1921 sa_free_attr_string(prefix);
1922
1923 /* A resource level optionset is needed */
1924
1925 need_optionset = 1;
1926 if (resource == NULL) {
1927 ret = SA_NO_MEMORY;
1928 break;
1929 }
1930 continue;
1931 }
1932
1933 if (iszfs && strcmp(token, SHOPT_DESCRIPTION) == 0) {
1934 if (resource == NULL)
1935 (void) sa_set_share_description(
1936 (sa_share_t)group, value);
1937 else
1938 (void) sa_set_resource_description(
1939 resource, value);
1940 continue;
1941 }
1942
1943 if (need_optionset) {
1944 optionset = sa_create_optionset(resource,
1945 "smb");
1946 need_optionset = 0;
1947 }
1948
1949 prop = sa_create_property(token, value);
1950 if (prop == NULL)
1951 ret = SA_NO_MEMORY;
1952 else
1953 ret = sa_add_property(optionset, prop);
1954 if (ret != SA_OK)
1955 break;
1956 if (!iszfs)
1957 ret = sa_commit_properties(optionset, !persist);
1958 }
1959 }
1960 free(dup);
1961 return (ret);
1962 }
1963
1964 /*
1965 * smb_sprint_option(rbuff, rbuffsize, incr, prop, sep)
1966 *
1967 * provides a mechanism to format SMB properties into legacy output
1968 * format. If the buffer would overflow, it is reallocated and grown
1969 * as appropriate. Special cases of converting internal form of values
1970 * to those used by "share" are done. this function does one property
1971 * at a time.
1972 */
1973
1974 static void
1975 smb_sprint_option(char **rbuff, size_t *rbuffsize, size_t incr,
1976 sa_property_t prop, int sep)
1977 {
1978 char *name;
1979 char *value;
1980 int curlen;
1981 char *buff = *rbuff;
1982 size_t buffsize = *rbuffsize;
1983
1984 name = sa_get_property_attr(prop, "type");
1985 value = sa_get_property_attr(prop, "value");
1986 if (buff != NULL)
1987 curlen = strlen(buff);
1988 else
1989 curlen = 0;
1990 if (name != NULL) {
1991 int len;
1992 len = strlen(name) + sep;
1993
1994 /*
1995 * A future RFE would be to replace this with more
1996 * generic code and to possibly handle more types.
1997 *
1998 * For now, everything else is treated as a string. If
1999 * we get any properties that aren't exactly
2000 * name/value pairs, we may need to
2001 * interpret/transform.
2002 */
2003 if (value != NULL)
2004 len += 1 + strlen(value);
2005
2006 while (buffsize <= (curlen + len)) {
2007 /* need more room */
2008 buffsize += incr;
2009 buff = realloc(buff, buffsize);
2010 *rbuff = buff;
2011 *rbuffsize = buffsize;
2012 if (buff == NULL) {
2013 /* realloc failed so free everything */
2014 if (*rbuff != NULL)
2015 free(*rbuff);
2016 goto err;
2017 }
2018 }
2019 if (buff == NULL)
2020 goto err;
2021 (void) snprintf(buff + curlen, buffsize - curlen,
2022 "%s%s=%s", sep ? "," : "",
2023 name, value != NULL ? value : "\"\"");
2024
2025 }
2026 err:
2027 if (name != NULL)
2028 sa_free_attr_string(name);
2029 if (value != NULL)
2030 sa_free_attr_string(value);
2031 }
2032
2033 /*
2034 * smb_format_resource_options(resource, hier)
2035 *
2036 * format all the options on the group into a flattened option
2037 * string. If hier is non-zero, walk up the tree to get inherited
2038 * options.
2039 */
2040
2041 static char *
2042 smb_format_options(sa_group_t group, int hier)
2043 {
2044 sa_optionset_t options = NULL;
2045 sa_property_t prop;
2046 int sep = 0;
2047 char *buff;
2048 size_t buffsize;
2049
2050
2051 buff = malloc(OPT_CHUNK);
2052 if (buff == NULL)
2053 return (NULL);
2054
2055 buff[0] = '\0';
2056 buffsize = OPT_CHUNK;
2057
2058 /*
2059 * We may have a an optionset relative to this item. format
2060 * these if we find them and then add any security definitions.
2061 */
2062
2063 options = sa_get_derived_optionset(group, "smb", hier);
2064
2065 /*
2066 * do the default set first but skip any option that is also
2067 * in the protocol specific optionset.
2068 */
2069 if (options != NULL) {
2070 for (prop = sa_get_property(options, NULL);
2071 prop != NULL; prop = sa_get_next_property(prop)) {
2072 /*
2073 * use this one since we skipped any
2074 * of these that were also in
2075 * optdefault
2076 */
2077 smb_sprint_option(&buff, &buffsize, OPT_CHUNK,
2078 prop, sep);
2079 if (buff == NULL) {
2080 /*
2081 * buff could become NULL if there
2082 * isn't enough memory for
2083 * smb_sprint_option to realloc()
2084 * as necessary. We can't really
2085 * do anything about it at this
2086 * point so we return NULL. The
2087 * caller should handle the
2088 * failure.
2089 */
2090 if (options != NULL)
2091 sa_free_derived_optionset(
2092 options);
2093 return (buff);
2094 }
2095 sep = 1;
2096 }
2097 }
2098
2099 if (options != NULL)
2100 sa_free_derived_optionset(options);
2101 return (buff);
2102 }
2103
2104 /*
2105 * smb_rename_resource(resource, newname)
2106 *
2107 * Change the current exported name of the resource to newname.
2108 */
2109 /*ARGSUSED*/
2110 int
2111 smb_rename_resource(sa_handle_t handle, sa_resource_t resource, char *newname)
2112 {
2113 int ret = SA_OK;
2114 int err;
2115 char *oldname;
2116
2117 if (!smb_isonline())
2118 return (SA_OK);
2119
2120 oldname = sa_get_resource_attr(resource, "name");
2121 if (oldname == NULL)
2122 return (SA_NO_SUCH_RESOURCE);
2123
2124 err = smb_share_rename(oldname, newname);
2125
2126 sa_free_attr_string(oldname);
2127
2128 /* improve error values somewhat */
2129 switch (err) {
2130 case NERR_Success:
2131 break;
2132 case NERR_InternalError:
2133 ret = SA_SYSTEM_ERR;
2134 break;
2135 case NERR_DuplicateShare:
2136 ret = SA_DUPLICATE_NAME;
2137 break;
2138 default:
2139 ret = SA_CONFIG_ERR;
2140 break;
2141 }
2142
2143 return (ret);
2144 }
2145
2146 static int
2147 smb_build_shareinfo(sa_share_t share, sa_resource_t resource, smb_share_t *si)
2148 {
2149 sa_optionset_t opts;
2150 char *path;
2151 char *rname;
2152 char *val = NULL;
2153 char csc_value[SMB_CSC_BUFSZ];
2154 char strbuf[sizeof ("required")];
2155
2156 bzero(si, sizeof (smb_share_t));
2157
2158 if ((path = sa_get_share_attr(share, "path")) == NULL)
2159 return (SA_NO_SUCH_PATH);
2160
2161 if ((rname = sa_get_resource_attr(resource, "name")) == NULL) {
2162 sa_free_attr_string(path);
2163 return (SA_NO_SUCH_RESOURCE);
2164 }
2165
2166 (void) strlcpy(si->shr_path, path, sizeof (si->shr_path));
2167 (void) strlcpy(si->shr_name, rname, sizeof (si->shr_name));
2168 sa_free_attr_string(path);
2169 sa_free_attr_string(rname);
2170
2171 val = sa_get_resource_description(resource);
2172 if (val == NULL)
2173 val = sa_get_share_description(share);
2174
2175 if (val != NULL) {
2176 (void) strlcpy(si->shr_cmnt, val, sizeof (si->shr_cmnt));
2177 sa_free_share_description(val);
2178 }
2179
2180 si->shr_flags = (sa_is_persistent(share))
2181 ? SMB_SHRF_PERM : SMB_SHRF_TRANS;
2182
2183 opts = sa_get_derived_optionset(resource, SMB_PROTOCOL_NAME, 1);
2184 if (opts == NULL)
2185 return (SA_OK);
2186
2187 if (smb_saprop_getbool(opts, SHOPT_CATIA, B_FALSE))
2188 si->shr_flags |= SMB_SHRF_CATIA;
2189
2190 if (smb_saprop_getbool(opts, SHOPT_ABE, B_FALSE))
2191 si->shr_flags |= SMB_SHRF_ABE;
2192
2193 if (smb_saprop_getbool(opts, SHOPT_GUEST, B_FALSE))
2194 si->shr_flags |= SMB_SHRF_GUEST_OK;
2195
2196 if (smb_saprop_getbool(opts, SHOPT_DFSROOT, B_FALSE))
2197 si->shr_flags |= SMB_SHRF_DFSROOT;
2198
2199 if (smb_saprop_getbool(opts, SHOPT_CA, B_FALSE))
2200 si->shr_flags |= SMB_SHRF_CA;
2201
2202 if (smb_saprop_getbool(opts, SHOPT_FSO, B_FALSE))
2203 si->shr_flags |= SMB_SHRF_FSO;
2204
2205 /* Quotas are enabled by default. */
2206 if (smb_saprop_getbool(opts, SHOPT_QUOTAS, B_TRUE))
2207 si->shr_flags |= SMB_SHRF_QUOTAS;
2208
2209 if (smb_saprop_getstr(opts, SHOPT_ENCRYPT, strbuf, sizeof (strbuf)))
2210 smb_cfg_set_require(strbuf, &si->shr_encrypt);
2211
2212 (void) smb_saprop_getstr(opts, SHOPT_AD_CONTAINER, si->shr_container,
2213 sizeof (si->shr_container));
2214
2215 if (smb_saprop_getstr(opts, SHOPT_CSC, csc_value, sizeof (csc_value)))
2216 smb_csc_option(csc_value, si);
2217
2218 if (smb_saprop_getstr(opts, SHOPT_RO, si->shr_access_ro,
2219 sizeof (si->shr_access_ro)))
2220 si->shr_flags |= SMB_SHRF_ACC_RO;
2221
2222 if (smb_saprop_getstr(opts, SHOPT_RW, si->shr_access_rw,
2223 sizeof (si->shr_access_rw)))
2224 si->shr_flags |= SMB_SHRF_ACC_RW;
2225
2226 if (smb_saprop_getstr(opts, SHOPT_NONE, si->shr_access_none,
2227 sizeof (si->shr_access_none)))
2228 si->shr_flags |= SMB_SHRF_ACC_NONE;
2229
2230 sa_free_derived_optionset(opts);
2231 return (SA_OK);
2232 }
2233
2234 /*
2235 * Map a client-side caching (CSC) option to the appropriate share
2236 * flag. Only one option is allowed; an error will be logged if
2237 * multiple options have been specified. We don't need to do anything
2238 * about multiple values here because the SRVSVC will not recognize
2239 * a value containing multiple flags and will return the default value.
2240 *
2241 * If the option value is not recognized, it will be ignored: invalid
2242 * values will typically be caught and rejected by sharemgr.
2243 */
2244 static void
2245 smb_csc_option(const char *value, smb_share_t *si)
2246 {
2247 char buf[SMB_CSC_BUFSZ];
2248 int i;
2249
2250 for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
2251 if (strcasecmp(value, cscopt[i].value) == 0) {
2252 si->shr_flags |= cscopt[i].flag;
2253 break;
2254 }
2255 }
2256
2257 switch (si->shr_flags & SMB_SHRF_CSC_MASK) {
2258 case 0:
2259 case SMB_SHRF_CSC_DISABLED:
2260 case SMB_SHRF_CSC_MANUAL:
2261 case SMB_SHRF_CSC_AUTO:
2262 case SMB_SHRF_CSC_VDO:
2263 break;
2264
2265 default:
2266 buf[0] = '\0';
2267
2268 for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
2269 if (si->shr_flags & cscopt[i].flag) {
2270 (void) strlcat(buf, " ", SMB_CSC_BUFSZ);
2271 (void) strlcat(buf, cscopt[i].value,
2272 SMB_CSC_BUFSZ);
2273 }
2274 }
2275
2276 syslog(LOG_ERR, "csc option conflict:%s", buf);
2277 break;
2278 }
2279 }
2280
2281 /*
2282 * Return the option name for the first CSC flag (there should be only
2283 * one) encountered in the share flags.
2284 */
2285 static char *
2286 smb_csc_name(const smb_share_t *si)
2287 {
2288 int i;
2289
2290 for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
2291 if (si->shr_flags & cscopt[i].flag)
2292 return (cscopt[i].value);
2293 }
2294
2295 return (NULL);
2296 }
2297
2298 /*
2299 * smb_get_defaultgrp
2300 *
2301 * If default group for CIFS shares (i.e. "smb") exists
2302 * then it will return the group handle, otherwise it will
2303 * create the group and return the handle.
2304 *
2305 * All the shares created by CIFS clients (this is only possible
2306 * via RPC) will be added to "smb" groups.
2307 */
2308 static sa_group_t
2309 smb_get_defaultgrp(sa_handle_t handle)
2310 {
2311 sa_group_t group = NULL;
2312 int err;
2313
2314 group = sa_get_group(handle, SMB_DEFAULT_SHARE_GROUP);
2315 if (group != NULL)
2316 return (group);
2317
2318 group = sa_create_group(handle, SMB_DEFAULT_SHARE_GROUP, &err);
2319 if (group == NULL)
2320 return (NULL);
2321
2322 if (sa_create_optionset(group, SMB_DEFAULT_SHARE_GROUP) == NULL) {
2323 (void) sa_remove_group(group);
2324 group = NULL;
2325 }
2326
2327 return (group);
2328 }
2329
2330 /*
2331 * Checks to see if the command args are the supported substitution specifier.
2332 * i.e. <cmd> %U %S
2333 */
2334 static int
2335 cmd_validator(int index, char *value)
2336 {
2337 char cmd[MAXPATHLEN];
2338 char *ptr, *v;
2339 boolean_t skip_cmdname;
2340
2341 if (string_length_check_validator(index, value) != SA_OK)
2342 return (SA_BAD_VALUE);
2343
2344 if (*value == '\0')
2345 return (SA_OK);
2346
2347 (void) strlcpy(cmd, value, sizeof (cmd));
2348
2349 ptr = cmd;
2350 skip_cmdname = B_TRUE;
2351 do {
2352 if ((v = strsep(&ptr, " ")) == NULL)
2353 break;
2354
2355 if (*v != '\0') {
2356
2357 if (skip_cmdname) {
2358 skip_cmdname = B_FALSE;
2359 continue;
2360 }
2361
2362 if ((strlen(v) != 2) || *v != '%')
2363 return (SA_BAD_VALUE);
2364
2365 if (strpbrk(v, SMB_VALID_SUB_CHRS) == NULL)
2366 return (SA_BAD_VALUE);
2367 }
2368
2369 } while (v != NULL);
2370
2371 /*
2372 * If skip_cmdname is still true then the string contains
2373 * only spaces. Don't allow such a string.
2374 */
2375 if (skip_cmdname)
2376 return (SA_BAD_VALUE);
2377
2378 return (SA_OK);
2379 }
2380
2381 /*ARGSUSED*/
2382 static int
2383 disposition_validator(int index, char *value)
2384 {
2385 if (value == NULL)
2386 return (SA_BAD_VALUE);
2387
2388 if (*value == '\0')
2389 return (SA_OK);
2390
2391 if ((strcasecmp(value, SMB_EXEC_DISP_CONTINUE) == 0) ||
2392 (strcasecmp(value, SMB_EXEC_DISP_TERMINATE) == 0))
2393 return (SA_OK);
2394
2395 return (SA_BAD_VALUE);
2396 }
2397
2398 /*ARGSUSED*/
2399 static int
2400 protocol_validator(int index, char *value)
2401 {
2402 if (value == NULL)
2403 return (SA_BAD_VALUE);
2404
2405 if (*value == '\0')
2406 return (SA_OK);
2407
2408 if (smb_config_check_protocol(value) == 0)
2409 return (SA_OK);
2410
2411 return (SA_BAD_VALUE);
2412
2413 }
2414
2415 /*
2416 * Updates the optionset properties of the share resource.
2417 * The properties are given as a list of name-value pair.
2418 * The name argument should be the optionset property name and the value
2419 * should be a valid value for the specified property.
2420 *
2421 * When calling this function for permanent shares, the caller must also
2422 * call sa_commit_properties() to commit the changes to SMF.
2423 */
2424 static int
2425 smb_update_optionset_props(sa_handle_t handle, sa_resource_t resource,
2426 nvlist_t *nvl)
2427 {
2428 sa_property_t prop;
2429 sa_optionset_t opts;
2430 int err = SA_OK;
2431 nvpair_t *cur;
2432 char *name, *val;
2433
2434 if ((opts = sa_get_optionset(resource, SMB_PROTOCOL_NAME)) == NULL) {
2435 opts = sa_create_optionset(resource, SMB_PROTOCOL_NAME);
2436 if (opts == NULL)
2437 return (SA_CONFIG_ERR);
2438 }
2439
2440 cur = nvlist_next_nvpair(nvl, NULL);
2441 while (cur != NULL) {
2442 name = nvpair_name(cur);
2443 err = nvpair_value_string(cur, &val);
2444 if ((err != 0) || (name == NULL) || (val == NULL)) {
2445 err = SA_CONFIG_ERR;
2446 break;
2447 }
2448
2449 prop = NULL;
2450 if ((prop = sa_get_property(opts, name)) == NULL) {
2451 prop = sa_create_property(name, val);
2452 if (prop != NULL) {
2453 err = sa_valid_property(handle, opts,
2454 SMB_PROTOCOL_NAME, prop);
2455 if (err != SA_OK) {
2456 (void) sa_remove_property(prop);
2457 break;
2458 }
2459 }
2460 err = sa_add_property(opts, prop);
2461 if (err != SA_OK)
2462 break;
2463 } else {
2464 err = sa_update_property(prop, val);
2465 if (err != SA_OK)
2466 break;
2467 }
2468
2469 cur = nvlist_next_nvpair(nvl, cur);
2470 }
2471
2472 return (err);
2473 }
2474
2475 static boolean_t
2476 smb_saprop_getbool(sa_optionset_t opts, char *propname, boolean_t def)
2477 {
2478 sa_property_t prop;
2479 char *val;
2480 boolean_t ret = def;
2481
2482 prop = sa_get_property(opts, propname);
2483 if ((val = sa_get_property_attr(prop, "value")) != NULL) {
2484 if (def) {
2485 /* Default is true, ret false if... */
2486 if ((strcasecmp(val, "false") == 0) ||
2487 (strcmp(val, "0") == 0))
2488 ret = B_FALSE;
2489 } else {
2490 /* Default is false, ret true if... */
2491 if ((strcasecmp(val, "true") == 0) ||
2492 (strcmp(val, "1") == 0))
2493 ret = B_TRUE;
2494 }
2495 free(val);
2496 }
2497
2498 return (ret);
2499 }
2500
2501 static boolean_t
2502 smb_saprop_getstr(sa_optionset_t opts, char *propname, char *buf, size_t bufsz)
2503 {
2504 sa_property_t prop;
2505 char *val;
2506
2507 prop = sa_get_property(opts, propname);
2508 if ((val = sa_get_property_attr(prop, "value")) != NULL) {
2509 (void) strlcpy(buf, val, bufsz);
2510 free(val);
2511 return (B_TRUE);
2512 }
2513
2514 return (B_FALSE);
2515 }