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