Print this page
Revert "OS-871 zone stuck in shutting_down - waiting for kernel thread nfsauth_refresh_thread to terminate"
This reverts commit 887d2a84c612cea61b6ad544f54cf790cfb9de3e.
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/fs.d/nfs/mountd/mountd.c
+++ new/usr/src/cmd/fs.d/nfs/mountd/mountd.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) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24 - * Copyright 2012 Joyent, Inc. All rights reserved.
25 24 * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
26 25 * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
27 26 */
28 27
29 28 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
30 29 /* All Rights Reserved */
31 30
32 31 /*
33 32 * Portions of this source code were derived from Berkeley 4.3 BSD
34 33 * under license from the Regents of the University of California.
35 34 */
36 35
37 36 #include <stdio.h>
38 37 #include <stdio_ext.h>
39 38 #include <stdlib.h>
40 39 #include <ctype.h>
41 40 #include <sys/types.h>
42 41 #include <string.h>
43 42 #include <syslog.h>
44 43 #include <sys/param.h>
45 44 #include <rpc/rpc.h>
46 45 #include <sys/stat.h>
47 46 #include <netconfig.h>
48 47 #include <netdir.h>
49 48 #include <sys/file.h>
50 49 #include <sys/time.h>
51 50 #include <sys/errno.h>
52 51 #include <rpcsvc/mount.h>
53 52 #include <sys/pathconf.h>
54 53 #include <sys/systeminfo.h>
55 54 #include <sys/utsname.h>
56 55 #include <sys/wait.h>
57 56 #include <sys/resource.h>
58 57 #include <signal.h>
59 58 #include <locale.h>
60 59 #include <unistd.h>
61 60 #include <errno.h>
62 61 #include <sys/socket.h>
63 62 #include <netinet/in.h>
64 63 #include <arpa/inet.h>
65 64 #include <netdb.h>
66 65 #include <thread.h>
67 66 #include <assert.h>
68 67 #include <priv_utils.h>
69 68 #include <nfs/auth.h>
70 69 #include <nfs/nfssys.h>
71 70 #include <nfs/nfs.h>
72 71 #include <nfs/nfs_sec.h>
73 72 #include <rpcsvc/daemon_utils.h>
74 73 #include <deflt.h>
75 74 #include "../../fslib.h"
76 75 #include <sharefs/share.h>
77 76 #include <sharefs/sharetab.h>
78 77 #include "../lib/sharetab.h"
79 78 #include "mountd.h"
80 79 #include <tsol/label.h>
81 80 #include <sys/tsol/label_macro.h>
82 81 #include <libtsnet.h>
83 82 #include <sys/sdt.h>
84 83 #include <libscf.h>
85 84 #include <limits.h>
86 85 #include <sys/nvpair.h>
87 86 #include <attr.h>
88 87 #include "smfcfg.h"
89 88 #include <pwd.h>
90 89 #include <grp.h>
91 90 #include <alloca.h>
92 91
93 92 extern int daemonize_init(void);
94 93 extern void daemonize_fini(int);
95 94
96 95 extern int _nfssys(int, void *);
97 96
98 97 struct sh_list *share_list;
99 98
100 99 rwlock_t sharetab_lock; /* lock to protect the cached sharetab */
101 100 static mutex_t mnttab_lock; /* prevent concurrent mnttab readers */
102 101
103 102 static mutex_t logging_queue_lock;
104 103 static cond_t logging_queue_cv;
105 104
106 105 static share_t *find_lofsentry(char *, int *);
107 106 static int getclientsflavors_old(share_t *, struct cln *, int *);
108 107 static int getclientsflavors_new(share_t *, struct cln *, int *);
109 108 static int check_client_old(share_t *, struct cln *, int, uid_t, gid_t, uint_t,
110 109 gid_t *, uid_t *, gid_t *, uint_t *, gid_t **);
111 110 static int check_client_new(share_t *, struct cln *, int, uid_t, gid_t, uint_t,
112 111 gid_t *, uid_t *, gid_t *i, uint_t *, gid_t **);
113 112 static void mnt(struct svc_req *, SVCXPRT *);
114 113 static void mnt_pathconf(struct svc_req *);
115 114 static int mount(struct svc_req *r);
116 115 static void sh_free(struct sh_list *);
117 116 static void umount(struct svc_req *);
118 117 static void umountall(struct svc_req *);
119 118 static int newopts(char *);
120 119 static tsol_tpent_t *get_client_template(struct sockaddr *);
121 120
122 121 static int debug;
123 122 static int verbose;
124 123 static int rejecting;
125 124 static int mount_vers_min = MOUNTVERS;
126 125 static int mount_vers_max = MOUNTVERS3;
127 126 static int mountd_port = 0;
128 127
129 128 extern void nfscmd_func(void *, char *, size_t, door_desc_t *, uint_t);
130 129
131 130 thread_t nfsauth_thread;
132 131 thread_t cmd_thread;
133 132 thread_t logging_thread;
134 133
135 134 typedef struct logging_data {
136 135 char *ld_host;
137 136 char *ld_path;
138 137 char *ld_rpath;
139 138 int ld_status;
140 139 char *ld_netid;
141 140 struct netbuf *ld_nb;
142 141 struct logging_data *ld_next;
143 142 } logging_data;
144 143
145 144 static logging_data *logging_head = NULL;
146 145 static logging_data *logging_tail = NULL;
147 146
148 147 /*
149 148 * Our copy of some system variables obtained using sysconf(3c)
150 149 */
151 150 static long ngroups_max; /* _SC_NGROUPS_MAX */
152 151 static long pw_size; /* _SC_GETPW_R_SIZE_MAX */
153 152
154 153 /* ARGSUSED */
155 154 static void *
156 155 nfsauth_svc(void *arg)
157 156 {
158 157 int doorfd = -1;
159 158 uint_t darg;
160 159 #ifdef DEBUG
161 160 int dfd;
162 161 #endif
163 162
164 163 if ((doorfd = door_create(nfsauth_func, NULL,
165 164 DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
166 165 syslog(LOG_ERR, "Unable to create door: %m\n");
167 166 exit(10);
168 167 }
169 168
170 169 #ifdef DEBUG
171 170 /*
172 171 * Create a file system path for the door
173 172 */
174 173 if ((dfd = open(MOUNTD_DOOR, O_RDWR|O_CREAT|O_TRUNC,
175 174 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) {
176 175 syslog(LOG_ERR, "Unable to open %s: %m\n", MOUNTD_DOOR);
177 176 (void) close(doorfd);
178 177 exit(11);
179 178 }
180 179
181 180 /*
182 181 * Clean up any stale namespace associations
183 182 */
184 183 (void) fdetach(MOUNTD_DOOR);
185 184
186 185 /*
187 186 * Register in namespace to pass to the kernel to door_ki_open
188 187 */
189 188 if (fattach(doorfd, MOUNTD_DOOR) == -1) {
190 189 syslog(LOG_ERR, "Unable to fattach door: %m\n");
191 190 (void) close(dfd);
192 191 (void) close(doorfd);
193 192 exit(12);
194 193 }
195 194 (void) close(dfd);
196 195 #endif
197 196
198 197 /*
199 198 * Must pass the doorfd down to the kernel.
200 199 */
201 200 darg = doorfd;
202 201 (void) _nfssys(MOUNTD_ARGS, &darg);
203 202
204 203 /*
205 204 * Wait for incoming calls
206 205 */
207 206 /*CONSTCOND*/
208 207 for (;;)
209 208 (void) pause();
210 209
211 210 /*NOTREACHED*/
212 211 syslog(LOG_ERR, gettext("Door server exited"));
213 212 return (NULL);
214 213 }
215 214
216 215 /*
217 216 * NFS command service thread code for setup and handling of the
218 217 * nfs_cmd requests for character set conversion and other future
219 218 * events.
220 219 */
221 220
222 221 static void *
223 222 cmd_svc(void *arg)
224 223 {
225 224 int doorfd = -1;
226 225 uint_t darg;
227 226
228 227 if ((doorfd = door_create(nfscmd_func, NULL,
229 228 DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
230 229 syslog(LOG_ERR, "Unable to create cmd door: %m\n");
231 230 exit(10);
232 231 }
233 232
234 233 /*
235 234 * Must pass the doorfd down to the kernel.
236 235 */
237 236 darg = doorfd;
238 237 (void) _nfssys(NFSCMD_ARGS, &darg);
239 238
240 239 /*
241 240 * Wait for incoming calls
242 241 */
243 242 /*CONSTCOND*/
244 243 for (;;)
245 244 (void) pause();
246 245
247 246 /*NOTREACHED*/
248 247 syslog(LOG_ERR, gettext("Cmd door server exited"));
249 248 return (NULL);
250 249 }
251 250
252 251 static void
253 252 free_logging_data(logging_data *lq)
254 253 {
255 254 if (lq != NULL) {
256 255 free(lq->ld_host);
257 256 free(lq->ld_netid);
258 257
259 258 if (lq->ld_nb != NULL) {
260 259 free(lq->ld_nb->buf);
261 260 free(lq->ld_nb);
262 261 }
263 262
264 263 free(lq->ld_path);
265 264 free(lq->ld_rpath);
266 265
267 266 free(lq);
268 267 }
269 268 }
270 269
271 270 static logging_data *
272 271 remove_head_of_queue(void)
273 272 {
274 273 logging_data *lq;
275 274
276 275 /*
277 276 * Pull it off the queue.
278 277 */
279 278 lq = logging_head;
280 279 if (lq) {
281 280 logging_head = lq->ld_next;
282 281
283 282 /*
284 283 * Drained it.
285 284 */
286 285 if (logging_head == NULL) {
287 286 logging_tail = NULL;
288 287 }
289 288 }
290 289
291 290 return (lq);
292 291 }
293 292
294 293 static void
295 294 do_logging_queue(logging_data *lq)
296 295 {
297 296 int cleared = 0;
298 297 char *host;
299 298
300 299 while (lq) {
301 300 struct cln cln;
302 301
303 302 if (lq->ld_host == NULL) {
304 303 DTRACE_PROBE(mountd, name_by_lazy);
305 304 cln_init_lazy(&cln, lq->ld_netid, lq->ld_nb);
306 305 host = cln_gethost(&cln);
307 306 } else
308 307 host = lq->ld_host;
309 308
310 309 audit_mountd_mount(host, lq->ld_path, lq->ld_status); /* BSM */
311 310
312 311 /* add entry to mount list */
313 312 if (lq->ld_rpath)
314 313 mntlist_new(host, lq->ld_rpath);
315 314
316 315 if (lq->ld_host == NULL)
317 316 cln_fini(&cln);
318 317
319 318 free_logging_data(lq);
320 319 cleared++;
321 320
322 321 (void) mutex_lock(&logging_queue_lock);
323 322 lq = remove_head_of_queue();
324 323 (void) mutex_unlock(&logging_queue_lock);
325 324 }
326 325
327 326 DTRACE_PROBE1(mountd, logging_cleared, cleared);
328 327 }
329 328
330 329 static void *
331 330 logging_svc(void *arg)
332 331 {
333 332 logging_data *lq;
334 333
335 334 for (;;) {
336 335 (void) mutex_lock(&logging_queue_lock);
337 336 while (logging_head == NULL) {
338 337 (void) cond_wait(&logging_queue_cv,
339 338 &logging_queue_lock);
340 339 }
341 340
342 341 lq = remove_head_of_queue();
343 342 (void) mutex_unlock(&logging_queue_lock);
344 343
345 344 do_logging_queue(lq);
346 345 }
347 346
348 347 /*NOTREACHED*/
349 348 syslog(LOG_ERR, gettext("Logging server exited"));
350 349 return (NULL);
351 350 }
352 351
353 352 static int
354 353 convert_int(int *val, char *str)
355 354 {
356 355 long lval;
357 356
358 357 if (str == NULL || !isdigit(*str))
359 358 return (-1);
360 359
361 360 lval = strtol(str, &str, 10);
362 361 if (*str != '\0' || lval > INT_MAX)
363 362 return (-2);
364 363
365 364 *val = (int)lval;
366 365 return (0);
367 366 }
368 367
369 368 /*
370 369 * This function is called for each configured network type to
371 370 * bind and register our RPC service programs.
372 371 *
373 372 * On TCP or UDP, we may want to bind MOUNTPROG on a specific port
374 373 * (when mountd_port is specified) in which case we'll use the
375 374 * variant of svc_tp_create() that lets us pass a bind address.
376 375 */
377 376 static void
378 377 md_svc_tp_create(struct netconfig *nconf)
379 378 {
380 379 char port_str[8];
381 380 struct nd_hostserv hs;
382 381 struct nd_addrlist *al = NULL;
383 382 SVCXPRT *xprt = NULL;
384 383 rpcvers_t vers;
385 384
386 385 vers = mount_vers_max;
387 386
388 387 /*
389 388 * If mountd_port is set and this is an inet transport,
390 389 * bind this service on the specified port. The TLI way
391 390 * to create such a bind address is netdir_getbyname()
392 391 * with the special "host" HOST_SELF_BIND. This builds
393 392 * an all-zeros IP address with the specified port.
394 393 */
395 394 if (mountd_port != 0 &&
396 395 (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
397 396 strcmp(nconf->nc_protofmly, NC_INET6) == 0)) {
398 397 int err;
399 398
400 399 snprintf(port_str, sizeof (port_str), "%u",
401 400 (unsigned short)mountd_port);
402 401
403 402 hs.h_host = HOST_SELF_BIND;
404 403 hs.h_serv = port_str;
405 404 err = netdir_getbyname((struct netconfig *)nconf, &hs, &al);
406 405 if (err == 0 && al != NULL) {
407 406 xprt = svc_tp_create_addr(mnt, MOUNTPROG, vers,
408 407 nconf, al->n_addrs);
409 408 netdir_free(al, ND_ADDRLIST);
410 409 }
411 410 if (xprt == NULL) {
412 411 syslog(LOG_ERR, "mountd: unable to create "
413 412 "(MOUNTD,%d) on transport %s (port %d)",
414 413 vers, nconf->nc_netid, mountd_port);
415 414 }
416 415 /* fall-back to default bind */
417 416 }
418 417 if (xprt == NULL) {
419 418 /*
420 419 * Had mountd_port=0, or non-inet transport,
421 420 * or the bind to a specific port failed.
422 421 * Do a default bind.
423 422 */
424 423 xprt = svc_tp_create(mnt, MOUNTPROG, vers, nconf);
425 424 }
426 425 if (xprt == NULL) {
427 426 syslog(LOG_ERR, "mountd: unable to create "
428 427 "(MOUNTD,%d) on transport %s",
429 428 vers, nconf->nc_netid);
430 429 return;
431 430 }
432 431
433 432 /*
434 433 * Register additional versions on this transport.
435 434 */
436 435 while (--vers >= mount_vers_min) {
437 436 if (!svc_reg(xprt, MOUNTPROG, vers, mnt, nconf)) {
438 437 (void) syslog(LOG_ERR, "mountd: "
439 438 "failed to register vers %d on %s",
440 439 vers, nconf->nc_netid);
441 440 }
442 441 }
443 442 }
444 443
445 444 int
446 445 main(int argc, char *argv[])
447 446 {
448 447 int pid;
449 448 int c;
450 449 int rpc_svc_fdunlim = 1;
451 450 int rpc_svc_mode = RPC_SVC_MT_AUTO;
452 451 int maxrecsz = RPC_MAXDATASIZE;
453 452 bool_t exclbind = TRUE;
454 453 bool_t can_do_mlp;
455 454 long thr_flags = (THR_NEW_LWP|THR_DAEMON);
456 455 char defval[4];
457 456 int defvers, ret, bufsz;
458 457 struct rlimit rl;
459 458 int listen_backlog = 0;
460 459 int max_threads = 0;
461 460 int tmp;
462 461 struct netconfig *nconf;
463 462 NCONF_HANDLE *nc;
464 463
465 464 int pipe_fd = -1;
466 465
467 466 /*
468 467 * Mountd requires uid 0 for:
469 468 * /etc/rmtab updates (we could chown it to daemon)
470 469 * /etc/dfs/dfstab reading (it wants to lock out share which
471 470 * doesn't do any locking before first truncate;
472 471 * NFS share does; should use fcntl locking instead)
473 472 * Needed privileges:
474 473 * auditing
475 474 * nfs syscall
476 475 * file dac search (so it can stat all files)
477 476 * Optional privileges:
478 477 * MLP
|
↓ open down ↓ |
444 lines elided |
↑ open up ↑ |
479 478 */
480 479 can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP);
481 480 if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, -1, -1,
482 481 PRIV_SYS_NFS, PRIV_PROC_AUDIT, PRIV_FILE_DAC_SEARCH,
483 482 PRIV_NET_PRIVADDR,
484 483 can_do_mlp ? PRIV_NET_BINDMLP : NULL, NULL) == -1) {
485 484 (void) fprintf(stderr,
486 485 "%s: must be run with sufficient privileges\n",
487 486 argv[0]);
488 487 exit(1);
489 - }
490 -
491 - /* Mountd cannot run in a non-global zone. */
492 - if (getzoneid() != GLOBAL_ZONEID) {
493 - (void) fprintf(stderr, "%s: can only run in the global zone\n",
494 - argv[0]);
495 - exit(1);
496 488 }
497 489
498 490 if (getrlimit(RLIMIT_NOFILE, &rl) != 0) {
499 491 syslog(LOG_ERR, "getrlimit failed");
500 492 } else {
501 493 rl.rlim_cur = rl.rlim_max;
502 494 if (setrlimit(RLIMIT_NOFILE, &rl) != 0)
503 495 syslog(LOG_ERR, "setrlimit failed");
504 496 }
505 497
506 498 (void) enable_extended_FILE_stdio(-1, -1);
507 499
508 500 ret = nfs_smf_get_iprop("mountd_max_threads", &max_threads,
509 501 DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD);
510 502 if (ret != SA_OK) {
511 503 syslog(LOG_ERR, "Reading of mountd_max_threads from SMF "
512 504 "failed, using default value");
513 505 }
514 506
515 507 ret = nfs_smf_get_iprop("mountd_port", &mountd_port,
516 508 DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD);
517 509 if (ret != SA_OK) {
518 510 syslog(LOG_ERR, "Reading of mountd_port from SMF "
519 511 "failed, using default value");
520 512 }
521 513
522 514 while ((c = getopt(argc, argv, "dvrm:p:")) != EOF) {
523 515 switch (c) {
524 516 case 'd':
525 517 debug++;
526 518 break;
527 519 case 'v':
528 520 verbose++;
529 521 break;
530 522 case 'r':
531 523 rejecting = 1;
532 524 break;
533 525 case 'm':
534 526 if (convert_int(&tmp, optarg) != 0 || tmp < 1) {
535 527 (void) fprintf(stderr, "%s: invalid "
536 528 "max_threads option, using defaults\n",
537 529 argv[0]);
538 530 break;
539 531 }
540 532 max_threads = tmp;
541 533 break;
542 534 case 'p':
543 535 if (convert_int(&tmp, optarg) != 0 || tmp < 1 ||
544 536 tmp > UINT16_MAX) {
545 537 (void) fprintf(stderr, "%s: invalid port "
546 538 "number\n", argv[0]);
547 539 break;
548 540 }
549 541 mountd_port = tmp;
550 542 break;
551 543 default:
552 544 fprintf(stderr, "usage: mountd [-v] [-r]\n");
553 545 exit(1);
554 546 }
555 547 }
556 548
557 549 /*
558 550 * Read in the NFS version values from config file.
559 551 */
560 552 bufsz = 4;
561 553 ret = nfs_smf_get_prop("server_versmin", defval, DEFAULT_INSTANCE,
562 554 SCF_TYPE_INTEGER, NFSD, &bufsz);
563 555 if (ret == SA_OK) {
564 556 errno = 0;
565 557 defvers = strtol(defval, (char **)NULL, 10);
566 558 if (errno == 0) {
567 559 mount_vers_min = defvers;
568 560 /*
569 561 * special because NFSv2 is
570 562 * supported by mount v1 & v2
571 563 */
572 564 if (defvers == NFS_VERSION)
573 565 mount_vers_min = MOUNTVERS;
574 566 }
575 567 }
576 568
577 569 bufsz = 4;
578 570 ret = nfs_smf_get_prop("server_versmax", defval, DEFAULT_INSTANCE,
579 571 SCF_TYPE_INTEGER, NFSD, &bufsz);
580 572 if (ret == SA_OK) {
581 573 errno = 0;
582 574 defvers = strtol(defval, (char **)NULL, 10);
583 575 if (errno == 0) {
584 576 mount_vers_max = defvers;
585 577 }
586 578 }
587 579
588 580 ret = nfs_smf_get_iprop("mountd_listen_backlog", &listen_backlog,
589 581 DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD);
590 582 if (ret != SA_OK) {
591 583 syslog(LOG_ERR, "Reading of mountd_listen_backlog from SMF "
592 584 "failed, using default value");
593 585 }
594 586
595 587 /*
596 588 * Sanity check versions,
597 589 * even though we may get versions > MOUNTVERS3, we still need
598 590 * to start nfsauth service, so continue on regardless of values.
599 591 */
600 592 if (mount_vers_max > MOUNTVERS3)
601 593 mount_vers_max = MOUNTVERS3;
602 594 if (mount_vers_min > mount_vers_max) {
603 595 fprintf(stderr, "server_versmin > server_versmax\n");
604 596 mount_vers_max = mount_vers_min;
605 597 }
606 598 (void) setlocale(LC_ALL, "");
607 599 (void) rwlock_init(&sharetab_lock, USYNC_THREAD, NULL);
608 600 (void) mutex_init(&mnttab_lock, USYNC_THREAD, NULL);
609 601 (void) mutex_init(&logging_queue_lock, USYNC_THREAD, NULL);
610 602 (void) cond_init(&logging_queue_cv, USYNC_THREAD, NULL);
611 603
612 604 netgroup_init();
613 605
614 606 #if !defined(TEXT_DOMAIN)
615 607 #define TEXT_DOMAIN "SYS_TEST"
616 608 #endif
617 609 (void) textdomain(TEXT_DOMAIN);
618 610
619 611 /* Don't drop core if the NFS module isn't loaded. */
620 612 (void) signal(SIGSYS, SIG_IGN);
621 613
622 614 if (!debug)
623 615 pipe_fd = daemonize_init();
624 616
625 617 /*
626 618 * If we coredump it'll be in /core
627 619 */
628 620 if (chdir("/") < 0)
629 621 fprintf(stderr, "chdir /: %s\n", strerror(errno));
630 622
631 623 if (!debug)
632 624 openlog("mountd", LOG_PID, LOG_DAEMON);
633 625
634 626 /*
635 627 * establish our lock on the lock file and write our pid to it.
636 628 * exit if some other process holds the lock, or if there's any
637 629 * error in writing/locking the file.
638 630 */
639 631 pid = _enter_daemon_lock(MOUNTD);
640 632 switch (pid) {
641 633 case 0:
642 634 break;
643 635 case -1:
644 636 fprintf(stderr, "error locking for %s: %s\n", MOUNTD,
645 637 strerror(errno));
646 638 exit(2);
647 639 default:
648 640 /* daemon was already running */
649 641 exit(0);
650 642 }
651 643
652 644 audit_mountd_setup(); /* BSM */
653 645
654 646 /*
655 647 * Get required system variables
656 648 */
657 649 if ((ngroups_max = sysconf(_SC_NGROUPS_MAX)) == -1) {
658 650 syslog(LOG_ERR, "Unable to get _SC_NGROUPS_MAX");
659 651 exit(1);
660 652 }
661 653 if ((pw_size = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1) {
662 654 syslog(LOG_ERR, "Unable to get _SC_GETPW_R_SIZE_MAX");
663 655 exit(1);
664 656 }
665 657
666 658 /*
667 659 * Set number of file descriptors to unlimited
668 660 */
669 661 if (!rpc_control(RPC_SVC_USE_POLLFD, &rpc_svc_fdunlim)) {
670 662 syslog(LOG_INFO, "unable to set number of FDs to unlimited");
671 663 }
672 664
673 665 /*
674 666 * Tell RPC that we want automatic thread mode.
675 667 * A new thread will be spawned for each request.
676 668 */
677 669 if (!rpc_control(RPC_SVC_MTMODE_SET, &rpc_svc_mode)) {
678 670 fprintf(stderr, "unable to set automatic MT mode\n");
679 671 exit(1);
680 672 }
681 673
682 674 /*
683 675 * Enable non-blocking mode and maximum record size checks for
684 676 * connection oriented transports.
685 677 */
686 678 if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) {
687 679 fprintf(stderr, "unable to set RPC max record size\n");
688 680 }
689 681
690 682 /*
691 683 * Prevent our non-priv udp and tcp ports bound w/wildcard addr
692 684 * from being hijacked by a bind to a more specific addr.
693 685 */
694 686 if (!rpc_control(__RPC_SVC_EXCLBIND_SET, &exclbind)) {
695 687 fprintf(stderr, "warning: unable to set udp/tcp EXCLBIND\n");
696 688 }
697 689
698 690 /*
699 691 * Set the maximum number of outstanding connection
700 692 * indications (listen backlog) to the value specified.
701 693 */
702 694 if (listen_backlog > 0 && !rpc_control(__RPC_SVC_LSTNBKLOG_SET,
703 695 &listen_backlog)) {
704 696 fprintf(stderr, "unable to set listen backlog\n");
705 697 exit(1);
706 698 }
707 699
708 700 /*
709 701 * If max_threads was specified, then set the
710 702 * maximum number of threads to the value specified.
711 703 */
712 704 if (max_threads > 0 && !rpc_control(RPC_SVC_THRMAX_SET, &max_threads)) {
713 705 fprintf(stderr, "unable to set max_threads\n");
714 706 exit(1);
715 707 }
716 708
717 709 if (mountd_port < 0 || mountd_port > UINT16_MAX) {
718 710 fprintf(stderr, "unable to use specified port\n");
719 711 exit(1);
720 712 }
721 713
722 714 /*
723 715 * Make sure to unregister any previous versions in case the
724 716 * user is reconfiguring the server in interesting ways.
725 717 */
726 718 svc_unreg(MOUNTPROG, MOUNTVERS);
727 719 svc_unreg(MOUNTPROG, MOUNTVERS_POSIX);
728 720 svc_unreg(MOUNTPROG, MOUNTVERS3);
729 721
730 722 /*
731 723 * Create the nfsauth thread with same signal disposition
732 724 * as the main thread. We need to create a separate thread
733 725 * since mountd() will be both an RPC server (for remote
734 726 * traffic) _and_ a doors server (for kernel upcalls).
735 727 */
736 728 if (thr_create(NULL, 0, nfsauth_svc, 0, thr_flags, &nfsauth_thread)) {
737 729 fprintf(stderr,
738 730 gettext("Failed to create NFSAUTH svc thread\n"));
739 731 exit(2);
740 732 }
741 733
742 734 /*
743 735 * Create the cmd service thread with same signal disposition
744 736 * as the main thread. We need to create a separate thread
745 737 * since mountd() will be both an RPC server (for remote
746 738 * traffic) _and_ a doors server (for kernel upcalls).
747 739 */
748 740 if (thr_create(NULL, 0, cmd_svc, 0, thr_flags, &cmd_thread)) {
749 741 syslog(LOG_ERR, gettext("Failed to create CMD svc thread"));
750 742 exit(2);
751 743 }
752 744
753 745 /*
754 746 * Create an additional thread to service the rmtab and
755 747 * audit_mountd_mount logging for mount requests. Use the same
756 748 * signal disposition as the main thread. We create
757 749 * a separate thread to allow the mount request threads to
758 750 * clear as soon as possible.
759 751 */
760 752 if (thr_create(NULL, 0, logging_svc, 0, thr_flags, &logging_thread)) {
761 753 syslog(LOG_ERR, gettext("Failed to create LOGGING svc thread"));
762 754 exit(2);
763 755 }
764 756
765 757 /*
766 758 * Enumerate network transports and create service listeners
767 759 * as appropriate for each.
768 760 */
769 761 if ((nc = setnetconfig()) == NULL) {
770 762 syslog(LOG_ERR, "setnetconfig failed: %m");
771 763 return (-1);
772 764 }
773 765 while ((nconf = getnetconfig(nc)) != NULL) {
774 766 /*
775 767 * Skip things like tpi_raw, invisible...
776 768 */
777 769 if ((nconf->nc_flag & NC_VISIBLE) == 0)
778 770 continue;
779 771 if (nconf->nc_semantics != NC_TPI_CLTS &&
780 772 nconf->nc_semantics != NC_TPI_COTS &&
781 773 nconf->nc_semantics != NC_TPI_COTS_ORD)
782 774 continue;
783 775
784 776 md_svc_tp_create(nconf);
785 777 }
786 778 (void) endnetconfig(nc);
787 779
788 780 /*
789 781 * Start serving
790 782 */
791 783 rmtab_load();
792 784
793 785 daemonize_fini(pipe_fd);
794 786
795 787 /* Get rid of the most dangerous basic privileges. */
796 788 __fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_INFO, PRIV_PROC_SESSION,
797 789 (char *)NULL);
798 790
799 791 svc_run();
800 792 syslog(LOG_ERR, "Error: svc_run shouldn't have returned");
801 793 abort();
802 794
803 795 /* NOTREACHED */
804 796 return (0);
805 797 }
806 798
807 799 /*
808 800 * Server procedure switch routine
809 801 */
810 802 void
811 803 mnt(struct svc_req *rqstp, SVCXPRT *transp)
812 804 {
813 805 switch (rqstp->rq_proc) {
814 806 case NULLPROC:
815 807 errno = 0;
816 808 if (!svc_sendreply(transp, xdr_void, (char *)0))
817 809 log_cant_reply(transp);
818 810 return;
819 811
820 812 case MOUNTPROC_MNT:
821 813 (void) mount(rqstp);
822 814 return;
823 815
824 816 case MOUNTPROC_DUMP:
825 817 mntlist_send(transp);
826 818 return;
827 819
828 820 case MOUNTPROC_UMNT:
829 821 umount(rqstp);
830 822 return;
831 823
832 824 case MOUNTPROC_UMNTALL:
833 825 umountall(rqstp);
834 826 return;
835 827
836 828 case MOUNTPROC_EXPORT:
837 829 case MOUNTPROC_EXPORTALL:
838 830 export(rqstp);
839 831 return;
840 832
841 833 case MOUNTPROC_PATHCONF:
842 834 if (rqstp->rq_vers == MOUNTVERS_POSIX)
843 835 mnt_pathconf(rqstp);
844 836 else
845 837 svcerr_noproc(transp);
846 838 return;
847 839
848 840 default:
849 841 svcerr_noproc(transp);
850 842 return;
851 843 }
852 844 }
853 845
854 846 void
855 847 log_cant_reply_cln(struct cln *cln)
856 848 {
857 849 int saverrno;
858 850 char *host;
859 851
860 852 saverrno = errno; /* save error code */
861 853
862 854 host = cln_gethost(cln);
863 855 if (host == NULL)
864 856 return;
865 857
866 858 errno = saverrno;
867 859 if (errno == 0)
868 860 syslog(LOG_ERR, "couldn't send reply to %s", host);
869 861 else
870 862 syslog(LOG_ERR, "couldn't send reply to %s: %m", host);
871 863 }
872 864
873 865 void
874 866 log_cant_reply(SVCXPRT *transp)
875 867 {
876 868 int saverrno;
877 869 struct cln cln;
878 870
879 871 saverrno = errno; /* save error code */
880 872 cln_init(&cln, transp);
881 873 errno = saverrno;
882 874
883 875 log_cant_reply_cln(&cln);
884 876
885 877 cln_fini(&cln);
886 878 }
887 879
888 880 /*
889 881 * Answer pathconf questions for the mount point fs
890 882 */
891 883 static void
892 884 mnt_pathconf(struct svc_req *rqstp)
893 885 {
894 886 SVCXPRT *transp;
895 887 struct pathcnf p;
896 888 char *path, rpath[MAXPATHLEN];
897 889 struct stat st;
898 890
899 891 transp = rqstp->rq_xprt;
900 892 path = NULL;
901 893 (void) memset((caddr_t)&p, 0, sizeof (p));
902 894
903 895 if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
904 896 svcerr_decode(transp);
905 897 return;
906 898 }
907 899 if (lstat(path, &st) < 0) {
908 900 _PC_SET(_PC_ERROR, p.pc_mask);
909 901 goto done;
910 902 }
911 903 /*
912 904 * Get a path without symbolic links.
913 905 */
914 906 if (realpath(path, rpath) == NULL) {
915 907 syslog(LOG_DEBUG,
916 908 "mount request: realpath failed on %s: %m",
917 909 path);
918 910 _PC_SET(_PC_ERROR, p.pc_mask);
919 911 goto done;
920 912 }
921 913 (void) memset((caddr_t)&p, 0, sizeof (p));
922 914 /*
923 915 * can't ask about devices over NFS
924 916 */
925 917 _PC_SET(_PC_MAX_CANON, p.pc_mask);
926 918 _PC_SET(_PC_MAX_INPUT, p.pc_mask);
927 919 _PC_SET(_PC_PIPE_BUF, p.pc_mask);
928 920 _PC_SET(_PC_VDISABLE, p.pc_mask);
929 921
930 922 errno = 0;
931 923 p.pc_link_max = pathconf(rpath, _PC_LINK_MAX);
932 924 if (errno)
933 925 _PC_SET(_PC_LINK_MAX, p.pc_mask);
934 926 p.pc_name_max = pathconf(rpath, _PC_NAME_MAX);
935 927 if (errno)
936 928 _PC_SET(_PC_NAME_MAX, p.pc_mask);
937 929 p.pc_path_max = pathconf(rpath, _PC_PATH_MAX);
938 930 if (errno)
939 931 _PC_SET(_PC_PATH_MAX, p.pc_mask);
940 932 if (pathconf(rpath, _PC_NO_TRUNC) == 1)
941 933 _PC_SET(_PC_NO_TRUNC, p.pc_mask);
942 934 if (pathconf(rpath, _PC_CHOWN_RESTRICTED) == 1)
943 935 _PC_SET(_PC_CHOWN_RESTRICTED, p.pc_mask);
944 936
945 937 done:
946 938 errno = 0;
947 939 if (!svc_sendreply(transp, xdr_ppathcnf, (char *)&p))
948 940 log_cant_reply(transp);
949 941 if (path != NULL)
950 942 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
951 943 }
952 944
953 945 /*
954 946 * If the rootmount (export) option is specified, the all mount requests for
955 947 * subdirectories return EACCES.
956 948 */
957 949 static int
958 950 checkrootmount(share_t *sh, char *rpath)
959 951 {
960 952 char *val;
961 953
962 954 if ((val = getshareopt(sh->sh_opts, SHOPT_NOSUB)) != NULL) {
963 955 free(val);
964 956 if (strcmp(sh->sh_path, rpath) != 0)
965 957 return (0);
966 958 else
967 959 return (1);
968 960 } else
969 961 return (1);
970 962 }
971 963
972 964 #define MAX_FLAVORS 128
973 965
974 966 /*
975 967 * Return only EACCES if client does not have access
976 968 * to this directory.
977 969 * "If the server exports only /a/b, an attempt to
978 970 * mount a/b/c will fail with ENOENT if the directory
979 971 * does not exist"... However, if the client
980 972 * does not have access to /a/b, an attacker can
981 973 * determine whether the directory exists.
982 974 * This routine checks either existence of the file or
983 975 * existence of the file name entry in the mount table.
984 976 * If the file exists and there is no file name entry,
985 977 * the error returned should be EACCES.
986 978 * If the file does not exist, it must be determined
987 979 * whether the client has access to a parent
988 980 * directory. If the client has access to a parent
989 981 * directory, the error returned should be ENOENT,
990 982 * otherwise EACCES.
991 983 */
992 984 static int
993 985 mount_enoent_error(struct cln *cln, char *path, char *rpath, int *flavor_list)
994 986 {
995 987 char *checkpath, *dp;
996 988 share_t *sh = NULL;
997 989 int realpath_error = ENOENT, reply_error = EACCES, lofs_tried = 0;
998 990 int flavor_count;
999 991
1000 992 checkpath = strdup(path);
1001 993 if (checkpath == NULL) {
1002 994 syslog(LOG_ERR, "mount_enoent: no memory");
1003 995 return (EACCES);
1004 996 }
1005 997
1006 998 /* CONSTCOND */
1007 999 while (1) {
1008 1000 if (sh) {
1009 1001 sharefree(sh);
1010 1002 sh = NULL;
1011 1003 }
1012 1004
1013 1005 if ((sh = findentry(rpath)) == NULL &&
1014 1006 (sh = find_lofsentry(rpath, &lofs_tried)) == NULL) {
1015 1007 /*
1016 1008 * There is no file name entry.
1017 1009 * If the file (with symbolic links resolved) exists,
1018 1010 * the error returned should be EACCES.
1019 1011 */
1020 1012 if (realpath_error == 0)
1021 1013 break;
1022 1014 } else if (checkrootmount(sh, rpath) == 0) {
1023 1015 /*
1024 1016 * This is a "nosub" only export, in which case,
1025 1017 * mounting subdirectories isn't allowed.
1026 1018 * If the file (with symbolic links resolved) exists,
1027 1019 * the error returned should be EACCES.
1028 1020 */
1029 1021 if (realpath_error == 0)
1030 1022 break;
1031 1023 } else {
1032 1024 /*
1033 1025 * Check permissions in mount table.
1034 1026 */
1035 1027 if (newopts(sh->sh_opts))
1036 1028 flavor_count = getclientsflavors_new(sh, cln,
1037 1029 flavor_list);
1038 1030 else
1039 1031 flavor_count = getclientsflavors_old(sh, cln,
1040 1032 flavor_list);
1041 1033 if (flavor_count != 0) {
1042 1034 /*
1043 1035 * Found entry in table and
1044 1036 * client has correct permissions.
1045 1037 */
1046 1038 reply_error = ENOENT;
1047 1039 break;
1048 1040 }
1049 1041 }
1050 1042
1051 1043 /*
1052 1044 * Check all parent directories.
1053 1045 */
1054 1046 dp = strrchr(checkpath, '/');
1055 1047 if (dp == NULL)
1056 1048 break;
1057 1049 *dp = '\0';
1058 1050 if (strlen(checkpath) == 0)
1059 1051 break;
1060 1052 /*
1061 1053 * Get the real path (no symbolic links in it)
1062 1054 */
1063 1055 if (realpath(checkpath, rpath) == NULL) {
1064 1056 if (errno != ENOENT)
1065 1057 break;
1066 1058 } else {
1067 1059 realpath_error = 0;
1068 1060 }
1069 1061 }
1070 1062
1071 1063 if (sh)
1072 1064 sharefree(sh);
1073 1065 free(checkpath);
1074 1066 return (reply_error);
1075 1067 }
1076 1068
1077 1069 /*
1078 1070 * We need to inform the caller whether or not we were
1079 1071 * able to add a node to the queue. If we are not, then
1080 1072 * it is up to the caller to go ahead and log the data.
1081 1073 */
1082 1074 static int
1083 1075 enqueue_logging_data(char *host, SVCXPRT *transp, char *path,
1084 1076 char *rpath, int status, int error)
1085 1077 {
1086 1078 logging_data *lq;
1087 1079 struct netbuf *nb;
1088 1080
1089 1081 lq = (logging_data *)calloc(1, sizeof (logging_data));
1090 1082 if (lq == NULL)
1091 1083 goto cleanup;
1092 1084
1093 1085 /*
1094 1086 * We might not yet have the host...
1095 1087 */
1096 1088 if (host) {
1097 1089 DTRACE_PROBE1(mountd, log_host, host);
1098 1090 lq->ld_host = strdup(host);
1099 1091 if (lq->ld_host == NULL)
1100 1092 goto cleanup;
1101 1093 } else {
1102 1094 DTRACE_PROBE(mountd, log_no_host);
1103 1095
1104 1096 lq->ld_netid = strdup(transp->xp_netid);
1105 1097 if (lq->ld_netid == NULL)
1106 1098 goto cleanup;
1107 1099
1108 1100 lq->ld_nb = calloc(1, sizeof (struct netbuf));
1109 1101 if (lq->ld_nb == NULL)
1110 1102 goto cleanup;
1111 1103
1112 1104 nb = svc_getrpccaller(transp);
1113 1105 if (nb == NULL) {
1114 1106 DTRACE_PROBE(mountd, e__nb__enqueue);
1115 1107 goto cleanup;
1116 1108 }
1117 1109
1118 1110 DTRACE_PROBE(mountd, nb_set_enqueue);
1119 1111
1120 1112 lq->ld_nb->maxlen = nb->maxlen;
1121 1113 lq->ld_nb->len = nb->len;
1122 1114
1123 1115 lq->ld_nb->buf = malloc(lq->ld_nb->len);
1124 1116 if (lq->ld_nb->buf == NULL)
1125 1117 goto cleanup;
1126 1118
1127 1119 bcopy(nb->buf, lq->ld_nb->buf, lq->ld_nb->len);
1128 1120 }
1129 1121
1130 1122 lq->ld_path = strdup(path);
1131 1123 if (lq->ld_path == NULL)
1132 1124 goto cleanup;
1133 1125
1134 1126 if (!error) {
1135 1127 lq->ld_rpath = strdup(rpath);
1136 1128 if (lq->ld_rpath == NULL)
1137 1129 goto cleanup;
1138 1130 }
1139 1131
1140 1132 lq->ld_status = status;
1141 1133
1142 1134 /*
1143 1135 * Add to the tail of the logging queue.
1144 1136 */
1145 1137 (void) mutex_lock(&logging_queue_lock);
1146 1138 if (logging_tail == NULL) {
1147 1139 logging_tail = logging_head = lq;
1148 1140 } else {
1149 1141 logging_tail->ld_next = lq;
1150 1142 logging_tail = lq;
1151 1143 }
1152 1144 (void) cond_signal(&logging_queue_cv);
1153 1145 (void) mutex_unlock(&logging_queue_lock);
1154 1146
1155 1147 return (TRUE);
1156 1148
1157 1149 cleanup:
1158 1150
1159 1151 free_logging_data(lq);
1160 1152
1161 1153 return (FALSE);
1162 1154 }
1163 1155
1164 1156
1165 1157 #define CLN_CLNAMES (1 << 0)
1166 1158 #define CLN_HOST (1 << 1)
1167 1159
1168 1160 static void
1169 1161 cln_init_common(struct cln *cln, SVCXPRT *transp, char *netid,
1170 1162 struct netbuf *nbuf)
1171 1163 {
1172 1164 if ((cln->transp = transp) != NULL) {
1173 1165 assert(netid == NULL && nbuf == NULL);
1174 1166 cln->netid = transp->xp_netid;
1175 1167 cln->nbuf = svc_getrpccaller(transp);
1176 1168 } else {
1177 1169 cln->netid = netid;
1178 1170 cln->nbuf = nbuf;
1179 1171 }
1180 1172
1181 1173 cln->nconf = NULL;
1182 1174 cln->clnames = NULL;
1183 1175 cln->host = NULL;
1184 1176
1185 1177 cln->flags = 0;
1186 1178 }
1187 1179
1188 1180 void
1189 1181 cln_init(struct cln *cln, SVCXPRT *transp)
1190 1182 {
1191 1183 cln_init_common(cln, transp, NULL, NULL);
1192 1184 }
1193 1185
1194 1186 void
1195 1187 cln_init_lazy(struct cln *cln, char *netid, struct netbuf *nbuf)
1196 1188 {
1197 1189 cln_init_common(cln, NULL, netid, nbuf);
1198 1190 }
1199 1191
1200 1192 void
1201 1193 cln_fini(struct cln *cln)
1202 1194 {
1203 1195 if (cln->nconf != NULL)
1204 1196 freenetconfigent(cln->nconf);
1205 1197
1206 1198 if (cln->clnames != NULL)
1207 1199 netdir_free(cln->clnames, ND_HOSTSERVLIST);
1208 1200
1209 1201 free(cln->host);
1210 1202 }
1211 1203
1212 1204 struct netbuf *
1213 1205 cln_getnbuf(struct cln *cln)
1214 1206 {
1215 1207 return (cln->nbuf);
1216 1208 }
1217 1209
1218 1210 struct nd_hostservlist *
1219 1211 cln_getclientsnames(struct cln *cln)
1220 1212 {
1221 1213 if ((cln->flags & CLN_CLNAMES) == 0) {
1222 1214 /*
1223 1215 * nconf is not needed if we do not have nbuf (see
1224 1216 * cln_gethost() too), so we check for nbuf and in a case it is
1225 1217 * NULL we do not try to get nconf.
1226 1218 */
1227 1219 if (cln->netid != NULL && cln->nbuf != NULL) {
1228 1220 cln->nconf = getnetconfigent(cln->netid);
1229 1221 if (cln->nconf == NULL)
1230 1222 syslog(LOG_ERR, "%s: getnetconfigent failed",
1231 1223 cln->netid);
1232 1224 }
1233 1225
1234 1226 if (cln->nconf != NULL && cln->nbuf != NULL)
1235 1227 (void) __netdir_getbyaddr_nosrv(cln->nconf,
1236 1228 &cln->clnames, cln->nbuf);
1237 1229
1238 1230 cln->flags |= CLN_CLNAMES;
1239 1231 }
1240 1232
1241 1233 return (cln->clnames);
1242 1234 }
1243 1235
1244 1236 /*
1245 1237 * Return B_TRUE if the host is already available at no cost
1246 1238 */
1247 1239 boolean_t
1248 1240 cln_havehost(struct cln *cln)
1249 1241 {
1250 1242 return ((cln->flags & (CLN_CLNAMES | CLN_HOST)) != 0);
1251 1243 }
1252 1244
1253 1245 char *
1254 1246 cln_gethost(struct cln *cln)
1255 1247 {
1256 1248 if (cln_getclientsnames(cln) != NULL)
1257 1249 return (cln->clnames->h_hostservs[0].h_host);
1258 1250
1259 1251 if ((cln->flags & CLN_HOST) == 0) {
1260 1252 if (cln->nconf == NULL || cln->nbuf == NULL) {
1261 1253 cln->host = strdup("(anon)");
1262 1254 } else {
1263 1255 char host[MAXIPADDRLEN];
1264 1256
1265 1257 if (strcmp(cln->nconf->nc_protofmly, NC_INET) == 0) {
1266 1258 struct sockaddr_in *sa;
1267 1259
1268 1260 /* LINTED pointer alignment */
1269 1261 sa = (struct sockaddr_in *)(cln->nbuf->buf);
1270 1262 (void) inet_ntoa_r(sa->sin_addr, host);
1271 1263
1272 1264 cln->host = strdup(host);
1273 1265 } else if (strcmp(cln->nconf->nc_protofmly,
1274 1266 NC_INET6) == 0) {
1275 1267 struct sockaddr_in6 *sa;
1276 1268
1277 1269 /* LINTED pointer alignment */
1278 1270 sa = (struct sockaddr_in6 *)(cln->nbuf->buf);
1279 1271 (void) inet_ntop(AF_INET6,
1280 1272 sa->sin6_addr.s6_addr,
1281 1273 host, INET6_ADDRSTRLEN);
1282 1274
1283 1275 cln->host = strdup(host);
1284 1276 } else {
1285 1277 syslog(LOG_ERR, gettext("Client's address is "
1286 1278 "neither IPv4 nor IPv6"));
1287 1279
1288 1280 cln->host = strdup("(anon)");
1289 1281 }
1290 1282 }
1291 1283
1292 1284 cln->flags |= CLN_HOST;
1293 1285 }
1294 1286
1295 1287 return (cln->host);
1296 1288 }
1297 1289
1298 1290 /*
1299 1291 * Check mount requests, add to mounted list if ok
1300 1292 */
1301 1293 static int
1302 1294 mount(struct svc_req *rqstp)
1303 1295 {
1304 1296 SVCXPRT *transp;
1305 1297 int version, vers;
1306 1298 struct fhstatus fhs;
1307 1299 struct mountres3 mountres3;
1308 1300 char fh[FHSIZE3];
1309 1301 int len = FHSIZE3;
1310 1302 char *path, rpath[MAXPATHLEN];
1311 1303 share_t *sh = NULL;
1312 1304 struct cln cln;
1313 1305 char *host = NULL;
1314 1306 int error = 0, lofs_tried = 0, enqueued;
1315 1307 int flavor_list[MAX_FLAVORS];
1316 1308 int flavor_count;
1317 1309 ucred_t *uc = NULL;
1318 1310
1319 1311 int audit_status;
1320 1312
1321 1313 transp = rqstp->rq_xprt;
1322 1314 version = rqstp->rq_vers;
1323 1315 path = NULL;
1324 1316
1325 1317 if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
1326 1318 svcerr_decode(transp);
1327 1319 return (EACCES);
1328 1320 }
1329 1321
1330 1322 cln_init(&cln, transp);
1331 1323
1332 1324 /*
1333 1325 * Put off getting the name for the client until we
1334 1326 * need it. This is a performance gain. If we are logging,
1335 1327 * then we don't care about performance and might as well
1336 1328 * get the host name now in case we need to spit out an
1337 1329 * error message.
1338 1330 */
1339 1331 if (verbose) {
1340 1332 DTRACE_PROBE(mountd, name_by_verbose);
1341 1333 if ((host = cln_gethost(&cln)) == NULL) {
1342 1334 /*
1343 1335 * We failed to get a name for the client, even
1344 1336 * 'anon', probably because we ran out of memory.
1345 1337 * In this situation it doesn't make sense to
1346 1338 * allow the mount to succeed.
1347 1339 */
1348 1340 error = EACCES;
1349 1341 goto reply;
1350 1342 }
1351 1343 }
1352 1344
1353 1345 /*
1354 1346 * If the version being used is less than the minimum version,
1355 1347 * the filehandle translation should not be provided to the
1356 1348 * client.
1357 1349 */
1358 1350 if (rejecting || version < mount_vers_min) {
1359 1351 if (verbose)
1360 1352 syslog(LOG_NOTICE, "Rejected mount: %s for %s",
1361 1353 host, path);
1362 1354 error = EACCES;
1363 1355 goto reply;
1364 1356 }
1365 1357
1366 1358 /*
1367 1359 * Trusted Extension doesn't support nfsv2. nfsv2 client
1368 1360 * uses MOUNT protocol v1 and v2. To prevent circumventing
1369 1361 * TX label policy via using nfsv2 client, reject a mount
1370 1362 * request with version less than 3 and log an error.
1371 1363 */
1372 1364 if (is_system_labeled()) {
1373 1365 if (version < 3) {
1374 1366 if (verbose)
1375 1367 syslog(LOG_ERR,
1376 1368 "Rejected mount: TX doesn't support NFSv2");
1377 1369 error = EACCES;
1378 1370 goto reply;
1379 1371 }
1380 1372 }
1381 1373
1382 1374 /*
1383 1375 * Get the real path (no symbolic links in it)
1384 1376 */
1385 1377 if (realpath(path, rpath) == NULL) {
1386 1378 error = errno;
1387 1379 if (verbose)
1388 1380 syslog(LOG_ERR,
1389 1381 "mount request: realpath: %s: %m", path);
1390 1382 if (error == ENOENT)
1391 1383 error = mount_enoent_error(&cln, path, rpath,
1392 1384 flavor_list);
1393 1385 goto reply;
1394 1386 }
1395 1387
1396 1388 if ((sh = findentry(rpath)) == NULL &&
1397 1389 (sh = find_lofsentry(rpath, &lofs_tried)) == NULL) {
1398 1390 error = EACCES;
1399 1391 goto reply;
1400 1392 }
1401 1393
1402 1394 /*
1403 1395 * Check if this is a "nosub" only export, in which case, mounting
1404 1396 * subdirectories isn't allowed. Bug 1184573.
1405 1397 */
1406 1398 if (checkrootmount(sh, rpath) == 0) {
1407 1399 error = EACCES;
1408 1400 goto reply;
1409 1401 }
1410 1402
1411 1403 if (newopts(sh->sh_opts))
1412 1404 flavor_count = getclientsflavors_new(sh, &cln, flavor_list);
1413 1405 else
1414 1406 flavor_count = getclientsflavors_old(sh, &cln, flavor_list);
1415 1407
1416 1408 if (flavor_count == 0) {
1417 1409 error = EACCES;
1418 1410 goto reply;
1419 1411 }
1420 1412
1421 1413 /*
1422 1414 * Check MAC policy here. The server side policy should be
1423 1415 * consistent with client side mount policy, i.e.
1424 1416 * - we disallow an admin_low unlabeled client to mount
1425 1417 * - we disallow mount from a lower labeled client.
1426 1418 */
1427 1419 if (is_system_labeled()) {
1428 1420 m_label_t *clabel = NULL;
1429 1421 m_label_t *slabel = NULL;
1430 1422 m_label_t admin_low;
1431 1423
1432 1424 if (svc_getcallerucred(rqstp->rq_xprt, &uc) != 0) {
1433 1425 syslog(LOG_ERR,
1434 1426 "mount request: Failed to get caller's ucred : %m");
1435 1427 error = EACCES;
1436 1428 goto reply;
1437 1429 }
1438 1430 if ((clabel = ucred_getlabel(uc)) == NULL) {
1439 1431 syslog(LOG_ERR,
1440 1432 "mount request: can't get client label from ucred");
1441 1433 error = EACCES;
1442 1434 goto reply;
1443 1435 }
1444 1436
1445 1437 bsllow(&admin_low);
1446 1438 if (blequal(&admin_low, clabel)) {
1447 1439 struct sockaddr *ca;
1448 1440 tsol_tpent_t *tp;
1449 1441
1450 1442 ca = (struct sockaddr *)(void *)svc_getrpccaller(
1451 1443 rqstp->rq_xprt)->buf;
1452 1444 if (ca == NULL) {
1453 1445 error = EACCES;
1454 1446 goto reply;
1455 1447 }
1456 1448 /*
1457 1449 * get trusted network template associated
1458 1450 * with the client.
1459 1451 */
1460 1452 tp = get_client_template(ca);
1461 1453 if (tp == NULL || tp->host_type != SUN_CIPSO) {
1462 1454 if (tp != NULL)
1463 1455 tsol_freetpent(tp);
1464 1456 error = EACCES;
1465 1457 goto reply;
1466 1458 }
1467 1459 tsol_freetpent(tp);
1468 1460 } else {
1469 1461 if ((slabel = m_label_alloc(MAC_LABEL)) == NULL) {
1470 1462 error = EACCES;
1471 1463 goto reply;
1472 1464 }
1473 1465
1474 1466 if (getlabel(rpath, slabel) != 0) {
1475 1467 m_label_free(slabel);
1476 1468 error = EACCES;
1477 1469 goto reply;
1478 1470 }
1479 1471
1480 1472 if (!bldominates(clabel, slabel)) {
1481 1473 m_label_free(slabel);
1482 1474 error = EACCES;
1483 1475 goto reply;
1484 1476 }
1485 1477 m_label_free(slabel);
1486 1478 }
1487 1479 }
1488 1480
1489 1481 /*
1490 1482 * Now get the filehandle.
1491 1483 *
1492 1484 * NFS V2 clients get a 32 byte filehandle.
1493 1485 * NFS V3 clients get a 32 or 64 byte filehandle, depending on
1494 1486 * the embedded FIDs.
1495 1487 */
1496 1488 vers = (version == MOUNTVERS3) ? NFS_V3 : NFS_VERSION;
1497 1489
1498 1490 /* LINTED pointer alignment */
1499 1491 while (nfs_getfh(rpath, vers, &len, fh) < 0) {
1500 1492 if (errno == EINVAL &&
1501 1493 (sh = find_lofsentry(rpath, &lofs_tried)) != NULL) {
1502 1494 errno = 0;
1503 1495 continue;
1504 1496 }
1505 1497 error = errno == EINVAL ? EACCES : errno;
1506 1498 syslog(LOG_DEBUG, "mount request: getfh failed on %s: %m",
1507 1499 path);
1508 1500 break;
1509 1501 }
1510 1502
1511 1503 if (version == MOUNTVERS3) {
1512 1504 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len = len;
1513 1505 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val = fh;
1514 1506 } else {
1515 1507 bcopy(fh, &fhs.fhstatus_u.fhs_fhandle, NFS_FHSIZE);
1516 1508 }
1517 1509
1518 1510 reply:
1519 1511 if (uc != NULL)
1520 1512 ucred_free(uc);
1521 1513
1522 1514 switch (version) {
1523 1515 case MOUNTVERS:
1524 1516 case MOUNTVERS_POSIX:
1525 1517 if (error == EINVAL)
1526 1518 fhs.fhs_status = NFSERR_ACCES;
1527 1519 else if (error == EREMOTE)
1528 1520 fhs.fhs_status = NFSERR_REMOTE;
1529 1521 else
1530 1522 fhs.fhs_status = error;
1531 1523
1532 1524 if (!svc_sendreply(transp, xdr_fhstatus, (char *)&fhs))
1533 1525 log_cant_reply_cln(&cln);
1534 1526
1535 1527 audit_status = fhs.fhs_status;
1536 1528 break;
1537 1529
1538 1530 case MOUNTVERS3:
1539 1531 if (!error) {
1540 1532 mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_val =
1541 1533 flavor_list;
1542 1534 mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_len =
1543 1535 flavor_count;
1544 1536
1545 1537 } else if (error == ENAMETOOLONG)
1546 1538 error = MNT3ERR_NAMETOOLONG;
1547 1539
1548 1540 mountres3.fhs_status = error;
1549 1541 if (!svc_sendreply(transp, xdr_mountres3, (char *)&mountres3))
1550 1542 log_cant_reply_cln(&cln);
1551 1543
1552 1544 audit_status = mountres3.fhs_status;
1553 1545 break;
1554 1546 }
1555 1547
1556 1548 if (cln_havehost(&cln))
1557 1549 host = cln_gethost(&cln);
1558 1550
1559 1551 if (verbose)
1560 1552 syslog(LOG_NOTICE, "MOUNT: %s %s %s",
1561 1553 (host == NULL) ? "unknown host" : host,
1562 1554 error ? "denied" : "mounted", path);
1563 1555
1564 1556 /*
1565 1557 * If we can not create a queue entry, go ahead and do it
1566 1558 * in the context of this thread.
1567 1559 */
1568 1560 enqueued = enqueue_logging_data(host, transp, path, rpath,
1569 1561 audit_status, error);
1570 1562 if (enqueued == FALSE) {
1571 1563 if (host == NULL) {
1572 1564 DTRACE_PROBE(mountd, name_by_in_thread);
1573 1565 host = cln_gethost(&cln);
1574 1566 }
1575 1567
1576 1568 DTRACE_PROBE(mountd, logged_in_thread);
1577 1569 audit_mountd_mount(host, path, audit_status); /* BSM */
1578 1570 if (!error)
1579 1571 mntlist_new(host, rpath); /* add entry to mount list */
1580 1572 }
1581 1573
1582 1574 if (path != NULL)
1583 1575 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
1584 1576
1585 1577 if (sh)
1586 1578 sharefree(sh);
1587 1579
1588 1580 cln_fini(&cln);
1589 1581
1590 1582 return (error);
1591 1583 }
1592 1584
1593 1585 /*
1594 1586 * Determine whether two paths are within the same file system.
1595 1587 * Returns nonzero (true) if paths are the same, zero (false) if
1596 1588 * they are different. If an error occurs, return false.
1597 1589 *
1598 1590 * Use the actual FSID if it's available (via getattrat()); otherwise,
1599 1591 * fall back on st_dev.
1600 1592 *
1601 1593 * With ZFS snapshots, st_dev differs from the regular file system
1602 1594 * versus the snapshot. But the fsid is the same throughout. Thus
1603 1595 * the fsid is a better test.
1604 1596 */
1605 1597 static int
1606 1598 same_file_system(const char *path1, const char *path2)
1607 1599 {
1608 1600 uint64_t fsid1, fsid2;
1609 1601 struct stat64 st1, st2;
1610 1602 nvlist_t *nvl1 = NULL;
1611 1603 nvlist_t *nvl2 = NULL;
1612 1604
1613 1605 if ((getattrat(AT_FDCWD, XATTR_VIEW_READONLY, path1, &nvl1) == 0) &&
1614 1606 (getattrat(AT_FDCWD, XATTR_VIEW_READONLY, path2, &nvl2) == 0) &&
1615 1607 (nvlist_lookup_uint64(nvl1, A_FSID, &fsid1) == 0) &&
1616 1608 (nvlist_lookup_uint64(nvl2, A_FSID, &fsid2) == 0)) {
1617 1609 nvlist_free(nvl1);
1618 1610 nvlist_free(nvl2);
1619 1611 /*
1620 1612 * We have found fsid's for both paths.
1621 1613 */
1622 1614
1623 1615 if (fsid1 == fsid2)
1624 1616 return (B_TRUE);
1625 1617
1626 1618 return (B_FALSE);
1627 1619 }
1628 1620
1629 1621 nvlist_free(nvl1);
1630 1622 nvlist_free(nvl2);
1631 1623
1632 1624 /*
1633 1625 * We were unable to find fsid's for at least one of the paths.
1634 1626 * fall back on st_dev.
1635 1627 */
1636 1628
1637 1629 if (stat64(path1, &st1) < 0) {
1638 1630 syslog(LOG_NOTICE, "%s: %m", path1);
1639 1631 return (B_FALSE);
1640 1632 }
1641 1633 if (stat64(path2, &st2) < 0) {
1642 1634 syslog(LOG_NOTICE, "%s: %m", path2);
1643 1635 return (B_FALSE);
1644 1636 }
1645 1637
1646 1638 if (st1.st_dev == st2.st_dev)
1647 1639 return (B_TRUE);
1648 1640
1649 1641 return (B_FALSE);
1650 1642 }
1651 1643
1652 1644 share_t *
1653 1645 findentry(char *path)
1654 1646 {
1655 1647 share_t *sh = NULL;
1656 1648 struct sh_list *shp;
1657 1649 char *p1, *p2;
1658 1650
1659 1651 check_sharetab();
1660 1652
1661 1653 (void) rw_rdlock(&sharetab_lock);
1662 1654
1663 1655 for (shp = share_list; shp; shp = shp->shl_next) {
1664 1656 sh = shp->shl_sh;
1665 1657 for (p1 = sh->sh_path, p2 = path; *p1 == *p2; p1++, p2++)
1666 1658 if (*p1 == '\0')
1667 1659 goto done; /* exact match */
1668 1660
1669 1661 /*
1670 1662 * Now compare the pathnames for three cases:
1671 1663 *
1672 1664 * Parent: /export/foo (no trailing slash on parent)
1673 1665 * Child: /export/foo/bar
1674 1666 *
1675 1667 * Parent: /export/foo/ (trailing slash on parent)
1676 1668 * Child: /export/foo/bar
1677 1669 *
1678 1670 * Parent: /export/foo/ (no trailing slash on child)
1679 1671 * Child: /export/foo
1680 1672 */
1681 1673 if ((*p1 == '\0' && *p2 == '/') ||
1682 1674 (*p1 == '\0' && *(p1-1) == '/') ||
1683 1675 (*p2 == '\0' && *p1 == '/' && *(p1+1) == '\0')) {
1684 1676 /*
1685 1677 * We have a subdirectory. Test whether the
1686 1678 * subdirectory is in the same file system.
1687 1679 */
1688 1680 if (same_file_system(path, sh->sh_path))
1689 1681 goto done;
1690 1682 }
1691 1683 }
1692 1684 done:
1693 1685 sh = shp ? sharedup(sh) : NULL;
1694 1686
1695 1687 (void) rw_unlock(&sharetab_lock);
1696 1688
1697 1689 return (sh);
1698 1690 }
1699 1691
1700 1692
1701 1693 static int
1702 1694 is_substring(char **mntp, char **path)
1703 1695 {
1704 1696 char *p1 = *mntp, *p2 = *path;
1705 1697
1706 1698 if (*p1 == '\0' && *p2 == '\0') /* exact match */
1707 1699 return (1);
1708 1700 else if (*p1 == '\0' && *p2 == '/')
1709 1701 return (1);
1710 1702 else if (*p1 == '\0' && *(p1-1) == '/') {
1711 1703 *path = --p2; /* we need the slash in p2 */
1712 1704 return (1);
1713 1705 } else if (*p2 == '\0') {
1714 1706 while (*p1 == '/')
1715 1707 p1++;
1716 1708 if (*p1 == '\0') /* exact match */
1717 1709 return (1);
1718 1710 }
1719 1711 return (0);
1720 1712 }
1721 1713
1722 1714 /*
1723 1715 * find_lofsentry() searches for the real path which this requested LOFS path
1724 1716 * (rpath) shadows. If found, it will return the sharetab entry of
1725 1717 * the real path that corresponds to the LOFS path.
1726 1718 * We first search mnttab to see if the requested path is an automounted
1727 1719 * path. If it is an automounted path, it will trigger the mount by stat()ing
1728 1720 * the requested path. Note that it is important to check that this path is
1729 1721 * actually an automounted path, otherwise we would stat() a path which may
1730 1722 * turn out to be NFS and block indefinitely on a dead server. The automounter
1731 1723 * times-out if the server is dead, so there's no risk of hanging this
1732 1724 * thread waiting for stat().
1733 1725 * After the mount has been triggered (if necessary), we look for a
1734 1726 * mountpoint of type LOFS (by searching /etc/mnttab again) which
1735 1727 * is a substring of the rpath. If found, we construct a new path by
1736 1728 * concatenating the mnt_special and the remaining of rpath, call findentry()
1737 1729 * to make sure the 'real path' is shared.
1738 1730 */
1739 1731 static share_t *
1740 1732 find_lofsentry(char *rpath, int *done_flag)
1741 1733 {
1742 1734 struct stat r_stbuf;
1743 1735 mntlist_t *ml, *mntl, *mntpnt = NULL;
1744 1736 share_t *retcode = NULL;
1745 1737 char tmp_path[MAXPATHLEN];
1746 1738 int mntpnt_len = 0, tmp;
1747 1739 char *p1, *p2;
1748 1740
1749 1741 if ((*done_flag)++)
1750 1742 return (retcode);
1751 1743
1752 1744 /*
1753 1745 * While fsgetmntlist() uses lockf() to
1754 1746 * lock the mnttab before reading it in,
1755 1747 * the lock ignores threads in the same process.
1756 1748 * Read in the mnttab with the protection of a mutex.
1757 1749 */
1758 1750 (void) mutex_lock(&mnttab_lock);
1759 1751 mntl = fsgetmntlist();
1760 1752 (void) mutex_unlock(&mnttab_lock);
1761 1753
1762 1754 /*
1763 1755 * Obtain the mountpoint for the requested path.
1764 1756 */
1765 1757 for (ml = mntl; ml; ml = ml->mntl_next) {
1766 1758 for (p1 = ml->mntl_mnt->mnt_mountp, p2 = rpath;
1767 1759 *p1 == *p2 && *p1; p1++, p2++)
1768 1760 ;
1769 1761 if (is_substring(&p1, &p2) &&
1770 1762 (tmp = strlen(ml->mntl_mnt->mnt_mountp)) >= mntpnt_len) {
1771 1763 mntpnt = ml;
1772 1764 mntpnt_len = tmp;
1773 1765 }
1774 1766 }
1775 1767
1776 1768 /*
1777 1769 * If the path needs to be autoFS mounted, trigger the mount by
1778 1770 * stat()ing it. This is determined by checking whether the
1779 1771 * mountpoint we just found is of type autofs.
1780 1772 */
1781 1773 if (mntpnt != NULL &&
1782 1774 strcmp(mntpnt->mntl_mnt->mnt_fstype, "autofs") == 0) {
1783 1775 /*
1784 1776 * The requested path is a substring of an autoFS filesystem.
1785 1777 * Trigger the mount.
1786 1778 */
1787 1779 if (stat(rpath, &r_stbuf) < 0) {
1788 1780 if (verbose)
1789 1781 syslog(LOG_NOTICE, "%s: %m", rpath);
1790 1782 goto done;
1791 1783 }
1792 1784 if ((r_stbuf.st_mode & S_IFMT) == S_IFDIR) {
1793 1785 /*
1794 1786 * The requested path is a directory, stat(2) it
1795 1787 * again with a trailing '.' to force the autoFS
1796 1788 * module to trigger the mount of indirect
1797 1789 * automount entries, such as /net/jurassic/.
1798 1790 */
1799 1791 if (strlen(rpath) + 2 > MAXPATHLEN) {
1800 1792 if (verbose) {
1801 1793 syslog(LOG_NOTICE,
1802 1794 "%s/.: exceeds MAXPATHLEN %d",
1803 1795 rpath, MAXPATHLEN);
1804 1796 }
1805 1797 goto done;
1806 1798 }
1807 1799 (void) strcpy(tmp_path, rpath);
1808 1800 (void) strcat(tmp_path, "/.");
1809 1801
1810 1802 if (stat(tmp_path, &r_stbuf) < 0) {
1811 1803 if (verbose)
1812 1804 syslog(LOG_NOTICE, "%s: %m", tmp_path);
1813 1805 goto done;
1814 1806 }
1815 1807 }
1816 1808
1817 1809 /*
1818 1810 * The mount has been triggered, re-read mnttab to pick up
1819 1811 * the changes made by autoFS.
1820 1812 */
1821 1813 fsfreemntlist(mntl);
1822 1814 (void) mutex_lock(&mnttab_lock);
1823 1815 mntl = fsgetmntlist();
1824 1816 (void) mutex_unlock(&mnttab_lock);
1825 1817 }
1826 1818
1827 1819 /*
1828 1820 * The autoFS mountpoint has been triggered if necessary,
1829 1821 * now search mnttab again to determine if the requested path
1830 1822 * is an LOFS mount of a shared path.
1831 1823 */
1832 1824 mntpnt_len = 0;
1833 1825 for (ml = mntl; ml; ml = ml->mntl_next) {
1834 1826 if (strcmp(ml->mntl_mnt->mnt_fstype, "lofs"))
1835 1827 continue;
1836 1828
1837 1829 for (p1 = ml->mntl_mnt->mnt_mountp, p2 = rpath;
1838 1830 *p1 == *p2 && *p1; p1++, p2++)
1839 1831 ;
1840 1832
1841 1833 if (is_substring(&p1, &p2) &&
1842 1834 ((tmp = strlen(ml->mntl_mnt->mnt_mountp)) >= mntpnt_len)) {
1843 1835 mntpnt_len = tmp;
1844 1836
1845 1837 if ((strlen(ml->mntl_mnt->mnt_special) + strlen(p2)) >
1846 1838 MAXPATHLEN) {
1847 1839 if (verbose) {
1848 1840 syslog(LOG_NOTICE, "%s%s: exceeds %d",
1849 1841 ml->mntl_mnt->mnt_special, p2,
1850 1842 MAXPATHLEN);
1851 1843 }
1852 1844 if (retcode)
1853 1845 sharefree(retcode);
1854 1846 retcode = NULL;
1855 1847 goto done;
1856 1848 }
1857 1849
1858 1850 (void) strcpy(tmp_path, ml->mntl_mnt->mnt_special);
1859 1851 (void) strcat(tmp_path, p2);
1860 1852 if (retcode)
1861 1853 sharefree(retcode);
1862 1854 retcode = findentry(tmp_path);
1863 1855 }
1864 1856 }
1865 1857
1866 1858 if (retcode) {
1867 1859 assert(strlen(tmp_path) > 0);
1868 1860 (void) strcpy(rpath, tmp_path);
1869 1861 }
1870 1862
1871 1863 done:
1872 1864 fsfreemntlist(mntl);
1873 1865 return (retcode);
1874 1866 }
1875 1867
1876 1868 /*
1877 1869 * Determine whether an access list grants rights to a particular host.
1878 1870 * We match on aliases of the hostname as well as on the canonical name.
1879 1871 * Names in the access list may be either hosts or netgroups; they're
1880 1872 * not distinguished syntactically. We check for hosts first because
1881 1873 * it's cheaper, then try netgroups.
1882 1874 *
1883 1875 * Return values:
1884 1876 * 1 - access is granted
1885 1877 * 0 - access is denied
1886 1878 * -1 - an error occured
1887 1879 */
1888 1880 int
1889 1881 in_access_list(struct cln *cln,
1890 1882 char *access_list) /* N.B. we clobber this "input" parameter */
1891 1883 {
1892 1884 char addr[INET_ADDRSTRLEN];
1893 1885 char buff[256];
1894 1886 int nentries = 0;
1895 1887 char *cstr = access_list;
1896 1888 char *gr = access_list;
1897 1889 int i;
1898 1890 int response;
1899 1891 int ret;
1900 1892 struct netbuf *pnb;
1901 1893 struct nd_hostservlist *clnames = NULL;
1902 1894
1903 1895 /* If no access list - then it's unrestricted */
1904 1896 if (access_list == NULL || *access_list == '\0')
1905 1897 return (1);
1906 1898
1907 1899 if ((pnb = cln_getnbuf(cln)) == NULL)
1908 1900 return (-1);
1909 1901
1910 1902 for (;;) {
1911 1903 if ((cstr = strpbrk(cstr, "[:")) != NULL) {
1912 1904 if (*cstr == ':') {
1913 1905 *cstr = '\0';
1914 1906 } else {
1915 1907 assert(*cstr == '[');
1916 1908 cstr = strchr(cstr + 1, ']');
1917 1909 if (cstr == NULL)
1918 1910 return (-1);
1919 1911 cstr++;
1920 1912 continue;
1921 1913 }
1922 1914 }
1923 1915
1924 1916 /*
1925 1917 * If the list name has a '-' prepended then a match of
1926 1918 * the following name implies failure instead of success.
1927 1919 */
1928 1920 if (*gr == '-') {
1929 1921 response = 0;
1930 1922 gr++;
1931 1923 } else {
1932 1924 response = 1;
1933 1925 }
1934 1926
1935 1927 /*
1936 1928 * First check if we have '@' entry, as it doesn't
1937 1929 * require client hostname.
1938 1930 */
1939 1931 if (*gr == '@') {
1940 1932 gr++;
1941 1933
1942 1934 /* Netname support */
1943 1935 if (!isdigit(*gr) && *gr != '[') {
1944 1936 struct netent n, *np;
1945 1937
1946 1938 if ((np = getnetbyname_r(gr, &n, buff,
1947 1939 sizeof (buff))) != NULL &&
1948 1940 np->n_net != 0) {
1949 1941 while ((np->n_net & 0xFF000000u) == 0)
1950 1942 np->n_net <<= 8;
1951 1943 np->n_net = htonl(np->n_net);
1952 1944 if (inet_ntop(AF_INET, &np->n_net, addr,
1953 1945 INET_ADDRSTRLEN) == NULL)
1954 1946 break;
1955 1947 ret = inet_matchaddr(pnb->buf, addr);
1956 1948 if (ret == -1) {
1957 1949 if (errno == EINVAL) {
1958 1950 syslog(LOG_WARNING,
1959 1951 "invalid access "
1960 1952 "list entry: %s",
1961 1953 addr);
1962 1954 }
1963 1955 return (-1);
1964 1956 } else if (ret == 1) {
1965 1957 return (response);
1966 1958 }
1967 1959 }
1968 1960 } else {
1969 1961 ret = inet_matchaddr(pnb->buf, gr);
1970 1962 if (ret == -1) {
1971 1963 if (errno == EINVAL) {
1972 1964 syslog(LOG_WARNING,
1973 1965 "invalid access list "
1974 1966 "entry: %s", gr);
1975 1967 }
1976 1968 return (-1);
1977 1969 } else if (ret == 1) {
1978 1970 return (response);
1979 1971 }
1980 1972 }
1981 1973
1982 1974 goto next;
1983 1975 }
1984 1976
1985 1977 /*
1986 1978 * No other checks can be performed if client address
1987 1979 * can't be resolved.
1988 1980 */
1989 1981 if ((clnames = cln_getclientsnames(cln)) == NULL)
1990 1982 goto next;
1991 1983
1992 1984 /* Otherwise loop through all client hostname aliases */
1993 1985 for (i = 0; i < clnames->h_cnt; i++) {
1994 1986 char *host = clnames->h_hostservs[i].h_host;
1995 1987
1996 1988 /*
1997 1989 * If the list name begins with a dot then
1998 1990 * do a domain name suffix comparison.
1999 1991 * A single dot matches any name with no
2000 1992 * suffix.
2001 1993 */
2002 1994 if (*gr == '.') {
2003 1995 if (*(gr + 1) == '\0') { /* single dot */
2004 1996 if (strchr(host, '.') == NULL)
2005 1997 return (response);
2006 1998 } else {
2007 1999 int off = strlen(host) - strlen(gr);
2008 2000 if (off > 0 &&
2009 2001 strcasecmp(host + off, gr) == 0) {
2010 2002 return (response);
2011 2003 }
2012 2004 }
2013 2005 } else {
2014 2006 /* Just do a hostname match */
2015 2007 if (strcasecmp(gr, host) == 0)
2016 2008 return (response);
2017 2009 }
2018 2010 }
2019 2011
2020 2012 nentries++;
2021 2013
2022 2014 next:
2023 2015 if (cstr == NULL)
2024 2016 break;
2025 2017
2026 2018 gr = ++cstr;
2027 2019 }
2028 2020
2029 2021 if (clnames == NULL)
2030 2022 return (0);
2031 2023
2032 2024 return (netgroup_check(clnames, access_list, nentries));
2033 2025 }
2034 2026
2035 2027
2036 2028 static char *optlist[] = {
2037 2029 #define OPT_RO 0
2038 2030 SHOPT_RO,
2039 2031 #define OPT_RW 1
2040 2032 SHOPT_RW,
2041 2033 #define OPT_ROOT 2
2042 2034 SHOPT_ROOT,
2043 2035 #define OPT_SECURE 3
2044 2036 SHOPT_SECURE,
2045 2037 #define OPT_ANON 4
2046 2038 SHOPT_ANON,
2047 2039 #define OPT_WINDOW 5
2048 2040 SHOPT_WINDOW,
2049 2041 #define OPT_NOSUID 6
2050 2042 SHOPT_NOSUID,
2051 2043 #define OPT_ACLOK 7
2052 2044 SHOPT_ACLOK,
2053 2045 #define OPT_SEC 8
2054 2046 SHOPT_SEC,
2055 2047 #define OPT_NONE 9
2056 2048 SHOPT_NONE,
2057 2049 #define OPT_UIDMAP 10
2058 2050 SHOPT_UIDMAP,
2059 2051 #define OPT_GIDMAP 11
2060 2052 SHOPT_GIDMAP,
2061 2053 NULL
2062 2054 };
2063 2055
2064 2056 static int
2065 2057 map_flavor(char *str)
2066 2058 {
2067 2059 seconfig_t sec;
2068 2060
2069 2061 if (nfs_getseconfig_byname(str, &sec))
2070 2062 return (-1);
2071 2063
2072 2064 return (sec.sc_nfsnum);
2073 2065 }
2074 2066
2075 2067 /*
2076 2068 * If the option string contains a "sec="
2077 2069 * option, then use new option syntax.
2078 2070 */
2079 2071 static int
2080 2072 newopts(char *opts)
2081 2073 {
2082 2074 char *head, *p, *val;
2083 2075
2084 2076 if (!opts || *opts == '\0')
2085 2077 return (0);
2086 2078
2087 2079 head = strdup(opts);
2088 2080 if (head == NULL) {
2089 2081 syslog(LOG_ERR, "opts: no memory");
2090 2082 return (0);
2091 2083 }
2092 2084
2093 2085 p = head;
2094 2086 while (*p) {
2095 2087 if (getsubopt(&p, optlist, &val) == OPT_SEC) {
2096 2088 free(head);
2097 2089 return (1);
2098 2090 }
2099 2091 }
2100 2092
2101 2093 free(head);
2102 2094 return (0);
2103 2095 }
2104 2096
2105 2097 /*
2106 2098 * Given an export and the clients hostname(s)
2107 2099 * determine the security flavors that this
2108 2100 * client is permitted to use.
2109 2101 *
2110 2102 * This routine is called only for "old" syntax, i.e.
2111 2103 * only one security flavor is allowed. So we need
2112 2104 * to determine two things: the particular flavor,
2113 2105 * and whether the client is allowed to use this
2114 2106 * flavor, i.e. is in the access list.
2115 2107 *
2116 2108 * Note that if there is no access list, then the
2117 2109 * default is that access is granted.
2118 2110 */
2119 2111 static int
2120 2112 getclientsflavors_old(share_t *sh, struct cln *cln, int *flavors)
2121 2113 {
2122 2114 char *opts, *p, *val;
2123 2115 boolean_t ok = B_FALSE;
2124 2116 int defaultaccess = 1;
2125 2117 boolean_t reject = B_FALSE;
2126 2118
2127 2119 opts = strdup(sh->sh_opts);
2128 2120 if (opts == NULL) {
2129 2121 syslog(LOG_ERR, "getclientsflavors: no memory");
2130 2122 return (0);
2131 2123 }
2132 2124
2133 2125 flavors[0] = AUTH_SYS;
2134 2126 p = opts;
2135 2127
2136 2128 while (*p) {
2137 2129
2138 2130 switch (getsubopt(&p, optlist, &val)) {
2139 2131 case OPT_SECURE:
2140 2132 flavors[0] = AUTH_DES;
2141 2133 break;
2142 2134
2143 2135 case OPT_RO:
2144 2136 case OPT_RW:
2145 2137 defaultaccess = 0;
2146 2138 if (in_access_list(cln, val) > 0)
2147 2139 ok = B_TRUE;
2148 2140 break;
2149 2141
2150 2142 case OPT_NONE:
2151 2143 defaultaccess = 0;
2152 2144 if (in_access_list(cln, val) > 0)
2153 2145 reject = B_TRUE;
2154 2146 }
2155 2147 }
2156 2148
2157 2149 free(opts);
2158 2150
2159 2151 /* none takes precedence over everything else */
2160 2152 if (reject)
2161 2153 ok = B_FALSE;
2162 2154
2163 2155 return (defaultaccess || ok);
2164 2156 }
2165 2157
2166 2158 /*
2167 2159 * Given an export and the clients hostname(s)
2168 2160 * determine the security flavors that this
2169 2161 * client is permitted to use.
2170 2162 *
2171 2163 * This is somewhat more complicated than the "old"
2172 2164 * routine because the options may contain multiple
2173 2165 * security flavors (sec=) each with its own access
2174 2166 * lists. So a client could be granted access based
2175 2167 * on a number of security flavors. Note that the
2176 2168 * type of access might not always be the same, the
2177 2169 * client may get readonly access with one flavor
2178 2170 * and readwrite with another, however the client
2179 2171 * is not told this detail, it gets only the list
2180 2172 * of flavors, and only if the client is using
2181 2173 * version 3 of the mount protocol.
2182 2174 */
2183 2175 static int
2184 2176 getclientsflavors_new(share_t *sh, struct cln *cln, int *flavors)
2185 2177 {
2186 2178 char *opts, *p, *val;
2187 2179 char *lasts;
2188 2180 char *f;
2189 2181 boolean_t defaultaccess = B_TRUE; /* default access is rw */
2190 2182 boolean_t access_ok = B_FALSE;
2191 2183 int count, c;
2192 2184 boolean_t reject = B_FALSE;
2193 2185
2194 2186 opts = strdup(sh->sh_opts);
2195 2187 if (opts == NULL) {
2196 2188 syslog(LOG_ERR, "getclientsflavors: no memory");
2197 2189 return (0);
2198 2190 }
2199 2191
2200 2192 p = opts;
2201 2193 count = c = 0;
2202 2194
2203 2195 while (*p) {
2204 2196 switch (getsubopt(&p, optlist, &val)) {
2205 2197 case OPT_SEC:
2206 2198 if (reject)
2207 2199 access_ok = B_FALSE;
2208 2200
2209 2201 /*
2210 2202 * Before a new sec=xxx option, check if we need
2211 2203 * to move the c index back to the previous count.
2212 2204 */
2213 2205 if (!defaultaccess && !access_ok) {
2214 2206 c = count;
2215 2207 }
2216 2208
2217 2209 /* get all the sec=f1[:f2] flavors */
2218 2210 while ((f = strtok_r(val, ":", &lasts)) != NULL) {
2219 2211 flavors[c++] = map_flavor(f);
2220 2212 val = NULL;
2221 2213 }
2222 2214
2223 2215 /* for a new sec=xxx option, default is rw access */
2224 2216 defaultaccess = B_TRUE;
2225 2217 access_ok = B_FALSE;
2226 2218 reject = B_FALSE;
2227 2219 break;
2228 2220
2229 2221 case OPT_RO:
2230 2222 case OPT_RW:
2231 2223 defaultaccess = B_FALSE;
2232 2224 if (in_access_list(cln, val) > 0)
2233 2225 access_ok = B_TRUE;
2234 2226 break;
2235 2227
2236 2228 case OPT_NONE:
2237 2229 defaultaccess = B_FALSE;
2238 2230 if (in_access_list(cln, val) > 0)
2239 2231 reject = B_TRUE; /* none overides rw/ro */
2240 2232 break;
2241 2233 }
2242 2234 }
2243 2235
2244 2236 if (reject)
2245 2237 access_ok = B_FALSE;
2246 2238
2247 2239 if (!defaultaccess && !access_ok)
2248 2240 c = count;
2249 2241
2250 2242 free(opts);
2251 2243
2252 2244 return (c);
2253 2245 }
2254 2246
2255 2247 /*
2256 2248 * This is a tricky piece of code that parses the
2257 2249 * share options looking for a match on the auth
2258 2250 * flavor that the client is using. If it finds
2259 2251 * a match, then the client is given ro, rw, or
2260 2252 * no access depending whether it is in the access
2261 2253 * list. There is a special case for "secure"
2262 2254 * flavor. Other flavors are values of the new "sec=" option.
2263 2255 */
2264 2256 int
2265 2257 check_client(share_t *sh, struct cln *cln, int flavor, uid_t clnt_uid,
2266 2258 gid_t clnt_gid, uint_t clnt_ngids, gid_t *clnt_gids, uid_t *srv_uid,
2267 2259 gid_t *srv_gid, uint_t *srv_ngids, gid_t **srv_gids)
2268 2260 {
2269 2261 if (newopts(sh->sh_opts))
2270 2262 return (check_client_new(sh, cln, flavor, clnt_uid, clnt_gid,
2271 2263 clnt_ngids, clnt_gids, srv_uid, srv_gid, srv_ngids,
2272 2264 srv_gids));
2273 2265 else
2274 2266 return (check_client_old(sh, cln, flavor, clnt_uid, clnt_gid,
2275 2267 clnt_ngids, clnt_gids, srv_uid, srv_gid, srv_ngids,
2276 2268 srv_gids));
2277 2269 }
2278 2270
2279 2271 extern int _getgroupsbymember(const char *, gid_t[], int, int);
2280 2272
2281 2273 /*
2282 2274 * Get supplemental groups for uid
2283 2275 */
2284 2276 static int
2285 2277 getusergroups(uid_t uid, uint_t *ngrps, gid_t **grps)
2286 2278 {
2287 2279 struct passwd pwd;
2288 2280 char *pwbuf = alloca(pw_size);
2289 2281 gid_t *tmpgrps = alloca(ngroups_max * sizeof (gid_t));
2290 2282 int tmpngrps;
2291 2283
2292 2284 if (getpwuid_r(uid, &pwd, pwbuf, pw_size) == NULL)
2293 2285 return (-1);
2294 2286
2295 2287 tmpgrps[0] = pwd.pw_gid;
2296 2288
2297 2289 tmpngrps = _getgroupsbymember(pwd.pw_name, tmpgrps, ngroups_max, 1);
2298 2290 if (tmpngrps <= 0) {
2299 2291 syslog(LOG_WARNING,
2300 2292 "getusergroups(): Unable to get groups for user %s",
2301 2293 pwd.pw_name);
2302 2294
2303 2295 return (-1);
2304 2296 }
2305 2297
2306 2298 *grps = malloc(tmpngrps * sizeof (gid_t));
2307 2299 if (*grps == NULL) {
2308 2300 syslog(LOG_ERR,
2309 2301 "getusergroups(): Memory allocation failed: %m");
2310 2302
2311 2303 return (-1);
2312 2304 }
2313 2305
2314 2306 *ngrps = tmpngrps;
2315 2307 (void) memcpy(*grps, tmpgrps, tmpngrps * sizeof (gid_t));
2316 2308
2317 2309 return (0);
2318 2310 }
2319 2311
2320 2312 /*
2321 2313 * is_a_number(number)
2322 2314 *
2323 2315 * is the string a number in one of the forms we want to use?
2324 2316 */
2325 2317
2326 2318 static int
2327 2319 is_a_number(char *number)
2328 2320 {
2329 2321 int ret = 1;
2330 2322 int hex = 0;
2331 2323
2332 2324 if (strncmp(number, "0x", 2) == 0) {
2333 2325 number += 2;
2334 2326 hex = 1;
2335 2327 } else if (*number == '-') {
2336 2328 number++; /* skip the minus */
2337 2329 }
2338 2330 while (ret == 1 && *number != '\0') {
2339 2331 if (hex) {
2340 2332 ret = isxdigit(*number++);
2341 2333 } else {
2342 2334 ret = isdigit(*number++);
2343 2335 }
2344 2336 }
2345 2337 return (ret);
2346 2338 }
2347 2339
2348 2340 static boolean_t
2349 2341 get_uid(char *value, uid_t *uid)
2350 2342 {
2351 2343 if (!is_a_number(value)) {
2352 2344 struct passwd *pw;
2353 2345 /*
2354 2346 * in this case it would have to be a
2355 2347 * user name
2356 2348 */
2357 2349 pw = getpwnam(value);
2358 2350 if (pw == NULL)
2359 2351 return (B_FALSE);
2360 2352 *uid = pw->pw_uid;
2361 2353 endpwent();
2362 2354 } else {
2363 2355 uint64_t intval;
2364 2356 intval = strtoull(value, NULL, 0);
2365 2357 if (intval > UID_MAX && intval != -1)
2366 2358 return (B_FALSE);
2367 2359 *uid = (uid_t)intval;
2368 2360 }
2369 2361
2370 2362 return (B_TRUE);
2371 2363 }
2372 2364
2373 2365 static boolean_t
2374 2366 get_gid(char *value, gid_t *gid)
2375 2367 {
2376 2368 if (!is_a_number(value)) {
2377 2369 struct group *gr;
2378 2370 /*
2379 2371 * in this case it would have to be a
2380 2372 * group name
2381 2373 */
2382 2374 gr = getgrnam(value);
2383 2375 if (gr == NULL)
2384 2376 return (B_FALSE);
2385 2377 *gid = gr->gr_gid;
2386 2378 endgrent();
2387 2379 } else {
2388 2380 uint64_t intval;
2389 2381 intval = strtoull(value, NULL, 0);
2390 2382 if (intval > UID_MAX && intval != -1)
2391 2383 return (B_FALSE);
2392 2384 *gid = (gid_t)intval;
2393 2385 }
2394 2386
2395 2387 return (B_TRUE);
2396 2388 }
2397 2389
2398 2390 static int
2399 2391 check_client_old(share_t *sh, struct cln *cln, int flavor, uid_t clnt_uid,
2400 2392 gid_t clnt_gid, uint_t clnt_ngids, gid_t *clnt_gids, uid_t *srv_uid,
2401 2393 gid_t *srv_gid, uint_t *srv_ngids, gid_t **srv_gids)
2402 2394 {
2403 2395 char *opts, *p, *val;
2404 2396 int match; /* Set when a flavor is matched */
2405 2397 int perm = 0; /* Set when "ro", "rw" or "root" is matched */
2406 2398 int list = 0; /* Set when "ro", "rw" is found */
2407 2399 int ro_val = 0; /* Set if ro option is 'ro=' */
2408 2400 int rw_val = 0; /* Set if rw option is 'rw=' */
2409 2401
2410 2402 boolean_t map_deny = B_FALSE;
2411 2403
2412 2404 opts = strdup(sh->sh_opts);
2413 2405 if (opts == NULL) {
2414 2406 syslog(LOG_ERR, "check_client: no memory");
2415 2407 return (0);
2416 2408 }
2417 2409
2418 2410 /*
2419 2411 * If client provided 16 supplemental groups with AUTH_SYS, lookup
2420 2412 * locally for all of them
2421 2413 */
2422 2414 if (flavor == AUTH_SYS && clnt_ngids == NGRPS && ngroups_max > NGRPS)
2423 2415 if (getusergroups(clnt_uid, srv_ngids, srv_gids) == 0)
2424 2416 perm |= NFSAUTH_GROUPS;
2425 2417
2426 2418 p = opts;
2427 2419 match = AUTH_UNIX;
2428 2420
2429 2421 while (*p) {
2430 2422 switch (getsubopt(&p, optlist, &val)) {
2431 2423
2432 2424 case OPT_SECURE:
2433 2425 match = AUTH_DES;
2434 2426
2435 2427 if (perm & NFSAUTH_GROUPS) {
2436 2428 free(*srv_gids);
2437 2429 *srv_ngids = 0;
2438 2430 *srv_gids = NULL;
2439 2431 perm &= ~NFSAUTH_GROUPS;
2440 2432 }
2441 2433
2442 2434 break;
2443 2435
2444 2436 case OPT_RO:
2445 2437 list++;
2446 2438 if (val != NULL)
2447 2439 ro_val++;
2448 2440 if (in_access_list(cln, val) > 0)
2449 2441 perm |= NFSAUTH_RO;
2450 2442 break;
2451 2443
2452 2444 case OPT_RW:
2453 2445 list++;
2454 2446 if (val != NULL)
2455 2447 rw_val++;
2456 2448 if (in_access_list(cln, val) > 0)
2457 2449 perm |= NFSAUTH_RW;
2458 2450 break;
2459 2451
2460 2452 case OPT_ROOT:
2461 2453 /*
2462 2454 * Check if the client is in
2463 2455 * the root list. Only valid
2464 2456 * for AUTH_SYS.
2465 2457 */
2466 2458 if (flavor != AUTH_SYS)
2467 2459 break;
2468 2460
2469 2461 if (val == NULL || *val == '\0')
2470 2462 break;
2471 2463
2472 2464 if (clnt_uid != 0)
2473 2465 break;
2474 2466
2475 2467 if (in_access_list(cln, val) > 0) {
2476 2468 perm |= NFSAUTH_ROOT;
2477 2469 perm |= NFSAUTH_UIDMAP | NFSAUTH_GIDMAP;
2478 2470 map_deny = B_FALSE;
2479 2471
2480 2472 if (perm & NFSAUTH_GROUPS) {
2481 2473 free(*srv_gids);
2482 2474 *srv_ngids = 0;
2483 2475 *srv_gids = NULL;
2484 2476 perm &= ~NFSAUTH_GROUPS;
2485 2477 }
2486 2478 }
2487 2479 break;
2488 2480
2489 2481 case OPT_NONE:
2490 2482 /*
2491 2483 * Check if the client should have no access
2492 2484 * to this share at all. This option behaves
2493 2485 * more like "root" than either "rw" or "ro".
2494 2486 */
2495 2487 if (in_access_list(cln, val) > 0)
2496 2488 perm |= NFSAUTH_DENIED;
2497 2489 break;
2498 2490
2499 2491 case OPT_UIDMAP: {
2500 2492 char *c;
2501 2493 char *n;
2502 2494
2503 2495 /*
2504 2496 * The uidmap is supported for AUTH_SYS only.
2505 2497 */
2506 2498 if (flavor != AUTH_SYS)
2507 2499 break;
2508 2500
2509 2501 if (perm & NFSAUTH_UIDMAP || map_deny)
2510 2502 break;
2511 2503
2512 2504 for (c = val; c != NULL; c = n) {
2513 2505 char *s;
2514 2506 char *al;
2515 2507 uid_t srv;
2516 2508
2517 2509 n = strchr(c, '~');
2518 2510 if (n != NULL)
2519 2511 *n++ = '\0';
2520 2512
2521 2513 s = strchr(c, ':');
2522 2514 if (s != NULL) {
2523 2515 *s++ = '\0';
2524 2516 al = strchr(s, ':');
2525 2517 if (al != NULL)
2526 2518 *al++ = '\0';
2527 2519 }
2528 2520
2529 2521 if (s == NULL || al == NULL)
2530 2522 continue;
2531 2523
2532 2524 if (*c == '\0') {
2533 2525 if (clnt_uid != (uid_t)-1)
2534 2526 continue;
2535 2527 } else if (strcmp(c, "*") != 0) {
2536 2528 uid_t clnt;
2537 2529
2538 2530 if (!get_uid(c, &clnt))
2539 2531 continue;
2540 2532
2541 2533 if (clnt_uid != clnt)
2542 2534 continue;
2543 2535 }
2544 2536
2545 2537 if (*s == '\0')
2546 2538 srv = UID_NOBODY;
2547 2539 else if (!get_uid(s, &srv))
2548 2540 continue;
2549 2541 else if (srv == (uid_t)-1) {
2550 2542 map_deny = B_TRUE;
2551 2543 break;
2552 2544 }
2553 2545
2554 2546 if (in_access_list(cln, al) > 0) {
2555 2547 *srv_uid = srv;
2556 2548 perm |= NFSAUTH_UIDMAP;
2557 2549
2558 2550 if (perm & NFSAUTH_GROUPS) {
2559 2551 free(*srv_gids);
2560 2552 *srv_ngids = 0;
2561 2553 *srv_gids = NULL;
2562 2554 perm &= ~NFSAUTH_GROUPS;
2563 2555 }
2564 2556
2565 2557 break;
2566 2558 }
2567 2559 }
2568 2560
2569 2561 break;
2570 2562 }
2571 2563
2572 2564 case OPT_GIDMAP: {
2573 2565 char *c;
2574 2566 char *n;
2575 2567
2576 2568 /*
2577 2569 * The gidmap is supported for AUTH_SYS only.
2578 2570 */
2579 2571 if (flavor != AUTH_SYS)
2580 2572 break;
2581 2573
2582 2574 if (perm & NFSAUTH_GIDMAP || map_deny)
2583 2575 break;
2584 2576
2585 2577 for (c = val; c != NULL; c = n) {
2586 2578 char *s;
2587 2579 char *al;
2588 2580 gid_t srv;
2589 2581
2590 2582 n = strchr(c, '~');
2591 2583 if (n != NULL)
2592 2584 *n++ = '\0';
2593 2585
2594 2586 s = strchr(c, ':');
2595 2587 if (s != NULL) {
2596 2588 *s++ = '\0';
2597 2589 al = strchr(s, ':');
2598 2590 if (al != NULL)
2599 2591 *al++ = '\0';
2600 2592 }
2601 2593
2602 2594 if (s == NULL || al == NULL)
2603 2595 break;
2604 2596
2605 2597 if (*c == '\0') {
2606 2598 if (clnt_gid != (gid_t)-1)
2607 2599 continue;
2608 2600 } else if (strcmp(c, "*") != 0) {
2609 2601 gid_t clnt;
2610 2602
2611 2603 if (!get_gid(c, &clnt))
2612 2604 continue;
2613 2605
2614 2606 if (clnt_gid != clnt)
2615 2607 continue;
2616 2608 }
2617 2609
2618 2610 if (*s == '\0')
2619 2611 srv = UID_NOBODY;
2620 2612 else if (!get_gid(s, &srv))
2621 2613 continue;
2622 2614 else if (srv == (gid_t)-1) {
2623 2615 map_deny = B_TRUE;
2624 2616 break;
2625 2617 }
2626 2618
2627 2619 if (in_access_list(cln, al) > 0) {
2628 2620 *srv_gid = srv;
2629 2621 perm |= NFSAUTH_GIDMAP;
2630 2622
2631 2623 if (perm & NFSAUTH_GROUPS) {
2632 2624 free(*srv_gids);
2633 2625 *srv_ngids = 0;
2634 2626 *srv_gids = NULL;
2635 2627 perm &= ~NFSAUTH_GROUPS;
2636 2628 }
2637 2629
2638 2630 break;
2639 2631 }
2640 2632 }
2641 2633
2642 2634 break;
2643 2635 }
2644 2636
2645 2637 default:
2646 2638 break;
2647 2639 }
2648 2640 }
2649 2641
2650 2642 free(opts);
2651 2643
2652 2644 if (perm & NFSAUTH_ROOT) {
2653 2645 *srv_uid = 0;
2654 2646 *srv_gid = 0;
2655 2647 }
2656 2648
2657 2649 if (map_deny)
2658 2650 perm |= NFSAUTH_DENIED;
2659 2651
2660 2652 if (!(perm & NFSAUTH_UIDMAP))
2661 2653 *srv_uid = clnt_uid;
2662 2654 if (!(perm & NFSAUTH_GIDMAP))
2663 2655 *srv_gid = clnt_gid;
2664 2656
2665 2657 if (flavor != match || perm & NFSAUTH_DENIED)
2666 2658 return (NFSAUTH_DENIED);
2667 2659
2668 2660 if (list) {
2669 2661 /*
2670 2662 * If the client doesn't match an "ro" or "rw"
2671 2663 * list then set no access.
2672 2664 */
2673 2665 if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0)
2674 2666 perm |= NFSAUTH_DENIED;
2675 2667 } else {
2676 2668 /*
2677 2669 * The client matched a flavor entry that
2678 2670 * has no explicit "rw" or "ro" determination.
2679 2671 * Default it to "rw".
2680 2672 */
2681 2673 perm |= NFSAUTH_RW;
2682 2674 }
2683 2675
2684 2676 /*
2685 2677 * The client may show up in both ro= and rw=
2686 2678 * lists. If so, then turn off the RO access
2687 2679 * bit leaving RW access.
2688 2680 */
2689 2681 if (perm & NFSAUTH_RO && perm & NFSAUTH_RW) {
2690 2682 /*
2691 2683 * Logically cover all permutations of rw=,ro=.
2692 2684 * In the case where, rw,ro=<host> we would like
2693 2685 * to remove RW access for the host. In all other cases
2694 2686 * RW wins the precedence battle.
2695 2687 */
2696 2688 if (!rw_val && ro_val) {
2697 2689 perm &= ~(NFSAUTH_RW);
2698 2690 } else {
2699 2691 perm &= ~(NFSAUTH_RO);
2700 2692 }
2701 2693 }
2702 2694
2703 2695 return (perm);
2704 2696 }
2705 2697
2706 2698 /*
2707 2699 * Check if the client has access by using a flavor different from
2708 2700 * the given "flavor". If "flavor" is not in the flavor list,
2709 2701 * return TRUE to indicate that this "flavor" is a wrong sec.
2710 2702 */
2711 2703 static bool_t
2712 2704 is_wrongsec(share_t *sh, struct cln *cln, int flavor)
2713 2705 {
2714 2706 int flavor_list[MAX_FLAVORS];
2715 2707 int flavor_count, i;
2716 2708
2717 2709 /* get the flavor list that the client has access with */
2718 2710 flavor_count = getclientsflavors_new(sh, cln, flavor_list);
2719 2711
2720 2712 if (flavor_count == 0)
2721 2713 return (FALSE);
2722 2714
2723 2715 /*
2724 2716 * Check if the given "flavor" is in the flavor_list.
2725 2717 */
2726 2718 for (i = 0; i < flavor_count; i++) {
2727 2719 if (flavor == flavor_list[i])
2728 2720 return (FALSE);
2729 2721 }
2730 2722
2731 2723 /*
2732 2724 * If "flavor" is not in the flavor_list, return TRUE to indicate
2733 2725 * that the client should have access by using a security flavor
2734 2726 * different from this "flavor".
2735 2727 */
2736 2728 return (TRUE);
2737 2729 }
2738 2730
2739 2731 /*
2740 2732 * Given an export and the client's hostname, we
2741 2733 * check the security options to see whether the
2742 2734 * client is allowed to use the given security flavor.
2743 2735 *
2744 2736 * The strategy is to proceed through the options looking
2745 2737 * for a flavor match, then pay attention to the ro, rw,
2746 2738 * and root options.
2747 2739 *
2748 2740 * Note that an entry may list several flavors in a
2749 2741 * single entry, e.g.
2750 2742 *
2751 2743 * sec=krb5,rw=clnt1:clnt2,ro,sec=sys,ro
2752 2744 *
2753 2745 */
2754 2746
2755 2747 static int
2756 2748 check_client_new(share_t *sh, struct cln *cln, int flavor, uid_t clnt_uid,
2757 2749 gid_t clnt_gid, uint_t clnt_ngids, gid_t *clnt_gids, uid_t *srv_uid,
2758 2750 gid_t *srv_gid, uint_t *srv_ngids, gid_t **srv_gids)
2759 2751 {
2760 2752 char *opts, *p, *val;
2761 2753 char *lasts;
2762 2754 char *f;
2763 2755 int match = 0; /* Set when a flavor is matched */
2764 2756 int perm = 0; /* Set when "ro", "rw" or "root" is matched */
2765 2757 int list = 0; /* Set when "ro", "rw" is found */
2766 2758 int ro_val = 0; /* Set if ro option is 'ro=' */
2767 2759 int rw_val = 0; /* Set if rw option is 'rw=' */
2768 2760
2769 2761 boolean_t map_deny = B_FALSE;
2770 2762
2771 2763 opts = strdup(sh->sh_opts);
2772 2764 if (opts == NULL) {
2773 2765 syslog(LOG_ERR, "check_client: no memory");
2774 2766 return (0);
2775 2767 }
2776 2768
2777 2769 /*
2778 2770 * If client provided 16 supplemental groups with AUTH_SYS, lookup
2779 2771 * locally for all of them
2780 2772 */
2781 2773 if (flavor == AUTH_SYS && clnt_ngids == NGRPS && ngroups_max > NGRPS)
2782 2774 if (getusergroups(clnt_uid, srv_ngids, srv_gids) == 0)
2783 2775 perm |= NFSAUTH_GROUPS;
2784 2776
2785 2777 p = opts;
2786 2778
2787 2779 while (*p) {
2788 2780 switch (getsubopt(&p, optlist, &val)) {
2789 2781
2790 2782 case OPT_SEC:
2791 2783 if (match)
2792 2784 goto done;
2793 2785
2794 2786 while ((f = strtok_r(val, ":", &lasts))
2795 2787 != NULL) {
2796 2788 if (flavor == map_flavor(f)) {
2797 2789 match = 1;
2798 2790 break;
2799 2791 }
2800 2792 val = NULL;
2801 2793 }
2802 2794 break;
2803 2795
2804 2796 case OPT_RO:
2805 2797 if (!match)
2806 2798 break;
2807 2799
2808 2800 list++;
2809 2801 if (val != NULL)
2810 2802 ro_val++;
2811 2803 if (in_access_list(cln, val) > 0)
2812 2804 perm |= NFSAUTH_RO;
2813 2805 break;
2814 2806
2815 2807 case OPT_RW:
2816 2808 if (!match)
2817 2809 break;
2818 2810
2819 2811 list++;
2820 2812 if (val != NULL)
2821 2813 rw_val++;
2822 2814 if (in_access_list(cln, val) > 0)
2823 2815 perm |= NFSAUTH_RW;
2824 2816 break;
2825 2817
2826 2818 case OPT_ROOT:
2827 2819 /*
2828 2820 * Check if the client is in
2829 2821 * the root list. Only valid
2830 2822 * for AUTH_SYS.
2831 2823 */
2832 2824 if (flavor != AUTH_SYS)
2833 2825 break;
2834 2826
2835 2827 if (!match)
2836 2828 break;
2837 2829
2838 2830 if (val == NULL || *val == '\0')
2839 2831 break;
2840 2832
2841 2833 if (clnt_uid != 0)
2842 2834 break;
2843 2835
2844 2836 if (in_access_list(cln, val) > 0) {
2845 2837 perm |= NFSAUTH_ROOT;
2846 2838 perm |= NFSAUTH_UIDMAP | NFSAUTH_GIDMAP;
2847 2839 map_deny = B_FALSE;
2848 2840
2849 2841 if (perm & NFSAUTH_GROUPS) {
2850 2842 free(*srv_gids);
2851 2843 *srv_gids = NULL;
2852 2844 *srv_ngids = 0;
2853 2845 perm &= ~NFSAUTH_GROUPS;
2854 2846 }
2855 2847 }
2856 2848 break;
2857 2849
2858 2850 case OPT_NONE:
2859 2851 /*
2860 2852 * Check if the client should have no access
2861 2853 * to this share at all. This option behaves
2862 2854 * more like "root" than either "rw" or "ro".
2863 2855 */
2864 2856 if (in_access_list(cln, val) > 0)
2865 2857 perm |= NFSAUTH_DENIED;
2866 2858 break;
2867 2859
2868 2860 case OPT_UIDMAP: {
2869 2861 char *c;
2870 2862 char *n;
2871 2863
2872 2864 /*
2873 2865 * The uidmap is supported for AUTH_SYS only.
2874 2866 */
2875 2867 if (flavor != AUTH_SYS)
2876 2868 break;
2877 2869
2878 2870 if (!match || perm & NFSAUTH_UIDMAP || map_deny)
2879 2871 break;
2880 2872
2881 2873 for (c = val; c != NULL; c = n) {
2882 2874 char *s;
2883 2875 char *al;
2884 2876 uid_t srv;
2885 2877
2886 2878 n = strchr(c, '~');
2887 2879 if (n != NULL)
2888 2880 *n++ = '\0';
2889 2881
2890 2882 s = strchr(c, ':');
2891 2883 if (s != NULL) {
2892 2884 *s++ = '\0';
2893 2885 al = strchr(s, ':');
2894 2886 if (al != NULL)
2895 2887 *al++ = '\0';
2896 2888 }
2897 2889
2898 2890 if (s == NULL || al == NULL)
2899 2891 continue;
2900 2892
2901 2893 if (*c == '\0') {
2902 2894 if (clnt_uid != (uid_t)-1)
2903 2895 continue;
2904 2896 } else if (strcmp(c, "*") != 0) {
2905 2897 uid_t clnt;
2906 2898
2907 2899 if (!get_uid(c, &clnt))
2908 2900 continue;
2909 2901
2910 2902 if (clnt_uid != clnt)
2911 2903 continue;
2912 2904 }
2913 2905
2914 2906 if (*s == '\0')
2915 2907 srv = UID_NOBODY;
2916 2908 else if (!get_uid(s, &srv))
2917 2909 continue;
2918 2910 else if (srv == (uid_t)-1) {
2919 2911 map_deny = B_TRUE;
2920 2912 break;
2921 2913 }
2922 2914
2923 2915 if (in_access_list(cln, al) > 0) {
2924 2916 *srv_uid = srv;
2925 2917 perm |= NFSAUTH_UIDMAP;
2926 2918
2927 2919 if (perm & NFSAUTH_GROUPS) {
2928 2920 free(*srv_gids);
2929 2921 *srv_gids = NULL;
2930 2922 *srv_ngids = 0;
2931 2923 perm &= ~NFSAUTH_GROUPS;
2932 2924 }
2933 2925
2934 2926 break;
2935 2927 }
2936 2928 }
2937 2929
2938 2930 break;
2939 2931 }
2940 2932
2941 2933 case OPT_GIDMAP: {
2942 2934 char *c;
2943 2935 char *n;
2944 2936
2945 2937 /*
2946 2938 * The gidmap is supported for AUTH_SYS only.
2947 2939 */
2948 2940 if (flavor != AUTH_SYS)
2949 2941 break;
2950 2942
2951 2943 if (!match || perm & NFSAUTH_GIDMAP || map_deny)
2952 2944 break;
2953 2945
2954 2946 for (c = val; c != NULL; c = n) {
2955 2947 char *s;
2956 2948 char *al;
2957 2949 gid_t srv;
2958 2950
2959 2951 n = strchr(c, '~');
2960 2952 if (n != NULL)
2961 2953 *n++ = '\0';
2962 2954
2963 2955 s = strchr(c, ':');
2964 2956 if (s != NULL) {
2965 2957 *s++ = '\0';
2966 2958 al = strchr(s, ':');
2967 2959 if (al != NULL)
2968 2960 *al++ = '\0';
2969 2961 }
2970 2962
2971 2963 if (s == NULL || al == NULL)
2972 2964 break;
2973 2965
2974 2966 if (*c == '\0') {
2975 2967 if (clnt_gid != (gid_t)-1)
2976 2968 continue;
2977 2969 } else if (strcmp(c, "*") != 0) {
2978 2970 gid_t clnt;
2979 2971
2980 2972 if (!get_gid(c, &clnt))
2981 2973 continue;
2982 2974
2983 2975 if (clnt_gid != clnt)
2984 2976 continue;
2985 2977 }
2986 2978
2987 2979 if (*s == '\0')
2988 2980 srv = UID_NOBODY;
2989 2981 else if (!get_gid(s, &srv))
2990 2982 continue;
2991 2983 else if (srv == (gid_t)-1) {
2992 2984 map_deny = B_TRUE;
2993 2985 break;
2994 2986 }
2995 2987
2996 2988 if (in_access_list(cln, al) > 0) {
2997 2989 *srv_gid = srv;
2998 2990 perm |= NFSAUTH_GIDMAP;
2999 2991
3000 2992 if (perm & NFSAUTH_GROUPS) {
3001 2993 free(*srv_gids);
3002 2994 *srv_gids = NULL;
3003 2995 *srv_ngids = 0;
3004 2996 perm &= ~NFSAUTH_GROUPS;
3005 2997 }
3006 2998
3007 2999 break;
3008 3000 }
3009 3001 }
3010 3002
3011 3003 break;
3012 3004 }
3013 3005
3014 3006 default:
3015 3007 break;
3016 3008 }
3017 3009 }
3018 3010
3019 3011 done:
3020 3012 if (perm & NFSAUTH_ROOT) {
3021 3013 *srv_uid = 0;
3022 3014 *srv_gid = 0;
3023 3015 }
3024 3016
3025 3017 if (map_deny)
3026 3018 perm |= NFSAUTH_DENIED;
3027 3019
3028 3020 if (!(perm & NFSAUTH_UIDMAP))
3029 3021 *srv_uid = clnt_uid;
3030 3022 if (!(perm & NFSAUTH_GIDMAP))
3031 3023 *srv_gid = clnt_gid;
3032 3024
3033 3025 /*
3034 3026 * If no match then set the perm accordingly
3035 3027 */
3036 3028 if (!match || perm & NFSAUTH_DENIED) {
3037 3029 free(opts);
3038 3030 return (NFSAUTH_DENIED);
3039 3031 }
3040 3032
3041 3033 if (list) {
3042 3034 /*
3043 3035 * If the client doesn't match an "ro" or "rw" list then
3044 3036 * check if it may have access by using a different flavor.
3045 3037 * If so, return NFSAUTH_WRONGSEC.
3046 3038 * If not, return NFSAUTH_DENIED.
3047 3039 */
3048 3040 if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0) {
3049 3041 if (is_wrongsec(sh, cln, flavor))
3050 3042 perm |= NFSAUTH_WRONGSEC;
3051 3043 else
3052 3044 perm |= NFSAUTH_DENIED;
3053 3045 }
3054 3046 } else {
3055 3047 /*
3056 3048 * The client matched a flavor entry that
3057 3049 * has no explicit "rw" or "ro" determination.
3058 3050 * Make sure it defaults to "rw".
3059 3051 */
3060 3052 perm |= NFSAUTH_RW;
3061 3053 }
3062 3054
3063 3055 /*
3064 3056 * The client may show up in both ro= and rw=
3065 3057 * lists. If so, then turn off the RO access
3066 3058 * bit leaving RW access.
3067 3059 */
3068 3060 if (perm & NFSAUTH_RO && perm & NFSAUTH_RW) {
3069 3061 /*
3070 3062 * Logically cover all permutations of rw=,ro=.
3071 3063 * In the case where, rw,ro=<host> we would like
3072 3064 * to remove RW access for the host. In all other cases
3073 3065 * RW wins the precedence battle.
3074 3066 */
3075 3067 if (!rw_val && ro_val) {
3076 3068 perm &= ~(NFSAUTH_RW);
3077 3069 } else {
3078 3070 perm &= ~(NFSAUTH_RO);
3079 3071 }
3080 3072 }
3081 3073
3082 3074 free(opts);
3083 3075
3084 3076 return (perm);
3085 3077 }
3086 3078
3087 3079 void
3088 3080 check_sharetab()
3089 3081 {
3090 3082 FILE *f;
3091 3083 struct stat st;
3092 3084 static timestruc_t last_sharetab_time;
3093 3085 timestruc_t prev_sharetab_time;
3094 3086 share_t *sh;
3095 3087 struct sh_list *shp, *shp_prev;
3096 3088 int res, c = 0;
3097 3089
3098 3090 /*
3099 3091 * read in /etc/dfs/sharetab if it has changed
3100 3092 */
3101 3093 if (stat(SHARETAB, &st) != 0) {
3102 3094 syslog(LOG_ERR, "Cannot stat %s: %m", SHARETAB);
3103 3095 return;
3104 3096 }
3105 3097
3106 3098 if (st.st_mtim.tv_sec == last_sharetab_time.tv_sec &&
3107 3099 st.st_mtim.tv_nsec == last_sharetab_time.tv_nsec) {
3108 3100 /*
3109 3101 * No change.
3110 3102 */
3111 3103 return;
3112 3104 }
3113 3105
3114 3106 /*
3115 3107 * Remember the mod time, then after getting the
3116 3108 * write lock check again. If another thread
3117 3109 * already did the update, then there's no
3118 3110 * work to do.
3119 3111 */
3120 3112 prev_sharetab_time = last_sharetab_time;
3121 3113
3122 3114 (void) rw_wrlock(&sharetab_lock);
3123 3115
3124 3116 if (prev_sharetab_time.tv_sec != last_sharetab_time.tv_sec ||
3125 3117 prev_sharetab_time.tv_nsec != last_sharetab_time.tv_nsec) {
3126 3118 (void) rw_unlock(&sharetab_lock);
3127 3119 return;
3128 3120 }
3129 3121
3130 3122 /*
3131 3123 * Note that since the sharetab is now in memory
3132 3124 * and a snapshot is taken, we no longer have to
3133 3125 * lock the file.
3134 3126 */
3135 3127 f = fopen(SHARETAB, "r");
3136 3128 if (f == NULL) {
3137 3129 syslog(LOG_ERR, "Cannot open %s: %m", SHARETAB);
3138 3130 (void) rw_unlock(&sharetab_lock);
3139 3131 return;
3140 3132 }
3141 3133
3142 3134 /*
3143 3135 * Once we are sure /etc/dfs/sharetab has been
3144 3136 * modified, flush netgroup cache entries.
3145 3137 */
3146 3138 netgrp_cache_flush();
3147 3139
3148 3140 sh_free(share_list); /* free old list */
3149 3141 share_list = NULL;
3150 3142
3151 3143 while ((res = getshare(f, &sh)) > 0) {
3152 3144 c++;
3153 3145 if (strcmp(sh->sh_fstype, "nfs") != 0)
3154 3146 continue;
3155 3147
3156 3148 shp = malloc(sizeof (*shp));
3157 3149 if (shp == NULL)
3158 3150 goto alloc_failed;
3159 3151 if (share_list == NULL)
3160 3152 share_list = shp;
3161 3153 else
3162 3154 /* LINTED not used before set */
3163 3155 shp_prev->shl_next = shp;
3164 3156 shp_prev = shp;
3165 3157 shp->shl_next = NULL;
3166 3158 shp->shl_sh = sharedup(sh);
3167 3159 if (shp->shl_sh == NULL)
3168 3160 goto alloc_failed;
3169 3161 }
3170 3162
3171 3163 if (res < 0)
3172 3164 syslog(LOG_ERR, "%s: invalid at line %d\n",
3173 3165 SHARETAB, c + 1);
3174 3166
3175 3167 if (stat(SHARETAB, &st) != 0) {
3176 3168 syslog(LOG_ERR, "Cannot stat %s: %m", SHARETAB);
3177 3169 (void) fclose(f);
3178 3170 (void) rw_unlock(&sharetab_lock);
3179 3171 return;
3180 3172 }
3181 3173
3182 3174 last_sharetab_time = st.st_mtim;
3183 3175 (void) fclose(f);
3184 3176 (void) rw_unlock(&sharetab_lock);
3185 3177
3186 3178 return;
3187 3179
3188 3180 alloc_failed:
3189 3181
3190 3182 syslog(LOG_ERR, "check_sharetab: no memory");
3191 3183 sh_free(share_list);
3192 3184 share_list = NULL;
3193 3185 (void) fclose(f);
3194 3186 (void) rw_unlock(&sharetab_lock);
3195 3187 }
3196 3188
3197 3189 static void
3198 3190 sh_free(struct sh_list *shp)
3199 3191 {
3200 3192 struct sh_list *next;
3201 3193
3202 3194 while (shp) {
3203 3195 sharefree(shp->shl_sh);
3204 3196 next = shp->shl_next;
3205 3197 free(shp);
3206 3198 shp = next;
3207 3199 }
3208 3200 }
3209 3201
3210 3202
3211 3203 /*
3212 3204 * Remove an entry from mounted list
3213 3205 */
3214 3206 static void
3215 3207 umount(struct svc_req *rqstp)
3216 3208 {
3217 3209 char *host, *path, *remove_path;
3218 3210 char rpath[MAXPATHLEN];
3219 3211 SVCXPRT *transp;
3220 3212 struct cln cln;
3221 3213
3222 3214 transp = rqstp->rq_xprt;
3223 3215 path = NULL;
3224 3216 if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
3225 3217 svcerr_decode(transp);
3226 3218 return;
3227 3219 }
3228 3220
3229 3221 cln_init(&cln, transp);
3230 3222
3231 3223 errno = 0;
3232 3224 if (!svc_sendreply(transp, xdr_void, (char *)NULL))
3233 3225 log_cant_reply_cln(&cln);
3234 3226
3235 3227 host = cln_gethost(&cln);
3236 3228 if (host == NULL) {
3237 3229 /*
3238 3230 * Without the hostname we can't do audit or delete
3239 3231 * this host from the mount entries.
3240 3232 */
3241 3233 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
3242 3234 return;
3243 3235 }
3244 3236
3245 3237 if (verbose)
3246 3238 syslog(LOG_NOTICE, "UNMOUNT: %s unmounted %s", host, path);
3247 3239
3248 3240 audit_mountd_umount(host, path);
3249 3241
3250 3242 remove_path = rpath; /* assume we will use the cannonical path */
3251 3243 if (realpath(path, rpath) == NULL) {
3252 3244 if (verbose)
3253 3245 syslog(LOG_WARNING, "UNMOUNT: realpath: %s: %m ", path);
3254 3246 remove_path = path; /* use path provided instead */
3255 3247 }
3256 3248
3257 3249 mntlist_delete(host, remove_path); /* remove from mount list */
3258 3250
3259 3251 cln_fini(&cln);
3260 3252
3261 3253 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
3262 3254 }
3263 3255
3264 3256 /*
3265 3257 * Remove all entries for one machine from mounted list
3266 3258 */
3267 3259 static void
3268 3260 umountall(struct svc_req *rqstp)
3269 3261 {
3270 3262 SVCXPRT *transp;
3271 3263 char *host;
3272 3264 struct cln cln;
3273 3265
3274 3266 transp = rqstp->rq_xprt;
3275 3267 if (!svc_getargs(transp, xdr_void, NULL)) {
3276 3268 svcerr_decode(transp);
3277 3269 return;
3278 3270 }
3279 3271 /*
3280 3272 * We assume that this call is asynchronous and made via rpcbind
3281 3273 * callit routine. Therefore return control immediately. The error
3282 3274 * causes rpcbind to remain silent, as opposed to every machine
3283 3275 * on the net blasting the requester with a response.
3284 3276 */
3285 3277 svcerr_systemerr(transp);
3286 3278
3287 3279 cln_init(&cln, transp);
3288 3280
3289 3281 host = cln_gethost(&cln);
3290 3282 if (host == NULL) {
3291 3283 /* Can't do anything without the name of the client */
3292 3284 return;
3293 3285 }
3294 3286
3295 3287 /*
3296 3288 * Remove all hosts entries from mount list
3297 3289 */
3298 3290 mntlist_delete_all(host);
3299 3291
3300 3292 if (verbose)
3301 3293 syslog(LOG_NOTICE, "UNMOUNTALL: from %s", host);
3302 3294
3303 3295 cln_fini(&cln);
3304 3296 }
3305 3297
3306 3298 void *
3307 3299 exmalloc(size_t size)
3308 3300 {
3309 3301 void *ret;
3310 3302
3311 3303 if ((ret = malloc(size)) == NULL) {
3312 3304 syslog(LOG_ERR, "Out of memory");
3313 3305 exit(1);
3314 3306 }
3315 3307 return (ret);
3316 3308 }
3317 3309
3318 3310 static tsol_tpent_t *
3319 3311 get_client_template(struct sockaddr *sock)
3320 3312 {
3321 3313 in_addr_t v4client;
3322 3314 in6_addr_t v6client;
3323 3315 char v4_addr[INET_ADDRSTRLEN];
3324 3316 char v6_addr[INET6_ADDRSTRLEN];
3325 3317 tsol_rhent_t *rh;
3326 3318 tsol_tpent_t *tp;
3327 3319
3328 3320 switch (sock->sa_family) {
3329 3321 case AF_INET:
3330 3322 v4client = ((struct sockaddr_in *)(void *)sock)->
3331 3323 sin_addr.s_addr;
3332 3324 if (inet_ntop(AF_INET, &v4client, v4_addr, INET_ADDRSTRLEN) ==
3333 3325 NULL)
3334 3326 return (NULL);
3335 3327 rh = tsol_getrhbyaddr(v4_addr, sizeof (v4_addr), AF_INET);
3336 3328 if (rh == NULL)
3337 3329 return (NULL);
3338 3330 tp = tsol_gettpbyname(rh->rh_template);
3339 3331 tsol_freerhent(rh);
3340 3332 return (tp);
3341 3333 break;
3342 3334 case AF_INET6:
3343 3335 v6client = ((struct sockaddr_in6 *)(void *)sock)->sin6_addr;
3344 3336 if (inet_ntop(AF_INET6, &v6client, v6_addr, INET6_ADDRSTRLEN) ==
3345 3337 NULL)
3346 3338 return (NULL);
3347 3339 rh = tsol_getrhbyaddr(v6_addr, sizeof (v6_addr), AF_INET6);
3348 3340 if (rh == NULL)
3349 3341 return (NULL);
3350 3342 tp = tsol_gettpbyname(rh->rh_template);
3351 3343 tsol_freerhent(rh);
3352 3344 return (tp);
3353 3345 break;
3354 3346 default:
3355 3347 return (NULL);
3356 3348 }
3357 3349 }
|
↓ open down ↓ |
2852 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX