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) 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /*
27 * AUTOMOUNT specific functions
28 */
29 #include <stdio.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <zone.h>
35 #include <errno.h>
36 #include <locale.h>
37 #include <fcntl.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <syslog.h>
41 #include "libshare.h"
42 #include "libshare_impl.h"
43 #include <pwd.h>
44 #include <limits.h>
45 #include <libscf.h>
46 #include <strings.h>
47 #include <libdlpi.h>
48 #include "smfcfg.h"
49
50
51 static int autofs_init();
52 static void autofs_fini();
53 static int autofs_validate_property(sa_handle_t, sa_property_t, sa_optionset_t);
54 static int autofs_set_proto_prop(sa_property_t);
55 static sa_protocol_properties_t autofs_get_proto_set();
56 static char *autofs_get_status();
57 static uint64_t autofs_features();
58
59 static int initautofsprotofromsmf();
60 static int true_false_validator(int index, char *value);
61 static int strlen_validator(int index, char *value);
62 static int range_check_validator(int index, char *value);
63
64 /*
65 * ops vector that provides the protocol specific info and operations
66 * for share management.
67 */
68 struct sa_plugin_ops sa_plugin_ops = {
69 SA_PLUGIN_VERSION,
70 "autofs",
71 autofs_init, /* Init autofs */
72 autofs_fini, /* Fini autofs */
73 NULL, /* Start Sharing */
74 NULL, /* stop sharing */
75 autofs_validate_property,
76 NULL, /* valid_space */
77 NULL, /* security_prop */
78 NULL, /* parse optstring */
79 NULL, /* format optstring */
80 autofs_set_proto_prop, /* Set properties */
81 autofs_get_proto_set, /* get properties */
82 autofs_get_status, /* get status */
83 NULL, /* space_alias */
84 NULL, /* update_legacy */
85 NULL, /* delete_legacy */
86 NULL, /* change notify */
87 NULL, /* enable resource */
88 NULL, /* disable resource */
89 autofs_features, /* features */
90 NULL, /* transient shares */
91 NULL, /* notify resource */
92 NULL, /* rename resource */
93 NULL, /* run_command */
94 NULL, /* command_help */
95 NULL /* delete_proto_section */
96 };
97
98
99 static sa_protocol_properties_t protoset;
100
101 #define AUTOMOUNT_VERBOSE_DEFAULT 0
102 #define AUTOMOUNTD_VERBOSE_DEFAULT 0
103 #define AUTOMOUNT_NOBROWSE_DEFAULT 0
104 #define AUTOMOUNT_TIMEOUT_DEFAULT 600
105 #define AUTOMOUNT_TRACE_DEFAULT 0
106 /*
107 * Protocol Management functions
108 */
109 struct proto_option_defs {
110 char *tag;
111 char *name; /* display name -- remove protocol identifier */
112 int index;
113 scf_type_t type;
114 union {
115 int intval;
116 char *string;
117 } defvalue;
118 int32_t minval;
119 int32_t maxval;
120 int (*check)(int, char *);
121 } proto_options[] = {
122 #define PROTO_OPT_AUTOMOUNT_TIMEOUT 0
123 { "timeout",
124 "timeout", PROTO_OPT_AUTOMOUNT_TIMEOUT,
125 SCF_TYPE_INTEGER, AUTOMOUNT_TIMEOUT_DEFAULT,
126 1, INT32_MAX, range_check_validator},
127 #define PROTO_OPT_AUTOMOUNT_VERBOSE 1
128 { "automount_verbose",
129 "automount_verbose", PROTO_OPT_AUTOMOUNT_VERBOSE,
130 SCF_TYPE_BOOLEAN, AUTOMOUNT_VERBOSE_DEFAULT, 0, 1,
131 true_false_validator},
132 #define PROTO_OPT_AUTOMOUNTD_VERBOSE 2
133 { "automountd_verbose",
134 "automountd_verbose", PROTO_OPT_AUTOMOUNTD_VERBOSE,
135 SCF_TYPE_BOOLEAN, AUTOMOUNTD_VERBOSE_DEFAULT, 0, 1,
136 true_false_validator},
137 #define PROTO_OPT_AUTOMOUNTD_NOBROWSE 3
138 { "nobrowse",
139 "nobrowse", PROTO_OPT_AUTOMOUNTD_NOBROWSE, SCF_TYPE_BOOLEAN,
140 AUTOMOUNT_NOBROWSE_DEFAULT, 0, 1, true_false_validator},
141 #define PROTO_OPT_AUTOMOUNTD_TRACE 4
142 { "trace",
143 "trace", PROTO_OPT_AUTOMOUNTD_TRACE,
144 SCF_TYPE_INTEGER, AUTOMOUNT_TRACE_DEFAULT,
145 0, 20, range_check_validator},
146 #define PROTO_OPT_AUTOMOUNTD_ENV 5
147 { "environment",
148 "environment", PROTO_OPT_AUTOMOUNTD_ENV, SCF_TYPE_ASTRING,
149 0, 0, 1024, strlen_validator},
150 {NULL, NULL, 0, 0, 0, 0, 0, NULL}
151 };
152
153 #define AUTOFS_PROP_MAX (sizeof (proto_options) / sizeof (proto_options[0]))
154
155 static void
add_defaults()156 add_defaults()
157 {
158 int i;
159 char number[MAXDIGITS];
160
161 for (i = 0; proto_options[i].tag != NULL; i++) {
162 sa_property_t prop;
163 prop = sa_get_protocol_property(protoset,
164 proto_options[i].name);
165 if (prop == NULL) {
166 /* add the default value */
167 switch (proto_options[i].type) {
168 case SCF_TYPE_INTEGER:
169 (void) snprintf(number, sizeof (number), "%d",
170 proto_options[i].defvalue.intval);
171 prop = sa_create_property(proto_options[i].name,
172 number);
173 break;
174
175 case SCF_TYPE_BOOLEAN:
176 prop = sa_create_property(proto_options[i].name,
177 proto_options[i].defvalue.intval ?
178 "true" : "false");
179 break;
180
181 default:
182 /* treat as strings of zero length */
183 prop = sa_create_property(proto_options[i].name,
184 "");
185 break;
186 }
187 if (prop != NULL)
188 (void) sa_add_protocol_property(protoset, prop);
189 }
190 }
191 }
192
193 static int
autofs_init()194 autofs_init()
195 {
196 int ret = SA_OK;
197
198 if (sa_plugin_ops.sa_init != autofs_init) {
199 (void) printf(dgettext(TEXT_DOMAIN,
200 "AUTOFS plugin not installed properly\n"));
201 return (SA_CONFIG_ERR);
202 }
203
204 ret = initautofsprotofromsmf();
205 if (ret != SA_OK) {
206 (void) printf(dgettext(TEXT_DOMAIN,
207 "AUTOFS plugin problem with SMF properties: %s\n"),
208 sa_errorstr(ret));
209 ret = SA_OK;
210 }
211 add_defaults();
212 return (ret);
213 }
214
215 static void
free_protoprops()216 free_protoprops()
217 {
218 if (protoset != NULL) {
219 xmlFreeNode(protoset);
220 protoset = NULL;
221 }
222 }
223
224 static void
autofs_fini()225 autofs_fini()
226 {
227 free_protoprops();
228 }
229
230 static int
findprotoopt(char * propname)231 findprotoopt(char *propname)
232 {
233 int i;
234
235 for (i = 0; proto_options[i].tag != NULL; i++)
236 if (strcmp(proto_options[i].name, propname) == 0)
237 return (i);
238 return (-1);
239 }
240
241 static int
autofs_validate_property(sa_handle_t handle,sa_property_t property,sa_optionset_t parent)242 autofs_validate_property(sa_handle_t handle, sa_property_t property,
243 sa_optionset_t parent)
244 {
245 int ret = SA_OK;
246 char *propname;
247 int optionindex;
248 char *value;
249
250 #ifdef lint
251 handle = handle;
252 parent = parent;
253 #endif
254 propname = sa_get_property(property, "type");
255 if (propname == NULL)
256 return (SA_NO_SUCH_PROP);
257
258 if ((optionindex = findprotoopt(propname)) < 0)
259 ret = SA_NO_SUCH_PROP;
260
261 if (ret != SA_OK) {
262 if (propname != NULL)
263 sa_free_attr_string(propname);
264 return (ret);
265 }
266
267 value = sa_get_property_attr(property, "value");
268 if (value != NULL) {
269 /*
270 * If any property is added to AUTOFS, which is a different
271 * type than the below list, a case needs to be added for that
272 * to check the values. For now AUTOFS type are just integers,
273 * string and boolean properties. Just taking care of them.
274 */
275 switch (proto_options[optionindex].type) {
276 case SCF_TYPE_INTEGER:
277 case SCF_TYPE_BOOLEAN:
278 case SCF_TYPE_ASTRING:
279 ret = proto_options[optionindex].check(optionindex,
280 value);
281 break;
282 default:
283 break;
284 }
285 }
286
287 /* Free the value */
288 if (value != NULL)
289 sa_free_attr_string(value);
290 if (propname != NULL)
291 sa_free_attr_string(propname);
292 return (ret);
293 }
294
295 /*
296 * service_in_state(service, chkstate)
297 *
298 * Want to know if the specified service is in the desired state
299 * (chkstate) or not. Return true (1) if it is and false (0) if it
300 * isn't.
301 */
302 static int
service_in_state(char * service,const char * chkstate)303 service_in_state(char *service, const char *chkstate)
304 {
305 char *state;
306 int ret = B_FALSE;
307
308 state = smf_get_state(service);
309 if (state != NULL) {
310 /* got the state so get the equality for the return value */
311 ret = strcmp(state, chkstate) == 0 ? B_TRUE : B_FALSE;
312 free(state);
313 }
314 return (ret);
315 }
316
317 static void
restart_service(char * service)318 restart_service(char *service)
319 {
320 int ret = -1;
321
322 /*
323 * Only attempt to restart the service if it is
324 * currently running. In the future, it may be
325 * desirable to use smf_refresh_instance if the AUTOFS
326 * services ever implement the refresh method.
327 */
328 if (service_in_state(service, SCF_STATE_STRING_ONLINE)) {
329 ret = smf_restart_instance(service);
330 /*
331 * There are only a few SMF errors at this point, but
332 * it is also possible that a bad value may have put
333 * the service into maintenance if there wasn't an
334 * SMF level error.
335 */
336 if (ret != 0) {
337 (void) fprintf(stderr,
338 dgettext(TEXT_DOMAIN,
339 "%s failed to restart: %s\n"),
340 scf_strerror(scf_error()));
341 } else {
342 /*
343 * Check whether it has gone to "maintenance"
344 * mode or not. Maintenance implies something
345 * went wrong.
346 */
347 if (service_in_state(service,
348 SCF_STATE_STRING_MAINT)) {
349 (void) fprintf(stderr,
350 dgettext(TEXT_DOMAIN,
351 "%s failed to restart\n"),
352 service);
353 }
354 }
355 }
356 }
357
358 static int
is_a_number(char * number)359 is_a_number(char *number)
360 {
361 int ret = 1;
362 int hex = 0;
363
364 if (strncmp(number, "0x", 2) == 0) {
365 number += 2;
366 hex = 1;
367 } else if (*number == '-') {
368 number++; /* skip the minus */
369 }
370 while (ret == 1 && *number != '\0') {
371 if (hex) {
372 ret = isxdigit(*number++);
373 } else {
374 ret = isdigit(*number++);
375 }
376 }
377 return (ret);
378 }
379
380 /*
381 * fixcaselower(str)
382 *
383 * convert a string to lower case (inplace).
384 */
385
386 static void
fixcaselower(char * str)387 fixcaselower(char *str)
388 {
389 while (*str) {
390 *str = tolower(*str);
391 str++;
392 }
393 }
394
395 /*
396 * skipwhitespace(str)
397 *
398 * Skip leading white space. It is assumed that it is called with a
399 * valid pointer.
400 */
401 static char *
skipwhitespace(char * str)402 skipwhitespace(char *str)
403 {
404 while (*str && isspace(*str))
405 str++;
406
407 return (str);
408 }
409
410 /*
411 * extractprop()
412 *
413 * Extract the property and value out of the line and create the
414 * property in the optionset.
415 */
416 static int
extractprop(char * name,char * value)417 extractprop(char *name, char *value)
418 {
419 sa_property_t prop;
420 int index;
421 int ret = SA_OK;
422 /*
423 * Remove any leading
424 * white space.
425 */
426 name = skipwhitespace(name);
427
428 index = findprotoopt(name);
429 if (index >= 0) {
430 fixcaselower(name);
431 prop = sa_create_property(proto_options[index].name, value);
432 if (prop != NULL)
433 ret = sa_add_protocol_property(protoset, prop);
434 else
435 ret = SA_NO_MEMORY;
436 }
437 return (ret);
438 }
439
440 static int
initautofsprotofromsmf(void)441 initautofsprotofromsmf(void)
442 {
443 char name[PATH_MAX];
444 char value[PATH_MAX];
445 int ret = SA_OK, bufsz = 0, i;
446 char *instance = NULL;
447 scf_type_t sctype;
448
449 protoset = sa_create_protocol_properties("autofs");
450 if (protoset != NULL) {
451 for (i = 0; proto_options[i].tag != NULL; i++) {
452 bzero(value, PATH_MAX);
453 (void) strncpy(name, proto_options[i].name, PATH_MAX);
454 sctype = proto_options[i].type;
455 bufsz = PATH_MAX;
456 ret = autofs_smf_get_prop(name, value,
457 instance, sctype, AUTOFS_FMRI, &bufsz);
458 if (ret == SA_OK) {
459 ret = extractprop(name, value);
460 }
461 }
462 } else {
463 ret = SA_NO_MEMORY;
464 }
465 return (ret);
466 }
467
468 static int
range_check_validator(int index,char * value)469 range_check_validator(int index, char *value)
470 {
471 int ret = SA_OK;
472 if (!is_a_number(value)) {
473 ret = SA_BAD_VALUE;
474 } else {
475 int val;
476 errno = 0;
477 val = strtoul(value, NULL, 0);
478 if (errno != 0)
479 return (SA_BAD_VALUE);
480
481 if (val < proto_options[index].minval ||
482 val > proto_options[index].maxval)
483 ret = SA_BAD_VALUE;
484 }
485 return (ret);
486 }
487
488 static int
true_false_validator(int index,char * value)489 true_false_validator(int index, char *value)
490 {
491
492 #ifdef lint
493 index = index;
494 #endif
495 if ((strcasecmp(value, "true") == 0) ||
496 (strcasecmp(value, "on") == 0) ||
497 (strcasecmp(value, "yes") == 0) ||
498 (strcmp(value, "1") == 0) ||
499 (strcasecmp(value, "false") == 0) ||
500 (strcasecmp(value, "off") == 0) ||
501 (strcasecmp(value, "no") == 0) ||
502 (strcmp(value, "0") == 0)) {
503 return (SA_OK);
504 }
505 return (SA_BAD_VALUE);
506 }
507
508 static int
strlen_validator(int index,char * value)509 strlen_validator(int index, char *value)
510 {
511 int ret = SA_OK;
512 if (value == NULL) {
513 if (proto_options[index].minval == 0) {
514 return (ret);
515 } else {
516 return (SA_BAD_VALUE);
517 }
518 }
519 if (strlen(value) > proto_options[index].maxval ||
520 strlen(value) < proto_options[index].minval)
521 ret = SA_BAD_VALUE;
522 return (ret);
523 }
524
525 static int
autofs_validate_proto_prop(int index,char * name,char * value)526 autofs_validate_proto_prop(int index, char *name, char *value)
527 {
528 #ifdef lint
529 name = name;
530 #endif
531 return (proto_options[index].check(index, value));
532 }
533
534 static int
autofs_set_proto_prop(sa_property_t prop)535 autofs_set_proto_prop(sa_property_t prop)
536 {
537 int ret = SA_OK;
538 char *name;
539 char *value, *instance = NULL;
540 scf_type_t sctype;
541
542 name = sa_get_property_attr(prop, "type");
543 value = sa_get_property_attr(prop, "value");
544 if (name != NULL && value != NULL) {
545 int index = findprotoopt(name);
546 if (index >= 0) {
547 ret = autofs_validate_proto_prop(index, name, value);
548 if (ret == SA_OK) {
549 sctype = proto_options[index].type;
550 if (sctype == SCF_TYPE_BOOLEAN) {
551 if (value != NULL)
552 sa_free_attr_string(value);
553 if (string_to_boolean(value) == 0)
554 value = strdup("0");
555 else
556 value = strdup("1");
557 }
558 ret = autofs_smf_set_prop(name, value,
559 instance, sctype, AUTOFS_FMRI);
560 /*
561 * Make an instance based FMRI.
562 * For now its DEFAULT_AUTOFS_FMRI.
563 */
564 if (ret == SA_OK)
565 restart_service(AUTOFS_DEFAULT_FMRI);
566 }
567 } else {
568 ret = SA_NO_SUCH_PROP;
569 }
570 } else {
571 ret = SA_CONFIG_ERR;
572 }
573
574 if (name != NULL)
575 sa_free_attr_string(name);
576 if (value != NULL)
577 sa_free_attr_string(value);
578 return (ret);
579 }
580
581
582 static sa_protocol_properties_t
autofs_get_proto_set(void)583 autofs_get_proto_set(void)
584 {
585 return (protoset);
586 }
587
588 static uint64_t
autofs_features(void)589 autofs_features(void)
590 {
591 return (0);
592 }
593
594 static char *
autofs_get_status(void)595 autofs_get_status(void)
596 {
597 return (smf_get_state(AUTOFS_DEFAULT_FMRI));
598 }
599