Print this page
NEX-15279 support NFS server in zone
NEX-15520 online NFS shares cause zoneadm halt to hang in nfs_export_zone_fini
Portions contributed by: Dan Kruchinin dan.kruchinin@nexenta.com
Portions contributed by: Stepan Zastupov stepan.zastupov@gmail.com
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-16156 Excessive time spent checking status of NFS services when sharing datasets during import
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-16156 Excessive time spent checking status of NFS services when sharing datasets during import
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-4179 segmentation fault when sharing with 'sec=none,root=*' options
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-2502 4.0.3 RC4 Unable to mount NFS shares
Revert "NEX-2394 mountd() door services are sub-optimal in large scale deployments".
This reverts commit c6e1673e3a4b8ba866c77dee7b8f03f858be07d6.
The fix for NEX-2394 worked fine when putting the mountd binary in 4.0.2,
but needs additional work in a 4.0.3 environment
NEX-2394 mountd() door services are sub-optimal in large scale deployments
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Ryuji Masuda <ryuji.masuda@nexenta.com>
Reviewed by: Kirill Davydychev <kirill.davydychev@nexenta.com>
NEX-1128 NFS server: Generic uid and gid remapping for AUTH_SYS
Reviewed by: Jan Kryl <jan.kryl@nexenta.com>
OS-141 mountd(1m) needs to be able to set listen backlog
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
4295 libshare sa_get_proto_status sometimes returns unallocated strings
Reviewed by: Marcel Telka <marcel@telka.sk>
Approved by: Garrett D'Amore <garrett@damore.org>
OS-20 share_nfs(1m) charset handling is unreliable
OS-22 Page fault at nfscmd_dropped_entrysize+0x1e()
OS-23 NFSv2/3/4: READDIR responses are inconsistent when charset conversion fails
OS-24 rfs3_readdir(): Issues related to nfscmd_convdirent()
Reviewed by: Jan Kryl <jan.kryl@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
re #3541 rb11254 - nfs nohide - "nfssrv: need ability to go to submounts for v3 and v2 protocols"
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/lib/libshare/nfs/libshare_nfs.c
+++ new/usr/src/lib/libshare/nfs/libshare_nfs.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
|
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
24 - * Copyright 2016 Nexenta Systems, Inc.
24 + */
25 +
26 +/*
25 27 * Copyright (c) 2014, 2016 by Delphix. All rights reserved.
28 + * Copyright 2018 Nexenta Systems, Inc.
26 29 */
27 30
28 31 /*
29 32 * NFS specific functions
30 33 */
34 +
31 35 #include <stdio.h>
32 36 #include <string.h>
33 37 #include <ctype.h>
34 38 #include <stdlib.h>
35 39 #include <unistd.h>
36 -#include <zone.h>
37 40 #include <errno.h>
38 41 #include <locale.h>
39 42 #include <signal.h>
40 43 #include <strings.h>
41 44 #include "libshare.h"
42 45 #include "libshare_impl.h"
43 46 #include <nfs/export.h>
44 47 #include <pwd.h>
45 48 #include <grp.h>
46 49 #include <limits.h>
47 50 #include <libscf.h>
48 51 #include <syslog.h>
49 52 #include <rpcsvc/daemon_utils.h>
50 53 #include "nfslog_config.h"
51 54 #include "nfslogtab.h"
52 55 #include "libshare_nfs.h"
53 56 #include <nfs/nfs.h>
54 57 #include <nfs/nfssys.h>
55 58 #include <netconfig.h>
56 59 #include "smfcfg.h"
57 60
58 61 /* should really be in some global place */
59 62 #define DEF_WIN 30000
60 63 #define OPT_CHUNK 1024
61 64
62 65 int debug = 0;
63 66
64 67 #define NFS_SERVER_SVC "svc:/network/nfs/server:default"
65 68 #define NFS_CLIENT_SVC (char *)"svc:/network/nfs/client:default"
66 69
67 70 /* internal functions */
68 71 static int nfs_init();
69 72 static void nfs_fini();
70 73 static int nfs_enable_share(sa_share_t);
71 74 static int nfs_disable_share(sa_share_t, char *);
72 75 static int nfs_validate_property(sa_handle_t, sa_property_t, sa_optionset_t);
73 76 static int nfs_validate_security_mode(char *);
74 77 static int nfs_is_security_opt(char *);
75 78 static int nfs_parse_legacy_options(sa_group_t, char *);
76 79 static char *nfs_format_options(sa_group_t, int);
77 80 static int nfs_set_proto_prop(sa_property_t);
78 81 static sa_protocol_properties_t nfs_get_proto_set();
79 82 static char *nfs_get_status();
80 83 static char *nfs_space_alias(char *);
81 84 static uint64_t nfs_features();
82 85
83 86 /*
84 87 * ops vector that provides the protocol specific info and operations
85 88 * for share management.
86 89 */
87 90
88 91 struct sa_plugin_ops sa_plugin_ops = {
89 92 SA_PLUGIN_VERSION,
90 93 "nfs",
91 94 nfs_init,
92 95 nfs_fini,
93 96 nfs_enable_share,
94 97 nfs_disable_share,
95 98 nfs_validate_property,
96 99 nfs_validate_security_mode,
97 100 nfs_is_security_opt,
98 101 nfs_parse_legacy_options,
99 102 nfs_format_options,
100 103 nfs_set_proto_prop,
101 104 nfs_get_proto_set,
102 105 nfs_get_status,
103 106 nfs_space_alias,
104 107 NULL, /* update_legacy */
105 108 NULL, /* delete_legacy */
106 109 NULL, /* change_notify */
107 110 NULL, /* enable_resource */
108 111 NULL, /* disable_resource */
109 112 nfs_features,
110 113 NULL, /* transient shares */
111 114 NULL, /* notify resource */
112 115 NULL, /* rename_resource */
113 116 NULL, /* run_command */
114 117 NULL, /* command_help */
115 118 NULL /* delete_proto_section */
|
↓ open down ↓ |
69 lines elided |
↑ open up ↑ |
116 119 };
117 120
118 121 /*
119 122 * list of support services needed
120 123 * defines should come from head/rpcsvc/daemon_utils.h
121 124 */
122 125
123 126 static char *service_list_default[] =
124 127 { STATD, LOCKD, MOUNTD, NFSD, NFSMAPID, RQUOTAD, REPARSED, NULL };
125 128 static char *service_list_logging[] =
126 - { STATD, LOCKD, MOUNTD, NFSD, NFSMAPID, RQUOTAD, NFSLOGD, REPARSED,
127 - NULL };
129 + { NFSLOGD, NULL };
128 130
129 131 /*
130 132 * option definitions. Make sure to keep the #define for the option
131 133 * index just before the entry it is the index for. Changing the order
132 134 * can cause breakage. E.g OPT_RW is index 1 and must precede the
133 135 * line that includes the SHOPT_RW and OPT_RW entries.
134 136 */
135 137
136 138 struct option_defs optdefs[] = {
137 139 #define OPT_RO 0
138 140 {SHOPT_RO, OPT_RO, OPT_TYPE_ACCLIST},
139 141 #define OPT_RW 1
140 142 {SHOPT_RW, OPT_RW, OPT_TYPE_ACCLIST},
141 143 #define OPT_ROOT 2
142 144 {SHOPT_ROOT, OPT_ROOT, OPT_TYPE_ACCLIST},
143 145 #define OPT_SECURE 3
144 146 {SHOPT_SECURE, OPT_SECURE, OPT_TYPE_DEPRECATED},
145 147 #define OPT_ANON 4
146 148 {SHOPT_ANON, OPT_ANON, OPT_TYPE_USER},
147 149 #define OPT_WINDOW 5
148 150 {SHOPT_WINDOW, OPT_WINDOW, OPT_TYPE_NUMBER},
149 151 #define OPT_NOSUID 6
150 152 {SHOPT_NOSUID, OPT_NOSUID, OPT_TYPE_BOOLEAN},
151 153 #define OPT_ACLOK 7
152 154 {SHOPT_ACLOK, OPT_ACLOK, OPT_TYPE_BOOLEAN},
153 155 #define OPT_NOSUB 8
154 156 {SHOPT_NOSUB, OPT_NOSUB, OPT_TYPE_BOOLEAN},
155 157 #define OPT_SEC 9
156 158 {SHOPT_SEC, OPT_SEC, OPT_TYPE_SECURITY},
157 159 #define OPT_PUBLIC 10
158 160 {SHOPT_PUBLIC, OPT_PUBLIC, OPT_TYPE_BOOLEAN, OPT_SHARE_ONLY},
159 161 #define OPT_INDEX 11
160 162 {SHOPT_INDEX, OPT_INDEX, OPT_TYPE_FILE},
161 163 #define OPT_LOG 12
162 164 {SHOPT_LOG, OPT_LOG, OPT_TYPE_LOGTAG},
163 165 #define OPT_CKSUM 13
164 166 {SHOPT_CKSUM, OPT_CKSUM, OPT_TYPE_STRINGSET},
165 167 #define OPT_NONE 14
166 168 {SHOPT_NONE, OPT_NONE, OPT_TYPE_ACCLIST},
|
↓ open down ↓ |
29 lines elided |
↑ open up ↑ |
167 169 #define OPT_ROOT_MAPPING 15
168 170 {SHOPT_ROOT_MAPPING, OPT_ROOT_MAPPING, OPT_TYPE_USER},
169 171 #define OPT_CHARSET_MAP 16
170 172 {"", OPT_CHARSET_MAP, OPT_TYPE_ACCLIST},
171 173 #define OPT_NOACLFAB 17
172 174 {SHOPT_NOACLFAB, OPT_NOACLFAB, OPT_TYPE_BOOLEAN},
173 175 #define OPT_UIDMAP 18
174 176 {SHOPT_UIDMAP, OPT_UIDMAP, OPT_TYPE_MAPPING},
175 177 #define OPT_GIDMAP 19
176 178 {SHOPT_GIDMAP, OPT_GIDMAP, OPT_TYPE_MAPPING},
179 +#define OPT_NOHIDE 20
180 + {SHOPT_NOHIDE, OPT_NOHIDE, OPT_TYPE_BOOLEAN},
177 181 #ifdef VOLATILE_FH_TEST /* XXX added for testing volatile fh's only */
178 -#define OPT_VOLFH 20
182 +#define OPT_VOLFH 21
179 183 {SHOPT_VOLFH, OPT_VOLFH},
180 184 #endif /* VOLATILE_FH_TEST */
181 185 NULL
182 186 };
183 187
184 188 /*
185 189 * Codesets that may need to be converted to UTF-8 for file paths.
186 190 * Add new names here to add new property support. If we ever get a
187 191 * way to query the kernel for character sets, this should become
188 192 * dynamically loaded. Make sure changes here are reflected in
189 - * cmd/fs.d/nfs/mountd/nfscmd.c
193 + * cmd/fs.d/nfs/mountd/nfs_cmd.c
190 194 */
191 195
192 196 static char *legal_conv[] = {
193 197 "euc-cn",
194 198 "euc-jp",
195 199 "euc-jpms",
196 200 "euc-kr",
197 201 "euc-tw",
198 202 "iso8859-1",
199 203 "iso8859-2",
200 204 "iso8859-5",
201 205 "iso8859-6",
202 206 "iso8859-7",
203 207 "iso8859-8",
204 208 "iso8859-9",
205 209 "iso8859-13",
206 210 "iso8859-15",
207 211 "koi8-r",
208 212 NULL
209 213 };
210 214
211 215 /*
212 216 * list of properties that are related to security flavors.
213 217 */
214 218 static char *seclist[] = {
215 219 SHOPT_RO,
216 220 SHOPT_RW,
217 221 SHOPT_ROOT,
218 222 SHOPT_WINDOW,
219 223 SHOPT_NONE,
220 224 SHOPT_ROOT_MAPPING,
221 225 SHOPT_UIDMAP,
222 226 SHOPT_GIDMAP,
223 227 NULL
224 228 };
225 229
226 230 /* structure for list of securities */
227 231 struct securities {
228 232 sa_security_t security;
229 233 struct securities *next;
230 234 };
231 235
232 236 /*
233 237 * findcharset(charset)
234 238 *
235 239 * Returns B_TRUE if the charset is a legal conversion otherwise
236 240 * B_FALSE. This will need to be rewritten to be more efficient when
237 241 * we have a dynamic list of legal conversions.
238 242 */
239 243
240 244 static boolean_t
241 245 findcharset(char *charset)
242 246 {
243 247 int i;
244 248
245 249 for (i = 0; legal_conv[i] != NULL; i++)
246 250 if (strcmp(charset, legal_conv[i]) == 0)
247 251 return (B_TRUE);
248 252 return (B_FALSE);
249 253 }
250 254
251 255 /*
252 256 * findopt(name)
253 257 *
254 258 * Lookup option "name" in the option table and return the table
255 259 * index.
256 260 */
257 261
258 262 static int
259 263 findopt(char *name)
260 264 {
261 265 int i;
262 266 if (name != NULL) {
263 267 for (i = 0; optdefs[i].tag != NULL; i++) {
264 268 if (strcmp(optdefs[i].tag, name) == 0)
265 269 return (optdefs[i].index);
266 270 }
267 271 if (findcharset(name))
268 272 return (OPT_CHARSET_MAP);
269 273 }
270 274 return (-1);
271 275 }
272 276
273 277 /*
274 278 * gettype(name)
275 279 *
276 280 * Return the type of option "name".
277 281 */
278 282
279 283 static int
280 284 gettype(char *name)
281 285 {
282 286 int optdef;
283 287
284 288 optdef = findopt(name);
285 289 if (optdef != -1)
286 290 return (optdefs[optdef].type);
287 291 return (OPT_TYPE_ANY);
288 292 }
289 293
290 294 /*
291 295 * nfs_validate_security_mode(mode)
292 296 *
293 297 * is the specified mode string a valid one for use with NFS?
294 298 */
295 299
296 300 static int
297 301 nfs_validate_security_mode(char *mode)
298 302 {
299 303 seconfig_t secinfo;
300 304 int err;
301 305
302 306 (void) memset(&secinfo, '\0', sizeof (secinfo));
303 307 err = nfs_getseconfig_byname(mode, &secinfo);
304 308 if (err == SC_NOERROR)
305 309 return (1);
306 310 return (0);
307 311 }
308 312
309 313 /*
310 314 * nfs_is_security_opt(tok)
311 315 *
312 316 * check to see if tok represents an option that is only valid in some
313 317 * security flavor.
314 318 */
315 319
316 320 static int
317 321 nfs_is_security_opt(char *tok)
318 322 {
319 323 int i;
320 324
321 325 for (i = 0; seclist[i] != NULL; i++) {
322 326 if (strcmp(tok, seclist[i]) == 0)
323 327 return (1);
324 328 }
325 329 return (0);
326 330 }
327 331
328 332 /*
329 333 * find_security(seclist, sec)
330 334 *
331 335 * Walk the current list of security flavors and return true if it is
332 336 * present, else return false.
333 337 */
334 338
335 339 static int
336 340 find_security(struct securities *seclist, sa_security_t sec)
337 341 {
338 342 while (seclist != NULL) {
339 343 if (seclist->security == sec)
340 344 return (1);
341 345 seclist = seclist->next;
342 346 }
343 347 return (0);
344 348 }
345 349
346 350 /*
347 351 * make_security_list(group, securitymodes, proto)
348 352 * go through the list of securitymodes and add them to the
349 353 * group's list of security optionsets. We also keep a list of
350 354 * those optionsets so we don't have to find them later. All of
351 355 * these will get copies of the same properties.
352 356 */
353 357
354 358 static struct securities *
355 359 make_security_list(sa_group_t group, char *securitymodes, char *proto)
356 360 {
357 361 char *tok, *next = NULL;
358 362 struct securities *curp, *headp = NULL, *prev;
359 363 sa_security_t check;
360 364 int freetok = 0;
361 365
362 366 for (tok = securitymodes; tok != NULL; tok = next) {
363 367 next = strchr(tok, ':');
364 368 if (next != NULL)
365 369 *next++ = '\0';
366 370 if (strcmp(tok, "default") == 0) {
367 371 /* resolve default into the real type */
368 372 tok = nfs_space_alias(tok);
369 373 freetok = 1;
370 374 }
371 375 check = sa_get_security(group, tok, proto);
372 376
373 377 /* add to the security list if it isn't there already */
374 378 if (check == NULL || !find_security(headp, check)) {
375 379 curp = (struct securities *)calloc(1,
376 380 sizeof (struct securities));
377 381 if (curp != NULL) {
378 382 if (check == NULL) {
379 383 curp->security = sa_create_security(
380 384 group, tok, proto);
381 385 } else {
382 386 curp->security = check;
383 387 }
384 388 /*
385 389 * note that the first time through the loop,
386 390 * headp will be NULL and prev will be
387 391 * undefined. Since headp is NULL, we set
388 392 * both it and prev to the curp (first
389 393 * structure to be allocated).
390 394 *
391 395 * later passes through the loop will have
392 396 * headp not being NULL and prev will be used
393 397 * to allocate at the end of the list.
394 398 */
395 399 if (headp == NULL) {
396 400 headp = curp;
397 401 prev = curp;
398 402 } else {
399 403 prev->next = curp;
400 404 prev = curp;
401 405 }
402 406 }
403 407 }
404 408
405 409 if (freetok) {
406 410 freetok = 0;
407 411 sa_free_attr_string(tok);
408 412 }
409 413 }
410 414 return (headp);
411 415 }
412 416
413 417 static void
414 418 free_security_list(struct securities *sec)
415 419 {
416 420 struct securities *next;
417 421 if (sec != NULL) {
418 422 for (next = sec->next; sec != NULL; sec = next) {
419 423 next = sec->next;
420 424 free(sec);
421 425 }
422 426 }
423 427 }
424 428
425 429 /*
426 430 * nfs_alistcat(str1, str2, sep)
427 431 *
428 432 * concatenate str1 and str2 into a new string using sep as a separate
429 433 * character. If memory allocation fails, return NULL;
430 434 */
431 435
432 436 static char *
433 437 nfs_alistcat(char *str1, char *str2, char sep)
434 438 {
435 439 char *newstr;
436 440 size_t len;
437 441
438 442 len = strlen(str1) + strlen(str2) + 2;
439 443 newstr = (char *)malloc(len);
440 444 if (newstr != NULL)
441 445 (void) snprintf(newstr, len, "%s%c%s", str1, sep, str2);
442 446 return (newstr);
443 447 }
444 448
445 449 /*
446 450 * add_security_prop(sec, name, value, persist, iszfs)
447 451 *
448 452 * Add the property to the securities structure. This accumulates
449 453 * properties for as part of parsing legacy options.
450 454 */
451 455
452 456 static int
453 457 add_security_prop(struct securities *sec, char *name, char *value,
454 458 int persist, int iszfs)
455 459 {
456 460 sa_property_t prop;
457 461 int ret = SA_OK;
458 462
459 463 for (; sec != NULL; sec = sec->next) {
460 464 if (value == NULL) {
461 465 if (strcmp(name, SHOPT_RW) == 0 ||
462 466 strcmp(name, SHOPT_RO) == 0)
463 467 value = "*";
464 468 else
465 469 value = "true";
466 470 }
467 471
468 472 /*
469 473 * Get the existing property, if it exists, so we can
470 474 * determine what to do with it. The ro/rw/root
471 475 * properties can be merged if multiple instances of
472 476 * these properies are given. For example, if "rw"
473 477 * exists with a value "host1" and a later token of
474 478 * rw="host2" is seen, the values are merged into a
475 479 * single rw="host1:host2".
476 480 */
477 481 prop = sa_get_property(sec->security, name);
478 482
479 483 if (prop != NULL) {
480 484 char *oldvalue;
481 485 char *newvalue;
482 486
483 487 /*
484 488 * The security options of ro/rw/root/uidmap/gidmap
485 489 * might appear multiple times. If they do, the values
486 490 * need to be merged. If it was previously empty, the
487 491 * new value alone is added.
488 492 */
489 493 oldvalue = sa_get_property_attr(prop, "value");
490 494 if (oldvalue != NULL) {
491 495 char sep = ':';
492 496
493 497 if (strcmp(name, SHOPT_UIDMAP) == 0 ||
494 498 strcmp(name, SHOPT_GIDMAP) == 0)
495 499 sep = '~';
496 500
497 501 /*
498 502 * The general case is to concatenate the new
499 503 * value onto the old value for multiple
500 504 * rw(ro/root/uidmap/gidmap) properties. For
501 505 * rw/ro/root a special case exists when either
502 506 * the old or new is the "all" case. In the
503 507 * special case, if both are "all", then it is
504 508 * "all", else if one is an access-list, that
505 509 * replaces the "all".
506 510 */
507 511 if (strcmp(oldvalue, "*") == 0) {
508 512 /* Replace old value with new value. */
509 513 newvalue = strdup(value);
510 514 } else if (strcmp(value, "*") == 0 ||
511 515 strcmp(oldvalue, value) == 0) {
512 516 /*
513 517 * Keep old value and ignore
514 518 * the new value.
515 519 */
516 520 newvalue = NULL;
517 521 } else {
518 522 /*
519 523 * Make a new list of old plus new
520 524 * access-list.
521 525 */
522 526 newvalue = nfs_alistcat(oldvalue,
523 527 value, sep);
524 528 }
525 529
526 530 if (newvalue != NULL) {
527 531 (void) sa_remove_property(prop);
528 532 prop = sa_create_property(name,
529 533 newvalue);
530 534 ret = sa_add_property(sec->security,
531 535 prop);
532 536 free(newvalue);
533 537 }
534 538
535 539 sa_free_attr_string(oldvalue);
536 540 }
537 541 } else {
538 542 prop = sa_create_property(name, value);
539 543 ret = sa_add_property(sec->security, prop);
540 544 }
541 545 if (ret == SA_OK && !iszfs) {
542 546 ret = sa_commit_properties(sec->security, !persist);
543 547 }
544 548 }
545 549 return (ret);
546 550 }
547 551
548 552 /*
549 553 * check to see if group/share is persistent.
550 554 */
551 555 static int
552 556 is_persistent(sa_group_t group)
553 557 {
554 558 char *type;
555 559 int persist = 1;
556 560
557 561 type = sa_get_group_attr(group, "type");
558 562 if (type != NULL && strcmp(type, "persist") != 0)
559 563 persist = 0;
560 564 if (type != NULL)
561 565 sa_free_attr_string(type);
562 566 return (persist);
563 567 }
564 568
565 569 /*
566 570 * invalid_security(options)
567 571 *
568 572 * search option string for any invalid sec= type.
569 573 * return true (1) if any are not valid else false (0)
570 574 */
571 575 static int
572 576 invalid_security(char *options)
573 577 {
574 578 char *copy, *base, *token, *value;
575 579 int ret = 0;
576 580
577 581 copy = strdup(options);
578 582 token = base = copy;
579 583 while (token != NULL && ret == 0) {
580 584 token = strtok(base, ",");
581 585 base = NULL;
582 586 if (token != NULL) {
583 587 value = strchr(token, '=');
584 588 if (value != NULL)
585 589 *value++ = '\0';
586 590 if (strcmp(token, SHOPT_SEC) == 0) {
587 591 /* HAVE security flavors so check them */
588 592 char *tok, *next;
589 593 for (next = NULL, tok = value; tok != NULL;
590 594 tok = next) {
591 595 next = strchr(tok, ':');
592 596 if (next != NULL)
593 597 *next++ = '\0';
594 598 ret = !nfs_validate_security_mode(tok);
595 599 if (ret)
596 600 break;
597 601 }
598 602 }
599 603 }
600 604 }
601 605 if (copy != NULL)
602 606 free(copy);
603 607 return (ret);
604 608 }
605 609
606 610 /*
607 611 * nfs_parse_legacy_options(group, options)
608 612 *
609 613 * Parse the old style options into internal format and store on the
610 614 * specified group. Group could be a share for full legacy support.
611 615 */
612 616
613 617 static int
614 618 nfs_parse_legacy_options(sa_group_t group, char *options)
615 619 {
616 620 char *dup;
617 621 char *base;
618 622 char *token;
619 623 sa_optionset_t optionset;
620 624 struct securities *security_list = NULL;
621 625 sa_property_t prop;
622 626 int ret = SA_OK;
623 627 int iszfs = 0;
624 628 sa_group_t parent;
625 629 int persist = 0;
626 630 char *lasts;
627 631
628 632 /* do we have an existing optionset? */
629 633 optionset = sa_get_optionset(group, "nfs");
630 634 if (optionset == NULL) {
631 635 /* didn't find existing optionset so create one */
632 636 optionset = sa_create_optionset(group, "nfs");
633 637 } else {
634 638 /*
635 639 * Have an existing optionset . Ideally, we would need
636 640 * to compare options in order to detect errors. For
637 641 * now, we assume that the first optionset is the
638 642 * correct one and the others will be the same. An
639 643 * empty optionset is the same as no optionset so we
640 644 * don't want to exit in that case. Getting an empty
641 645 * optionset can occur with ZFS property checking.
642 646 */
643 647 if (sa_get_property(optionset, NULL) != NULL)
644 648 return (ret);
645 649 }
646 650
647 651 if (strcmp(options, SHOPT_RW) == 0) {
648 652 /*
649 653 * there is a special case of only the option "rw"
650 654 * being the default option. We don't have to do
651 655 * anything.
652 656 */
653 657 return (ret);
654 658 }
655 659
656 660 /*
657 661 * check if security types are present and validate them. If
658 662 * any are not legal, fail.
659 663 */
660 664
661 665 if (invalid_security(options)) {
662 666 return (SA_INVALID_SECURITY);
663 667 }
664 668
665 669 /*
666 670 * in order to not attempt to change ZFS properties unless
667 671 * absolutely necessary, we never do it in the legacy parsing.
668 672 */
669 673 if (sa_is_share(group)) {
670 674 char *zfs;
671 675 parent = sa_get_parent_group(group);
672 676 if (parent != NULL) {
673 677 zfs = sa_get_group_attr(parent, "zfs");
674 678 if (zfs != NULL) {
675 679 sa_free_attr_string(zfs);
676 680 iszfs++;
677 681 }
678 682 }
679 683 } else {
680 684 iszfs = sa_group_is_zfs(group);
681 685 }
682 686
683 687 /* We need a copy of options for the next part. */
684 688 dup = strdup(options);
685 689 if (dup == NULL)
686 690 return (SA_NO_MEMORY);
687 691
688 692 /*
689 693 * we need to step through each option in the string and then
690 694 * add either the option or the security option as needed. If
691 695 * this is not a persistent share, don't commit to the
692 696 * repository. If there is an error, we also want to abort the
693 697 * processing and report it.
694 698 */
695 699 persist = is_persistent(group);
696 700 base = dup;
697 701 token = dup;
698 702 lasts = NULL;
699 703 while (token != NULL && ret == SA_OK) {
700 704 token = strtok_r(base, ",", &lasts);
701 705 base = NULL;
702 706 if (token != NULL) {
703 707 char *value;
704 708 /*
705 709 * if the option has a value, it will have an '=' to
706 710 * separate the name from the value. The following
707 711 * code will result in value != NULL and token
708 712 * pointing to just the name if there is a value.
709 713 */
710 714 value = strchr(token, '=');
711 715 if (value != NULL) {
712 716 *value++ = '\0';
713 717 }
714 718 if (strcmp(token, SHOPT_SEC) == 0 ||
715 719 strcmp(token, SHOPT_SECURE) == 0) {
716 720 /*
717 721 * Once in security parsing, we only
718 722 * do security. We do need to move
719 723 * between the security node and the
720 724 * toplevel. The security tag goes on
721 725 * the root while the following ones
722 726 * go on the security.
723 727 */
724 728 if (security_list != NULL) {
725 729 /*
726 730 * have an old list so close it and
727 731 * start the new
728 732 */
729 733 free_security_list(security_list);
730 734 }
731 735 if (strcmp(token, SHOPT_SECURE) == 0) {
732 736 value = "dh";
733 737 } else {
734 738 if (value == NULL) {
735 739 ret = SA_SYNTAX_ERR;
736 740 break;
737 741 }
738 742 }
739 743 security_list = make_security_list(group,
740 744 value, "nfs");
741 745 } else {
742 746 /*
743 747 * Note that the "old" syntax allowed a
744 748 * default security model. This must be
745 749 * accounted for and internally converted to
746 750 * "standard" security structure.
747 751 */
748 752 if (nfs_is_security_opt(token)) {
749 753 if (security_list == NULL) {
750 754 /*
751 755 * need to have a
752 756 * security
753 757 * option. This will
754 758 * be "closed" when a
755 759 * defined "sec="
756 760 * option is
757 761 * seen. This is
758 762 * technically an
759 763 * error but will be
760 764 * allowed with
761 765 * warning.
762 766 */
763 767 security_list =
764 768 make_security_list(group,
765 769 "default",
766 770 "nfs");
767 771 }
768 772 if (security_list != NULL) {
769 773 ret = add_security_prop(
770 774 security_list, token,
771 775 value, persist, iszfs);
772 776 } else {
773 777 ret = SA_NO_MEMORY;
774 778 }
775 779 } else {
776 780 /* regular options */
777 781 if (value == NULL) {
778 782 if (strcmp(token, SHOPT_RW) ==
779 783 0 || strcmp(token,
780 784 SHOPT_RO) == 0) {
781 785 value = "*";
782 786 } else {
783 787 value = "global";
784 788 if (strcmp(token,
785 789 SHOPT_LOG) != 0) {
786 790 value = "true";
787 791 }
788 792 }
789 793 }
790 794 /*
791 795 * In all cases, create the
792 796 * property specified. If the
793 797 * value was NULL, the default
794 798 * value will have been
795 799 * substituted.
796 800 */
797 801 prop = sa_create_property(token, value);
798 802 ret = sa_add_property(optionset, prop);
799 803 if (ret != SA_OK)
800 804 break;
801 805
802 806 if (!iszfs) {
803 807 ret = sa_commit_properties(
804 808 optionset, !persist);
805 809 }
806 810 }
807 811 }
808 812 }
809 813 }
810 814 if (security_list != NULL)
811 815 free_security_list(security_list);
812 816
813 817 free(dup);
814 818 return (ret);
815 819 }
816 820
817 821 /*
818 822 * is_a_number(number)
819 823 *
820 824 * is the string a number in one of the forms we want to use?
821 825 */
822 826
823 827 static int
824 828 is_a_number(char *number)
825 829 {
826 830 int ret = 1;
827 831 int hex = 0;
828 832
829 833 if (strncmp(number, "0x", 2) == 0) {
830 834 number += 2;
831 835 hex = 1;
832 836 } else if (*number == '-') {
833 837 number++; /* skip the minus */
834 838 }
835 839 while (ret == 1 && *number != '\0') {
836 840 if (hex) {
837 841 ret = isxdigit(*number++);
838 842 } else {
839 843 ret = isdigit(*number++);
840 844 }
841 845 }
842 846 return (ret);
843 847 }
844 848
845 849 /*
846 850 * Look for the specified tag in the configuration file. If it is found,
847 851 * enable logging and set the logging configuration information for exp.
848 852 */
849 853 static void
850 854 configlog(struct exportdata *exp, char *tag)
851 855 {
852 856 nfsl_config_t *configlist = NULL, *configp;
853 857 int error = 0;
854 858 char globaltag[] = DEFAULTTAG;
855 859
856 860 /*
857 861 * Sends config errors to stderr
858 862 */
859 863 nfsl_errs_to_syslog = B_FALSE;
860 864
861 865 /*
862 866 * get the list of configuration settings
863 867 */
864 868 error = nfsl_getconfig_list(&configlist);
865 869 if (error) {
866 870 (void) fprintf(stderr,
867 871 dgettext(TEXT_DOMAIN, "Cannot get log configuration: %s\n"),
868 872 strerror(error));
869 873 }
870 874
871 875 if (tag == NULL)
872 876 tag = globaltag;
873 877 if ((configp = nfsl_findconfig(configlist, tag, &error)) == NULL) {
874 878 nfsl_freeconfig_list(&configlist);
875 879 (void) fprintf(stderr,
876 880 dgettext(TEXT_DOMAIN, "No tags matching \"%s\"\n"), tag);
877 881 /* bad configuration */
878 882 error = ENOENT;
879 883 goto err;
880 884 }
881 885
882 886 if ((exp->ex_tag = strdup(tag)) == NULL) {
883 887 error = ENOMEM;
884 888 goto out;
885 889 }
886 890 if ((exp->ex_log_buffer = strdup(configp->nc_bufferpath)) == NULL) {
887 891 error = ENOMEM;
888 892 goto out;
889 893 }
890 894 exp->ex_flags |= EX_LOG;
891 895 if (configp->nc_rpclogpath != NULL)
892 896 exp->ex_flags |= EX_LOG_ALLOPS;
893 897 out:
894 898 if (configlist != NULL)
895 899 nfsl_freeconfig_list(&configlist);
896 900
897 901 err:
898 902 if (error != 0) {
899 903 free(exp->ex_tag);
900 904 free(exp->ex_log_buffer);
901 905 (void) fprintf(stderr,
902 906 dgettext(TEXT_DOMAIN, "Cannot set log configuration: %s\n"),
903 907 strerror(error));
904 908 }
905 909 }
906 910
907 911 /*
908 912 * fill_export_from_optionset(export, optionset)
909 913 *
910 914 * In order to share, we need to set all the possible general options
911 915 * into the export structure. Share info will be filled in by the
912 916 * caller. Various property values get turned into structure specific
913 917 * values.
914 918 */
915 919
916 920 static int
917 921 fill_export_from_optionset(struct exportdata *export, sa_optionset_t optionset)
918 922 {
919 923 sa_property_t option;
920 924 int ret = SA_OK;
921 925
922 926 for (option = sa_get_property(optionset, NULL);
923 927 option != NULL; option = sa_get_next_property(option)) {
924 928 char *name;
925 929 char *value;
926 930 uint32_t val;
927 931
928 932 /*
929 933 * since options may be set/reset multiple times, always do an
930 934 * explicit set or clear of the option. This allows defaults
931 935 * to be set and then the protocol specific to override.
932 936 */
933 937
934 938 name = sa_get_property_attr(option, "type");
935 939 value = sa_get_property_attr(option, "value");
936 940 switch (findopt(name)) {
937 941 case OPT_ANON:
938 942 if (value != NULL && is_a_number(value)) {
939 943 val = strtoul(value, NULL, 0);
940 944 } else {
941 945 struct passwd *pw;
942 946 pw = getpwnam(value != NULL ? value : "nobody");
943 947 if (pw != NULL) {
944 948 val = pw->pw_uid;
945 949 } else {
946 950 val = UID_NOBODY;
947 951 }
948 952 endpwent();
949 953 }
950 954 export->ex_anon = val;
951 955 break;
952 956 case OPT_NOSUID:
953 957 if (value != NULL && (strcasecmp(value, "true") == 0 ||
954 958 strcmp(value, "1") == 0))
955 959 export->ex_flags |= EX_NOSUID;
956 960 else
957 961 export->ex_flags &= ~EX_NOSUID;
958 962 break;
959 963 case OPT_ACLOK:
960 964 if (value != NULL && (strcasecmp(value, "true") == 0 ||
961 965 strcmp(value, "1") == 0))
962 966 export->ex_flags |= EX_ACLOK;
963 967 else
964 968 export->ex_flags &= ~EX_ACLOK;
965 969 break;
966 970 case OPT_NOSUB:
967 971 if (value != NULL && (strcasecmp(value, "true") == 0 ||
968 972 strcmp(value, "1") == 0))
969 973 export->ex_flags |= EX_NOSUB;
970 974 else
971 975 export->ex_flags &= ~EX_NOSUB;
972 976 break;
973 977 case OPT_PUBLIC:
974 978 if (value != NULL && (strcasecmp(value, "true") == 0 ||
975 979 strcmp(value, "1") == 0))
976 980 export->ex_flags |= EX_PUBLIC;
977 981 else
978 982 export->ex_flags &= ~EX_PUBLIC;
979 983 break;
980 984 case OPT_INDEX:
981 985 if (value != NULL && (strcmp(value, "..") == 0 ||
982 986 strchr(value, '/') != NULL)) {
983 987 /* this is an error */
984 988 (void) printf(dgettext(TEXT_DOMAIN,
985 989 "NFS: index=\"%s\" not valid;"
986 990 "must be a filename.\n"),
987 991 value);
988 992 break;
989 993 }
990 994 if (value != NULL && *value != '\0' &&
991 995 strcmp(value, ".") != 0) {
992 996 /* valid index file string */
993 997 if (export->ex_index != NULL) {
994 998 /* left over from "default" */
995 999 free(export->ex_index);
996 1000 }
997 1001 /* remember to free */
998 1002 export->ex_index = strdup(value);
999 1003 if (export->ex_index == NULL) {
1000 1004 (void) printf(dgettext(TEXT_DOMAIN,
1001 1005 "NFS: out of memory setting "
1002 1006 "index property\n"));
1003 1007 break;
1004 1008 }
1005 1009 export->ex_flags |= EX_INDEX;
1006 1010 }
1007 1011 break;
1008 1012 case OPT_LOG:
1009 1013 if (value == NULL)
1010 1014 value = strdup("global");
1011 1015 if (value != NULL)
1012 1016 configlog(export,
1013 1017 strlen(value) ? value : "global");
1014 1018 break;
1015 1019 case OPT_CHARSET_MAP:
1016 1020 /*
1017 1021 * Set EX_CHARMAP when there is at least one
1018 1022 * charmap conversion property. This will get
1019 1023 * checked by the nfs server when it needs to.
|
↓ open down ↓ |
820 lines elided |
↑ open up ↑ |
1020 1024 */
1021 1025 export->ex_flags |= EX_CHARMAP;
1022 1026 break;
1023 1027 case OPT_NOACLFAB:
1024 1028 if (value != NULL && (strcasecmp(value, "true") == 0 ||
1025 1029 strcmp(value, "1") == 0))
1026 1030 export->ex_flags |= EX_NOACLFAB;
1027 1031 else
1028 1032 export->ex_flags &= ~EX_NOACLFAB;
1029 1033 break;
1034 + case OPT_NOHIDE:
1035 + if (value != NULL && (strcasecmp(value, "true") == 0 ||
1036 + strcmp(value, "1") == 0))
1037 + export->ex_flags |= EX_NOHIDE;
1038 + else
1039 + export->ex_flags &= ~EX_NOHIDE;
1040 +
1041 + break;
1030 1042 default:
1031 1043 /* have a syntactic error */
1032 1044 (void) printf(dgettext(TEXT_DOMAIN,
1033 1045 "NFS: unrecognized option %s=%s\n"),
1034 1046 name != NULL ? name : "",
1035 1047 value != NULL ? value : "");
1036 1048 break;
1037 1049 }
1038 1050 if (name != NULL)
1039 1051 sa_free_attr_string(name);
1040 1052 if (value != NULL)
1041 1053 sa_free_attr_string(value);
1042 1054 }
1043 1055 return (ret);
1044 1056 }
1045 1057
1046 1058 /*
1047 1059 * cleanup_export(export)
1048 1060 *
1049 1061 * Cleanup the allocated areas so we don't leak memory
1050 1062 */
1051 1063
1052 1064 static void
1053 1065 cleanup_export(struct exportdata *export)
1054 1066 {
1055 1067 int i;
1056 1068
1057 1069 free(export->ex_index);
1058 1070
1059 1071 for (i = 0; i < export->ex_seccnt; i++) {
1060 1072 struct secinfo *s = &export->ex_secinfo[i];
1061 1073
1062 1074 while (s->s_rootcnt > 0)
1063 1075 free(s->s_rootnames[--s->s_rootcnt]);
1064 1076
1065 1077 free(s->s_rootnames);
1066 1078 }
1067 1079 free(export->ex_secinfo);
1068 1080 }
1069 1081
1070 1082 /*
1071 1083 * Given a seconfig entry and a colon-separated
1072 1084 * list of names, allocate an array big enough
1073 1085 * to hold the root list, then convert each name to
1074 1086 * a principal name according to the security
1075 1087 * info and assign it to an array element.
1076 1088 * Return the array and its size.
1077 1089 */
1078 1090 static caddr_t *
1079 1091 get_rootnames(seconfig_t *sec, char *list, int *count)
1080 1092 {
1081 1093 caddr_t *a;
1082 1094 int c, i;
1083 1095 char *host, *p;
1084 1096
1085 1097 /*
1086 1098 * Count the number of strings in the list.
1087 1099 * This is the number of colon separators + 1.
1088 1100 */
1089 1101 c = 1;
1090 1102 for (p = list; *p; p++)
1091 1103 if (*p == ':')
1092 1104 c++;
1093 1105 *count = c;
1094 1106
1095 1107 a = (caddr_t *)malloc(c * sizeof (char *));
1096 1108 if (a == NULL) {
1097 1109 (void) printf(dgettext(TEXT_DOMAIN,
1098 1110 "get_rootnames: no memory\n"));
1099 1111 *count = 0;
1100 1112 } else {
1101 1113 for (i = 0; i < c; i++) {
1102 1114 host = strtok(list, ":");
1103 1115 if (!nfs_get_root_principal(sec, host, &a[i])) {
1104 1116 while (i > 0)
1105 1117 free(a[--i]);
1106 1118 free(a);
1107 1119 a = NULL;
1108 1120 *count = 0;
1109 1121 break;
1110 1122 }
1111 1123 list = NULL;
1112 1124 }
1113 1125 }
1114 1126
1115 1127 return (a);
1116 1128 }
1117 1129
1118 1130 /*
1119 1131 * fill_security_from_secopts(sp, secopts)
1120 1132 *
1121 1133 * Fill the secinfo structure from the secopts optionset.
1122 1134 */
1123 1135
1124 1136 static int
1125 1137 fill_security_from_secopts(struct secinfo *sp, sa_security_t secopts)
1126 1138 {
1127 1139 sa_property_t prop;
1128 1140 char *type;
1129 1141 int longform;
1130 1142 int err = SC_NOERROR;
1131 1143 uint32_t val;
1132 1144
1133 1145 type = sa_get_security_attr(secopts, "sectype");
1134 1146 if (type != NULL) {
1135 1147 /* named security type needs secinfo to be filled in */
1136 1148 err = nfs_getseconfig_byname(type, &sp->s_secinfo);
1137 1149 sa_free_attr_string(type);
1138 1150 if (err != SC_NOERROR)
1139 1151 return (err);
1140 1152 } else {
1141 1153 /* default case */
1142 1154 err = nfs_getseconfig_default(&sp->s_secinfo);
1143 1155 if (err != SC_NOERROR)
1144 1156 return (err);
1145 1157 }
1146 1158
1147 1159 err = SA_OK;
1148 1160 for (prop = sa_get_property(secopts, NULL);
1149 1161 prop != NULL && err == SA_OK;
1150 1162 prop = sa_get_next_property(prop)) {
1151 1163 char *name;
1152 1164 char *value;
1153 1165
1154 1166 name = sa_get_property_attr(prop, "type");
1155 1167 value = sa_get_property_attr(prop, "value");
1156 1168
1157 1169 longform = value != NULL && strcmp(value, "*") != 0;
1158 1170
1159 1171 switch (findopt(name)) {
1160 1172 case OPT_RO:
1161 1173 sp->s_flags |= longform ? M_ROL : M_RO;
1162 1174 break;
1163 1175 case OPT_RW:
1164 1176 sp->s_flags |= longform ? M_RWL : M_RW;
1165 1177 break;
1166 1178 case OPT_ROOT:
1167 1179 sp->s_flags |= M_ROOT;
1168 1180 /*
1169 1181 * if we are using AUTH_UNIX, handle like other things
1170 1182 * such as RO/RW
1171 1183 */
1172 1184 if (sp->s_secinfo.sc_rpcnum == AUTH_UNIX)
1173 1185 break;
1174 1186 /* not AUTH_UNIX */
1175 1187 if (value != NULL) {
1176 1188 sp->s_rootnames = get_rootnames(&sp->s_secinfo,
1177 1189 value, &sp->s_rootcnt);
1178 1190 if (sp->s_rootnames == NULL) {
1179 1191 err = SA_BAD_VALUE;
1180 1192 (void) fprintf(stderr,
1181 1193 dgettext(TEXT_DOMAIN,
1182 1194 "Bad root list\n"));
1183 1195 }
1184 1196 }
1185 1197 break;
1186 1198 case OPT_NONE:
1187 1199 sp->s_flags |= M_NONE;
1188 1200 break;
1189 1201 case OPT_WINDOW:
1190 1202 if (value != NULL) {
1191 1203 sp->s_window = atoi(value);
1192 1204 /* just in case */
1193 1205 if (sp->s_window < 0)
1194 1206 sp->s_window = DEF_WIN;
1195 1207 }
1196 1208 break;
1197 1209 case OPT_ROOT_MAPPING:
1198 1210 if (value != NULL && is_a_number(value)) {
1199 1211 val = strtoul(value, NULL, 0);
1200 1212 } else {
1201 1213 struct passwd *pw;
1202 1214 pw = getpwnam(value != NULL ? value : "nobody");
1203 1215 if (pw != NULL) {
1204 1216 val = pw->pw_uid;
1205 1217 } else {
1206 1218 val = UID_NOBODY;
1207 1219 }
1208 1220 endpwent();
1209 1221 }
1210 1222 sp->s_rootid = val;
1211 1223 break;
1212 1224 case OPT_UIDMAP:
1213 1225 case OPT_GIDMAP:
1214 1226 sp->s_flags |= M_MAP;
1215 1227 break;
1216 1228 default:
1217 1229 break;
1218 1230 }
1219 1231 if (name != NULL)
1220 1232 sa_free_attr_string(name);
1221 1233 if (value != NULL)
1222 1234 sa_free_attr_string(value);
1223 1235 }
1224 1236 /* if rw/ro options not set, use default of RW */
1225 1237 if ((sp->s_flags & NFS_RWMODES) == 0)
1226 1238 sp->s_flags |= M_RW;
1227 1239 return (err);
1228 1240 }
1229 1241
1230 1242 /*
1231 1243 * This is for testing only
1232 1244 * It displays the export structure that
1233 1245 * goes into the kernel.
1234 1246 */
1235 1247 static void
1236 1248 printarg(char *path, struct exportdata *ep)
1237 1249 {
1238 1250 int i, j;
1239 1251 struct secinfo *sp;
1240 1252
1241 1253 if (debug == 0)
1242 1254 return;
1243 1255
1244 1256 (void) printf("%s:\n", path);
1245 1257 (void) printf("\tex_version = %d\n", ep->ex_version);
1246 1258 (void) printf("\tex_path = %s\n", ep->ex_path);
1247 1259 (void) printf("\tex_pathlen = %ld\n", (ulong_t)ep->ex_pathlen);
1248 1260 (void) printf("\tex_flags: (0x%02x) ", ep->ex_flags);
1249 1261 if (ep->ex_flags & EX_NOSUID)
1250 1262 (void) printf("NOSUID ");
1251 1263 if (ep->ex_flags & EX_ACLOK)
1252 1264 (void) printf("ACLOK ");
1253 1265 if (ep->ex_flags & EX_PUBLIC)
1254 1266 (void) printf("PUBLIC ");
1255 1267 if (ep->ex_flags & EX_NOSUB)
1256 1268 (void) printf("NOSUB ");
1257 1269 if (ep->ex_flags & EX_LOG)
1258 1270 (void) printf("LOG ");
1259 1271 if (ep->ex_flags & EX_CHARMAP)
1260 1272 (void) printf("CHARMAP ");
1261 1273 if (ep->ex_flags & EX_LOG_ALLOPS)
1262 1274 (void) printf("LOG_ALLOPS ");
1263 1275 if (ep->ex_flags == 0)
1264 1276 (void) printf("(none)");
1265 1277 (void) printf("\n");
1266 1278 if (ep->ex_flags & EX_LOG) {
1267 1279 (void) printf("\tex_log_buffer = %s\n",
1268 1280 (ep->ex_log_buffer ? ep->ex_log_buffer : "(NULL)"));
1269 1281 (void) printf("\tex_tag = %s\n",
1270 1282 (ep->ex_tag ? ep->ex_tag : "(NULL)"));
1271 1283 }
1272 1284 (void) printf("\tex_anon = %d\n", ep->ex_anon);
1273 1285 (void) printf("\tex_seccnt = %d\n", ep->ex_seccnt);
1274 1286 (void) printf("\n");
1275 1287 for (i = 0; i < ep->ex_seccnt; i++) {
1276 1288 sp = &ep->ex_secinfo[i];
1277 1289 (void) printf("\t\ts_secinfo = %s\n", sp->s_secinfo.sc_name);
1278 1290 (void) printf("\t\ts_flags: (0x%02x) ", sp->s_flags);
1279 1291 if (sp->s_flags & M_ROOT) (void) printf("M_ROOT ");
1280 1292 if (sp->s_flags & M_RO) (void) printf("M_RO ");
1281 1293 if (sp->s_flags & M_ROL) (void) printf("M_ROL ");
1282 1294 if (sp->s_flags & M_RW) (void) printf("M_RW ");
1283 1295 if (sp->s_flags & M_RWL) (void) printf("M_RWL ");
1284 1296 if (sp->s_flags & M_NONE) (void) printf("M_NONE ");
1285 1297 if (sp->s_flags & M_MAP) (void) printf("M_MAP ");
1286 1298 if (sp->s_flags == 0) (void) printf("(none)");
1287 1299 (void) printf("\n");
1288 1300 (void) printf("\t\ts_window = %d\n", sp->s_window);
1289 1301 (void) printf("\t\ts_rootid = %d\n", sp->s_rootid);
1290 1302 (void) printf("\t\ts_rootcnt = %d ", sp->s_rootcnt);
1291 1303 (void) fflush(stdout);
1292 1304 for (j = 0; j < sp->s_rootcnt; j++)
1293 1305 (void) printf("%s ", sp->s_rootnames[j] ?
1294 1306 sp->s_rootnames[j] : "<null>");
1295 1307 (void) printf("\n\n");
1296 1308 }
1297 1309 }
1298 1310
1299 1311 /*
1300 1312 * count_security(opts)
1301 1313 *
1302 1314 * Count the number of security types (flavors). The optionset has
1303 1315 * been populated with the security flavors as a holding mechanism.
1304 1316 * We later use this number to allocate data structures.
1305 1317 */
1306 1318
1307 1319 static int
1308 1320 count_security(sa_optionset_t opts)
1309 1321 {
1310 1322 int count = 0;
1311 1323 sa_property_t prop;
1312 1324 if (opts != NULL) {
1313 1325 for (prop = sa_get_property(opts, NULL); prop != NULL;
1314 1326 prop = sa_get_next_property(prop)) {
1315 1327 count++;
1316 1328 }
1317 1329 }
1318 1330 return (count);
1319 1331 }
1320 1332
1321 1333 /*
1322 1334 * nfs_sprint_option(rbuff, rbuffsize, incr, prop, sep)
1323 1335 *
1324 1336 * provides a mechanism to format NFS properties into legacy output
1325 1337 * format. If the buffer would overflow, it is reallocated and grown
1326 1338 * as appropriate. Special cases of converting internal form of values
1327 1339 * to those used by "share" are done. this function does one property
1328 1340 * at a time.
1329 1341 */
1330 1342
1331 1343 static int
1332 1344 nfs_sprint_option(char **rbuff, size_t *rbuffsize, size_t incr,
1333 1345 sa_property_t prop, int sep)
1334 1346 {
1335 1347 char *name;
1336 1348 char *value;
1337 1349 int curlen;
1338 1350 char *buff = *rbuff;
1339 1351 size_t buffsize = *rbuffsize;
1340 1352 int printed = B_FALSE;
1341 1353
1342 1354 name = sa_get_property_attr(prop, "type");
1343 1355 value = sa_get_property_attr(prop, "value");
1344 1356 if (buff != NULL)
1345 1357 curlen = strlen(buff);
1346 1358 else
1347 1359 curlen = 0;
1348 1360 if (name != NULL) {
1349 1361 int len;
1350 1362 len = strlen(name) + sep;
1351 1363
1352 1364 /*
1353 1365 * A future RFE would be to replace this with more
1354 1366 * generic code and to possibly handle more types.
1355 1367 */
1356 1368 switch (gettype(name)) {
1357 1369 case OPT_TYPE_BOOLEAN:
1358 1370 /*
1359 1371 * For NFS, boolean value of FALSE means it
1360 1372 * doesn't show up in the option list at all.
1361 1373 */
1362 1374 if (value != NULL && strcasecmp(value, "false") == 0)
1363 1375 goto skip;
1364 1376 if (value != NULL) {
1365 1377 sa_free_attr_string(value);
1366 1378 value = NULL;
1367 1379 }
1368 1380 break;
1369 1381 case OPT_TYPE_ACCLIST:
1370 1382 if (value != NULL && strcmp(value, "*") == 0) {
1371 1383 sa_free_attr_string(value);
1372 1384 value = NULL;
1373 1385 } else {
1374 1386 if (value != NULL)
1375 1387 len += 1 + strlen(value);
1376 1388 }
1377 1389 break;
1378 1390 case OPT_TYPE_LOGTAG:
1379 1391 if (value != NULL && strlen(value) == 0) {
1380 1392 sa_free_attr_string(value);
1381 1393 value = NULL;
1382 1394 } else {
1383 1395 if (value != NULL)
1384 1396 len += 1 + strlen(value);
1385 1397 }
1386 1398 break;
1387 1399 default:
1388 1400 if (value != NULL)
1389 1401 len += 1 + strlen(value);
1390 1402 break;
1391 1403 }
1392 1404 while (buffsize <= (curlen + len)) {
1393 1405 /* need more room */
1394 1406 buffsize += incr;
1395 1407 buff = realloc(buff, buffsize);
1396 1408 if (buff == NULL) {
1397 1409 /* realloc failed so free everything */
1398 1410 if (*rbuff != NULL)
1399 1411 free(*rbuff);
1400 1412 }
1401 1413 *rbuff = buff;
1402 1414 *rbuffsize = buffsize;
1403 1415 if (buff == NULL)
1404 1416 goto skip;
1405 1417
1406 1418 }
1407 1419
1408 1420 if (buff == NULL)
1409 1421 goto skip;
1410 1422
1411 1423 if (value == NULL) {
1412 1424 (void) snprintf(buff + curlen, buffsize - curlen,
1413 1425 "%s%s", sep ? "," : "", name);
1414 1426 } else {
1415 1427 (void) snprintf(buff + curlen, buffsize - curlen,
1416 1428 "%s%s=%s", sep ? "," : "",
1417 1429 name, value != NULL ? value : "");
1418 1430 }
1419 1431 printed = B_TRUE;
1420 1432 }
1421 1433 skip:
1422 1434 if (name != NULL)
1423 1435 sa_free_attr_string(name);
1424 1436 if (value != NULL)
1425 1437 sa_free_attr_string(value);
1426 1438 return (printed);
1427 1439 }
1428 1440
1429 1441 /*
1430 1442 * nfs_format_options(group, hier)
1431 1443 *
1432 1444 * format all the options on the group into an old-style option
1433 1445 * string. If hier is non-zero, walk up the tree to get inherited
1434 1446 * options.
1435 1447 */
1436 1448
1437 1449 static char *
1438 1450 nfs_format_options(sa_group_t group, int hier)
1439 1451 {
1440 1452 sa_optionset_t options = NULL;
1441 1453 sa_optionset_t secoptions = NULL;
1442 1454 sa_property_t prop, secprop;
1443 1455 sa_security_t security = NULL;
1444 1456 char *buff;
1445 1457 size_t buffsize;
1446 1458 char *sectype = NULL;
1447 1459 int sep = 0;
1448 1460
1449 1461
1450 1462 buff = malloc(OPT_CHUNK);
1451 1463 if (buff == NULL) {
1452 1464 return (NULL);
1453 1465 }
1454 1466
1455 1467 buff[0] = '\0';
1456 1468 buffsize = OPT_CHUNK;
1457 1469
1458 1470 /*
1459 1471 * We may have a an optionset relative to this item. format
1460 1472 * these if we find them and then add any security definitions.
1461 1473 */
1462 1474
1463 1475 options = sa_get_derived_optionset(group, "nfs", hier);
1464 1476
1465 1477 /*
1466 1478 * do the default set first but skip any option that is also
1467 1479 * in the protocol specific optionset.
1468 1480 */
1469 1481 if (options != NULL) {
1470 1482 for (prop = sa_get_property(options, NULL);
1471 1483 prop != NULL; prop = sa_get_next_property(prop)) {
1472 1484 /*
1473 1485 * use this one since we skipped any
1474 1486 * of these that were also in
1475 1487 * optdefault
1476 1488 */
1477 1489 if (nfs_sprint_option(&buff, &buffsize, OPT_CHUNK,
1478 1490 prop, sep))
1479 1491 sep = 1;
1480 1492 if (buff == NULL) {
1481 1493 /*
1482 1494 * buff could become NULL if there
1483 1495 * isn't enough memory for
1484 1496 * nfs_sprint_option to realloc()
1485 1497 * as necessary. We can't really
1486 1498 * do anything about it at this
1487 1499 * point so we return NULL. The
1488 1500 * caller should handle the
1489 1501 * failure.
1490 1502 */
1491 1503 if (options != NULL)
1492 1504 sa_free_derived_optionset(
1493 1505 options);
1494 1506 return (buff);
1495 1507 }
1496 1508 }
1497 1509 }
1498 1510 secoptions = (sa_optionset_t)sa_get_all_security_types(group,
1499 1511 "nfs", hier);
1500 1512 if (secoptions != NULL) {
1501 1513 for (secprop = sa_get_property(secoptions, NULL);
1502 1514 secprop != NULL;
1503 1515 secprop = sa_get_next_property(secprop)) {
1504 1516 sectype = sa_get_property_attr(secprop, "type");
1505 1517 security =
1506 1518 (sa_security_t)sa_get_derived_security(
1507 1519 group, sectype, "nfs", hier);
1508 1520 if (security != NULL) {
1509 1521 if (sectype != NULL) {
1510 1522 prop = sa_create_property(
1511 1523 "sec", sectype);
1512 1524 if (prop == NULL)
1513 1525 goto err;
1514 1526 if (nfs_sprint_option(&buff,
1515 1527 &buffsize, OPT_CHUNK, prop, sep))
1516 1528 sep = 1;
1517 1529 (void) sa_remove_property(prop);
1518 1530 if (buff == NULL)
1519 1531 goto err;
1520 1532 }
1521 1533 for (prop = sa_get_property(security,
1522 1534 NULL); prop != NULL;
1523 1535 prop = sa_get_next_property(prop)) {
1524 1536 if (nfs_sprint_option(&buff,
1525 1537 &buffsize, OPT_CHUNK, prop, sep))
1526 1538 sep = 1;
1527 1539 if (buff == NULL)
1528 1540 goto err;
1529 1541 }
1530 1542 sa_free_derived_optionset(security);
1531 1543 }
1532 1544 if (sectype != NULL)
1533 1545 sa_free_attr_string(sectype);
1534 1546 }
1535 1547 sa_free_derived_optionset(secoptions);
1536 1548 }
1537 1549
1538 1550 if (options != NULL)
1539 1551 sa_free_derived_optionset(options);
1540 1552 return (buff);
1541 1553
1542 1554 err:
1543 1555 /*
1544 1556 * If we couldn't allocate memory for option printing, we need
1545 1557 * to break out of the nested loops, cleanup and return NULL.
1546 1558 */
1547 1559 if (secoptions != NULL)
1548 1560 sa_free_derived_optionset(secoptions);
1549 1561 if (security != NULL)
1550 1562 sa_free_derived_optionset(security);
1551 1563 if (sectype != NULL)
1552 1564 sa_free_attr_string(sectype);
1553 1565 if (options != NULL)
1554 1566 sa_free_derived_optionset(options);
1555 1567 return (buff);
1556 1568 }
1557 1569
1558 1570 /*
1559 1571 * Append an entry to the nfslogtab file
1560 1572 */
1561 1573 static int
1562 1574 nfslogtab_add(char *dir, char *buffer, char *tag)
1563 1575 {
1564 1576 FILE *f;
1565 1577 struct logtab_ent lep;
1566 1578 int error = 0;
1567 1579
1568 1580 /*
1569 1581 * Open the file for update and create it if necessary.
1570 1582 * This may leave the I/O offset at the end of the file,
1571 1583 * so rewind back to the beginning of the file.
1572 1584 */
1573 1585 f = fopen(NFSLOGTAB, "a+");
1574 1586 if (f == NULL) {
1575 1587 error = errno;
1576 1588 goto out;
1577 1589 }
1578 1590 rewind(f);
1579 1591
1580 1592 if (lockf(fileno(f), F_LOCK, 0L) < 0) {
1581 1593 (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
1582 1594 "share complete, however failed to lock %s "
1583 1595 "for update: %s\n"), NFSLOGTAB, strerror(errno));
1584 1596 error = -1;
1585 1597 goto out;
1586 1598 }
1587 1599
1588 1600 if (logtab_deactivate_after_boot(f) == -1) {
1589 1601 (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
1590 1602 "share complete, however could not deactivate "
1591 1603 "entries in %s\n"), NFSLOGTAB);
1592 1604 error = -1;
1593 1605 goto out;
1594 1606 }
1595 1607
1596 1608 /*
1597 1609 * Remove entries matching buffer and sharepoint since we're
1598 1610 * going to replace it with perhaps an entry with a new tag.
1599 1611 */
1600 1612 if (logtab_rement(f, buffer, dir, NULL, -1)) {
1601 1613 (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
1602 1614 "share complete, however could not remove matching "
1603 1615 "entries in %s\n"), NFSLOGTAB);
1604 1616 error = -1;
1605 1617 goto out;
1606 1618 }
1607 1619
1608 1620 /*
1609 1621 * Deactivate all active entries matching this sharepoint
1610 1622 */
1611 1623 if (logtab_deactivate(f, NULL, dir, NULL)) {
1612 1624 (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
1613 1625 "share complete, however could not deactivate matching "
1614 1626 "entries in %s\n"), NFSLOGTAB);
1615 1627 error = -1;
1616 1628 goto out;
1617 1629 }
1618 1630
1619 1631 lep.le_buffer = buffer;
1620 1632 lep.le_path = dir;
1621 1633 lep.le_tag = tag;
1622 1634 lep.le_state = LES_ACTIVE;
1623 1635
1624 1636 /*
1625 1637 * Add new sharepoint / buffer location to nfslogtab
1626 1638 */
1627 1639 if (logtab_putent(f, &lep) < 0) {
1628 1640 (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
1629 1641 "share complete, however could not add %s to %s\n"),
1630 1642 dir, NFSLOGTAB);
1631 1643 error = -1;
1632 1644 }
1633 1645
1634 1646 out:
1635 1647 if (f != NULL)
1636 1648 (void) fclose(f);
1637 1649 return (error);
1638 1650 }
1639 1651
1640 1652 /*
1641 1653 * Deactivate an entry from the nfslogtab file
1642 1654 */
1643 1655 static int
1644 1656 nfslogtab_deactivate(char *path)
1645 1657 {
1646 1658 FILE *f;
1647 1659 int error = 0;
1648 1660
1649 1661 f = fopen(NFSLOGTAB, "r+");
1650 1662 if (f == NULL) {
1651 1663 error = errno;
1652 1664 goto out;
1653 1665 }
1654 1666 if (lockf(fileno(f), F_LOCK, 0L) < 0) {
1655 1667 error = errno;
1656 1668 (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
1657 1669 "share complete, however could not lock %s for "
1658 1670 "update: %s\n"), NFSLOGTAB, strerror(error));
1659 1671 goto out;
1660 1672 }
1661 1673 if (logtab_deactivate(f, NULL, path, NULL) == -1) {
1662 1674 error = -1;
1663 1675 (void) fprintf(stderr,
1664 1676 dgettext(TEXT_DOMAIN,
1665 1677 "share complete, however could not "
1666 1678 "deactivate %s in %s\n"), path, NFSLOGTAB);
1667 1679 goto out;
1668 1680 }
1669 1681
1670 1682 out: if (f != NULL)
1671 1683 (void) fclose(f);
1672 1684
1673 1685 return (error);
1674 1686 }
1675 1687
1676 1688 /*
1677 1689 * check_public(group, skipshare)
1678 1690 *
1679 1691 * Check the group for any shares that have the public property
1680 1692 * enabled. We skip "skipshare" since that is the one we are
1681 1693 * working with. This is a separate function to make handling
1682 1694 * subgroups simpler. Returns true if there is a share with public.
1683 1695 */
1684 1696 static int
1685 1697 check_public(sa_group_t group, sa_share_t skipshare)
1686 1698 {
1687 1699 int exists = B_FALSE;
1688 1700 sa_share_t share;
1689 1701 sa_optionset_t opt;
1690 1702 sa_property_t prop;
1691 1703 char *shared;
1692 1704
1693 1705 for (share = sa_get_share(group, NULL); share != NULL;
1694 1706 share = sa_get_next_share(share)) {
1695 1707 if (share == skipshare)
1696 1708 continue;
1697 1709
1698 1710 opt = sa_get_optionset(share, "nfs");
1699 1711 if (opt == NULL)
1700 1712 continue;
1701 1713 prop = sa_get_property(opt, "public");
1702 1714 if (prop == NULL)
1703 1715 continue;
1704 1716 shared = sa_get_share_attr(share, "shared");
1705 1717 if (shared != NULL) {
1706 1718 exists = strcmp(shared, "true") == 0;
1707 1719 sa_free_attr_string(shared);
1708 1720 if (exists == B_TRUE)
1709 1721 break;
1710 1722 }
1711 1723 }
1712 1724
1713 1725 return (exists);
1714 1726 }
1715 1727
1716 1728 /*
1717 1729 * public_exists(handle, skipshare)
1718 1730 *
1719 1731 * check to see if public option is set on any other share than the
1720 1732 * one specified. Need to check zfs sub-groups as well as the top
1721 1733 * level groups.
1722 1734 */
1723 1735 static int
1724 1736 public_exists(sa_handle_t handle, sa_share_t skipshare)
1725 1737 {
1726 1738 sa_group_t group = NULL;
1727 1739
1728 1740 /*
1729 1741 * If we don't have a handle, we can only do syntax check. We
1730 1742 * can't check against other shares so we assume OK and will
1731 1743 * catch the problem only when we actually try to apply it.
1732 1744 */
1733 1745 if (handle == NULL)
1734 1746 return (SA_OK);
1735 1747
1736 1748 if (skipshare != NULL) {
1737 1749 group = sa_get_parent_group(skipshare);
1738 1750 if (group == NULL)
1739 1751 return (SA_NO_SUCH_GROUP);
1740 1752 }
1741 1753
1742 1754 for (group = sa_get_group(handle, NULL); group != NULL;
1743 1755 group = sa_get_next_group(group)) {
1744 1756 /* Walk any ZFS subgroups as well as all standard groups */
1745 1757 if (sa_group_is_zfs(group)) {
1746 1758 sa_group_t subgroup;
1747 1759 for (subgroup = sa_get_sub_group(group);
1748 1760 subgroup != NULL;
1749 1761 subgroup = sa_get_next_group(subgroup)) {
1750 1762 if (check_public(subgroup, skipshare))
1751 1763 return (B_TRUE);
1752 1764 }
1753 1765 } else {
1754 1766 if (check_public(group, skipshare))
1755 1767 return (B_TRUE);
1756 1768 }
1757 1769 }
1758 1770 return (B_FALSE);
1759 1771 }
1760 1772
1761 1773 /*
1762 1774 * sa_enable_share at the protocol level, enable_share must tell the
1763 1775 * implementation that it is to enable the share. This entails
1764 1776 * converting the path and options into the appropriate ioctl
1765 1777 * calls. It is assumed that all error checking of paths, etc. were
1766 1778 * done earlier.
1767 1779 */
1768 1780 static int
1769 1781 nfs_enable_share(sa_share_t share)
1770 1782 {
1771 1783 struct exportdata export;
1772 1784 sa_optionset_t secoptlist;
1773 1785 struct secinfo *sp;
|
↓ open down ↓ |
734 lines elided |
↑ open up ↑ |
1774 1786 int num_secinfo;
1775 1787 sa_optionset_t opt;
1776 1788 sa_security_t sec;
1777 1789 sa_property_t prop;
1778 1790 char *path;
1779 1791 int err = SA_OK;
1780 1792 int i;
1781 1793 int iszfs;
1782 1794 sa_handle_t handle;
1783 1795
1796 + static int check_services = B_TRUE;
1797 +
1784 1798 /* Don't drop core if the NFS module isn't loaded. */
1785 1799 (void) signal(SIGSYS, SIG_IGN);
1786 1800
1787 1801 /* get the path since it is important in several places */
1788 1802 path = sa_get_share_attr(share, "path");
1789 1803 if (path == NULL)
1790 1804 return (SA_NO_SUCH_PATH);
1791 1805
1792 1806 iszfs = sa_path_is_zfs(path);
1793 1807 /*
1794 1808 * find the optionsets and security sets. There may not be
1795 1809 * any or there could be one or two for each of optionset and
1796 1810 * security may have multiple, one per security type per
1797 1811 * protocol type.
1798 1812 */
1799 1813 opt = sa_get_derived_optionset(share, "nfs", 1);
1800 1814 secoptlist = (sa_optionset_t)sa_get_all_security_types(share, "nfs", 1);
1801 1815 if (secoptlist != NULL)
1802 1816 num_secinfo = MAX(1, count_security(secoptlist));
1803 1817 else
1804 1818 num_secinfo = 1;
1805 1819
1806 1820 /*
1807 1821 * walk through the options and fill in the structure
1808 1822 * appropriately.
1809 1823 */
1810 1824
1811 1825 (void) memset(&export, '\0', sizeof (export));
1812 1826
1813 1827 /*
1814 1828 * do non-security options first since there is only one after
1815 1829 * the derived group is constructed.
1816 1830 */
1817 1831 export.ex_version = EX_CURRENT_VERSION;
1818 1832 export.ex_anon = UID_NOBODY; /* this is our default value */
1819 1833 export.ex_index = NULL;
1820 1834 export.ex_path = path;
1821 1835 export.ex_pathlen = strlen(path) + 1;
1822 1836
1823 1837 if (opt != NULL)
1824 1838 err = fill_export_from_optionset(&export, opt);
1825 1839
1826 1840 /*
1827 1841 * check to see if "public" is set. If it is, then make sure
1828 1842 * no other share has it set. If it is already used, fail.
1829 1843 */
1830 1844
1831 1845 handle = sa_find_group_handle((sa_group_t)share);
1832 1846 if (export.ex_flags & EX_PUBLIC && public_exists(handle, share)) {
1833 1847 (void) printf(dgettext(TEXT_DOMAIN,
1834 1848 "NFS: Cannot share more than one file "
1835 1849 "system with 'public' property\n"));
1836 1850 err = SA_NOT_ALLOWED;
1837 1851 goto out;
1838 1852 }
1839 1853
1840 1854 sp = calloc(num_secinfo, sizeof (struct secinfo));
1841 1855 if (sp == NULL) {
1842 1856 err = SA_NO_MEMORY;
1843 1857 (void) printf(dgettext(TEXT_DOMAIN,
1844 1858 "NFS: NFS: no memory for security\n"));
1845 1859 goto out;
1846 1860 }
1847 1861 export.ex_secinfo = sp;
1848 1862 /* get default secinfo */
1849 1863 export.ex_seccnt = num_secinfo;
1850 1864 /*
1851 1865 * since we must have one security option defined, we
1852 1866 * init to the default and then override as we find
1853 1867 * defined security options. This handles the case
1854 1868 * where we have no defined options but we need to set
1855 1869 * up one.
1856 1870 */
1857 1871 sp[0].s_window = DEF_WIN;
1858 1872 sp[0].s_rootnames = NULL;
1859 1873 /* setup a default in case no properties defined */
1860 1874 if (nfs_getseconfig_default(&sp[0].s_secinfo)) {
1861 1875 (void) printf(dgettext(TEXT_DOMAIN,
1862 1876 "NFS: nfs_getseconfig_default: failed to "
1863 1877 "get default security mode\n"));
1864 1878 err = SA_CONFIG_ERR;
1865 1879 }
1866 1880 if (secoptlist != NULL) {
1867 1881 for (i = 0, prop = sa_get_property(secoptlist, NULL);
1868 1882 prop != NULL && i < num_secinfo;
1869 1883 prop = sa_get_next_property(prop), i++) {
1870 1884 char *sectype;
1871 1885 sectype = sa_get_property_attr(prop, "type");
1872 1886 /*
1873 1887 * if sectype is NULL, we probably
1874 1888 * have a memory problem and can't get
1875 1889 * the correct values. Rather than
1876 1890 * exporting with incorrect security,
1877 1891 * don't share it.
1878 1892 */
1879 1893 if (sectype == NULL) {
1880 1894 err = SA_NO_MEMORY;
1881 1895 (void) printf(dgettext(TEXT_DOMAIN,
1882 1896 "NFS: Cannot share %s: "
1883 1897 "no memory\n"), path);
1884 1898 goto out;
1885 1899 }
1886 1900 sec = (sa_security_t)sa_get_derived_security(
1887 1901 share, sectype, "nfs", 1);
|
↓ open down ↓ |
94 lines elided |
↑ open up ↑ |
1888 1902 sp[i].s_window = DEF_WIN;
1889 1903 sp[i].s_rootcnt = 0;
1890 1904 sp[i].s_rootnames = NULL;
1891 1905 (void) fill_security_from_secopts(&sp[i], sec);
1892 1906 if (sec != NULL)
1893 1907 sa_free_derived_security(sec);
1894 1908 if (sectype != NULL)
1895 1909 sa_free_attr_string(sectype);
1896 1910 }
1897 1911 }
1898 - /*
1899 - * when we get here, we can do the exportfs system call and
1900 - * initiate things. We probably want to enable the
1901 - * svc:/network/nfs/server service first if it isn't running.
1902 - */
1903 - /* check svc:/network/nfs/server status and start if needed */
1912 +
1904 1913 /* now add the share to the internal tables */
1905 1914 printarg(path, &export);
1906 1915 /*
1907 1916 * call the exportfs system call which is implemented
1908 1917 * via the nfssys() call as the EXPORTFS subfunction.
1909 1918 */
1910 1919 if (iszfs) {
1911 1920 struct exportfs_args ea;
1912 1921 share_t sh;
1913 - char *str;
1914 - priv_set_t *priv_effective;
1915 - int privileged;
1916 1922
1917 - /*
1918 - * If we aren't a privileged user
1919 - * and NFS server service isn't running
1920 - * then print out an error message
1921 - * and return EPERM
1922 - */
1923 + ea.dname = path;
1924 + ea.uex = &export;
1923 1925
1924 - priv_effective = priv_allocset();
1925 - (void) getppriv(PRIV_EFFECTIVE, priv_effective);
1926 -
1927 - privileged = (priv_isfullset(priv_effective) == B_TRUE);
1928 - priv_freeset(priv_effective);
1929 -
1930 - if (!privileged &&
1931 - (str = smf_get_state(NFS_SERVER_SVC)) != NULL) {
1932 - err = 0;
1933 - if (strcmp(str, SCF_STATE_STRING_ONLINE) != 0) {
1934 - (void) printf(dgettext(TEXT_DOMAIN,
1935 - "NFS: Cannot share remote "
1936 - "filesystem: %s\n"), path);
1937 - (void) printf(dgettext(TEXT_DOMAIN,
1938 - "NFS: Service needs to be enabled "
1939 - "by a privileged user\n"));
1940 - err = SA_SYSTEM_ERR;
1941 - errno = EPERM;
1942 - }
1943 - free(str);
1926 + (void) sa_sharetab_fill_zfs(share, &sh, "nfs");
1927 + err = sa_share_zfs(share, NULL, path, &sh, &ea, ZFS_SHARE_NFS);
1928 + if (err != SA_OK) {
1929 + errno = err;
1930 + err = -1;
1944 1931 }
1945 -
1946 - if (err == 0) {
1947 - ea.dname = path;
1948 - ea.uex = &export;
1949 -
1950 - (void) sa_sharetab_fill_zfs(share, &sh, "nfs");
1951 - err = sa_share_zfs(share, NULL, path, &sh,
1952 - &ea, ZFS_SHARE_NFS);
1953 - if (err != SA_OK) {
1954 - errno = err;
1955 - err = -1;
1956 - }
1957 - sa_emptyshare(&sh);
1958 - }
1932 + sa_emptyshare(&sh);
1959 1933 } else {
1960 1934 err = exportfs(path, &export);
1961 1935 }
1962 1936
1963 1937 if (err < 0) {
1964 1938 err = SA_SYSTEM_ERR;
1965 1939 switch (errno) {
1966 - case EREMOTE:
1967 - (void) printf(dgettext(TEXT_DOMAIN,
1968 - "NFS: Cannot share filesystems "
1969 - "in non-global zones: %s\n"), path);
1970 - err = SA_NOT_SUPPORTED;
1971 - break;
1972 1940 case EPERM:
1973 - if (getzoneid() != GLOBAL_ZONEID) {
1974 - (void) printf(dgettext(TEXT_DOMAIN,
1975 - "NFS: Cannot share file systems "
1976 - "in non-global zones: %s\n"), path);
1977 - err = SA_NOT_SUPPORTED;
1978 - break;
1979 - }
1980 1941 err = SA_NO_PERMISSION;
1981 1942 break;
1982 1943 case EEXIST:
1983 1944 err = SA_SHARE_EXISTS;
1984 1945 break;
1985 1946 default:
1986 1947 break;
1987 1948 }
1988 1949 } else {
1989 1950 /* update sharetab with an add/modify */
1990 1951 if (!iszfs) {
1991 1952 (void) sa_update_sharetab(share, "nfs");
1992 1953 }
1993 1954 }
1994 1955
1995 1956 if (err == SA_OK) {
1996 1957 /*
1997 - * enable services as needed. This should probably be
1998 - * done elsewhere in order to minimize the calls to
1999 - * check services.
1958 + * Enable services, if required.
1959 + * This is only done the first time the function is called,
1960 + * per instatiation of the library.
2000 1961 */
1962 + if (check_services) {
1963 + _check_services(service_list_default);
1964 + check_services = B_FALSE;
1965 + }
1966 +
2001 1967 /*
2002 - * check to see if logging and other services need to
2003 - * be triggered, but only if there wasn't an
2004 - * error. This is probably where sharetab should be
2005 - * updated with the NFS specific entry.
1968 + * Enable logging.
2006 1969 */
2007 1970 if (export.ex_flags & EX_LOG) {
2008 - /* enable logging */
2009 1971 if (nfslogtab_add(path, export.ex_log_buffer,
2010 1972 export.ex_tag) != 0) {
2011 1973 (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
2012 1974 "Could not enable logging for %s\n"),
2013 1975 path);
2014 1976 }
2015 1977 _check_services(service_list_logging);
2016 1978 } else {
2017 1979 /*
2018 1980 * don't have logging so remove it from file. It might
2019 1981 * not be thre, but that doesn't matter.
2020 1982 */
2021 1983 (void) nfslogtab_deactivate(path);
2022 - _check_services(service_list_default);
2023 1984 }
2024 1985 }
2025 1986
2026 1987 out:
2027 1988 if (path != NULL)
2028 1989 free(path);
2029 1990
2030 1991 cleanup_export(&export);
2031 1992 if (opt != NULL)
2032 1993 sa_free_derived_optionset(opt);
2033 1994 if (secoptlist != NULL)
2034 1995 (void) sa_destroy_optionset(secoptlist);
2035 1996 return (err);
2036 1997 }
2037 1998
2038 1999 /*
2039 2000 * nfs_disable_share(share, path)
2040 2001 *
2041 2002 * Unshare the specified share. Note that "path" is the same path as
2042 2003 * what is in the "share" object. It is passed in to avoid an
2043 2004 * additional lookup. A missing "path" value makes this a no-op
2044 2005 * function.
2045 2006 */
2046 2007 static int
2047 2008 nfs_disable_share(sa_share_t share, char *path)
2048 2009 {
2049 2010 int err;
2050 2011 int ret = SA_OK;
2051 2012 int iszfs;
2052 2013 sa_group_t parent;
2053 2014 sa_handle_t handle;
2054 2015
2055 2016 if (path == NULL)
2056 2017 return (ret);
2057 2018
2058 2019 /*
2059 2020 * If the share is in a ZFS group we need to handle it
2060 2021 * differently. Just being on a ZFS file system isn't
2061 2022 * enough since we may be in a legacy share case.
2062 2023 */
2063 2024 parent = sa_get_parent_group(share);
2064 2025 iszfs = sa_group_is_zfs(parent);
2065 2026 if (iszfs) {
2066 2027 struct exportfs_args ea;
2067 2028 share_t sh = { 0 };
2068 2029 ea.dname = path;
2069 2030 ea.uex = NULL;
2070 2031 sh.sh_path = path;
2071 2032 sh.sh_fstype = "nfs";
2072 2033
2073 2034 err = sa_share_zfs(share, NULL, path, &sh,
2074 2035 &ea, ZFS_UNSHARE_NFS);
2075 2036 if (err != SA_OK) {
2076 2037 errno = err;
2077 2038 err = -1;
2078 2039 }
2079 2040 } else {
2080 2041 err = exportfs(path, NULL);
|
↓ open down ↓ |
48 lines elided |
↑ open up ↑ |
2081 2042 }
2082 2043 if (err < 0) {
2083 2044 /*
2084 2045 * TBD: only an error in some
2085 2046 * cases - need better analysis
2086 2047 */
2087 2048 switch (errno) {
2088 2049 case EPERM:
2089 2050 case EACCES:
2090 2051 ret = SA_NO_PERMISSION;
2091 - if (getzoneid() != GLOBAL_ZONEID) {
2092 - ret = SA_NOT_SUPPORTED;
2093 - }
2094 2052 break;
2095 2053 case EINVAL:
2096 2054 case ENOENT:
2097 2055 ret = SA_NO_SUCH_PATH;
2098 2056 break;
2099 2057 default:
2100 2058 ret = SA_SYSTEM_ERR;
2101 2059 break;
2102 2060 }
2103 2061 }
2104 2062 if (ret == SA_OK || ret == SA_NO_SUCH_PATH) {
2105 2063 handle = sa_find_group_handle((sa_group_t)share);
2106 2064 if (!iszfs)
2107 2065 (void) sa_delete_sharetab(handle, path, "nfs");
2108 2066 /* just in case it was logged */
2109 2067 (void) nfslogtab_deactivate(path);
2110 2068 }
2111 2069 return (ret);
2112 2070 }
2113 2071
2114 2072 static int
2115 2073 check_user(char *value)
2116 2074 {
2117 2075 int ret = SA_OK;
2118 2076
2119 2077 if (!is_a_number(value)) {
2120 2078 struct passwd *pw;
2121 2079 /*
2122 2080 * in this case it would have to be a
2123 2081 * user name
2124 2082 */
2125 2083 pw = getpwnam(value);
2126 2084 if (pw == NULL)
2127 2085 ret = SA_BAD_VALUE;
2128 2086 endpwent();
2129 2087 } else {
2130 2088 uint64_t intval;
2131 2089 intval = strtoull(value, NULL, 0);
2132 2090 if (intval > UID_MAX && intval != -1)
2133 2091 ret = SA_BAD_VALUE;
2134 2092 }
2135 2093
2136 2094 return (ret);
2137 2095 }
2138 2096
2139 2097 static int
2140 2098 check_group(char *value)
2141 2099 {
2142 2100 int ret = SA_OK;
2143 2101
2144 2102 if (!is_a_number(value)) {
2145 2103 struct group *gr;
2146 2104 /*
2147 2105 * in this case it would have to be a
2148 2106 * group name
2149 2107 */
2150 2108 gr = getgrnam(value);
2151 2109 if (gr == NULL)
2152 2110 ret = SA_BAD_VALUE;
2153 2111 endgrent();
2154 2112 } else {
2155 2113 uint64_t intval;
2156 2114 intval = strtoull(value, NULL, 0);
2157 2115 if (intval > UID_MAX && intval != -1)
2158 2116 ret = SA_BAD_VALUE;
2159 2117 }
2160 2118
2161 2119 return (ret);
2162 2120 }
2163 2121
2164 2122 /*
2165 2123 * check_rorwnone(v1, v2, v3)
2166 2124 *
2167 2125 * check ro vs rw vs none values. Over time this may get beefed up.
2168 2126 * for now it just does simple checks. v1 is never NULL but v2 or v3
2169 2127 * could be.
2170 2128 */
2171 2129
2172 2130 static int
2173 2131 check_rorwnone(char *v1, char *v2, char *v3)
2174 2132 {
2175 2133 int ret = SA_OK;
2176 2134 if (v2 != NULL && strcmp(v1, v2) == 0)
2177 2135 ret = SA_VALUE_CONFLICT;
2178 2136 else if (v3 != NULL && strcmp(v1, v3) == 0)
2179 2137 ret = SA_VALUE_CONFLICT;
2180 2138
2181 2139 return (ret);
2182 2140 }
2183 2141
2184 2142 /*
2185 2143 * nfs_validate_property(handle, property, parent)
2186 2144 *
2187 2145 * Check that the property has a legitimate value for its type.
2188 2146 */
2189 2147
2190 2148 static int
2191 2149 nfs_validate_property(sa_handle_t handle, sa_property_t property,
2192 2150 sa_optionset_t parent)
2193 2151 {
2194 2152 int ret = SA_OK;
2195 2153 char *propname;
2196 2154 char *other1;
2197 2155 char *other2;
2198 2156 int optindex;
2199 2157 nfsl_config_t *configlist;
2200 2158 sa_group_t parent_group;
2201 2159 char *value;
2202 2160
2203 2161 propname = sa_get_property_attr(property, "type");
2204 2162
2205 2163 if ((optindex = findopt(propname)) < 0)
2206 2164 ret = SA_NO_SUCH_PROP;
2207 2165
2208 2166 /* need to validate value range here as well */
2209 2167
2210 2168 if (ret == SA_OK) {
2211 2169 parent_group = sa_get_parent_group((sa_share_t)parent);
2212 2170 if (optdefs[optindex].share && parent_group != NULL &&
2213 2171 !sa_is_share(parent_group))
2214 2172 ret = SA_PROP_SHARE_ONLY;
2215 2173 }
2216 2174 if (ret == SA_OK) {
2217 2175 if (optdefs[optindex].index == OPT_PUBLIC) {
2218 2176 /*
2219 2177 * Public is special in that only one instance can
2220 2178 * be in the repository at the same time.
2221 2179 */
2222 2180 if (public_exists(handle, parent_group)) {
2223 2181 sa_free_attr_string(propname);
2224 2182 return (SA_VALUE_CONFLICT);
2225 2183 }
2226 2184 }
2227 2185 value = sa_get_property_attr(property, "value");
2228 2186 if (value != NULL) {
2229 2187 /* first basic type checking */
2230 2188 switch (optdefs[optindex].type) {
2231 2189
2232 2190 case OPT_TYPE_NUMBER:
2233 2191 /* check that the value is all digits */
2234 2192 if (!is_a_number(value))
2235 2193 ret = SA_BAD_VALUE;
2236 2194 break;
2237 2195
2238 2196 case OPT_TYPE_BOOLEAN:
2239 2197 if (strlen(value) == 0 ||
2240 2198 strcasecmp(value, "true") == 0 ||
2241 2199 strcmp(value, "1") == 0 ||
2242 2200 strcasecmp(value, "false") == 0 ||
2243 2201 strcmp(value, "0") == 0) {
2244 2202 ret = SA_OK;
2245 2203 } else {
2246 2204 ret = SA_BAD_VALUE;
2247 2205 }
2248 2206 break;
2249 2207
2250 2208 case OPT_TYPE_USER:
2251 2209 ret = check_user(value);
2252 2210 break;
2253 2211
2254 2212 case OPT_TYPE_FILE:
2255 2213 if (strcmp(value, "..") == 0 ||
2256 2214 strchr(value, '/') != NULL) {
2257 2215 ret = SA_BAD_VALUE;
2258 2216 }
2259 2217 break;
2260 2218
2261 2219 case OPT_TYPE_ACCLIST: {
2262 2220 sa_property_t oprop1;
2263 2221 sa_property_t oprop2;
2264 2222 char *ovalue1 = NULL;
2265 2223 char *ovalue2 = NULL;
2266 2224
2267 2225 if (parent == NULL)
2268 2226 break;
2269 2227 /*
2270 2228 * access list handling. Should eventually
2271 2229 * validate that all the values make sense.
2272 2230 * Also, ro and rw may have cross value
2273 2231 * conflicts.
2274 2232 */
2275 2233 if (strcmp(propname, SHOPT_RO) == 0) {
2276 2234 other1 = SHOPT_RW;
2277 2235 other2 = SHOPT_NONE;
2278 2236 } else if (strcmp(propname, SHOPT_RW) == 0) {
2279 2237 other1 = SHOPT_RO;
2280 2238 other2 = SHOPT_NONE;
2281 2239 } else if (strcmp(propname, SHOPT_NONE) == 0) {
2282 2240 other1 = SHOPT_RO;
2283 2241 other2 = SHOPT_RW;
2284 2242 } else {
2285 2243 other1 = NULL;
2286 2244 other2 = NULL;
2287 2245 }
2288 2246 if (other1 == NULL && other2 == NULL)
2289 2247 break;
2290 2248
2291 2249 /* compare rw(ro) with ro(rw) */
2292 2250
2293 2251 oprop1 = sa_get_property(parent, other1);
2294 2252 oprop2 = sa_get_property(parent, other2);
2295 2253 if (oprop1 == NULL && oprop2 == NULL)
2296 2254 break;
2297 2255 /*
2298 2256 * Only potential confusion if other1
2299 2257 * or other2 exists. Check the values
2300 2258 * and run the check if there is a
2301 2259 * value other than the one we are
2302 2260 * explicitly looking at.
2303 2261 */
2304 2262 ovalue1 = sa_get_property_attr(oprop1, "value");
2305 2263 ovalue2 = sa_get_property_attr(oprop2, "value");
2306 2264 if (ovalue1 != NULL || ovalue2 != NULL)
2307 2265 ret = check_rorwnone(value, ovalue1,
2308 2266 ovalue2);
2309 2267
2310 2268 if (ovalue1 != NULL)
2311 2269 sa_free_attr_string(ovalue1);
2312 2270 if (ovalue2 != NULL)
2313 2271 sa_free_attr_string(ovalue2);
2314 2272 break;
2315 2273 }
2316 2274
2317 2275 case OPT_TYPE_LOGTAG:
2318 2276 if (nfsl_getconfig_list(&configlist) == 0) {
2319 2277 int error;
2320 2278 if (value == NULL ||
2321 2279 strlen(value) == 0) {
2322 2280 if (value != NULL)
2323 2281 sa_free_attr_string(
2324 2282 value);
2325 2283 value = strdup("global");
2326 2284 }
2327 2285 if (value != NULL &&
2328 2286 nfsl_findconfig(configlist, value,
2329 2287 &error) == NULL) {
2330 2288 ret = SA_BAD_VALUE;
2331 2289 }
2332 2290 /* Must always free when done */
2333 2291 nfsl_freeconfig_list(&configlist);
2334 2292 } else {
2335 2293 ret = SA_CONFIG_ERR;
2336 2294 }
2337 2295 break;
2338 2296
2339 2297 case OPT_TYPE_STRING:
2340 2298 /* whatever is here should be ok */
2341 2299 break;
2342 2300
2343 2301 case OPT_TYPE_SECURITY:
2344 2302 /*
2345 2303 * The "sec" property isn't used in the
2346 2304 * non-legacy parts of sharemgr. We need to
2347 2305 * reject it here. For legacy, it is pulled
2348 2306 * out well before we get here.
2349 2307 */
2350 2308 ret = SA_NO_SUCH_PROP;
2351 2309 break;
2352 2310
2353 2311 case OPT_TYPE_MAPPING: {
2354 2312 char *p;
2355 2313 char *n;
2356 2314 char *c;
2357 2315 int (*f)(char *);
2358 2316
2359 2317 sa_security_t security;
2360 2318
2361 2319 /*
2362 2320 * mapping is only supported for sec=sys
2363 2321 */
2364 2322 ret = SA_CONFIG_ERR;
2365 2323 if (parent_group == NULL)
2366 2324 break;
2367 2325
2368 2326 for (security = sa_get_security(parent_group,
2369 2327 NULL, NULL); security != NULL;
2370 2328 security = sa_get_next_security(security)) {
2371 2329 char *type;
2372 2330 char *sectype;
2373 2331
2374 2332 type = sa_get_security_attr(security,
2375 2333 "type");
2376 2334 if (type == NULL)
2377 2335 continue;
2378 2336
2379 2337 if (strcmp(type, "nfs") != 0) {
2380 2338 sa_free_attr_string(type);
2381 2339 continue;
2382 2340 }
2383 2341 sa_free_attr_string(type);
2384 2342
2385 2343 sectype = sa_get_security_attr(security,
2386 2344 "sectype");
2387 2345 if (sectype == NULL)
2388 2346 continue;
2389 2347
2390 2348 if (strcmp(sectype, "sys") != 0) {
2391 2349 sa_free_attr_string(sectype);
2392 2350 ret = SA_CONFIG_ERR;
2393 2351 break;
2394 2352 }
2395 2353 sa_free_attr_string(sectype);
2396 2354 ret = SA_OK;
2397 2355 }
2398 2356
2399 2357 if (ret != SA_OK)
2400 2358 break;
2401 2359
2402 2360 assert(optindex == OPT_UIDMAP ||
2403 2361 optindex == OPT_GIDMAP);
2404 2362 f = optindex == OPT_UIDMAP ? check_user :
2405 2363 check_group;
2406 2364
2407 2365
2408 2366 p = strdup(value);
2409 2367 if (p == NULL)
2410 2368 ret = SA_BAD_VALUE;
2411 2369
2412 2370 for (c = p; ret == SA_OK && c != NULL; c = n) {
2413 2371 char *s;
2414 2372 char *t;
2415 2373
2416 2374 n = strchr(c, '~');
2417 2375 if (n != NULL)
2418 2376 *n++ = '\0';
2419 2377
2420 2378 s = strchr(c, ':');
2421 2379 if (s != NULL) {
2422 2380 *s++ = '\0';
2423 2381 t = strchr(s, ':');
2424 2382 if (t != NULL)
2425 2383 *t = '\0';
2426 2384 }
2427 2385
2428 2386 if (s == NULL || t == NULL)
2429 2387 ret = SA_BAD_VALUE;
2430 2388
2431 2389 if (ret == SA_OK && *c != '\0' &&
2432 2390 strcmp(c, "*") != 0)
2433 2391 ret = f(c);
2434 2392
2435 2393 if (ret == SA_OK && *s != '\0' &&
2436 2394 strcmp(s, "-1") != 0)
2437 2395 ret = f(s);
2438 2396 }
2439 2397
2440 2398 free(p);
2441 2399
2442 2400 break;
2443 2401 }
2444 2402
2445 2403 default:
2446 2404 break;
2447 2405 }
2448 2406
2449 2407 if (value != NULL)
2450 2408 sa_free_attr_string(value);
2451 2409
2452 2410 if (ret == SA_OK && optdefs[optindex].check != NULL) {
2453 2411 /* do the property specific check */
2454 2412 ret = optdefs[optindex].check(handle, property);
2455 2413 }
2456 2414 }
2457 2415 }
2458 2416
2459 2417 if (propname != NULL)
2460 2418 sa_free_attr_string(propname);
2461 2419 return (ret);
2462 2420 }
2463 2421
2464 2422 /*
2465 2423 * Protocol management functions
2466 2424 *
2467 2425 * Properties defined in the default files are defined in
2468 2426 * proto_option_defs for parsing and validation. If "other" and
2469 2427 * "compare" are set, then the value for this property should be
2470 2428 * compared against the property specified in "other" using the
2471 2429 * "compare" check (either <= or >=) in order to ensure that the
2472 2430 * values are in the correct range. E.g. setting server_versmin
2473 2431 * higher than server_versmax should not be allowed.
2474 2432 */
2475 2433
2476 2434 struct proto_option_defs {
2477 2435 char *tag;
2478 2436 char *name; /* display name -- remove protocol identifier */
2479 2437 int index;
2480 2438 int type;
2481 2439 union {
2482 2440 int intval;
2483 2441 char *string;
2484 2442 } defvalue;
2485 2443 uint32_t svcs;
2486 2444 int32_t minval;
2487 2445 int32_t maxval;
2488 2446 char *other;
2489 2447 int compare;
2490 2448 #define OPT_CMP_GE 0
2491 2449 #define OPT_CMP_LE 1
2492 2450 int (*check)(char *);
2493 2451 } proto_options[] = {
2494 2452 #define PROTO_OPT_NFSD_SERVERS 0
2495 2453 {"nfsd_servers",
2496 2454 "servers", PROTO_OPT_NFSD_SERVERS, OPT_TYPE_NUMBER, 1024, SVC_NFSD,
2497 2455 1, INT32_MAX},
2498 2456 #define PROTO_OPT_LOCKD_LISTEN_BACKLOG 1
2499 2457 {"lockd_listen_backlog",
2500 2458 "lockd_listen_backlog", PROTO_OPT_LOCKD_LISTEN_BACKLOG,
2501 2459 OPT_TYPE_NUMBER, 32, SVC_LOCKD, 32, INT32_MAX},
2502 2460 #define PROTO_OPT_LOCKD_SERVERS 2
2503 2461 {"lockd_servers",
2504 2462 "lockd_servers", PROTO_OPT_LOCKD_SERVERS, OPT_TYPE_NUMBER, 256,
2505 2463 SVC_LOCKD, 1, INT32_MAX},
2506 2464 #define PROTO_OPT_LOCKD_RETRANSMIT_TIMEOUT 3
2507 2465 {"lockd_retransmit_timeout",
2508 2466 "lockd_retransmit_timeout", PROTO_OPT_LOCKD_RETRANSMIT_TIMEOUT,
2509 2467 OPT_TYPE_NUMBER, 5, SVC_LOCKD, 0, INT32_MAX},
2510 2468 #define PROTO_OPT_GRACE_PERIOD 4
2511 2469 {"grace_period",
2512 2470 "grace_period", PROTO_OPT_GRACE_PERIOD, OPT_TYPE_NUMBER, 90,
2513 2471 SVC_LOCKD, 0, INT32_MAX},
2514 2472 #define PROTO_OPT_NFS_SERVER_VERSMIN 5
2515 2473 {"nfs_server_versmin",
2516 2474 "server_versmin", PROTO_OPT_NFS_SERVER_VERSMIN, OPT_TYPE_NUMBER,
2517 2475 (int)NFS_VERSMIN_DEFAULT, SVC_NFSD|SVC_MOUNTD, NFS_VERSMIN,
2518 2476 NFS_VERSMAX, "server_versmax", OPT_CMP_LE},
2519 2477 #define PROTO_OPT_NFS_SERVER_VERSMAX 6
2520 2478 {"nfs_server_versmax",
2521 2479 "server_versmax", PROTO_OPT_NFS_SERVER_VERSMAX, OPT_TYPE_NUMBER,
2522 2480 (int)NFS_VERSMAX_DEFAULT, SVC_NFSD|SVC_MOUNTD, NFS_VERSMIN,
2523 2481 NFS_VERSMAX, "server_versmin", OPT_CMP_GE},
2524 2482 #define PROTO_OPT_NFS_CLIENT_VERSMIN 7
2525 2483 {"nfs_client_versmin",
2526 2484 "client_versmin", PROTO_OPT_NFS_CLIENT_VERSMIN, OPT_TYPE_NUMBER,
2527 2485 (int)NFS_VERSMIN_DEFAULT, SVC_CLIENT, NFS_VERSMIN, NFS_VERSMAX,
2528 2486 "client_versmax", OPT_CMP_LE},
2529 2487 #define PROTO_OPT_NFS_CLIENT_VERSMAX 8
2530 2488 {"nfs_client_versmax",
2531 2489 "client_versmax", PROTO_OPT_NFS_CLIENT_VERSMAX, OPT_TYPE_NUMBER,
2532 2490 (int)NFS_VERSMAX_DEFAULT, SVC_CLIENT, NFS_VERSMIN, NFS_VERSMAX,
2533 2491 "client_versmin", OPT_CMP_GE},
2534 2492 #define PROTO_OPT_NFS_SERVER_DELEGATION 9
2535 2493 {"nfs_server_delegation",
2536 2494 "server_delegation", PROTO_OPT_NFS_SERVER_DELEGATION,
2537 2495 OPT_TYPE_ONOFF, NFS_SERVER_DELEGATION_DEFAULT, SVC_NFSD, 0, 0},
2538 2496 #define PROTO_OPT_NFSMAPID_DOMAIN 10
2539 2497 {"nfsmapid_domain",
2540 2498 "nfsmapid_domain", PROTO_OPT_NFSMAPID_DOMAIN, OPT_TYPE_DOMAIN,
2541 2499 NULL, SVC_NFSMAPID, 0, 0},
2542 2500 #define PROTO_OPT_NFSD_MAX_CONNECTIONS 11
2543 2501 {"nfsd_max_connections",
2544 2502 "max_connections", PROTO_OPT_NFSD_MAX_CONNECTIONS,
2545 2503 OPT_TYPE_NUMBER, -1, SVC_NFSD, -1, INT32_MAX},
2546 2504 #define PROTO_OPT_NFSD_PROTOCOL 12
2547 2505 {"nfsd_protocol",
2548 2506 "protocol", PROTO_OPT_NFSD_PROTOCOL, OPT_TYPE_PROTOCOL, 0,
2549 2507 SVC_NFSD, 0, 0},
2550 2508 #define PROTO_OPT_NFSD_LISTEN_BACKLOG 13
2551 2509 {"nfsd_listen_backlog",
2552 2510 "listen_backlog", PROTO_OPT_NFSD_LISTEN_BACKLOG,
2553 2511 OPT_TYPE_NUMBER, 0, SVC_NFSD, 0, INT32_MAX},
2554 2512 #define PROTO_OPT_NFSD_DEVICE 14
2555 2513 {"nfsd_device",
2556 2514 "device", PROTO_OPT_NFSD_DEVICE,
2557 2515 OPT_TYPE_STRING, NULL, SVC_NFSD, 0, 0},
2558 2516 #define PROTO_OPT_MOUNTD_LISTEN_BACKLOG 15
2559 2517 {"mountd_listen_backlog",
2560 2518 "mountd_listen_backlog", PROTO_OPT_MOUNTD_LISTEN_BACKLOG,
2561 2519 OPT_TYPE_NUMBER, 64, SVC_NFSD|SVC_MOUNTD, 1, INT32_MAX},
2562 2520 #define PROTO_OPT_MOUNTD_MAX_THREADS 16
2563 2521 {"mountd_max_threads",
2564 2522 "mountd_max_threads", PROTO_OPT_MOUNTD_MAX_THREADS,
2565 2523 OPT_TYPE_NUMBER, 16, SVC_NFSD|SVC_MOUNTD, 1, INT32_MAX},
2566 2524 #define PROTO_OPT_MOUNTD_PORT 17
2567 2525 {"mountd_port",
2568 2526 "mountd_port", PROTO_OPT_MOUNTD_PORT,
2569 2527 OPT_TYPE_NUMBER, 0, SVC_MOUNTD, 1, UINT16_MAX},
2570 2528 #define PROTO_OPT_STATD_PORT 18
2571 2529 {"statd_port",
2572 2530 "statd_port", PROTO_OPT_STATD_PORT,
2573 2531 OPT_TYPE_NUMBER, 0, SVC_STATD, 1, UINT16_MAX},
2574 2532 {NULL}
2575 2533 };
2576 2534
2577 2535 /*
2578 2536 * the protoset holds the defined options so we don't have to read
2579 2537 * them multiple times
2580 2538 */
2581 2539 static sa_protocol_properties_t protoset;
2582 2540
2583 2541 static int
2584 2542 findprotoopt(char *name, int whichname)
2585 2543 {
2586 2544 int i;
2587 2545 for (i = 0; proto_options[i].tag != NULL; i++) {
2588 2546 if (whichname == 1) {
2589 2547 if (strcasecmp(proto_options[i].name, name) == 0)
2590 2548 return (i);
2591 2549 } else {
2592 2550 if (strcasecmp(proto_options[i].tag, name) == 0)
2593 2551 return (i);
2594 2552 }
2595 2553 }
2596 2554 return (-1);
2597 2555 }
2598 2556
2599 2557 /*
2600 2558 * fixcaselower(str)
2601 2559 *
2602 2560 * convert a string to lower case (inplace).
2603 2561 */
2604 2562
2605 2563 static void
2606 2564 fixcaselower(char *str)
2607 2565 {
2608 2566 while (*str) {
2609 2567 *str = tolower(*str);
2610 2568 str++;
2611 2569 }
2612 2570 }
2613 2571
2614 2572 /*
2615 2573 * skipwhitespace(str)
2616 2574 *
2617 2575 * Skip leading white space. It is assumed that it is called with a
2618 2576 * valid pointer.
2619 2577 */
2620 2578
2621 2579 static char *
2622 2580 skipwhitespace(char *str)
2623 2581 {
2624 2582 while (*str && isspace(*str))
2625 2583 str++;
2626 2584
2627 2585 return (str);
2628 2586 }
2629 2587
2630 2588 /*
2631 2589 * extractprop()
2632 2590 *
2633 2591 * Extract the property and value out of the line and create the
2634 2592 * property in the optionset.
2635 2593 */
2636 2594 static int
2637 2595 extractprop(char *name, char *value)
2638 2596 {
2639 2597 sa_property_t prop;
2640 2598 int index;
2641 2599 int ret = SA_OK;
2642 2600 /*
2643 2601 * Remove any leading
2644 2602 * white space.
2645 2603 */
2646 2604 name = skipwhitespace(name);
2647 2605
2648 2606 index = findprotoopt(name, 1);
2649 2607 if (index >= 0) {
2650 2608 fixcaselower(name);
2651 2609 prop = sa_create_property(proto_options[index].name, value);
2652 2610 if (prop != NULL)
2653 2611 ret = sa_add_protocol_property(protoset, prop);
2654 2612 else
2655 2613 ret = SA_NO_MEMORY;
2656 2614 }
2657 2615 return (ret);
2658 2616 }
2659 2617
2660 2618 scf_type_t
2661 2619 getscftype(int type)
2662 2620 {
2663 2621 scf_type_t ret;
2664 2622
2665 2623 switch (type) {
2666 2624 case OPT_TYPE_NUMBER:
2667 2625 ret = SCF_TYPE_INTEGER;
2668 2626 break;
2669 2627 case OPT_TYPE_BOOLEAN:
2670 2628 ret = SCF_TYPE_BOOLEAN;
2671 2629 break;
2672 2630 default:
2673 2631 ret = SCF_TYPE_ASTRING;
2674 2632 }
2675 2633 return (ret);
2676 2634 }
2677 2635
2678 2636 char *
2679 2637 getsvcname(uint32_t svcs)
2680 2638 {
2681 2639 char *service;
2682 2640 switch (svcs) {
2683 2641 case SVC_LOCKD:
2684 2642 service = LOCKD;
2685 2643 break;
2686 2644 case SVC_STATD:
2687 2645 service = STATD;
2688 2646 break;
2689 2647 case SVC_NFSD:
2690 2648 service = NFSD;
2691 2649 break;
2692 2650 case SVC_CLIENT:
2693 2651 service = NFS_CLIENT_SVC;
2694 2652 break;
2695 2653 case SVC_NFS4CBD:
2696 2654 service = NFS4CBD;
2697 2655 break;
2698 2656 case SVC_NFSMAPID:
2699 2657 service = NFSMAPID;
2700 2658 break;
2701 2659 case SVC_RQUOTAD:
2702 2660 service = RQUOTAD;
2703 2661 break;
2704 2662 case SVC_NFSLOGD:
2705 2663 service = NFSLOGD;
2706 2664 break;
2707 2665 case SVC_REPARSED:
2708 2666 service = REPARSED;
2709 2667 break;
2710 2668 default:
2711 2669 service = NFSD;
2712 2670 }
2713 2671 return (service);
2714 2672 }
2715 2673
2716 2674 /*
2717 2675 * initprotofromsmf()
2718 2676 *
2719 2677 * Read NFS SMF properties and add the defined values to the
2720 2678 * protoset. Note that default values are known from the built in
2721 2679 * table in case SMF doesn't have a definition. Not having
2722 2680 * SMF properties is OK since we have builtin default
2723 2681 * values.
2724 2682 */
2725 2683 static int
2726 2684 initprotofromsmf()
2727 2685 {
2728 2686 char name[PATH_MAX];
2729 2687 char value[PATH_MAX];
2730 2688 int ret = SA_OK, bufsz = 0, i;
2731 2689
2732 2690 protoset = sa_create_protocol_properties("nfs");
2733 2691 if (protoset != NULL) {
2734 2692 for (i = 0; proto_options[i].tag != NULL; i++) {
2735 2693 scf_type_t ptype;
2736 2694 char *svc_name;
2737 2695
2738 2696 bzero(value, PATH_MAX);
2739 2697 (void) strncpy(name, proto_options[i].name, PATH_MAX);
2740 2698 /* Replace NULL with the correct instance */
2741 2699 ptype = getscftype(proto_options[i].type);
2742 2700 svc_name = getsvcname(proto_options[i].svcs);
2743 2701 bufsz = PATH_MAX;
2744 2702 ret = nfs_smf_get_prop(name, value,
2745 2703 (char *)DEFAULT_INSTANCE, ptype,
2746 2704 svc_name, &bufsz);
2747 2705 if (ret == SA_OK) {
2748 2706 ret = extractprop(name, value);
2749 2707 }
2750 2708 }
2751 2709 } else {
2752 2710 ret = SA_NO_MEMORY;
2753 2711 }
2754 2712
2755 2713 return (ret);
2756 2714 }
2757 2715
2758 2716 /*
2759 2717 * add_defaults()
2760 2718 *
2761 2719 * Add the default values for any property not defined
2762 2720 * in NFS SMF repository.
2763 2721 * Values are set according to their defined types.
2764 2722 */
2765 2723
2766 2724 static void
2767 2725 add_defaults()
2768 2726 {
2769 2727 int i;
2770 2728 char number[MAXDIGITS];
2771 2729
2772 2730 for (i = 0; proto_options[i].tag != NULL; i++) {
2773 2731 sa_property_t prop;
2774 2732 prop = sa_get_protocol_property(protoset,
2775 2733 proto_options[i].name);
2776 2734 if (prop == NULL) {
2777 2735 /* add the default value */
2778 2736 switch (proto_options[i].type) {
2779 2737 case OPT_TYPE_NUMBER:
2780 2738 (void) snprintf(number, sizeof (number), "%d",
2781 2739 proto_options[i].defvalue.intval);
2782 2740 prop = sa_create_property(proto_options[i].name,
2783 2741 number);
2784 2742 break;
2785 2743
2786 2744 case OPT_TYPE_BOOLEAN:
2787 2745 prop = sa_create_property(proto_options[i].name,
2788 2746 proto_options[i].defvalue.intval ?
2789 2747 "true" : "false");
2790 2748 break;
2791 2749
2792 2750 case OPT_TYPE_ONOFF:
2793 2751 prop = sa_create_property(proto_options[i].name,
2794 2752 proto_options[i].defvalue.intval ?
2795 2753 "on" : "off");
2796 2754 break;
2797 2755
2798 2756 default:
2799 2757 /* treat as strings of zero length */
2800 2758 prop = sa_create_property(proto_options[i].name,
2801 2759 "");
2802 2760 break;
2803 2761 }
2804 2762 if (prop != NULL)
2805 2763 (void) sa_add_protocol_property(protoset, prop);
2806 2764 }
2807 2765 }
2808 2766 }
2809 2767
2810 2768 static void
2811 2769 free_protoprops()
2812 2770 {
2813 2771 if (protoset != NULL) {
2814 2772 xmlFreeNode(protoset);
2815 2773 protoset = NULL;
2816 2774 }
2817 2775 }
2818 2776
2819 2777 /*
2820 2778 * nfs_init()
2821 2779 *
2822 2780 * Initialize the NFS plugin.
2823 2781 */
2824 2782
2825 2783 static int
2826 2784 nfs_init()
2827 2785 {
2828 2786 int ret = SA_OK;
2829 2787
2830 2788 if (sa_plugin_ops.sa_init != nfs_init) {
2831 2789 (void) printf(dgettext(TEXT_DOMAIN,
2832 2790 "NFS plugin not properly initialized\n"));
2833 2791 return (SA_CONFIG_ERR);
2834 2792 }
2835 2793
2836 2794 ret = initprotofromsmf();
2837 2795 if (ret != SA_OK) {
2838 2796 (void) printf(dgettext(TEXT_DOMAIN,
2839 2797 "NFS plugin problem with SMF repository: %s\n"),
2840 2798 sa_errorstr(ret));
2841 2799 ret = SA_OK;
2842 2800 }
2843 2801 add_defaults();
2844 2802
2845 2803 return (ret);
2846 2804 }
2847 2805
2848 2806 /*
2849 2807 * nfs_fini()
2850 2808 *
2851 2809 * uninitialize the NFS plugin. Want to avoid memory leaks.
2852 2810 */
2853 2811
2854 2812 static void
2855 2813 nfs_fini()
2856 2814 {
2857 2815 free_protoprops();
2858 2816 }
2859 2817
2860 2818 /*
2861 2819 * nfs_get_proto_set()
2862 2820 *
2863 2821 * Return an optionset with all the protocol specific properties in
2864 2822 * it.
2865 2823 */
2866 2824
2867 2825 static sa_protocol_properties_t
2868 2826 nfs_get_proto_set()
2869 2827 {
2870 2828 return (protoset);
2871 2829 }
2872 2830
2873 2831 /*
2874 2832 * service_in_state(service, chkstate)
2875 2833 *
2876 2834 * Want to know if the specified service is in the desired state
2877 2835 * (chkstate) or not. Return true (1) if it is and false (0) if it
2878 2836 * isn't.
2879 2837 */
2880 2838 static int
2881 2839 service_in_state(char *service, const char *chkstate)
2882 2840 {
2883 2841 char *state;
2884 2842 int ret = B_FALSE;
2885 2843
2886 2844 state = smf_get_state(service);
2887 2845 if (state != NULL) {
2888 2846 /* got the state so get the equality for the return value */
2889 2847 ret = strcmp(state, chkstate) == 0 ? B_TRUE : B_FALSE;
2890 2848 free(state);
2891 2849 }
2892 2850 return (ret);
2893 2851 }
2894 2852
2895 2853 /*
2896 2854 * restart_service(svcs)
2897 2855 *
2898 2856 * Walk through the bit mask of services that need to be restarted in
2899 2857 * order to use the new property values. Some properties affect
2900 2858 * multiple daemons. Should only restart a service if it is currently
2901 2859 * enabled (online).
2902 2860 */
2903 2861
2904 2862 static void
2905 2863 restart_service(uint32_t svcs)
2906 2864 {
2907 2865 uint32_t mask;
2908 2866 int ret;
2909 2867 char *service;
2910 2868
2911 2869 for (mask = 1; svcs != 0; mask <<= 1) {
2912 2870 switch (svcs & mask) {
2913 2871 case SVC_LOCKD:
2914 2872 service = LOCKD;
2915 2873 break;
2916 2874 case SVC_STATD:
2917 2875 service = STATD;
2918 2876 break;
2919 2877 case SVC_NFSD:
2920 2878 service = NFSD;
2921 2879 break;
2922 2880 case SVC_MOUNTD:
2923 2881 service = MOUNTD;
2924 2882 break;
2925 2883 case SVC_NFS4CBD:
2926 2884 service = NFS4CBD;
2927 2885 break;
2928 2886 case SVC_NFSMAPID:
2929 2887 service = NFSMAPID;
2930 2888 break;
2931 2889 case SVC_RQUOTAD:
2932 2890 service = RQUOTAD;
2933 2891 break;
2934 2892 case SVC_NFSLOGD:
2935 2893 service = NFSLOGD;
2936 2894 break;
2937 2895 case SVC_REPARSED:
2938 2896 service = REPARSED;
2939 2897 break;
2940 2898 case SVC_CLIENT:
2941 2899 service = NFS_CLIENT_SVC;
2942 2900 break;
2943 2901 default:
2944 2902 continue;
2945 2903 }
2946 2904
2947 2905 /*
2948 2906 * Only attempt to restart the service if it is
2949 2907 * currently running. In the future, it may be
2950 2908 * desirable to use smf_refresh_instance if the NFS
2951 2909 * services ever implement the refresh method.
2952 2910 */
2953 2911 if (service_in_state(service, SCF_STATE_STRING_ONLINE)) {
2954 2912 ret = smf_restart_instance(service);
2955 2913 /*
2956 2914 * There are only a few SMF errors at this point, but
2957 2915 * it is also possible that a bad value may have put
2958 2916 * the service into maintenance if there wasn't an
2959 2917 * SMF level error.
2960 2918 */
2961 2919 if (ret != 0) {
2962 2920 (void) fprintf(stderr,
2963 2921 dgettext(TEXT_DOMAIN,
2964 2922 "%s failed to restart: %s\n"),
2965 2923 service, scf_strerror(scf_error()));
2966 2924 } else {
2967 2925 /*
2968 2926 * Check whether it has gone to "maintenance"
2969 2927 * mode or not. Maintenance implies something
2970 2928 * went wrong.
2971 2929 */
2972 2930 if (service_in_state(service,
2973 2931 SCF_STATE_STRING_MAINT)) {
2974 2932 (void) fprintf(stderr,
2975 2933 dgettext(TEXT_DOMAIN,
2976 2934 "%s failed to restart\n"),
2977 2935 service);
2978 2936 }
2979 2937 }
2980 2938 }
2981 2939 svcs &= ~mask;
2982 2940 }
2983 2941 }
2984 2942
2985 2943 /*
2986 2944 * nfs_minmax_check(name, value)
2987 2945 *
2988 2946 * Verify that the value for the property specified by index is valid
2989 2947 * relative to the opposite value in the case of a min/max variable.
2990 2948 * Currently, server_minvers/server_maxvers and
2991 2949 * client_minvers/client_maxvers are the only ones to check.
2992 2950 */
2993 2951
2994 2952 static int
2995 2953 nfs_minmax_check(int index, int value)
2996 2954 {
2997 2955 int val;
2998 2956 char *pval;
2999 2957 sa_property_t prop;
3000 2958 sa_optionset_t opts;
3001 2959 int ret = B_TRUE;
3002 2960
3003 2961 if (proto_options[index].other != NULL) {
3004 2962 /* have a property to compare against */
3005 2963 opts = nfs_get_proto_set();
3006 2964 prop = sa_get_property(opts, proto_options[index].other);
3007 2965 /*
3008 2966 * If we don't find the property, assume default
3009 2967 * values which will work since the max will be at the
3010 2968 * max and the min at the min.
3011 2969 */
3012 2970 if (prop != NULL) {
3013 2971 pval = sa_get_property_attr(prop, "value");
3014 2972 if (pval != NULL) {
3015 2973 val = strtoul(pval, NULL, 0);
3016 2974 if (proto_options[index].compare ==
3017 2975 OPT_CMP_LE) {
3018 2976 ret = value <= val ? B_TRUE : B_FALSE;
3019 2977 } else if (proto_options[index].compare ==
3020 2978 OPT_CMP_GE) {
3021 2979 ret = value >= val ? B_TRUE : B_FALSE;
3022 2980 }
3023 2981 sa_free_attr_string(pval);
3024 2982 }
3025 2983 }
3026 2984 }
3027 2985 return (ret);
3028 2986 }
3029 2987
3030 2988 /*
3031 2989 * nfs_validate_proto_prop(index, name, value)
3032 2990 *
3033 2991 * Verify that the property specified by name can take the new
3034 2992 * value. This is a sanity check to prevent bad values getting into
3035 2993 * the default files. All values need to be checked against what is
3036 2994 * allowed by their defined type. If a type isn't explicitly defined
3037 2995 * here, it is treated as a string.
3038 2996 *
3039 2997 * Note that OPT_TYPE_NUMBER will additionally check that the value is
3040 2998 * within the range specified and potentially against another property
3041 2999 * value as well as specified in the proto_options members other and
3042 3000 * compare.
3043 3001 */
3044 3002
3045 3003 static int
3046 3004 nfs_validate_proto_prop(int index, char *name, char *value)
3047 3005 {
3048 3006 int ret = SA_OK;
3049 3007 char *cp;
3050 3008 #ifdef lint
3051 3009 name = name;
3052 3010 #endif
3053 3011 switch (proto_options[index].type) {
3054 3012 case OPT_TYPE_NUMBER:
3055 3013 if (!is_a_number(value))
3056 3014 ret = SA_BAD_VALUE;
3057 3015 else {
3058 3016 int val;
3059 3017 val = strtoul(value, NULL, 0);
3060 3018 if (val < proto_options[index].minval ||
3061 3019 val > proto_options[index].maxval)
3062 3020 ret = SA_BAD_VALUE;
3063 3021 /*
3064 3022 * For server_versmin/server_versmax and
3065 3023 * client_versmin/client_versmax, the value of the
3066 3024 * min(max) should be checked to be correct relative
3067 3025 * to the current max(min).
3068 3026 */
3069 3027 if (!nfs_minmax_check(index, val)) {
3070 3028 ret = SA_BAD_VALUE;
3071 3029 }
3072 3030 }
3073 3031 break;
3074 3032
3075 3033 case OPT_TYPE_DOMAIN:
3076 3034 /*
3077 3035 * needs to be a qualified domain so will have at
3078 3036 * least one period and other characters on either
3079 3037 * side of it. A zero length string is also allowed
3080 3038 * and is the way to turn off the override.
3081 3039 */
3082 3040 if (strlen(value) == 0)
3083 3041 break;
3084 3042 cp = strchr(value, '.');
3085 3043 if (cp == NULL || cp == value || strchr(value, '@') != NULL)
3086 3044 ret = SA_BAD_VALUE;
3087 3045 break;
3088 3046
3089 3047 case OPT_TYPE_BOOLEAN:
3090 3048 if (strlen(value) == 0 ||
3091 3049 strcasecmp(value, "true") == 0 ||
3092 3050 strcmp(value, "1") == 0 ||
3093 3051 strcasecmp(value, "false") == 0 ||
3094 3052 strcmp(value, "0") == 0) {
3095 3053 ret = SA_OK;
3096 3054 } else {
3097 3055 ret = SA_BAD_VALUE;
3098 3056 }
3099 3057 break;
3100 3058
3101 3059 case OPT_TYPE_ONOFF:
3102 3060 if (strcasecmp(value, "on") != 0 &&
3103 3061 strcasecmp(value, "off") != 0) {
3104 3062 ret = SA_BAD_VALUE;
3105 3063 }
3106 3064 break;
3107 3065
3108 3066 case OPT_TYPE_PROTOCOL: {
3109 3067 struct netconfig *nconf;
3110 3068 void *nc;
3111 3069 boolean_t pfound = B_FALSE;
3112 3070
3113 3071 if (strcasecmp(value, "all") == 0)
3114 3072 break;
3115 3073
3116 3074 if ((nc = setnetconfig()) == NULL) {
3117 3075 (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
3118 3076 "setnetconfig failed: %s\n"), strerror(errno));
3119 3077 } else {
3120 3078 while ((nconf = getnetconfig(nc)) != NULL) {
3121 3079 if (strcmp(nconf->nc_proto, value) == 0) {
3122 3080 pfound = B_TRUE;
3123 3081 break;
3124 3082 }
3125 3083 }
3126 3084 (void) endnetconfig(nc);
3127 3085 }
3128 3086
3129 3087 if (!pfound)
3130 3088 ret = SA_BAD_VALUE;
3131 3089 break;
3132 3090 }
3133 3091
3134 3092 default:
3135 3093 /* treat as a string */
3136 3094 break;
3137 3095 }
3138 3096 return (ret);
3139 3097 }
3140 3098
3141 3099 /*
3142 3100 * nfs_set_proto_prop(prop)
3143 3101 *
3144 3102 * check that prop is valid.
3145 3103 */
3146 3104
3147 3105 static int
3148 3106 nfs_set_proto_prop(sa_property_t prop)
3149 3107 {
3150 3108 int ret = SA_OK;
3151 3109 char *name;
3152 3110 char *value;
3153 3111
3154 3112 name = sa_get_property_attr(prop, "type");
3155 3113 value = sa_get_property_attr(prop, "value");
3156 3114 if (name != NULL && value != NULL) {
3157 3115 scf_type_t sctype;
3158 3116 char *svc_name;
3159 3117 char *instance = NULL;
3160 3118 int index = findprotoopt(name, 1);
3161 3119
3162 3120 ret = nfs_validate_proto_prop(index, name, value);
3163 3121 if (ret == SA_OK) {
3164 3122 sctype = getscftype(proto_options[index].type);
3165 3123 svc_name = getsvcname(proto_options[index].svcs);
3166 3124 if (sctype == SCF_TYPE_BOOLEAN) {
3167 3125 if (value != NULL)
3168 3126 sa_free_attr_string(value);
3169 3127 if (string_to_boolean(value) == 0)
3170 3128 value = strdup("0");
3171 3129 else
3172 3130 value = strdup("1");
3173 3131 }
3174 3132 ret = nfs_smf_set_prop(name, value, instance, sctype,
3175 3133 svc_name);
3176 3134 if (ret == SA_OK) {
3177 3135 restart_service(proto_options[index].svcs);
3178 3136 } else {
3179 3137 (void) printf(dgettext(TEXT_DOMAIN,
3180 3138 "Cannot restart NFS services : %s\n"),
3181 3139 sa_errorstr(ret));
3182 3140 }
3183 3141 }
3184 3142 }
3185 3143 if (name != NULL)
3186 3144 sa_free_attr_string(name);
3187 3145 if (value != NULL)
3188 3146 sa_free_attr_string(value);
3189 3147 return (ret);
3190 3148 }
3191 3149
3192 3150 /*
3193 3151 * nfs_get_status()
3194 3152 *
3195 3153 * What is the current status of the nfsd? We use the SMF state here.
3196 3154 * Caller must free the returned value.
3197 3155 */
3198 3156
3199 3157 static char *
3200 3158 nfs_get_status()
3201 3159 {
3202 3160 return (smf_get_state(NFSD));
3203 3161 }
3204 3162
3205 3163 /*
3206 3164 * nfs_space_alias(alias)
3207 3165 *
3208 3166 * Lookup the space (security) name. If it is default, convert to the
3209 3167 * real name.
3210 3168 */
3211 3169
3212 3170 static char *
3213 3171 nfs_space_alias(char *space)
3214 3172 {
3215 3173 char *name = space;
3216 3174 seconfig_t secconf;
3217 3175
3218 3176 /*
3219 3177 * Only the space named "default" is special. If it is used,
3220 3178 * the default needs to be looked up and the real name used.
3221 3179 * This is normally "sys" but could be changed. We always
3222 3180 * change default to the real name.
3223 3181 */
3224 3182 if (strcmp(space, "default") == 0 &&
3225 3183 nfs_getseconfig_default(&secconf) == 0) {
3226 3184 if (nfs_getseconfig_bynumber(secconf.sc_nfsnum, &secconf) == 0)
3227 3185 name = secconf.sc_name;
3228 3186 }
3229 3187 return (strdup(name));
3230 3188 }
3231 3189
3232 3190 /*
3233 3191 * nfs_features()
3234 3192 *
3235 3193 * Return a mask of the features required.
3236 3194 */
3237 3195
3238 3196 static uint64_t
3239 3197 nfs_features()
3240 3198 {
3241 3199 return ((uint64_t)SA_FEATURE_DFSTAB | SA_FEATURE_SERVER);
3242 3200 }
|
↓ open down ↓ |
1139 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX