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