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 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
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 <signal.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 <strings.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>
54
55 #define SMBFS_PROTOCOL_NAME "smbfs"
56
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 *);
66
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 *);
74
75 int propset_changed = 0;
76
77 /*
78 * ops vector that provides the protocol specific info and operations
79 * for share management.
80 */
81
82 struct sa_plugin_ops sa_plugin_ops = {
83 SA_PLUGIN_VERSION,
84 SMBFS_PROTOCOL_NAME,
85 smbfs_init,
86 smbfs_fini,
87 NULL, /* share */
88 NULL, /* unshare */
89 NULL, /* valid_prop */
90 NULL, /* valid_space */
91 NULL, /* security_prop */
92 NULL, /* legacy_opts */
93 NULL, /* legacy_format */
94 smbfs_set_proto_prop,
95 smbfs_get_proto_set,
96 smbfs_get_status,
97 NULL, /* space_alias */
98 NULL, /* update_legacy */
99 NULL, /* delete_legacy */
100 NULL, /* change_notify */
101 NULL, /* enable_resource */
102 NULL, /* disable_resource */
103 smbfs_features,
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,
110 };
111
112 /*
113 * is_a_number(number)
114 *
115 * is the string a number in one of the forms we want to use?
116 */
117
118 static int
is_a_number(char * number)119 is_a_number(char *number)
120 {
121 int ret = 1;
122 int hex = 0;
123
124 if (strncmp(number, "0x", 2) == 0) {
125 number += 2;
126 hex = 1;
127 } else if (*number == '-') {
128 number++; /* skip the minus */
129 }
130
131 while (ret == 1 && *number != '\0') {
132 if (hex) {
133 ret = isxdigit(*number++);
134 } else {
135 ret = isdigit(*number++);
136 }
137 }
138 return (ret);
139 }
140
141 /*
142 * Protocol management functions
143 *
144 * properties defined in the default files are defined in
145 * proto_option_defs for parsing and validation.
146 */
147
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,
157 minauth_validator},
158 { "nbns_broadcast", NULL, PROTO_OPT_NBNS_BROADCAST,
159 0, 0, 0,
160 yes_no_validator},
161 { "nbns_enable", NULL, PROTO_OPT_NBNS_ENABLE,
162 0, 0, 0,
163 yes_no_validator},
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,
169 password_validator},
170 { "timeout", NULL, PROTO_OPT_TIMEOUT,
171 0, 0, 60,
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,
184 signing_validator},
185 {NULL}
186 };
187
188 /*
189 * Check the range of value as int range.
190 */
191 /*ARGSUSED*/
192 static int
range_check_validator(int index,char * section,char * value)193 range_check_validator(int index, char *section, char *value)
194 {
195 int ret = SA_OK;
196
197 if (value == NULL)
198 return (SA_BAD_VALUE);
199 if (strlen(value) == 0)
200 return (SA_OK);
201 if (!is_a_number(value)) {
202 ret = SA_BAD_VALUE;
203 } else {
204 int val;
205 val = strtoul(value, NULL, 0);
206 if (val < smbclnt_proto_options[index].minval ||
207 val > smbclnt_proto_options[index].maxval)
208 ret = SA_BAD_VALUE;
209 }
210 return (ret);
211 }
212
213 /*
214 * Check the length of the string
215 */
216 /*ARGSUSED*/
217 static int
string_length_check_validator(int index,char * section,char * value)218 string_length_check_validator(int index, char *section, char *value)
219 {
220 int ret = SA_OK;
221
222 if (value == NULL)
223 return (SA_BAD_VALUE);
224 if (strlen(value) == 0)
225 return (SA_OK);
226 if (strlen(value) > smbclnt_proto_options[index].maxval)
227 ret = SA_BAD_VALUE;
228 return (ret);
229 }
230
231 /*
232 * Check yes/no
233 */
234 /*ARGSUSED*/
235 static int
yes_no_validator(int index,char * section,char * value)236 yes_no_validator(int index, char *section, char *value)
237 {
238 if (value == NULL)
239 return (SA_BAD_VALUE);
240 if (strlen(value) == 0)
241 return (SA_OK);
242 if ((strcasecmp(value, "yes") == 0) ||
243 (strcasecmp(value, "no") == 0) ||
244 (strcasecmp(value, "true") == 0) ||
245 (strcasecmp(value, "false") == 0))
246 return (SA_OK);
247 return (SA_BAD_VALUE);
248 }
249
250 /*
251 * Check IP address.
252 */
253 /*ARGSUSED*/
254 static int
ip_address_validator(int index,char * section,char * value)255 ip_address_validator(int index, char *section, char *value)
256 {
257 int len;
258
259 if (value == NULL)
260 return (SA_BAD_VALUE);
261 len = strlen(value);
262 if (len == 0)
263 return (SA_OK);
264 if (len > MAX_VALUE_BUFLEN)
265 return (SA_BAD_VALUE);
266 return (SA_OK);
267 }
268
269 /*ARGSUSED*/
270 static int
minauth_validator(int index,char * section,char * value)271 minauth_validator(int index, char *section, char *value)
272 {
273 if (value == NULL)
274 return (SA_BAD_VALUE);
275 if (strlen(value) == 0)
276 return (SA_OK);
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)
282 return (SA_OK);
283 else
284 return (SA_BAD_VALUE);
285 }
286
287 /*ARGSUSED*/
288 static int
signing_validator(int index,char * section,char * value)289 signing_validator(int index, char *section, char *value)
290 {
291 if (value == NULL)
292 return (SA_BAD_VALUE);
293 if (strlen(value) == 0)
294 return (SA_OK);
295 if (strcmp(value, "disabled") == 0 ||
296 strcmp(value, "enabled") == 0 ||
297 strcmp(value, "required") == 0)
298 return (SA_OK);
299 else
300 return (SA_BAD_VALUE);
301 }
302
303 /*ARGSUSED*/
304 static int
password_validator(int index,char * section,char * value)305 password_validator(int index, char *section, char *value)
306 {
307 char buffer[100];
308
309 /* mangled passwords will start with this pattern */
310 if (strlen(value) == 0)
311 return (SA_OK);
312 if (strncmp(value, "$$1", 3) != 0)
313 return (SA_PASSWORD_ENC);
314 if (smb_simpledecrypt(buffer, value) != 0)
315 return (SA_BAD_VALUE);
316 return (SA_OK);
317 }
318
319
320 /*
321 * the protoset holds the defined options so we don't have to read
322 * them multiple times
323 */
324 sa_protocol_properties_t protoset;
325
326 static int
findprotoopt(char * name)327 findprotoopt(char *name)
328 {
329 int i;
330 for (i = 0; smbclnt_proto_options[i].name != NULL; i++) {
331 if (strcasecmp(smbclnt_proto_options[i].name, name) == 0)
332 return (i);
333 }
334 return (-1);
335 }
336
337 /*
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.
345 */
346 int
smbclnt_config_load()347 smbclnt_config_load()
348 {
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;
354
355 props = scf_simple_app_props_get(NULL, SMBC_DEFAULT_INSTANCE_FMRI);
356 if (props == NULL)
357 return (-1);
358
359 for (;;) {
360 lastprop = prop;
361 prop = (scf_simple_prop_t *)
362 scf_simple_app_props_next(props, lastprop);
363 if (prop == NULL)
364 break;
365
366 /* Ignore properties that don't have our prefix */
367 pgname = scf_simple_prop_pgname(prop);
368 if (strncmp("S-", pgname, 2) != 0)
369 continue;
370
371 /*
372 * Note property group name changes, which mark sections
373 *
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.
377 */
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);
383 if (lastpgname)
384 free(lastpgname);
385 lastpgname = strdup(pgname);
386 }
387 name = scf_simple_prop_name(prop);
388 value = scf_simple_prop_next_astring(prop);
389
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",
393 (xmlChar *)value);
394 continue;
395 }
396
397 /*
398 * We have an ordinary property. Add to the section.
399 *
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.
403 */
404 node = sa_create_property(name, value);
405 (void) sa_add_protocol_property(sect, node);
406 }
407 scf_simple_app_props_free(props);
408
409 if (lastpgname)
410 free(lastpgname);
411 return (0);
412 }
413
414 /*
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
419 * SMBC_MODIFIED.
420 */
421 int
smbfs_save_propset()422 smbfs_save_propset()
423 {
424 smb_scfhandle_t *handle = NULL;
425 char propgroup[256];
426 char *section = smbclnt_proto_options[PROTO_OPT_SECTION].value;
427 char *uu = NULL;
428 uuid_t uuid;
429 int i, ret = 0;
430 sa_property_t propset;
431 int new = 0, nonnull = 0;
432
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");
437 if (uu != NULL) {
438 (void) strlcat(propgroup, uu, sizeof (propgroup));
439 free(uu);
440 } else {
441 new = 1;
442 smbclnt_proto_options[PROTO_OPT_SECTION].flags |= SMBC_MODIFIED;
443 uuid_generate(uuid);
444 uuid_unparse(uuid, &propgroup[SMBC_PG_PREFIX_LEN]);
445 }
446
447 handle = smb_smf_scf_init(SMBC_FMRI_PREFIX);
448 if (handle == NULL) {
449 return (1);
450 }
451
452 if ((ret = smb_smf_instance_create(handle, SMBC_FMRI_PREFIX,
453 SMBC_PG_INSTANCE)) != SMBC_SMF_OK) {
454 goto out;
455 }
456
457 if ((ret = smb_smf_create_instance_pgroup(handle, propgroup))
458 != SMBC_SMF_OK) {
459 goto out;
460 }
461
462 if ((ret = smb_smf_start_transaction(handle)) != SMBC_SMF_OK) {
463 goto out;
464 }
465
466 for (i = PROTO_OPT_SECTION+1; i <= SMBC_OPT_MAX; i++) {
467 if ((smbclnt_proto_options[i].flags & SMBC_MODIFIED) == 0)
468 continue;
469 if (strcmp(smbclnt_proto_options[i].value, "") == 0)
470 ret = smb_smf_delete_property(handle,
471 smbclnt_proto_options[i].name);
472 else {
473 ret = smb_smf_set_string_property(handle,
474 smbclnt_proto_options[i].name,
475 smbclnt_proto_options[i].value);
476 nonnull = 1;
477 }
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)
482 goto outtrans;
483 }
484 /*
485 * Suppress new, null entries by not saving the section name.
486 */
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 &=
494 ~SMBC_MODIFIED;
495 }
496 propset_changed = 0;
497
498 outtrans:
499 ret = smb_smf_end_transaction(handle);
500 out:
501 smb_smf_scf_fini(handle);
502 return (ret);
503 }
504
505 /*
506 * initprotofromdefault()
507 *
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.
511 */
512
513 static int
initprotofromdefault()514 initprotofromdefault()
515 {
516 protoset = sa_create_protocol_properties(SMBFS_PROTOCOL_NAME);
517 if (protoset == NULL)
518 return (SA_NO_MEMORY);
519 if (smbclnt_config_load() != 0)
520 return (SA_OK);
521
522 return (SA_OK);
523 }
524
525 /*
526 *
527 * smbfs_features()
528 *
529 * Report the plugin's features
530 */
531 static uint64_t
smbfs_features()532 smbfs_features()
533 {
534 return (SA_FEATURE_HAS_SECTIONS | SA_FEATURE_ADD_PROPERTIES);
535 }
536
537 /*
538 * smbfs_init()
539 *
540 * Initialize the smb plugin.
541 */
542
543 static int
smbfs_init()544 smbfs_init()
545 {
546 int ret = SA_OK;
547
548 if (sa_plugin_ops.sa_init != smbfs_init) {
549 return (SA_SYSTEM_ERR);
550 }
551
552 if (initprotofromdefault() != SA_OK) {
553 return (SA_SYSTEM_ERR);
554 }
555
556 return (ret);
557 }
558
559 /*
560 * smbfs_fini()
561 *
562 * uninitialize the smb plugin. Want to avoid memory leaks.
563 */
564
565 static void
smbfs_fini()566 smbfs_fini()
567 {
568 if (propset_changed)
569 (void) smbfs_save_propset();
570 xmlFreeNode(protoset);
571 protoset = NULL;
572 }
573
574 /*
575 * smbfs_get_proto_set()
576 *
577 * Return an optionset with all the protocol specific properties in
578 * it.
579 */
580
581 static sa_protocol_properties_t
smbfs_get_proto_set()582 smbfs_get_proto_set()
583 {
584 return (protoset);
585 }
586
587 /*
588 * smbfs_validate_proto_prop(index, name, value)
589 *
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
592 * the default files.
593 */
594 static int
smbfs_validate_proto_prop(int index,char * section,char * name,char * value)595 smbfs_validate_proto_prop(int index, char *section, char *name, char *value)
596 {
597 if ((section == NULL) || (name == NULL) || (index < 0))
598 return (SA_BAD_VALUE);
599
600 if (smbclnt_proto_options[index].validator == NULL)
601 return (SA_OK);
602
603 return (smbclnt_proto_options[index].validator(index, section, value));
604 }
605
606 /*
607 * Save a property to our array; it will be stored to SMF later by
608 * smbfs_save_propset().
609 */
610 int
smbfs_save_property(int index,char * section,char * value)611 smbfs_save_property(int index, char *section, char *value)
612 {
613 char *s;
614
615 if (index == PROTO_OPT_WORKGROUP) {
616 index = PROTO_OPT_DOMAIN;
617 }
618 propset_changed = 1;
619 s = strdup(section);
620 if (s == NULL)
621 return (-1);
622 smbclnt_proto_options[PROTO_OPT_SECTION].value = s;
623 s = strdup(value);
624 if (s == NULL)
625 return (-1);
626 smbclnt_proto_options[index].value = s;
627 smbclnt_proto_options[index].flags |= SMBC_MODIFIED;
628 return (0);
629 }
630
631 /*
632 * smbfs_set_proto_prop(prop)
633 *
634 * check that prop is valid.
635 */
636 /*ARGSUSED*/
637 static int
smbfs_set_proto_prop(sa_property_t prop)638 smbfs_set_proto_prop(sa_property_t prop)
639 {
640 int ret = SA_OK;
641 char *name;
642 char *value;
643 char *section;
644 int i = -1;
645
646 section = sa_get_property_attr(prop, "section");
647 if (section == NULL)
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);
653 if (i >= 0) {
654 ret = smbfs_validate_proto_prop(i, section,
655 name, value);
656 if (ret == SA_OK) {
657 if (smbfs_save_property(i, section,
658 value) != 0) {
659 ret = SA_SYSTEM_ERR;
660 errno = EIO;
661 }
662 }
663 } else
664 ret = SA_INVALID_NAME;
665 }
666 if (name != NULL)
667 sa_free_attr_string(name);
668 if (value != NULL)
669 sa_free_attr_string(value);
670 if (section != NULL)
671 sa_free_attr_string(section);
672
673 return (ret);
674 }
675
676 /*
677 * smbfs_get_status()
678 *
679 * What is the current status of the smbd? We use the SMF state here.
680 * Caller must free the returned value.
681 */
682
683 static char *
smbfs_get_status()684 smbfs_get_status()
685 {
686 return (smf_get_state(SMBC_DEFAULT_INSTANCE_FMRI));
687 }
688
689 /*
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().
694 */
695 static int
smbfs_delete_section(char * section)696 smbfs_delete_section(char *section)
697 {
698 char propgroup[256];
699 char *uu = NULL;
700 sa_property_t propset;
701 int ret = SA_SYSTEM_ERR;
702
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");
707 if (uu == NULL)
708 goto out;
709 (void) strlcat(propgroup, uu, sizeof (propgroup));
710 free(uu);
711 if ((ret = smbfs_delete_property_group(propgroup)) != SMBC_SMF_OK)
712 goto out;
713 ret = SA_OK;
714 out:
715 return (ret);
716 }
717
718 /*
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.
722 */
723 static int
smbfs_delete_property_group(char * propgroup)724 smbfs_delete_property_group(char *propgroup)
725 {
726 smb_scfhandle_t *handle = NULL;
727 int ret = SA_SYSTEM_ERR;
728
729 handle = smb_smf_scf_init(SMBC_FMRI_PREFIX);
730 if (handle == NULL)
731 goto out;
732
733 if ((ret = smb_smf_instance_create(handle, SMBC_FMRI_PREFIX,
734 SMBC_PG_INSTANCE)) != SMBC_SMF_OK)
735 goto out;
736
737 if ((ret = smb_smf_delete_instance_pgroup(handle, propgroup))
738 != SMBC_SMF_OK)
739 goto out;
740 ret = SA_OK;
741 out:
742 smb_smf_scf_fini(handle);
743 return (ret);
744 }
745