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