4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * SMB specific functions
40 #include <sys/types.h>
44 #include "libshare_impl.h"
49 #include "libshare_smbfs.h"
50 #include <rpcsvc/daemon_utils.h>
51 #include <arpa/inet.h>
52 #include <uuid/uuid.h>
53 #include <netsmb/smb_lib.h>
55 #define SMBFS_PROTOCOL_NAME "smbfs"
57 /* internal functions */
58 static uint64_t smbfs_features();
59 static int smbfs_init();
60 static void smbfs_fini();
61 static int smbfs_set_proto_prop(sa_property_t
);
62 static sa_protocol_properties_t
smbfs_get_proto_set();
63 static char *smbfs_get_status();
64 static int smbfs_delete_section(char *);
65 static int smbfs_delete_property_group(char *);
67 static int range_check_validator(int, char *, char *);
68 static int string_length_check_validator(int, char *, char *);
69 static int yes_no_validator(int, char *, char *);
70 static int ip_address_validator(int, char *, char *);
71 static int minauth_validator(int, char *, char *);
72 static int password_validator(int, char *, char *);
73 static int signing_validator(int, char *, char *);
75 int propset_changed
= 0;
78 * ops vector that provides the protocol specific info and operations
79 * for share management.
82 struct sa_plugin_ops sa_plugin_ops
= {
89 NULL
, /* valid_prop */
90 NULL
, /* valid_space */
91 NULL
, /* security_prop */
92 NULL
, /* legacy_opts */
93 NULL
, /* legacy_format */
97 NULL
, /* space_alias */
98 NULL
, /* update_legacy */
99 NULL
, /* delete_legacy */
100 NULL
, /* change_notify */
101 NULL
, /* enable_resource */
102 NULL
, /* disable_resource */
104 NULL
, /* get_transient_shares */
105 NULL
, /* notify_resource */
106 NULL
, /* rename_resource */
107 NULL
, /* run_command */
108 NULL
, /* command_help */
109 smbfs_delete_section
,
113 * is_a_number(number)
115 * is the string a number in one of the forms we want to use?
119 is_a_number(char *number
)
124 if (strncmp(number
, "0x", 2) == 0) {
127 } else if (*number
== '-') {
128 number
++; /* skip the minus */
131 while (ret
== 1 && *number
!= '\0') {
133 ret
= isxdigit(*number
++);
135 ret
= isdigit(*number
++);
142 * Protocol management functions
144 * properties defined in the default files are defined in
145 * proto_option_defs for parsing and validation.
148 struct smbclnt_proto_option_defs smbclnt_proto_options
[] = {
149 { "section", NULL
, PROTO_OPT_SECTION
,
150 0, 0, MAX_VALUE_BUFLEN
,
151 string_length_check_validator
},
152 { "addr", NULL
, PROTO_OPT_ADDR
,
153 0, 0, MAX_VALUE_BUFLEN
,
154 ip_address_validator
},
155 { "minauth", NULL
, PROTO_OPT_MINAUTH
,
156 0, 0, MAX_VALUE_BUFLEN
,
158 { "nbns_broadcast", NULL
, PROTO_OPT_NBNS_BROADCAST
,
161 { "nbns_enable", NULL
, PROTO_OPT_NBNS_ENABLE
,
164 { "nbns", NULL
, PROTO_OPT_NBNSADDR
,
165 0, 0, MAX_VALUE_BUFLEN
,
166 ip_address_validator
},
167 { "password", NULL
, PROTO_OPT_PASSWORD
,
168 0, 0, MAX_VALUE_BUFLEN
,
170 { "timeout", NULL
, PROTO_OPT_TIMEOUT
,
172 range_check_validator
},
173 { "user", NULL
, PROTO_OPT_USER
,
174 0, 0, MAX_VALUE_BUFLEN
,
175 string_length_check_validator
},
176 { "domain", NULL
, PROTO_OPT_DOMAIN
,
177 0, 0, MAX_VALUE_BUFLEN
,
178 string_length_check_validator
},
179 { "workgroup", NULL
, PROTO_OPT_WORKGROUP
,
180 0, 0, MAX_VALUE_BUFLEN
,
181 string_length_check_validator
},
182 { "signing", NULL
, PROTO_OPT_SIGNING
,
183 0, 0, MAX_VALUE_BUFLEN
,
189 * Check the range of value as int range.
193 range_check_validator(int index
, char *section
, char *value
)
198 return (SA_BAD_VALUE
);
199 if (strlen(value
) == 0)
201 if (!is_a_number(value
)) {
205 val
= strtoul(value
, NULL
, 0);
206 if (val
< smbclnt_proto_options
[index
].minval
||
207 val
> smbclnt_proto_options
[index
].maxval
)
214 * Check the length of the string
218 string_length_check_validator(int index
, char *section
, char *value
)
223 return (SA_BAD_VALUE
);
224 if (strlen(value
) == 0)
226 if (strlen(value
) > smbclnt_proto_options
[index
].maxval
)
236 yes_no_validator(int index
, char *section
, char *value
)
239 return (SA_BAD_VALUE
);
240 if (strlen(value
) == 0)
242 if ((strcasecmp(value
, "yes") == 0) ||
243 (strcasecmp(value
, "no") == 0) ||
244 (strcasecmp(value
, "true") == 0) ||
245 (strcasecmp(value
, "false") == 0))
247 return (SA_BAD_VALUE
);
255 ip_address_validator(int index
, char *section
, char *value
)
260 return (SA_BAD_VALUE
);
264 if (len
> MAX_VALUE_BUFLEN
)
265 return (SA_BAD_VALUE
);
271 minauth_validator(int index
, char *section
, char *value
)
274 return (SA_BAD_VALUE
);
275 if (strlen(value
) == 0)
277 if (strcmp(value
, "kerberos") == 0 ||
278 strcmp(value
, "ntlmv2") == 0 ||
279 strcmp(value
, "ntlm") == 0 ||
280 strcmp(value
, "lm") == 0 ||
281 strcmp(value
, "none") == 0)
284 return (SA_BAD_VALUE
);
289 signing_validator(int index
, char *section
, char *value
)
292 return (SA_BAD_VALUE
);
293 if (strlen(value
) == 0)
295 if (strcmp(value
, "disabled") == 0 ||
296 strcmp(value
, "enabled") == 0 ||
297 strcmp(value
, "required") == 0)
300 return (SA_BAD_VALUE
);
305 password_validator(int index
, char *section
, char *value
)
309 /* mangled passwords will start with this pattern */
310 if (strlen(value
) == 0)
312 if (strncmp(value
, "$$1", 3) != 0)
313 return (SA_PASSWORD_ENC
);
314 if (smb_simpledecrypt(buffer
, value
) != 0)
315 return (SA_BAD_VALUE
);
321 * the protoset holds the defined options so we don't have to read
322 * them multiple times
324 sa_protocol_properties_t protoset
;
327 findprotoopt(char *name
)
330 for (i
= 0; smbclnt_proto_options
[i
].name
!= NULL
; i
++) {
331 if (strcasecmp(smbclnt_proto_options
[i
].name
, name
) == 0)
338 * Load the persistent settings from SMF. Each section is an SMF
339 * property group with an "S-" prefix and a UUID, and the section
340 * is itself a property which can have a more flexible name than
341 * a property group name can have. The section name need not be
342 * the first property, so we have to be a little flexible, but
343 * the change of name of the property groups is a reliable way
344 * to know that we're seeing a different section.
347 smbclnt_config_load()
349 scf_simple_app_props_t
*props
= NULL
;
350 scf_simple_prop_t
*prop
= NULL
, *lastprop
= NULL
;
351 char *lastpgname
= NULL
, *pgname
= NULL
;
352 char *name
= NULL
, *value
= NULL
;
353 sa_property_t sect
, node
;
355 props
= scf_simple_app_props_get(NULL
, SMBC_DEFAULT_INSTANCE_FMRI
);
361 prop
= (scf_simple_prop_t
*)
362 scf_simple_app_props_next(props
, lastprop
);
366 /* Ignore properties that don't have our prefix */
367 pgname
= scf_simple_prop_pgname(prop
);
368 if (strncmp("S-", pgname
, 2) != 0)
372 * Note property group name changes, which mark sections
374 * The memory allocated by sa_create_section is
375 * linked into the list of children under protoset,
376 * and will eventually be freed via that list.
378 if (lastpgname
== NULL
|| strcmp(lastpgname
, pgname
) != 0) {
379 sect
= sa_create_section(NULL
, pgname
+2);
380 (void) xmlSetProp(sect
, (xmlChar
*)"type",
381 (xmlChar
*)SMBFS_PROTOCOL_NAME
);
382 (void) sa_add_protocol_property(protoset
, sect
);
385 lastpgname
= strdup(pgname
);
387 name
= scf_simple_prop_name(prop
);
388 value
= scf_simple_prop_next_astring(prop
);
390 /* If we get a section name, apply it and consume it */
391 if (strncmp("section", name
, 7) == 0 && value
!= NULL
) {
392 (void) xmlSetProp(sect
, (xmlChar
*)"name",
398 * We have an ordinary property. Add to the section.
400 * The memory allocated by sa_create_property is
401 * linked into the list of children under "sect",
402 * and will eventually be freed via that list.
404 node
= sa_create_property(name
, value
);
405 (void) sa_add_protocol_property(sect
, node
);
407 scf_simple_app_props_free(props
);
415 * Save the set of properties for a particular section, which is
416 * stored as a single property group. Properties will have been
417 * changed earlier by one or more calls to smbfs_save_property(),
418 * which only set the value in our array and marked them as
424 smb_scfhandle_t
*handle
= NULL
;
426 char *section
= smbclnt_proto_options
[PROTO_OPT_SECTION
].value
;
430 sa_property_t propset
;
431 int new = 0, nonnull
= 0;
433 propset
= sa_get_protocol_section(protoset
, section
);
434 (void) strlcpy(propgroup
, SMBC_PG_PREFIX
, sizeof (propgroup
));
435 propgroup
[SMBC_PG_PREFIX_LEN
] = '\0';
436 uu
= sa_get_property_attr(propset
, "extra");
438 (void) strlcat(propgroup
, uu
, sizeof (propgroup
));
442 smbclnt_proto_options
[PROTO_OPT_SECTION
].flags
|= SMBC_MODIFIED
;
444 uuid_unparse(uuid
, &propgroup
[SMBC_PG_PREFIX_LEN
]);
447 handle
= smb_smf_scf_init(SMBC_FMRI_PREFIX
);
448 if (handle
== NULL
) {
452 if ((ret
= smb_smf_instance_create(handle
, SMBC_FMRI_PREFIX
,
453 SMBC_PG_INSTANCE
)) != SMBC_SMF_OK
) {
457 if ((ret
= smb_smf_create_instance_pgroup(handle
, propgroup
))
462 if ((ret
= smb_smf_start_transaction(handle
)) != SMBC_SMF_OK
) {
466 for (i
= PROTO_OPT_SECTION
+1; i
<= SMBC_OPT_MAX
; i
++) {
467 if ((smbclnt_proto_options
[i
].flags
& SMBC_MODIFIED
) == 0)
469 if (strcmp(smbclnt_proto_options
[i
].value
, "") == 0)
470 ret
= smb_smf_delete_property(handle
,
471 smbclnt_proto_options
[i
].name
);
473 ret
= smb_smf_set_string_property(handle
,
474 smbclnt_proto_options
[i
].name
,
475 smbclnt_proto_options
[i
].value
);
478 free(smbclnt_proto_options
[i
].value
);
479 smbclnt_proto_options
[i
].value
= NULL
;
480 smbclnt_proto_options
[i
].flags
&= ~SMBC_MODIFIED
;
481 if (ret
!= SMBC_SMF_OK
)
485 * Suppress new, null entries by not saving the section name.
487 if (!new || nonnull
) {
488 ret
= smb_smf_set_string_property(handle
,
489 smbclnt_proto_options
[PROTO_OPT_SECTION
].name
,
490 smbclnt_proto_options
[PROTO_OPT_SECTION
].value
);
491 free(smbclnt_proto_options
[PROTO_OPT_SECTION
].value
);
492 smbclnt_proto_options
[PROTO_OPT_SECTION
].value
= NULL
;
493 smbclnt_proto_options
[PROTO_OPT_SECTION
].flags
&=
499 ret
= smb_smf_end_transaction(handle
);
501 smb_smf_scf_fini(handle
);
506 * initprotofromdefault()
508 * read the default file(s) and add the defined values to the
509 * protoset. Note that default values are known from the built in
510 * table in case the file doesn't have a definition.
514 initprotofromdefault()
516 protoset
= sa_create_protocol_properties(SMBFS_PROTOCOL_NAME
);
517 if (protoset
== NULL
)
518 return (SA_NO_MEMORY
);
519 if (smbclnt_config_load() != 0)
529 * Report the plugin's features
534 return (SA_FEATURE_HAS_SECTIONS
| SA_FEATURE_ADD_PROPERTIES
);
540 * Initialize the smb plugin.
548 if (sa_plugin_ops
.sa_init
!= smbfs_init
) {
549 return (SA_SYSTEM_ERR
);
552 if (initprotofromdefault() != SA_OK
) {
553 return (SA_SYSTEM_ERR
);
562 * uninitialize the smb plugin. Want to avoid memory leaks.
569 (void) smbfs_save_propset();
570 xmlFreeNode(protoset
);
575 * smbfs_get_proto_set()
577 * Return an optionset with all the protocol specific properties in
581 static sa_protocol_properties_t
582 smbfs_get_proto_set()
588 * smbfs_validate_proto_prop(index, name, value)
590 * Verify that the property specifed by name can take the new
591 * value. This is a sanity check to prevent bad values getting into
595 smbfs_validate_proto_prop(int index
, char *section
, char *name
, char *value
)
597 if ((section
== NULL
) || (name
== NULL
) || (index
< 0))
598 return (SA_BAD_VALUE
);
600 if (smbclnt_proto_options
[index
].validator
== NULL
)
603 return (smbclnt_proto_options
[index
].validator(index
, section
, value
));
607 * Save a property to our array; it will be stored to SMF later by
608 * smbfs_save_propset().
611 smbfs_save_property(int index
, char *section
, char *value
)
615 if (index
== PROTO_OPT_WORKGROUP
) {
616 index
= PROTO_OPT_DOMAIN
;
622 smbclnt_proto_options
[PROTO_OPT_SECTION
].value
= s
;
626 smbclnt_proto_options
[index
].value
= s
;
627 smbclnt_proto_options
[index
].flags
|= SMBC_MODIFIED
;
632 * smbfs_set_proto_prop(prop)
634 * check that prop is valid.
638 smbfs_set_proto_prop(sa_property_t prop
)
646 section
= sa_get_property_attr(prop
, "section");
648 return (SA_NO_SECTION
);
649 name
= sa_get_property_attr(prop
, "type");
650 value
= sa_get_property_attr(prop
, "value");
651 if (name
!= NULL
&& value
!= NULL
) {
652 i
= findprotoopt(name
);
654 ret
= smbfs_validate_proto_prop(i
, section
,
657 if (smbfs_save_property(i
, section
,
664 ret
= SA_INVALID_NAME
;
667 sa_free_attr_string(name
);
669 sa_free_attr_string(value
);
671 sa_free_attr_string(section
);
679 * What is the current status of the smbd? We use the SMF state here.
680 * Caller must free the returned value.
686 return (smf_get_state(SMBC_DEFAULT_INSTANCE_FMRI
));
690 * Delete a section by its name, which we will have read into an
691 * XML optionset above. We need to find it and find its UUID to
692 * be able to generate the property group name in order to call
693 * smbfs_delete_property_group().
696 smbfs_delete_section(char *section
)
700 sa_property_t propset
;
701 int ret
= SA_SYSTEM_ERR
;
703 propset
= sa_get_protocol_section(protoset
, section
);
704 (void) strlcpy(propgroup
, SMBC_PG_PREFIX
, sizeof (propgroup
));
705 propgroup
[SMBC_PG_PREFIX_LEN
] = '\0';
706 uu
= sa_get_property_attr(propset
, "extra");
709 (void) strlcat(propgroup
, uu
, sizeof (propgroup
));
711 if ((ret
= smbfs_delete_property_group(propgroup
)) != SMBC_SMF_OK
)
719 * Delete a property group by its name. Called to do a 'delsect'
720 * or called when smbclnt_config_load() notices an empty section
721 * at the end of the properties.
724 smbfs_delete_property_group(char *propgroup
)
726 smb_scfhandle_t
*handle
= NULL
;
727 int ret
= SA_SYSTEM_ERR
;
729 handle
= smb_smf_scf_init(SMBC_FMRI_PREFIX
);
733 if ((ret
= smb_smf_instance_create(handle
, SMBC_FMRI_PREFIX
,
734 SMBC_PG_INSTANCE
)) != SMBC_SMF_OK
)
737 if ((ret
= smb_smf_delete_instance_pgroup(handle
, propgroup
))
742 smb_smf_scf_fini(handle
);