Print this page
6198 Let's EOL cachefs
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/fs.d/autofs/autod_nfs.c
+++ new/usr/src/cmd/fs.d/autofs/autod_nfs.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
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 2015 Nexenta Systems, Inc. All rights reserved.
24 24 * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
25 25 */
26 26
27 27 #include <stdio.h>
28 28 #include <unistd.h>
29 29 #include <stdlib.h>
30 30 #include <ctype.h>
31 31 #include <syslog.h>
32 32 #include <string.h>
33 33 #include <deflt.h>
34 34 #include <kstat.h>
35 35 #include <sys/param.h>
36 36 #include <sys/types.h>
37 37 #include <sys/time.h>
38 38 #include <sys/stat.h>
39 39 #include <sys/wait.h>
40 40 #include <sys/socket.h>
41 41 #include <netinet/in.h>
42 42 #include <signal.h>
43 43 #include <sys/signal.h>
44 44 #include <rpc/rpc.h>
45 45 #include <rpc/pmap_clnt.h>
46 46 #include <sys/mount.h>
47 47 #include <sys/mntent.h>
48 48 #include <sys/mnttab.h>
49 49 #include <sys/fstyp.h>
50 50 #include <sys/fsid.h>
51 51 #include <arpa/inet.h>
52 52 #include <netdb.h>
53 53 #include <netconfig.h>
54 54 #include <netdir.h>
55 55 #include <errno.h>
56 56 #define NFSCLIENT
57 57 #include <nfs/nfs.h>
58 58 #include <nfs/mount.h>
59 59 #include <rpcsvc/mount.h>
60 60 #include <rpc/nettype.h>
61 61 #include <locale.h>
62 62 #include <setjmp.h>
63 63 #include <sys/socket.h>
64 64 #include <thread.h>
65 65 #include <limits.h>
66 66 #include <nss_dbdefs.h> /* for NSS_BUFLEN_HOSTS */
67 67 #include <nfs/nfs_sec.h>
68 68 #include <sys/sockio.h>
69 69 #include <net/if.h>
70 70 #include <assert.h>
71 71 #include <nfs/nfs_clnt.h>
72 72 #include <rpcsvc/nfs4_prot.h>
73 73 #include <nfs/nfs4.h>
74 74 #define NO_RDDIR_CACHE
75 75 #include "automount.h"
76 76 #include "replica.h"
77 77 #include "nfs_subr.h"
78 78 #include "webnfs.h"
79 79 #include "nfs_resolve.h"
80 80 #include <sys/sockio.h>
81 81 #include <net/if.h>
82 82 #include <rpcsvc/daemon_utils.h>
83 83 #include <pwd.h>
84 84 #include <strings.h>
85 85 #include <tsol/label.h>
86 86 #include <zone.h>
87 87 #include <limits.h>
88 88 #include <libscf.h>
89 89 #include <libshare.h>
↓ open down ↓ |
89 lines elided |
↑ open up ↑ |
90 90 #include "smfcfg.h"
91 91
92 92 extern void set_nfsv4_ephemeral_mount_to(void);
93 93
94 94 extern char *nfs_get_qop_name();
95 95 extern AUTH *nfs_create_ah();
96 96 extern enum snego_stat nfs_sec_nego();
97 97
98 98 #define MAXHOSTS 512
99 99
100 -#define MNTTYPE_CACHEFS "cachefs"
101 -
102 100 /*
103 101 * host cache states
104 102 */
105 103 #define NOHOST 0
106 104 #define GOODHOST 1
107 105 #define DEADHOST 2
108 106
109 107 #define NFS_ARGS_EXTB_secdata(args, secdata) \
110 108 { (args).nfs_args_ext = NFS_ARGS_EXTB, \
111 109 (args).nfs_ext_u.nfs_extB.secdata = secdata; }
112 110
113 111 struct cache_entry {
114 112 struct cache_entry *cache_next;
115 113 char *cache_host;
116 114 time_t cache_time;
117 115 int cache_state;
118 116 rpcvers_t cache_reqvers;
119 117 rpcvers_t cache_outvers;
120 118 char *cache_proto;
121 119 };
122 120
123 121 struct mfs_snego_t {
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
124 122 int sec_opt;
125 123 bool_t snego_done;
126 124 char *nfs_flavor;
127 125 seconfig_t nfs_sec;
128 126 };
129 127 typedef struct mfs_snego_t mfs_snego_t;
130 128
131 129 static struct cache_entry *cache_head = NULL;
132 130 rwlock_t cache_lock; /* protect the cache chain */
133 131
134 -static enum nfsstat nfsmount(struct mapfs *, char *, char *, int, int, uid_t,
132 +static enum nfsstat nfsmount(struct mapfs *, char *, char *, int, uid_t,
135 133 action_list *);
136 134 static int is_nfs_port(char *);
137 135
138 136 static void netbuf_free(struct netbuf *);
139 137 static int get_pathconf(CLIENT *, char *, char *, struct pathcnf **, int);
140 138 static struct mapfs *enum_servers(struct mapent *, char *);
141 139 static struct mapfs *get_mysubnet_servers(struct mapfs *);
142 140 static int subnet_test(int af, struct sioc_addrreq *);
143 141 static struct netbuf *get_addr(char *, rpcprog_t, rpcvers_t,
144 142 struct netconfig **, char *, ushort_t, struct t_info *);
145 143
146 144 static struct netbuf *get_pubfh(char *, rpcvers_t, mfs_snego_t *,
147 145 struct netconfig **, char *, ushort_t, struct t_info *, caddr_t *,
148 146 bool_t, char *);
149 147
150 148 static int create_homedir(const char *, const char *);
151 149
152 150 enum type_of_stuff {
153 151 SERVER_ADDR = 0,
154 152 SERVER_PING = 1,
155 153 SERVER_FH = 2
156 154 };
157 155
158 156 static void *get_server_netinfo(enum type_of_stuff, char *, rpcprog_t,
159 157 rpcvers_t, mfs_snego_t *, struct netconfig **, char *, ushort_t,
160 158 struct t_info *, caddr_t *, bool_t, char *, enum clnt_stat *);
161 159 static void *get_netconfig_info(enum type_of_stuff, char *, rpcprog_t,
162 160 rpcvers_t, struct netconfig *, ushort_t, struct t_info *,
163 161 struct t_bind *, caddr_t *, bool_t, char *, enum clnt_stat *,
164 162 mfs_snego_t *);
165 163 static void *get_server_addrorping(char *, rpcprog_t, rpcvers_t,
166 164 struct netconfig *, ushort_t, struct t_info *, struct t_bind *,
167 165 caddr_t *, bool_t, char *, enum clnt_stat *, int);
168 166 static void *get_server_fh(char *, rpcprog_t, rpcvers_t, mfs_snego_t *,
169 167 struct netconfig *, ushort_t, struct t_info *, struct t_bind *,
170 168 caddr_t *, bool_t, char *, enum clnt_stat *);
171 169
172 170 struct mapfs *add_mfs(struct mapfs *, int, struct mapfs **, struct mapfs **);
173 171 void free_mfs(struct mapfs *);
174 172 static void dump_mfs(struct mapfs *, char *, int);
175 173 static char *dump_distance(struct mapfs *);
176 174 static void cache_free(struct cache_entry *);
177 175 static int cache_check(char *, rpcvers_t *, char *);
178 176 static void cache_enter(char *, rpcvers_t, rpcvers_t, char *, int);
179 177 void destroy_auth_client_handle(CLIENT *cl);
180 178
181 179 #ifdef CACHE_DEBUG
182 180 static void trace_host_cache();
183 181 static void trace_portmap_cache();
184 182 #endif /* CACHE_DEBUG */
185 183
186 184 static int rpc_timeout = 20;
187 185
188 186 #ifdef CACHE_DEBUG
189 187 /*
190 188 * host cache counters. These variables do not need to be protected
191 189 * by mutex's. They have been added to measure the utility of the
192 190 * goodhost/deadhost cache in the lazy hierarchical mounting scheme.
193 191 */
194 192 static int host_cache_accesses = 0;
195 193 static int host_cache_lookups = 0;
196 194 static int deadhost_cache_hits = 0;
197 195 static int goodhost_cache_hits = 0;
198 196
199 197 /*
200 198 * portmap cache counters. These variables do not need to be protected
201 199 * by mutex's. They have been added to measure the utility of the portmap
202 200 * cache in the lazy hierarchical mounting scheme.
203 201 */
204 202 static int portmap_cache_accesses = 0;
205 203 static int portmap_cache_lookups = 0;
206 204 static int portmap_cache_hits = 0;
207 205 #endif /* CACHE_DEBUG */
208 206
209 207 /*
210 208 * There are the defaults (range) for the client when determining
211 209 * which NFS version to use when probing the server (see above).
212 210 * These will only be used when the vers mount option is not used and
213 211 * these may be reset if /etc/default/nfs is configured to do so.
214 212 */
215 213 static rpcvers_t vers_max_default = NFS_VERSMAX_DEFAULT;
216 214 static rpcvers_t vers_min_default = NFS_VERSMIN_DEFAULT;
217 215
218 216 /*
219 217 * list of support services needed
220 218 */
221 219 static char *service_list[] = { STATD, LOCKD, NULL };
222 220 static char *service_list_v4[] = { STATD, LOCKD, NFS4CBD, NFSMAPID, NULL };
223 221
224 222 static void read_default_nfs(void);
225 223 static int is_v4_mount(char *);
226 224 static void start_nfs4cbd(void);
227 225
228 226 int
↓ open down ↓ |
84 lines elided |
↑ open up ↑ |
229 227 mount_nfs(
230 228 struct mapent *me,
231 229 char *mntpnt,
232 230 char *prevhost,
233 231 int overlay,
234 232 uid_t uid,
235 233 action_list **alpp)
236 234 {
237 235 struct mapfs *mfs, *mp;
238 236 int err = -1;
239 - int cached;
240 237 action_list *alp;
241 238 char *dir;
242 239
243 240
244 241 alp = *alpp;
245 242
246 243 read_default_nfs();
247 244
248 245 mfs = enum_servers(me, prevhost);
249 246 if (mfs == NULL)
250 247 return (ENOENT);
251 248
252 249 /*
253 250 * Try loopback if we have something on localhost; if nothing
254 251 * works, we will fall back to NFS
255 252 */
256 253 if (is_nfs_port(me->map_mntopts)) {
257 254 for (mp = mfs; mp; mp = mp->mfs_next) {
258 255 if (self_check(mp->mfs_host)) {
259 256 err = loopbackmount(mp->mfs_dir,
260 257 mntpnt, me->map_mntopts, overlay);
261 258 if (err) {
262 259 mp->mfs_ignore = 1;
263 260 } else {
264 261 /*
265 262 * Free action_list if there
266 263 * is one as it is not needed.
267 264 * Make sure to set alpp to null
268 265 * so caller doesn't try to free it
269 266 * again.
270 267 */
↓ open down ↓ |
21 lines elided |
↑ open up ↑ |
271 268 if (*alpp) {
272 269 free(*alpp);
273 270 *alpp = NULL;
274 271 }
275 272 break;
276 273 }
277 274 }
278 275 }
279 276 }
280 277 if (err) {
281 - cached = strcmp(me->map_mounter, MNTTYPE_CACHEFS) == 0;
282 278 dir = strdup(mfs->mfs_dir);
283 279 err = nfsmount(mfs, mntpnt, me->map_mntopts,
284 - cached, overlay, uid, alp);
280 + overlay, uid, alp);
285 281 if (err && trace > 1) {
286 282 trace_prt(1, " Couldn't mount %s:%s, err=%d\n",
287 283 mfs->mfs_host ? mfs->mfs_host : "",
288 284 mfs->mfs_dir ? mfs->mfs_dir : dir, err);
289 285 }
290 286 free(dir);
291 287 }
292 288 free_mfs(mfs);
293 289 return (err);
294 290 }
295 291
296 292
297 293 /*
298 294 * Using the new ioctl SIOCTONLINK to determine if a host is on the same
299 295 * subnet. Remove the old network, subnet check.
300 296 */
301 297
302 298 static struct mapfs *
303 299 get_mysubnet_servers(struct mapfs *mfs_in)
304 300 {
305 301 int s;
306 302 struct mapfs *mfs, *p, *mfs_head = NULL, *mfs_tail = NULL;
307 303
308 304 struct netconfig *nconf;
309 305 NCONF_HANDLE *nc = NULL;
310 306 struct nd_hostserv hs;
311 307 struct nd_addrlist *retaddrs;
312 308 struct netbuf *nb;
313 309 struct sioc_addrreq areq;
314 310 int res;
315 311 int af;
316 312 int i;
317 313 int sa_size;
318 314
319 315 hs.h_serv = "rpcbind";
320 316
321 317 for (mfs = mfs_in; mfs; mfs = mfs->mfs_next) {
322 318 nc = setnetconfig();
323 319
324 320 while (nconf = getnetconfig(nc)) {
325 321
326 322 /*
327 323 * Care about INET family only. proto_done flag
328 324 * indicates if we have already covered this
329 325 * protocol family. If so skip it
330 326 */
331 327 if (((strcmp(nconf->nc_protofmly, NC_INET6) == 0) ||
332 328 (strcmp(nconf->nc_protofmly, NC_INET) == 0)) &&
333 329 (nconf->nc_semantics == NC_TPI_CLTS)) {
334 330 } else
335 331 continue;
336 332
337 333 hs.h_host = mfs->mfs_host;
338 334
339 335 if (netdir_getbyname(nconf, &hs, &retaddrs) != ND_OK)
340 336 continue;
341 337
342 338 /*
343 339 * For each host address see if it's on our
344 340 * local subnet.
345 341 */
346 342
347 343 if (strcmp(nconf->nc_protofmly, NC_INET6) == 0)
348 344 af = AF_INET6;
349 345 else
350 346 af = AF_INET;
351 347 nb = retaddrs->n_addrs;
352 348 for (i = 0; i < retaddrs->n_cnt; i++, nb++) {
353 349 memset(&areq.sa_addr, 0, sizeof (areq.sa_addr));
354 350 memcpy(&areq.sa_addr, nb->buf, MIN(nb->len,
355 351 sizeof (areq.sa_addr)));
356 352 if (res = subnet_test(af, &areq)) {
357 353 p = add_mfs(mfs, DIST_MYNET,
358 354 &mfs_head, &mfs_tail);
359 355 if (!p) {
360 356 netdir_free(retaddrs,
361 357 ND_ADDRLIST);
362 358 endnetconfig(nc);
363 359 return (NULL);
364 360 }
365 361 break;
366 362 }
367 363 } /* end of every host */
368 364 if (trace > 2) {
369 365 trace_prt(1, "get_mysubnet_servers: host=%s "
370 366 "netid=%s res=%s\n", mfs->mfs_host,
371 367 nconf->nc_netid, res == 1?"SUC":"FAIL");
372 368 }
373 369
374 370 netdir_free(retaddrs, ND_ADDRLIST);
375 371 } /* end of while */
376 372
377 373 endnetconfig(nc);
378 374
379 375 } /* end of every map */
380 376
381 377 return (mfs_head);
382 378
383 379 }
384 380
385 381 int
386 382 subnet_test(int af, struct sioc_addrreq *areq)
387 383 {
388 384 int s;
389 385
390 386 if ((s = socket(af, SOCK_DGRAM, 0)) < 0) {
391 387 return (0);
392 388 }
393 389
394 390 areq->sa_res = -1;
395 391
396 392 if (ioctl(s, SIOCTONLINK, (caddr_t)areq) < 0) {
397 393 syslog(LOG_ERR, "subnet_test:SIOCTONLINK failed");
398 394 return (0);
399 395 }
400 396 close(s);
401 397 if (areq->sa_res == 1)
402 398 return (1);
403 399 else
404 400 return (0);
405 401
406 402
407 403 }
408 404
409 405 /*
410 406 * ping a bunch of hosts at once and sort by who responds first
411 407 */
412 408 static struct mapfs *
413 409 sort_servers(struct mapfs *mfs_in, int timeout)
414 410 {
415 411 struct mapfs *m1 = NULL;
416 412 enum clnt_stat clnt_stat;
417 413
418 414 if (!mfs_in)
419 415 return (NULL);
420 416
421 417 clnt_stat = nfs_cast(mfs_in, &m1, timeout);
422 418
423 419 if (!m1) {
424 420 char buff[2048] = {'\0'};
425 421
426 422 for (m1 = mfs_in; m1; m1 = m1->mfs_next) {
427 423 (void) strcat(buff, m1->mfs_host);
428 424 if (m1->mfs_next)
429 425 (void) strcat(buff, ",");
430 426 }
431 427
432 428 syslog(LOG_ERR, "servers %s not responding: %s",
433 429 buff, clnt_sperrno(clnt_stat));
434 430 }
435 431
436 432 return (m1);
437 433 }
438 434
439 435 /*
440 436 * Add a mapfs entry to the list described by *mfs_head and *mfs_tail,
441 437 * provided it is not marked "ignored" and isn't a dupe of ones we've
442 438 * already seen.
443 439 */
444 440 struct mapfs *
445 441 add_mfs(struct mapfs *mfs, int distance, struct mapfs **mfs_head,
446 442 struct mapfs **mfs_tail)
447 443 {
448 444 struct mapfs *tmp, *new;
449 445
450 446 for (tmp = *mfs_head; tmp; tmp = tmp->mfs_next)
451 447 if ((strcmp(tmp->mfs_host, mfs->mfs_host) == 0 &&
452 448 strcmp(tmp->mfs_dir, mfs->mfs_dir) == 0) ||
453 449 mfs->mfs_ignore)
454 450 return (*mfs_head);
455 451 new = (struct mapfs *)malloc(sizeof (struct mapfs));
456 452 if (!new) {
457 453 syslog(LOG_ERR, "Memory allocation failed: %m");
458 454 return (NULL);
459 455 }
460 456 bcopy(mfs, new, sizeof (struct mapfs));
461 457 new->mfs_next = NULL;
462 458 if (distance)
463 459 new->mfs_distance = distance;
464 460 if (!*mfs_head)
465 461 *mfs_tail = *mfs_head = new;
466 462 else {
467 463 (*mfs_tail)->mfs_next = new;
468 464 *mfs_tail = new;
469 465 }
470 466 return (*mfs_head);
471 467 }
472 468
473 469 static void
474 470 dump_mfs(struct mapfs *mfs, char *message, int level)
475 471 {
476 472 struct mapfs *m1;
477 473
478 474 if (trace <= level)
479 475 return;
480 476
481 477 trace_prt(1, "%s", message);
482 478 if (!mfs) {
483 479 trace_prt(0, "mfs is null\n");
484 480 return;
485 481 }
486 482 for (m1 = mfs; m1; m1 = m1->mfs_next)
487 483 trace_prt(0, "%s[%s] ", m1->mfs_host, dump_distance(m1));
488 484 trace_prt(0, "\n");
489 485 }
490 486
491 487 static char *
492 488 dump_distance(struct mapfs *mfs)
493 489 {
494 490 switch (mfs->mfs_distance) {
495 491 case 0: return ("zero");
496 492 case DIST_SELF: return ("self");
497 493 case DIST_MYSUB: return ("mysub");
498 494 case DIST_MYNET: return ("mynet");
499 495 case DIST_OTHER: return ("other");
500 496 default: return ("other");
501 497 }
502 498 }
503 499
504 500 /*
505 501 * Walk linked list "raw", building a new list consisting of members
506 502 * NOT found in list "filter", returning the result.
507 503 */
508 504 static struct mapfs *
509 505 filter_mfs(struct mapfs *raw, struct mapfs *filter)
510 506 {
511 507 struct mapfs *mfs, *p, *mfs_head = NULL, *mfs_tail = NULL;
512 508 int skip;
513 509
514 510 if (!raw)
515 511 return (NULL);
516 512 for (mfs = raw; mfs; mfs = mfs->mfs_next) {
517 513 for (skip = 0, p = filter; p; p = p->mfs_next) {
518 514 if (strcmp(p->mfs_host, mfs->mfs_host) == 0 &&
519 515 strcmp(p->mfs_dir, mfs->mfs_dir) == 0) {
520 516 skip = 1;
521 517 break;
522 518 }
523 519 }
524 520 if (skip)
525 521 continue;
526 522 p = add_mfs(mfs, 0, &mfs_head, &mfs_tail);
527 523 if (!p)
528 524 return (NULL);
529 525 }
530 526 return (mfs_head);
531 527 }
532 528
533 529 /*
534 530 * Walk a linked list of mapfs structs, freeing each member.
535 531 */
536 532 void
537 533 free_mfs(struct mapfs *mfs)
538 534 {
539 535 struct mapfs *tmp;
540 536
541 537 while (mfs) {
542 538 tmp = mfs->mfs_next;
543 539 free(mfs);
544 540 mfs = tmp;
545 541 }
546 542 }
547 543
548 544 /*
549 545 * New code for NFS client failover: we need to carry and sort
550 546 * lists of server possibilities rather than return a single
551 547 * entry. It preserves previous behaviour of sorting first by
552 548 * locality (loopback-or-preferred/subnet/net/other) and then
553 549 * by ping times. We'll short-circuit this process when we
554 550 * have ENOUGH or more entries.
555 551 */
556 552 static struct mapfs *
557 553 enum_servers(struct mapent *me, char *preferred)
558 554 {
559 555 struct mapfs *p, *m1, *m2, *mfs_head = NULL, *mfs_tail = NULL;
560 556
561 557 /*
562 558 * Short-circuit for simple cases.
563 559 */
564 560 if (!me->map_fs->mfs_next) {
565 561 p = add_mfs(me->map_fs, DIST_OTHER, &mfs_head, &mfs_tail);
566 562 if (!p)
567 563 return (NULL);
568 564 return (mfs_head);
569 565 }
570 566
571 567 dump_mfs(me->map_fs, " enum_servers: mapent: ", 2);
572 568
573 569 /*
574 570 * get addresses & see if any are myself
575 571 * or were mounted from previously in a
576 572 * hierarchical mount.
577 573 */
578 574 if (trace > 2)
579 575 trace_prt(1, " enum_servers: looking for pref/self\n");
580 576 for (m1 = me->map_fs; m1; m1 = m1->mfs_next) {
581 577 if (m1->mfs_ignore)
582 578 continue;
583 579 if (self_check(m1->mfs_host) ||
584 580 strcmp(m1->mfs_host, preferred) == 0) {
585 581 p = add_mfs(m1, DIST_SELF, &mfs_head, &mfs_tail);
586 582 if (!p)
587 583 return (NULL);
588 584 }
589 585 }
590 586 if (trace > 2 && m1)
591 587 trace_prt(1, " enum_servers: pref/self found, %s\n",
592 588 m1->mfs_host);
593 589
594 590 /*
595 591 * look for entries on this subnet
596 592 */
597 593 dump_mfs(m1, " enum_servers: input of get_mysubnet_servers: ", 2);
598 594 m1 = get_mysubnet_servers(me->map_fs);
599 595 dump_mfs(m1, " enum_servers: output of get_mysubnet_servers: ", 3);
600 596 if (m1 && m1->mfs_next) {
601 597 m2 = sort_servers(m1, rpc_timeout / 2);
602 598 dump_mfs(m2, " enum_servers: output of sort_servers: ", 3);
603 599 free_mfs(m1);
604 600 m1 = m2;
605 601 }
606 602
607 603 for (m2 = m1; m2; m2 = m2->mfs_next) {
608 604 p = add_mfs(m2, 0, &mfs_head, &mfs_tail);
609 605 if (!p)
610 606 return (NULL);
611 607 }
612 608 if (m1)
613 609 free_mfs(m1);
614 610
615 611 /*
616 612 * add the rest of the entries at the end
617 613 */
618 614 m1 = filter_mfs(me->map_fs, mfs_head);
619 615 dump_mfs(m1, " enum_servers: etc: output of filter_mfs: ", 3);
620 616 m2 = sort_servers(m1, rpc_timeout / 2);
621 617 dump_mfs(m2, " enum_servers: etc: output of sort_servers: ", 3);
622 618 if (m1)
623 619 free_mfs(m1);
624 620 m1 = m2;
625 621 for (m2 = m1; m2; m2 = m2->mfs_next) {
626 622 p = add_mfs(m2, DIST_OTHER, &mfs_head, &mfs_tail);
627 623 if (!p)
628 624 return (NULL);
629 625 }
630 626 if (m1)
631 627 free_mfs(m1);
↓ open down ↓ |
337 lines elided |
↑ open up ↑ |
632 628
633 629 done:
634 630 dump_mfs(mfs_head, " enum_servers: output: ", 1);
635 631 return (mfs_head);
636 632 }
637 633
638 634 static enum nfsstat
639 635 nfsmount(
640 636 struct mapfs *mfs_in,
641 637 char *mntpnt, char *opts,
642 - int cached, int overlay,
638 + int overlay,
643 639 uid_t uid,
644 640 action_list *alp)
645 641 {
646 642 CLIENT *cl;
647 643 char remname[MAXPATHLEN], *mnttabtext = NULL;
648 644 char mopts[MAX_MNTOPT_STR];
649 645 char netname[MAXNETNAMELEN+1];
650 646 char *mntopts = NULL;
651 647 int mnttabcnt = 0;
652 648 int loglevel;
653 649 struct mnttab m;
654 650 struct nfs_args *argp = NULL, *head = NULL, *tail = NULL,
655 651 *prevhead, *prevtail;
656 652 int flags;
657 653 struct fhstatus fhs;
658 654 struct timeval timeout;
659 655 enum clnt_stat rpc_stat;
660 656 enum nfsstat status;
661 657 struct stat stbuf;
662 658 struct netconfig *nconf;
663 659 rpcvers_t vers, versmin; /* used to negotiate nfs version in pingnfs */
664 660 /* and mount version with mountd */
665 661 rpcvers_t outvers; /* final version to be used during mount() */
666 662 rpcvers_t nfsvers; /* version in map options, 0 if not there */
667 663 rpcvers_t mountversmax; /* tracks the max mountvers during retries */
668 664
669 665 /* used to negotiate nfs version using webnfs */
670 666 rpcvers_t pubvers, pubversmin, pubversmax;
671 667 int posix;
672 668 struct nd_addrlist *retaddrs;
673 669 struct mountres3 res3;
674 670 nfs_fh3 fh3;
675 671 char *fstype;
676 672 int count, i;
677 673 char scerror_msg[MAXMSGLEN];
678 674 int *auths;
679 675 int delay;
680 676 int retries;
681 677 char *nfs_proto = NULL;
682 678 uint_t nfs_port = 0;
683 679 char *p, *host, *rhost, *dir;
684 680 struct mapfs *mfs = NULL;
685 681 int error, last_error = 0;
686 682 int replicated;
687 683 int entries = 0;
688 684 int v2cnt = 0, v3cnt = 0, v4cnt = 0;
689 685 int v2near = 0, v3near = 0, v4near = 0;
690 686 int skipentry = 0;
691 687 char *nfs_flavor;
692 688 seconfig_t nfs_sec;
693 689 int sec_opt, scerror;
694 690 struct sec_data *secdata;
695 691 int secflags;
696 692 struct netbuf *syncaddr;
697 693 bool_t use_pubfh;
698 694 ushort_t thisport;
699 695 int got_val;
700 696 mfs_snego_t mfssnego_init, mfssnego;
701 697
702 698 dump_mfs(mfs_in, " nfsmount: input: ", 2);
703 699 replicated = (mfs_in->mfs_next != NULL);
704 700 m.mnt_mntopts = opts;
705 701 if (replicated && hasmntopt(&m, MNTOPT_SOFT)) {
706 702 if (verbose)
707 703 syslog(LOG_WARNING,
↓ open down ↓ |
55 lines elided |
↑ open up ↑ |
708 704 "mount on %s is soft and will not be replicated.", mntpnt);
709 705 replicated = 0;
710 706 }
711 707 if (replicated && !hasmntopt(&m, MNTOPT_RO)) {
712 708 if (verbose)
713 709 syslog(LOG_WARNING,
714 710 "mount on %s is not read-only and will not be replicated.",
715 711 mntpnt);
716 712 replicated = 0;
717 713 }
718 - if (replicated && cached) {
719 - if (verbose)
720 - syslog(LOG_WARNING,
721 - "mount on %s is cached and will not be replicated.",
722 - mntpnt);
723 - replicated = 0;
724 - }
725 714 if (replicated)
726 715 loglevel = LOG_WARNING;
727 716 else
728 717 loglevel = LOG_ERR;
729 718
730 719 if (trace > 1) {
731 720 if (replicated)
732 721 trace_prt(1, " nfsmount: replicated mount on %s %s:\n",
733 722 mntpnt, opts);
734 723 else
735 724 trace_prt(1, " nfsmount: standard mount on %s %s:\n",
736 725 mntpnt, opts);
737 726 for (mfs = mfs_in; mfs; mfs = mfs->mfs_next)
738 727 trace_prt(1, " %s:%s\n",
739 728 mfs->mfs_host, mfs->mfs_dir);
740 729 }
741 730
742 731 /*
743 732 * Make sure mountpoint is safe to mount on
744 733 */
745 734 if (lstat(mntpnt, &stbuf) < 0) {
746 735 syslog(LOG_ERR, "Couldn't stat %s: %m", mntpnt);
747 736 return (NFSERR_NOENT);
748 737 }
749 738
750 739 /*
751 740 * Get protocol specified in options list, if any.
752 741 */
753 742 if ((str_opt(&m, "proto", &nfs_proto)) == -1) {
754 743 return (NFSERR_NOENT);
755 744 }
756 745
757 746 /*
758 747 * Get port specified in options list, if any.
759 748 */
760 749 got_val = nopt(&m, MNTOPT_PORT, (int *)&nfs_port);
761 750 if (!got_val)
762 751 nfs_port = 0; /* "unspecified" */
763 752 if (nfs_port > USHRT_MAX) {
764 753 syslog(LOG_ERR, "%s: invalid port number %d", mntpnt, nfs_port);
765 754 return (NFSERR_NOENT);
766 755 }
767 756
768 757 /*
769 758 * Set mount(2) flags here, outside of the loop.
770 759 */
771 760 flags = MS_OPTIONSTR;
772 761 flags |= (hasmntopt(&m, MNTOPT_RO) == NULL) ? 0 : MS_RDONLY;
773 762 flags |= (hasmntopt(&m, MNTOPT_NOSUID) == NULL) ? 0 : MS_NOSUID;
774 763 flags |= overlay ? MS_OVERLAY : 0;
775 764 if (mntpnt[strlen(mntpnt) - 1] != ' ')
776 765 /* direct mount point without offsets */
777 766 flags |= MS_OVERLAY;
778 767
779 768 use_pubfh = (hasmntopt(&m, MNTOPT_PUBLIC) == NULL) ? FALSE : TRUE;
780 769
781 770 (void) memset(&mfssnego_init, 0, sizeof (mfs_snego_t));
782 771 if (hasmntopt(&m, MNTOPT_SECURE) != NULL) {
783 772 if (++mfssnego_init.sec_opt > 1) {
784 773 syslog(loglevel,
785 774 "conflicting security options");
786 775 return (NFSERR_IO);
787 776 }
788 777 if (nfs_getseconfig_byname("dh", &mfssnego_init.nfs_sec)) {
789 778 syslog(loglevel,
790 779 "error getting dh information from %s",
791 780 NFSSEC_CONF);
792 781 return (NFSERR_IO);
793 782 }
794 783 }
795 784
796 785 if (hasmntopt(&m, MNTOPT_SEC) != NULL) {
797 786 if ((str_opt(&m, MNTOPT_SEC,
798 787 &mfssnego_init.nfs_flavor)) == -1) {
799 788 syslog(LOG_ERR, "nfsmount: no memory");
800 789 return (NFSERR_IO);
801 790 }
802 791 }
803 792
804 793 if (mfssnego_init.nfs_flavor) {
805 794 if (++mfssnego_init.sec_opt > 1) {
806 795 syslog(loglevel,
807 796 "conflicting security options");
808 797 free(mfssnego_init.nfs_flavor);
809 798 return (NFSERR_IO);
810 799 }
811 800 if (nfs_getseconfig_byname(mfssnego_init.nfs_flavor,
812 801 &mfssnego_init.nfs_sec)) {
813 802 syslog(loglevel,
814 803 "error getting %s information from %s",
815 804 mfssnego_init.nfs_flavor, NFSSEC_CONF);
816 805 free(mfssnego_init.nfs_flavor);
817 806 return (NFSERR_IO);
818 807 }
819 808 free(mfssnego_init.nfs_flavor);
820 809 }
821 810
822 811 nextentry:
823 812 skipentry = 0;
824 813
825 814 got_val = nopt(&m, MNTOPT_VERS, (int *)&nfsvers);
826 815 if (!got_val)
827 816 nfsvers = 0; /* "unspecified" */
828 817 if (set_versrange(nfsvers, &vers, &versmin) != 0) {
829 818 syslog(LOG_ERR, "Incorrect NFS version specified for %s",
830 819 mntpnt);
831 820 last_error = NFSERR_NOENT;
832 821 goto ret;
833 822 }
834 823
835 824 if (nfsvers != 0) {
836 825 pubversmax = pubversmin = nfsvers;
837 826 } else {
838 827 pubversmax = vers;
839 828 pubversmin = versmin;
840 829 }
841 830
842 831 /*
843 832 * Walk the whole list, pinging and collecting version
844 833 * info so that we can make sure the mount will be
845 834 * homogeneous with respect to version.
846 835 *
847 836 * If we have a version preference, this is easy; we'll
848 837 * just reject anything that doesn't match.
849 838 *
850 839 * If not, we want to try to provide the best compromise
851 840 * that considers proximity, preference for a higher version,
852 841 * sorted order, and number of replicas. We will count
853 842 * the number of V2 and V3 replicas and also the number
854 843 * which are "near", i.e. the localhost or on the same
855 844 * subnet.
856 845 */
857 846 for (mfs = mfs_in; mfs; mfs = mfs->mfs_next) {
858 847
859 848
860 849 if (mfs->mfs_ignore)
861 850 continue;
862 851
863 852 /*
864 853 * If the host is '[a:d:d:r:e:s:s'],
865 854 * only use 'a:d:d:r:e:s:s' for communication
866 855 */
867 856 host = strdup(mfs->mfs_host);
868 857 if (host == NULL) {
869 858 syslog(LOG_ERR, "nfsmount: no memory");
870 859 last_error = NFSERR_IO;
871 860 goto out;
872 861 }
873 862 unbracket(&host);
874 863
875 864 (void) memcpy(&mfssnego, &mfssnego_init, sizeof (mfs_snego_t));
876 865
877 866 if (use_pubfh == TRUE || mfs->mfs_flags & MFS_URL) {
878 867 char *path;
879 868
880 869 if (nfs_port != 0 && mfs->mfs_port != 0 &&
881 870 nfs_port != mfs->mfs_port) {
882 871
883 872 syslog(LOG_ERR, "nfsmount: port (%u) in nfs URL"
884 873 " not the same as port (%d) in port "
885 874 "option\n", mfs->mfs_port, nfs_port);
886 875 last_error = NFSERR_IO;
887 876 goto out;
888 877
889 878 } else if (nfs_port != 0)
890 879 thisport = nfs_port;
891 880 else
892 881 thisport = mfs->mfs_port;
893 882
894 883 dir = mfs->mfs_dir;
895 884
896 885 if ((mfs->mfs_flags & MFS_URL) == 0) {
897 886 path = malloc(strlen(dir) + 2);
898 887 if (path == NULL) {
899 888 syslog(LOG_ERR, "nfsmount: no memory");
900 889 last_error = NFSERR_IO;
901 890 goto out;
902 891 }
903 892 path[0] = (char)WNL_NATIVEPATH;
904 893 (void) strcpy(&path[1], dir);
905 894 } else {
906 895 path = dir;
907 896 }
908 897
909 898 argp = (struct nfs_args *)
910 899 malloc(sizeof (struct nfs_args));
911 900
912 901 if (!argp) {
913 902 if (path != dir)
914 903 free(path);
915 904 syslog(LOG_ERR, "nfsmount: no memory");
916 905 last_error = NFSERR_IO;
917 906 goto out;
918 907 }
919 908 (void) memset(argp, 0, sizeof (*argp));
920 909
921 910 /*
922 911 * RDMA support
923 912 * By now Mount argument struct has been allocated,
924 913 * either a pub_fh path will be taken or the regular
925 914 * one. So here if a protocol was specified and it
926 915 * was not rdma we let it be, else we set DO_RDMA.
927 916 * If no proto was there we advise on trying RDMA.
928 917 */
929 918 if (nfs_proto) {
930 919 if (strcmp(nfs_proto, "rdma") == 0) {
931 920 free(nfs_proto);
932 921 nfs_proto = NULL;
933 922 argp->flags |= NFSMNT_DORDMA;
934 923 }
935 924 } else
936 925 argp->flags |= NFSMNT_TRYRDMA;
937 926
938 927 for (pubvers = pubversmax; pubvers >= pubversmin;
939 928 pubvers--) {
940 929
941 930 nconf = NULL;
942 931 argp->addr = get_pubfh(host, pubvers, &mfssnego,
943 932 &nconf, nfs_proto, thisport, NULL,
944 933 &argp->fh, TRUE, path);
945 934
946 935 if (argp->addr != NULL)
947 936 break;
948 937
949 938 if (nconf != NULL)
950 939 freenetconfigent(nconf);
951 940 }
952 941
953 942 if (path != dir)
954 943 free(path);
955 944
956 945 if (argp->addr != NULL) {
957 946
958 947 /*
959 948 * The use of llock option for NFSv4
960 949 * mounts is not required since file
961 950 * locking is included within the protocol
962 951 */
963 952 if (pubvers != NFS_V4)
964 953 argp->flags |= NFSMNT_LLOCK;
965 954
966 955 argp->flags |= NFSMNT_PUBLIC;
967 956
968 957 vers = pubvers;
969 958 mfs->mfs_args = argp;
970 959 mfs->mfs_version = pubvers;
971 960 mfs->mfs_nconf = nconf;
972 961 mfs->mfs_flags |= MFS_FH_VIA_WEBNFS;
973 962
974 963 } else {
975 964 free(argp);
976 965
977 966 /*
978 967 * If -public was specified, give up
979 968 * on this entry now.
980 969 */
981 970 if (use_pubfh == TRUE) {
982 971 syslog(loglevel,
983 972 "%s: no public file handle support",
984 973 host);
985 974 last_error = NFSERR_NOENT;
986 975 mfs->mfs_ignore = 1;
987 976 continue;
988 977 }
989 978
990 979 /*
991 980 * Back off to a conventional mount.
992 981 *
993 982 * URL's can contain escape characters. Get
994 983 * rid of them.
995 984 */
996 985 path = malloc(strlen(dir) + 2);
997 986
998 987 if (path == NULL) {
999 988 syslog(LOG_ERR, "nfsmount: no memory");
1000 989 last_error = NFSERR_IO;
1001 990 goto out;
1002 991 }
1003 992
1004 993 strcpy(path, dir);
1005 994 URLparse(path);
1006 995 mfs->mfs_dir = path;
1007 996 mfs->mfs_flags |= MFS_ALLOC_DIR;
1008 997 mfs->mfs_flags &= ~MFS_URL;
1009 998 }
1010 999 }
1011 1000
1012 1001 if ((mfs->mfs_flags & MFS_FH_VIA_WEBNFS) == 0) {
1013 1002 i = pingnfs(host, get_retry(opts) + 1, &vers, versmin,
1014 1003 0, FALSE, NULL, nfs_proto);
1015 1004 if (i != RPC_SUCCESS) {
1016 1005 if (i == RPC_PROGVERSMISMATCH) {
1017 1006 syslog(loglevel, "server %s: NFS "
1018 1007 "protocol version mismatch",
1019 1008 host);
1020 1009 } else {
1021 1010 syslog(loglevel, "server %s not "
1022 1011 "responding", host);
1023 1012 }
1024 1013 mfs->mfs_ignore = 1;
1025 1014 last_error = NFSERR_NOENT;
1026 1015 continue;
1027 1016 }
1028 1017 if (nfsvers != 0 && nfsvers != vers) {
1029 1018 if (nfs_proto == NULL)
1030 1019 syslog(loglevel,
1031 1020 "NFS version %d "
1032 1021 "not supported by %s",
1033 1022 nfsvers, host);
1034 1023 else
1035 1024 syslog(loglevel,
1036 1025 "NFS version %d "
1037 1026 "with proto %s "
1038 1027 "not supported by %s",
1039 1028 nfsvers, nfs_proto, host);
1040 1029 mfs->mfs_ignore = 1;
1041 1030 last_error = NFSERR_NOENT;
1042 1031 continue;
1043 1032 }
1044 1033 }
1045 1034
1046 1035 free(host);
1047 1036
1048 1037 switch (vers) {
1049 1038 case NFS_V4: v4cnt++; break;
1050 1039 case NFS_V3: v3cnt++; break;
1051 1040 case NFS_VERSION: v2cnt++; break;
1052 1041 default: break;
1053 1042 }
1054 1043
1055 1044 /*
1056 1045 * It's not clear how useful this stuff is if
1057 1046 * we are using webnfs across the internet, but it
1058 1047 * can't hurt.
1059 1048 */
1060 1049 if (mfs->mfs_distance &&
1061 1050 mfs->mfs_distance <= DIST_MYSUB) {
1062 1051 switch (vers) {
1063 1052 case NFS_V4: v4near++; break;
1064 1053 case NFS_V3: v3near++; break;
1065 1054 case NFS_VERSION: v2near++; break;
1066 1055 default: break;
1067 1056 }
1068 1057 }
1069 1058
1070 1059 /*
1071 1060 * If the mount is not replicated, we don't want to
1072 1061 * ping every entry, so we'll stop here. This means
1073 1062 * that we may have to go back to "nextentry" above
1074 1063 * to consider another entry if we can't get
1075 1064 * all the way to mount(2) with this one.
1076 1065 */
1077 1066 if (!replicated)
1078 1067 break;
1079 1068
1080 1069 }
1081 1070
1082 1071 if (nfsvers == 0) {
1083 1072 /*
1084 1073 * Choose the NFS version.
1085 1074 * We prefer higher versions, but will choose a one-
1086 1075 * version downgrade in service if we can use a local
1087 1076 * network interface and avoid a router.
1088 1077 */
1089 1078 if (v4cnt && v4cnt >= v3cnt && (v4near || !v3near))
1090 1079 nfsvers = NFS_V4;
1091 1080 else if (v3cnt && v3cnt >= v2cnt && (v3near || !v2near))
1092 1081 nfsvers = NFS_V3;
1093 1082 else
1094 1083 nfsvers = NFS_VERSION;
1095 1084 if (trace > 2)
1096 1085 trace_prt(1,
1097 1086 " nfsmount: v4=%d[%d]v3=%d[%d],v2=%d[%d] => v%d.\n",
1098 1087 v4cnt, v4near, v3cnt, v3near,
1099 1088 v2cnt, v2near, nfsvers);
1100 1089 }
1101 1090
1102 1091 /*
1103 1092 * Since we don't support different NFS versions in replicated
1104 1093 * mounts, set fstype now.
1105 1094 * Also take the opportunity to set
1106 1095 * the mount protocol version as appropriate.
1107 1096 */
1108 1097 switch (nfsvers) {
1109 1098 case NFS_V4:
1110 1099 fstype = MNTTYPE_NFS4;
1111 1100 break;
1112 1101 case NFS_V3:
1113 1102 fstype = MNTTYPE_NFS3;
1114 1103 if (use_pubfh == FALSE) {
1115 1104 mountversmax = MOUNTVERS3;
1116 1105 versmin = MOUNTVERS3;
1117 1106 }
1118 1107 break;
1119 1108 case NFS_VERSION:
1120 1109 fstype = MNTTYPE_NFS;
1121 1110 if (use_pubfh == FALSE) {
1122 1111 mountversmax = MOUNTVERS_POSIX;
1123 1112 versmin = MOUNTVERS;
1124 1113 }
1125 1114 break;
1126 1115 }
1127 1116
1128 1117 /*
1129 1118 * Our goal here is to evaluate each of several possible
1130 1119 * replicas and try to come up with a list we can hand
1131 1120 * to mount(2). If we don't have a valid "head" at the
1132 1121 * end of this process, it means we have rejected all
1133 1122 * potential server:/path tuples. We will fail quietly
1134 1123 * in front of mount(2), and will have printed errors
1135 1124 * where we found them.
1136 1125 * XXX - do option work outside loop w careful design
1137 1126 * XXX - use macro for error condition free handling
1138 1127 */
1139 1128 for (mfs = mfs_in; mfs; mfs = mfs->mfs_next) {
1140 1129
1141 1130 /*
1142 1131 * Initialize retry and delay values on a per-server basis.
1143 1132 */
1144 1133 retries = get_retry(opts);
1145 1134 delay = INITDELAY;
1146 1135 retry:
1147 1136 if (mfs->mfs_ignore)
1148 1137 continue;
1149 1138
1150 1139 /*
1151 1140 * If we don't have a fh yet, and if this is not a replicated
1152 1141 * mount, we haven't done a pingnfs() on the next entry,
1153 1142 * so we don't know if the next entry is up or if it
1154 1143 * supports an NFS version we like. So if we had a problem
1155 1144 * with an entry, we need to go back and run through some new
1156 1145 * code.
1157 1146 */
1158 1147 if ((mfs->mfs_flags & MFS_FH_VIA_WEBNFS) == 0 &&
1159 1148 !replicated && skipentry)
1160 1149 goto nextentry;
1161 1150
1162 1151 vers = mountversmax;
1163 1152 host = mfs->mfs_host;
1164 1153 dir = mfs->mfs_dir;
1165 1154
1166 1155 /*
1167 1156 * Remember the possible '[a:d:d:r:e:s:s]' as the address to be
1168 1157 * later passed to mount(2) and used in the mnttab line, but
1169 1158 * only use 'a:d:d:r:e:s:s' for communication
1170 1159 */
1171 1160 rhost = strdup(host);
1172 1161 if (rhost == NULL) {
↓ open down ↓ |
438 lines elided |
↑ open up ↑ |
1173 1162 syslog(LOG_ERR, "nfsmount: no memory");
1174 1163 last_error = NFSERR_IO;
1175 1164 goto out;
1176 1165 }
1177 1166 unbracket(&host);
1178 1167
1179 1168 (void) sprintf(remname, "%s:%s", rhost, dir);
1180 1169 if (trace > 4 && replicated)
1181 1170 trace_prt(1, " nfsmount: examining %s\n", remname);
1182 1171
1183 - /*
1184 - * If it's cached we need to get cachefs to mount it.
1185 - */
1186 - if (cached) {
1187 - char *copts = opts;
1188 -
1189 - /*
1190 - * If we started with a URL we need to turn on
1191 - * -o public if not on already
1192 - */
1193 - if (use_pubfh == FALSE &&
1194 - (mfs->mfs_flags & MFS_FH_VIA_WEBNFS)) {
1195 -
1196 - copts = malloc(strlen(opts) +
1197 - strlen(",public")+1);
1198 -
1199 - if (copts == NULL) {
1200 - syslog(LOG_ERR, "nfsmount: no memory");
1201 - last_error = NFSERR_IO;
1202 - goto out;
1203 - }
1204 -
1205 - strcpy(copts, opts);
1206 -
1207 - if (strlen(copts) != 0)
1208 - strcat(copts, ",");
1209 -
1210 - strcat(copts, "public");
1211 - }
1212 -
1213 - last_error = mount_generic(remname, MNTTYPE_CACHEFS,
1214 - copts, mntpnt, overlay);
1215 -
1216 - if (copts != opts)
1217 - free(copts);
1218 -
1219 - if (last_error) {
1220 - skipentry = 1;
1221 - mfs->mfs_ignore = 1;
1222 - continue;
1223 - }
1224 - goto out;
1225 - }
1226 -
1227 1172 if (mfs->mfs_args == NULL) {
1228 1173
1229 1174 /*
1230 1175 * Allocate nfs_args structure
1231 1176 */
1232 1177 argp = (struct nfs_args *)
1233 1178 malloc(sizeof (struct nfs_args));
1234 1179
1235 1180 if (!argp) {
1236 1181 syslog(LOG_ERR, "nfsmount: no memory");
1237 1182 last_error = NFSERR_IO;
1238 1183 goto out;
1239 1184 }
1240 1185
1241 1186 (void) memset(argp, 0, sizeof (*argp));
1242 1187
1243 1188 /*
1244 1189 * RDMA support
1245 1190 * By now Mount argument struct has been allocated,
1246 1191 * either a pub_fh path will be taken or the regular
1247 1192 * one. So here if a protocol was specified and it
1248 1193 * was not rdma we let it be, else we set DO_RDMA.
1249 1194 * If no proto was there we advise on trying RDMA.
1250 1195 */
1251 1196 if (nfs_proto) {
1252 1197 if (strcmp(nfs_proto, "rdma") == 0) {
1253 1198 free(nfs_proto);
1254 1199 nfs_proto = NULL;
1255 1200 argp->flags |= NFSMNT_DORDMA;
1256 1201 }
1257 1202 } else
1258 1203 argp->flags |= NFSMNT_TRYRDMA;
1259 1204 } else {
1260 1205 argp = mfs->mfs_args;
1261 1206 mfs->mfs_args = NULL;
1262 1207
1263 1208 /*
1264 1209 * Skip entry if we already have file handle but the
1265 1210 * NFS version is wrong.
1266 1211 */
1267 1212 if ((mfs->mfs_flags & MFS_FH_VIA_WEBNFS) &&
1268 1213 mfs->mfs_version != nfsvers) {
1269 1214
1270 1215 free(argp);
1271 1216 skipentry = 1;
1272 1217 mfs->mfs_ignore = 1;
1273 1218 continue;
1274 1219 }
1275 1220 }
1276 1221
1277 1222 prevhead = head;
1278 1223 prevtail = tail;
1279 1224 if (!head)
1280 1225 head = tail = argp;
1281 1226 else
1282 1227 tail = tail->nfs_ext_u.nfs_extB.next = argp;
1283 1228
1284 1229 /*
1285 1230 * WebNFS and NFSv4 behave similarly in that they
1286 1231 * don't use the mount protocol. Therefore, avoid
1287 1232 * mount protocol like things when version 4 is being
1288 1233 * used.
1289 1234 */
1290 1235 if ((mfs->mfs_flags & MFS_FH_VIA_WEBNFS) == 0 &&
1291 1236 nfsvers != NFS_V4) {
1292 1237 timeout.tv_usec = 0;
1293 1238 timeout.tv_sec = rpc_timeout;
1294 1239 rpc_stat = RPC_TIMEDOUT;
1295 1240
1296 1241 /* Create the client handle. */
1297 1242
1298 1243 if (trace > 1) {
1299 1244 trace_prt(1,
1300 1245 " nfsmount: Get mount version: request "
1301 1246 "vers=%d min=%d\n", vers, versmin);
1302 1247 }
1303 1248
1304 1249 while ((cl = clnt_create_vers(host, MOUNTPROG, &outvers,
1305 1250 versmin, vers, "udp")) == NULL) {
1306 1251 if (trace > 4) {
1307 1252 trace_prt(1,
1308 1253 " nfsmount: Can't get mount "
1309 1254 "version: rpcerr=%d\n",
1310 1255 rpc_createerr.cf_stat);
1311 1256 }
1312 1257 if (rpc_createerr.cf_stat == RPC_UNKNOWNHOST ||
1313 1258 rpc_createerr.cf_stat == RPC_TIMEDOUT)
1314 1259 break;
1315 1260
1316 1261 /*
1317 1262 * backoff and return lower version to retry the ping.
1318 1263 * XXX we should be more careful and handle
1319 1264 * RPC_PROGVERSMISMATCH here, because that error
1320 1265 * is handled in clnt_create_vers(). It's not done to
1321 1266 * stay in sync with the nfs mount command.
1322 1267 */
1323 1268 vers--;
1324 1269 if (vers < versmin)
1325 1270 break;
1326 1271 if (trace > 4) {
1327 1272 trace_prt(1,
1328 1273 " nfsmount: Try version=%d\n",
1329 1274 vers);
1330 1275 }
1331 1276 }
1332 1277
1333 1278 if (cl == NULL) {
1334 1279 free(argp);
1335 1280 head = prevhead;
1336 1281 tail = prevtail;
1337 1282 if (tail)
1338 1283 tail->nfs_ext_u.nfs_extB.next = NULL;
1339 1284 last_error = NFSERR_NOENT;
1340 1285
1341 1286 if (rpc_createerr.cf_stat != RPC_UNKNOWNHOST &&
1342 1287 rpc_createerr.cf_stat !=
1343 1288 RPC_PROGVERSMISMATCH &&
1344 1289 retries-- > 0) {
1345 1290 DELAY(delay);
1346 1291 goto retry;
1347 1292 }
1348 1293
1349 1294 syslog(loglevel, "%s %s", host,
1350 1295 clnt_spcreateerror(
1351 1296 "server not responding"));
1352 1297 skipentry = 1;
1353 1298 mfs->mfs_ignore = 1;
1354 1299 continue;
1355 1300 }
1356 1301 if (trace > 1) {
1357 1302 trace_prt(1,
1358 1303 " nfsmount: mount version=%d\n", outvers);
1359 1304 }
1360 1305 #ifdef MALLOC_DEBUG
1361 1306 add_alloc("CLNT_HANDLE", cl, 0, __FILE__, __LINE__);
1362 1307 add_alloc("AUTH_HANDLE", cl->cl_auth, 0,
1363 1308 __FILE__, __LINE__);
1364 1309 #endif
1365 1310
1366 1311 if (__clnt_bindresvport(cl) < 0) {
1367 1312 free(argp);
1368 1313 head = prevhead;
1369 1314 tail = prevtail;
1370 1315 if (tail)
1371 1316 tail->nfs_ext_u.nfs_extB.next = NULL;
1372 1317 last_error = NFSERR_NOENT;
1373 1318
1374 1319 if (retries-- > 0) {
1375 1320 destroy_auth_client_handle(cl);
1376 1321 DELAY(delay);
1377 1322 goto retry;
1378 1323 }
1379 1324
1380 1325 syslog(loglevel, "mount %s: %s", host,
1381 1326 "Couldn't bind to reserved port");
1382 1327 destroy_auth_client_handle(cl);
1383 1328 skipentry = 1;
1384 1329 mfs->mfs_ignore = 1;
1385 1330 continue;
1386 1331 }
1387 1332
1388 1333 #ifdef MALLOC_DEBUG
1389 1334 drop_alloc("AUTH_HANDLE", cl->cl_auth,
1390 1335 __FILE__, __LINE__);
1391 1336 #endif
1392 1337 AUTH_DESTROY(cl->cl_auth);
1393 1338 if ((cl->cl_auth = authsys_create_default()) == NULL) {
1394 1339 free(argp);
1395 1340 head = prevhead;
1396 1341 tail = prevtail;
1397 1342 if (tail)
1398 1343 tail->nfs_ext_u.nfs_extB.next = NULL;
1399 1344 last_error = NFSERR_NOENT;
1400 1345
1401 1346 if (retries-- > 0) {
1402 1347 destroy_auth_client_handle(cl);
1403 1348 DELAY(delay);
1404 1349 goto retry;
1405 1350 }
1406 1351
1407 1352 syslog(loglevel, "mount %s: %s", host,
1408 1353 "Failed creating default auth handle");
1409 1354 destroy_auth_client_handle(cl);
1410 1355 skipentry = 1;
1411 1356 mfs->mfs_ignore = 1;
1412 1357 continue;
1413 1358 }
1414 1359 #ifdef MALLOC_DEBUG
1415 1360 add_alloc("AUTH_HANDLE", cl->cl_auth, 0,
1416 1361 __FILE__, __LINE__);
1417 1362 #endif
1418 1363 } else
1419 1364 cl = NULL;
1420 1365
1421 1366 /*
1422 1367 * set security options
1423 1368 */
1424 1369 sec_opt = 0;
1425 1370 (void) memset(&nfs_sec, 0, sizeof (nfs_sec));
1426 1371 if (hasmntopt(&m, MNTOPT_SECURE) != NULL) {
1427 1372 if (++sec_opt > 1) {
1428 1373 syslog(loglevel,
1429 1374 "conflicting security options for %s",
1430 1375 remname);
1431 1376 free(argp);
1432 1377 head = prevhead;
1433 1378 tail = prevtail;
1434 1379 if (tail)
1435 1380 tail->nfs_ext_u.nfs_extB.next = NULL;
1436 1381 last_error = NFSERR_IO;
1437 1382 destroy_auth_client_handle(cl);
1438 1383 skipentry = 1;
1439 1384 mfs->mfs_ignore = 1;
1440 1385 continue;
1441 1386 }
1442 1387 if (nfs_getseconfig_byname("dh", &nfs_sec)) {
1443 1388 syslog(loglevel,
1444 1389 "error getting dh information from %s",
1445 1390 NFSSEC_CONF);
1446 1391 free(argp);
1447 1392 head = prevhead;
1448 1393 tail = prevtail;
1449 1394 if (tail)
1450 1395 tail->nfs_ext_u.nfs_extB.next = NULL;
1451 1396 last_error = NFSERR_IO;
1452 1397 destroy_auth_client_handle(cl);
1453 1398 skipentry = 1;
1454 1399 mfs->mfs_ignore = 1;
1455 1400 continue;
1456 1401 }
1457 1402 }
1458 1403
1459 1404 nfs_flavor = NULL;
1460 1405 if (hasmntopt(&m, MNTOPT_SEC) != NULL) {
1461 1406 if ((str_opt(&m, MNTOPT_SEC, &nfs_flavor)) == -1) {
1462 1407 syslog(LOG_ERR, "nfsmount: no memory");
1463 1408 last_error = NFSERR_IO;
1464 1409 destroy_auth_client_handle(cl);
1465 1410 goto out;
1466 1411 }
1467 1412 }
1468 1413
1469 1414 if (nfs_flavor) {
1470 1415 if (++sec_opt > 1) {
1471 1416 syslog(loglevel,
1472 1417 "conflicting security options for %s",
1473 1418 remname);
1474 1419 free(nfs_flavor);
1475 1420 free(argp);
1476 1421 head = prevhead;
1477 1422 tail = prevtail;
1478 1423 if (tail)
1479 1424 tail->nfs_ext_u.nfs_extB.next = NULL;
1480 1425 last_error = NFSERR_IO;
1481 1426 destroy_auth_client_handle(cl);
1482 1427 skipentry = 1;
1483 1428 mfs->mfs_ignore = 1;
1484 1429 continue;
1485 1430 }
1486 1431 if (nfs_getseconfig_byname(nfs_flavor, &nfs_sec)) {
1487 1432 syslog(loglevel,
1488 1433 "error getting %s information from %s",
1489 1434 nfs_flavor, NFSSEC_CONF);
1490 1435 free(nfs_flavor);
1491 1436 free(argp);
1492 1437 head = prevhead;
1493 1438 tail = prevtail;
1494 1439 if (tail)
1495 1440 tail->nfs_ext_u.nfs_extB.next = NULL;
1496 1441 last_error = NFSERR_IO;
1497 1442 destroy_auth_client_handle(cl);
1498 1443 skipentry = 1;
1499 1444 mfs->mfs_ignore = 1;
1500 1445 continue;
1501 1446 }
1502 1447 free(nfs_flavor);
1503 1448 }
1504 1449
1505 1450 posix = (nfsvers != NFS_V4 &&
1506 1451 hasmntopt(&m, MNTOPT_POSIX) != NULL) ? 1 : 0;
1507 1452
1508 1453 if ((mfs->mfs_flags & MFS_FH_VIA_WEBNFS) == 0 &&
1509 1454 nfsvers != NFS_V4) {
1510 1455 bool_t give_up_on_mnt;
1511 1456 bool_t got_mnt_error;
1512 1457 /*
1513 1458 * If we started with a URL, if first byte of path is not "/",
1514 1459 * then the mount will likely fail, so we should try again
1515 1460 * with a prepended "/".
1516 1461 */
1517 1462 if (mfs->mfs_flags & MFS_ALLOC_DIR && *dir != '/')
1518 1463 give_up_on_mnt = FALSE;
1519 1464 else
1520 1465 give_up_on_mnt = TRUE;
1521 1466
1522 1467 got_mnt_error = FALSE;
1523 1468
1524 1469 try_mnt_slash:
1525 1470 if (got_mnt_error == TRUE) {
1526 1471 int i, l;
1527 1472
1528 1473 give_up_on_mnt = TRUE;
1529 1474 l = strlen(dir);
1530 1475
1531 1476 /*
1532 1477 * Insert a "/" to front of mfs_dir.
1533 1478 */
1534 1479 for (i = l; i > 0; i--)
1535 1480 dir[i] = dir[i-1];
1536 1481
1537 1482 dir[0] = '/';
1538 1483 }
1539 1484
1540 1485 /* Get fhandle of remote path from server's mountd */
1541 1486
1542 1487 switch (outvers) {
1543 1488 case MOUNTVERS:
1544 1489 if (posix) {
1545 1490 free(argp);
1546 1491 head = prevhead;
1547 1492 tail = prevtail;
1548 1493 if (tail)
1549 1494 tail->nfs_ext_u.nfs_extB.next =
1550 1495 NULL;
1551 1496 last_error = NFSERR_NOENT;
1552 1497 syslog(loglevel,
1553 1498 "can't get posix info for %s",
1554 1499 host);
1555 1500 destroy_auth_client_handle(cl);
1556 1501 skipentry = 1;
1557 1502 mfs->mfs_ignore = 1;
1558 1503 continue;
1559 1504 }
1560 1505 /* FALLTHRU */
1561 1506 case MOUNTVERS_POSIX:
1562 1507 if (nfsvers == NFS_V3) {
1563 1508 free(argp);
1564 1509 head = prevhead;
1565 1510 tail = prevtail;
1566 1511 if (tail)
1567 1512 tail->nfs_ext_u.nfs_extB.next =
1568 1513 NULL;
1569 1514 last_error = NFSERR_NOENT;
1570 1515 syslog(loglevel,
1571 1516 "%s doesn't support NFS Version 3",
1572 1517 host);
1573 1518 destroy_auth_client_handle(cl);
1574 1519 skipentry = 1;
1575 1520 mfs->mfs_ignore = 1;
1576 1521 continue;
1577 1522 }
1578 1523 rpc_stat = clnt_call(cl, MOUNTPROC_MNT,
1579 1524 xdr_dirpath, (caddr_t)&dir,
1580 1525 xdr_fhstatus, (caddr_t)&fhs, timeout);
1581 1526 if (rpc_stat != RPC_SUCCESS) {
1582 1527
1583 1528 if (give_up_on_mnt == FALSE) {
1584 1529 got_mnt_error = TRUE;
1585 1530 goto try_mnt_slash;
1586 1531 }
1587 1532
1588 1533 /*
1589 1534 * Given the way "clnt_sperror" works, the "%s"
1590 1535 * immediately following the "not responding"
1591 1536 * is correct.
1592 1537 */
1593 1538 free(argp);
1594 1539 head = prevhead;
1595 1540 tail = prevtail;
1596 1541 if (tail)
1597 1542 tail->nfs_ext_u.nfs_extB.next =
1598 1543 NULL;
1599 1544 last_error = NFSERR_NOENT;
1600 1545
1601 1546 if (retries-- > 0) {
1602 1547 destroy_auth_client_handle(cl);
1603 1548 DELAY(delay);
1604 1549 goto retry;
1605 1550 }
1606 1551
1607 1552 if (trace > 3) {
1608 1553 trace_prt(1,
1609 1554 " nfsmount: mount RPC "
1610 1555 "failed for %s\n",
1611 1556 host);
1612 1557 }
1613 1558 syslog(loglevel,
1614 1559 "%s server not responding%s",
1615 1560 host, clnt_sperror(cl, ""));
1616 1561 destroy_auth_client_handle(cl);
1617 1562 skipentry = 1;
1618 1563 mfs->mfs_ignore = 1;
1619 1564 continue;
1620 1565 }
1621 1566 if ((errno = fhs.fhs_status) != MNT_OK) {
1622 1567
1623 1568 if (give_up_on_mnt == FALSE) {
1624 1569 got_mnt_error = TRUE;
1625 1570 goto try_mnt_slash;
1626 1571 }
1627 1572
1628 1573 free(argp);
1629 1574 head = prevhead;
1630 1575 tail = prevtail;
1631 1576 if (tail)
1632 1577 tail->nfs_ext_u.nfs_extB.next =
1633 1578 NULL;
1634 1579 if (errno == EACCES) {
1635 1580 status = NFSERR_ACCES;
1636 1581 } else {
1637 1582 syslog(loglevel, "%s: %m",
1638 1583 host);
1639 1584 status = NFSERR_IO;
1640 1585 }
1641 1586 if (trace > 3) {
1642 1587 trace_prt(1,
1643 1588 " nfsmount: mount RPC gave"
1644 1589 " %d for %s:%s\n",
1645 1590 errno, host, dir);
1646 1591 }
1647 1592 last_error = status;
1648 1593 destroy_auth_client_handle(cl);
1649 1594 skipentry = 1;
1650 1595 mfs->mfs_ignore = 1;
1651 1596 continue;
1652 1597 }
1653 1598 argp->fh = malloc((sizeof (fhandle)));
1654 1599 if (!argp->fh) {
1655 1600 syslog(LOG_ERR, "nfsmount: no memory");
1656 1601 last_error = NFSERR_IO;
1657 1602 destroy_auth_client_handle(cl);
1658 1603 goto out;
1659 1604 }
1660 1605 (void) memcpy(argp->fh,
1661 1606 &fhs.fhstatus_u.fhs_fhandle,
1662 1607 sizeof (fhandle));
1663 1608 break;
1664 1609 case MOUNTVERS3:
1665 1610 posix = 0;
1666 1611 (void) memset((char *)&res3, '\0',
1667 1612 sizeof (res3));
1668 1613 rpc_stat = clnt_call(cl, MOUNTPROC_MNT,
1669 1614 xdr_dirpath, (caddr_t)&dir,
1670 1615 xdr_mountres3, (caddr_t)&res3, timeout);
1671 1616 if (rpc_stat != RPC_SUCCESS) {
1672 1617
1673 1618 if (give_up_on_mnt == FALSE) {
1674 1619 got_mnt_error = TRUE;
1675 1620 goto try_mnt_slash;
1676 1621 }
1677 1622
1678 1623 /*
1679 1624 * Given the way "clnt_sperror" works, the "%s"
1680 1625 * immediately following the "not responding"
1681 1626 * is correct.
1682 1627 */
1683 1628 free(argp);
1684 1629 head = prevhead;
1685 1630 tail = prevtail;
1686 1631 if (tail)
1687 1632 tail->nfs_ext_u.nfs_extB.next =
1688 1633 NULL;
1689 1634 last_error = NFSERR_NOENT;
1690 1635
1691 1636 if (retries-- > 0) {
1692 1637 destroy_auth_client_handle(cl);
1693 1638 DELAY(delay);
1694 1639 goto retry;
1695 1640 }
1696 1641
1697 1642 if (trace > 3) {
1698 1643 trace_prt(1,
1699 1644 " nfsmount: mount RPC "
1700 1645 "failed for %s\n",
1701 1646 host);
1702 1647 }
1703 1648 syslog(loglevel,
1704 1649 "%s server not responding%s",
1705 1650 remname, clnt_sperror(cl, ""));
1706 1651 destroy_auth_client_handle(cl);
1707 1652 skipentry = 1;
1708 1653 mfs->mfs_ignore = 1;
1709 1654 continue;
1710 1655 }
1711 1656 if ((errno = res3.fhs_status) != MNT_OK) {
1712 1657
1713 1658 if (give_up_on_mnt == FALSE) {
1714 1659 got_mnt_error = TRUE;
1715 1660 goto try_mnt_slash;
1716 1661 }
1717 1662
1718 1663 free(argp);
1719 1664 head = prevhead;
1720 1665 tail = prevtail;
1721 1666 if (tail)
1722 1667 tail->nfs_ext_u.nfs_extB.next =
1723 1668 NULL;
1724 1669 if (errno == EACCES) {
1725 1670 status = NFSERR_ACCES;
1726 1671 } else {
1727 1672 syslog(loglevel, "%s: %m",
1728 1673 remname);
1729 1674 status = NFSERR_IO;
1730 1675 }
1731 1676 if (trace > 3) {
1732 1677 trace_prt(1,
1733 1678 " nfsmount: mount RPC gave"
1734 1679 " %d for %s:%s\n",
1735 1680 errno, host, dir);
1736 1681 }
1737 1682 last_error = status;
1738 1683 destroy_auth_client_handle(cl);
1739 1684 skipentry = 1;
1740 1685 mfs->mfs_ignore = 1;
1741 1686 continue;
1742 1687 }
1743 1688
1744 1689 /*
1745 1690 * Negotiate the security flavor for nfs_mount
1746 1691 */
1747 1692 auths = res3.mountres3_u.mountinfo.
1748 1693 auth_flavors.auth_flavors_val;
1749 1694 count = res3.mountres3_u.mountinfo.
1750 1695 auth_flavors.auth_flavors_len;
1751 1696
1752 1697 if (sec_opt) {
1753 1698 for (i = 0; i < count; i++)
1754 1699 if (auths[i] ==
1755 1700 nfs_sec.sc_nfsnum) {
1756 1701 break;
1757 1702 }
1758 1703 if (i >= count) {
1759 1704 syslog(LOG_ERR,
1760 1705 "%s: does not support "
1761 1706 "security \"%s\"\n",
1762 1707 remname, nfs_sec.sc_name);
1763 1708 clnt_freeres(cl, xdr_mountres3,
1764 1709 (caddr_t)&res3);
1765 1710 free(argp);
1766 1711 head = prevhead;
1767 1712 tail = prevtail;
1768 1713 if (tail)
1769 1714 tail->nfs_ext_u.
1770 1715 nfs_extB.next =
1771 1716 NULL;
1772 1717 last_error = NFSERR_IO;
1773 1718 destroy_auth_client_handle(cl);
1774 1719 skipentry = 1;
1775 1720 mfs->mfs_ignore = 1;
1776 1721 continue;
1777 1722 }
1778 1723 } else if (count > 0) {
1779 1724 for (i = 0; i < count; i++) {
1780 1725 if (!(scerror =
1781 1726 nfs_getseconfig_bynumber(
1782 1727 auths[i], &nfs_sec))) {
1783 1728 sec_opt++;
1784 1729 break;
1785 1730 }
1786 1731 }
1787 1732 if (i >= count) {
1788 1733 if (nfs_syslog_scerr(scerror,
1789 1734 scerror_msg)
1790 1735 != -1) {
1791 1736 syslog(LOG_ERR,
1792 1737 "%s cannot be "
1793 1738 "mounted because it"
1794 1739 " is shared with "
1795 1740 "security flavor %d"
1796 1741 " which %s",
1797 1742 remname,
1798 1743 auths[i-1],
1799 1744 scerror_msg);
1800 1745 }
1801 1746 clnt_freeres(cl, xdr_mountres3,
1802 1747 (caddr_t)&res3);
1803 1748 free(argp);
1804 1749 head = prevhead;
1805 1750 tail = prevtail;
1806 1751 if (tail)
1807 1752 tail->nfs_ext_u.
1808 1753 nfs_extB.next =
1809 1754 NULL;
1810 1755 last_error = NFSERR_IO;
1811 1756 destroy_auth_client_handle(cl);
1812 1757 skipentry = 1;
1813 1758 mfs->mfs_ignore = 1;
1814 1759 continue;
1815 1760 }
1816 1761 }
1817 1762
1818 1763 fh3.fh3_length =
1819 1764 res3.mountres3_u.mountinfo.fhandle.
1820 1765 fhandle3_len;
1821 1766 (void) memcpy(fh3.fh3_u.data,
1822 1767 res3.mountres3_u.mountinfo.fhandle.
1823 1768 fhandle3_val,
1824 1769 fh3.fh3_length);
1825 1770 clnt_freeres(cl, xdr_mountres3,
1826 1771 (caddr_t)&res3);
1827 1772 argp->fh = malloc(sizeof (nfs_fh3));
1828 1773 if (!argp->fh) {
1829 1774 syslog(LOG_ERR, "nfsmount: no memory");
1830 1775 last_error = NFSERR_IO;
1831 1776 destroy_auth_client_handle(cl);
1832 1777 goto out;
1833 1778 }
1834 1779 (void) memcpy(argp->fh, &fh3, sizeof (nfs_fh3));
1835 1780 break;
1836 1781 default:
1837 1782 free(argp);
1838 1783 head = prevhead;
1839 1784 tail = prevtail;
1840 1785 if (tail)
1841 1786 tail->nfs_ext_u.nfs_extB.next = NULL;
1842 1787 last_error = NFSERR_NOENT;
1843 1788 syslog(loglevel,
1844 1789 "unknown MOUNT version %ld on %s",
1845 1790 vers, remname);
1846 1791 destroy_auth_client_handle(cl);
1847 1792 skipentry = 1;
1848 1793 mfs->mfs_ignore = 1;
1849 1794 continue;
1850 1795 } /* switch */
1851 1796 }
1852 1797 if (nfsvers == NFS_V4) {
1853 1798 argp->fh = strdup(dir);
1854 1799 if (argp->fh == NULL) {
1855 1800 syslog(LOG_ERR, "nfsmount: no memory");
1856 1801 last_error = NFSERR_IO;
1857 1802 goto out;
1858 1803 }
1859 1804 }
1860 1805
1861 1806 if (trace > 4)
1862 1807 trace_prt(1, " nfsmount: have %s filehandle for %s\n",
1863 1808 fstype, remname);
1864 1809
1865 1810 argp->flags |= NFSMNT_NEWARGS;
1866 1811 argp->flags |= NFSMNT_INT; /* default is "intr" */
1867 1812 argp->flags |= NFSMNT_HOSTNAME;
1868 1813 argp->hostname = strdup(host);
1869 1814 if (argp->hostname == NULL) {
1870 1815 syslog(LOG_ERR, "nfsmount: no memory");
1871 1816 last_error = NFSERR_IO;
1872 1817 goto out;
1873 1818 }
1874 1819
1875 1820 /*
1876 1821 * In this case, we want NFSv4 to behave like
1877 1822 * non-WebNFS so that we get the server address.
1878 1823 */
1879 1824 if ((mfs->mfs_flags & MFS_FH_VIA_WEBNFS) == 0) {
1880 1825 nconf = NULL;
1881 1826
1882 1827 if (nfs_port != 0)
1883 1828 thisport = nfs_port;
1884 1829 else
1885 1830 thisport = mfs->mfs_port;
1886 1831
1887 1832 /*
1888 1833 * For NFSv4, we want to avoid rpcbind, so call
1889 1834 * get_server_netinfo() directly to tell it that
1890 1835 * we want to go "direct_to_server". Otherwise,
1891 1836 * do what has always been done.
1892 1837 */
1893 1838 if (nfsvers == NFS_V4) {
1894 1839 enum clnt_stat cstat;
1895 1840
1896 1841 argp->addr = get_server_netinfo(SERVER_ADDR,
1897 1842 host, NFS_PROGRAM, nfsvers, NULL,
1898 1843 &nconf, nfs_proto, thisport, NULL,
1899 1844 NULL, TRUE, NULL, &cstat);
1900 1845 } else {
1901 1846 argp->addr = get_addr(host, NFS_PROGRAM,
1902 1847 nfsvers, &nconf, nfs_proto,
1903 1848 thisport, NULL);
1904 1849 }
1905 1850
1906 1851 if (argp->addr == NULL) {
1907 1852 if (argp->hostname)
1908 1853 free(argp->hostname);
1909 1854 free(argp->fh);
1910 1855 free(argp);
1911 1856 head = prevhead;
1912 1857 tail = prevtail;
1913 1858 if (tail)
1914 1859 tail->nfs_ext_u.nfs_extB.next = NULL;
1915 1860 last_error = NFSERR_NOENT;
1916 1861
1917 1862 if (retries-- > 0) {
1918 1863 destroy_auth_client_handle(cl);
1919 1864 DELAY(delay);
1920 1865 goto retry;
1921 1866 }
1922 1867
1923 1868 syslog(loglevel, "%s: no NFS service", host);
1924 1869 destroy_auth_client_handle(cl);
1925 1870 skipentry = 1;
1926 1871 mfs->mfs_ignore = 1;
1927 1872 continue;
1928 1873 }
1929 1874 if (trace > 4)
1930 1875 trace_prt(1,
1931 1876 "\tnfsmount: have net address for %s\n",
1932 1877 remname);
1933 1878
1934 1879 } else {
1935 1880 nconf = mfs->mfs_nconf;
1936 1881 mfs->mfs_nconf = NULL;
1937 1882 }
1938 1883
1939 1884 argp->flags |= NFSMNT_KNCONF;
1940 1885 argp->knconf = get_knconf(nconf);
1941 1886 if (argp->knconf == NULL) {
1942 1887 netbuf_free(argp->addr);
1943 1888 freenetconfigent(nconf);
1944 1889 if (argp->hostname)
1945 1890 free(argp->hostname);
1946 1891 free(argp->fh);
1947 1892 free(argp);
1948 1893 head = prevhead;
1949 1894 tail = prevtail;
1950 1895 if (tail)
1951 1896 tail->nfs_ext_u.nfs_extB.next = NULL;
1952 1897 last_error = NFSERR_NOSPC;
1953 1898 destroy_auth_client_handle(cl);
1954 1899 skipentry = 1;
1955 1900 mfs->mfs_ignore = 1;
1956 1901 continue;
1957 1902 }
1958 1903 if (trace > 4)
1959 1904 trace_prt(1,
1960 1905 "\tnfsmount: have net config for %s\n",
1961 1906 remname);
1962 1907
1963 1908 if (hasmntopt(&m, MNTOPT_SOFT) != NULL) {
1964 1909 argp->flags |= NFSMNT_SOFT;
1965 1910 }
1966 1911 if (hasmntopt(&m, MNTOPT_NOINTR) != NULL) {
1967 1912 argp->flags &= ~(NFSMNT_INT);
1968 1913 }
1969 1914 if (hasmntopt(&m, MNTOPT_NOAC) != NULL) {
1970 1915 argp->flags |= NFSMNT_NOAC;
1971 1916 }
1972 1917 if (hasmntopt(&m, MNTOPT_NOCTO) != NULL) {
1973 1918 argp->flags |= NFSMNT_NOCTO;
1974 1919 }
1975 1920 if (hasmntopt(&m, MNTOPT_FORCEDIRECTIO) != NULL) {
1976 1921 argp->flags |= NFSMNT_DIRECTIO;
1977 1922 }
1978 1923 if (hasmntopt(&m, MNTOPT_NOFORCEDIRECTIO) != NULL) {
1979 1924 argp->flags &= ~(NFSMNT_DIRECTIO);
1980 1925 }
1981 1926
1982 1927 /*
1983 1928 * Set up security data for argp->nfs_ext_u.nfs_extB.secdata.
1984 1929 */
1985 1930 if (mfssnego.snego_done) {
1986 1931 memcpy(&nfs_sec, &mfssnego.nfs_sec,
1987 1932 sizeof (seconfig_t));
1988 1933 } else if (!sec_opt) {
1989 1934 /*
1990 1935 * Get default security mode.
1991 1936 */
1992 1937 if (nfs_getseconfig_default(&nfs_sec)) {
1993 1938 syslog(loglevel,
1994 1939 "error getting default security entry\n");
1995 1940 free_knconf(argp->knconf);
1996 1941 netbuf_free(argp->addr);
1997 1942 freenetconfigent(nconf);
1998 1943 if (argp->hostname)
1999 1944 free(argp->hostname);
2000 1945 free(argp->fh);
2001 1946 free(argp);
2002 1947 head = prevhead;
2003 1948 tail = prevtail;
2004 1949 if (tail)
2005 1950 tail->nfs_ext_u.nfs_extB.next = NULL;
2006 1951 last_error = NFSERR_NOSPC;
2007 1952 destroy_auth_client_handle(cl);
2008 1953 skipentry = 1;
2009 1954 mfs->mfs_ignore = 1;
2010 1955 continue;
2011 1956 }
2012 1957 argp->flags |= NFSMNT_SECDEFAULT;
2013 1958 }
2014 1959
2015 1960 /*
2016 1961 * For AUTH_DH
2017 1962 * get the network address for the time service on
2018 1963 * the server. If an RPC based time service is
2019 1964 * not available then try the IP time service.
2020 1965 *
2021 1966 * Eventurally, we want to move this code to nfs_clnt_secdata()
2022 1967 * when autod_nfs.c and mount.c can share the same
2023 1968 * get_the_addr/get_netconfig_info routine.
2024 1969 */
2025 1970 secflags = 0;
2026 1971 syncaddr = NULL;
2027 1972 retaddrs = NULL;
2028 1973
2029 1974 if (nfs_sec.sc_rpcnum == AUTH_DH || nfsvers == NFS_V4) {
2030 1975 /*
2031 1976 * If not using the public fh and not NFS_V4, we can try
2032 1977 * talking RPCBIND. Otherwise, assume that firewalls
2033 1978 * prevent us from doing that.
2034 1979 */
2035 1980 if ((mfs->mfs_flags & MFS_FH_VIA_WEBNFS) == 0 &&
2036 1981 nfsvers != NFS_V4) {
2037 1982 enum clnt_stat cstat;
2038 1983 syncaddr = get_server_netinfo(SERVER_ADDR,
2039 1984 host, RPCBPROG, RPCBVERS, NULL, &nconf,
2040 1985 NULL, 0, NULL, NULL, FALSE, NULL, &cstat);
2041 1986 }
2042 1987
2043 1988 if (syncaddr != NULL) {
2044 1989 /* for flags in sec_data */
2045 1990 secflags |= AUTH_F_RPCTIMESYNC;
2046 1991 } else {
2047 1992 struct nd_hostserv hs;
2048 1993 int error;
2049 1994
2050 1995 hs.h_host = host;
2051 1996 hs.h_serv = "timserver";
2052 1997 error = netdir_getbyname(nconf, &hs, &retaddrs);
2053 1998
2054 1999 if (error != ND_OK &&
2055 2000 nfs_sec.sc_rpcnum == AUTH_DH) {
2056 2001 syslog(loglevel,
2057 2002 "%s: secure: no time service\n",
2058 2003 host);
2059 2004 free_knconf(argp->knconf);
2060 2005 netbuf_free(argp->addr);
2061 2006 freenetconfigent(nconf);
2062 2007 if (argp->hostname)
2063 2008 free(argp->hostname);
2064 2009 free(argp->fh);
2065 2010 free(argp);
2066 2011 head = prevhead;
2067 2012 tail = prevtail;
2068 2013 if (tail)
2069 2014 tail->nfs_ext_u.nfs_extB.next =
2070 2015 NULL;
2071 2016 last_error = NFSERR_IO;
2072 2017 destroy_auth_client_handle(cl);
2073 2018 skipentry = 1;
2074 2019 mfs->mfs_ignore = 1;
2075 2020 continue;
2076 2021 }
2077 2022
2078 2023 if (error == ND_OK)
2079 2024 syncaddr = retaddrs->n_addrs;
2080 2025
2081 2026 /*
2082 2027 * For potential usage by NFS V4 when AUTH_DH
2083 2028 * is negotiated via SECINFO in the kernel.
2084 2029 */
2085 2030 if (nfsvers == NFS_V4 && syncaddr &&
2086 2031 host2netname(netname, host, NULL)) {
2087 2032 argp->syncaddr =
2088 2033 malloc(sizeof (struct netbuf));
2089 2034 argp->syncaddr->buf =
2090 2035 malloc(syncaddr->len);
2091 2036 (void) memcpy(argp->syncaddr->buf,
2092 2037 syncaddr->buf, syncaddr->len);
2093 2038 argp->syncaddr->len = syncaddr->len;
2094 2039 argp->syncaddr->maxlen =
2095 2040 syncaddr->maxlen;
2096 2041 argp->netname = strdup(netname);
2097 2042 argp->flags |= NFSMNT_SECURE;
2098 2043 }
2099 2044 } /* syncaddr */
2100 2045 } /* AUTH_DH */
2101 2046
2102 2047 /*
2103 2048 * TSOL notes: automountd in tsol extension
2104 2049 * has "read down" capability, i.e. we allow
2105 2050 * a user to trigger an nfs mount into a lower
2106 2051 * labeled zone. We achieve this by always having
2107 2052 * root issue the mount request so that the
2108 2053 * lookup ops can go past /zone/<zone_name>
2109 2054 * on the server side.
2110 2055 */
2111 2056 if (is_system_labeled())
2112 2057 nfs_sec.sc_uid = (uid_t)0;
2113 2058 else
2114 2059 nfs_sec.sc_uid = uid;
2115 2060 /*
2116 2061 * If AUTH_DH is a chosen flavor now, its data will be stored
2117 2062 * in the sec_data structure via nfs_clnt_secdata().
2118 2063 */
2119 2064 if (!(secdata = nfs_clnt_secdata(&nfs_sec, host, argp->knconf,
2120 2065 syncaddr, secflags))) {
2121 2066 syslog(LOG_ERR,
2122 2067 "errors constructing security related data\n");
2123 2068 if (secflags & AUTH_F_RPCTIMESYNC)
2124 2069 netbuf_free(syncaddr);
2125 2070 else if (retaddrs)
2126 2071 netdir_free(retaddrs, ND_ADDRLIST);
2127 2072 if (argp->syncaddr)
2128 2073 netbuf_free(argp->syncaddr);
2129 2074 if (argp->netname)
2130 2075 free(argp->netname);
2131 2076 if (argp->hostname)
2132 2077 free(argp->hostname);
2133 2078 free_knconf(argp->knconf);
2134 2079 netbuf_free(argp->addr);
2135 2080 freenetconfigent(nconf);
2136 2081 free(argp->fh);
2137 2082 free(argp);
2138 2083 head = prevhead;
2139 2084 tail = prevtail;
2140 2085 if (tail)
2141 2086 tail->nfs_ext_u.nfs_extB.next = NULL;
2142 2087 last_error = NFSERR_IO;
2143 2088 destroy_auth_client_handle(cl);
2144 2089 skipentry = 1;
2145 2090 mfs->mfs_ignore = 1;
2146 2091 continue;
2147 2092 }
2148 2093 NFS_ARGS_EXTB_secdata(*argp, secdata);
2149 2094 /* end of security stuff */
2150 2095
2151 2096 if (trace > 4)
2152 2097 trace_prt(1,
2153 2098 " nfsmount: have secure info for %s\n", remname);
2154 2099
2155 2100 if (hasmntopt(&m, MNTOPT_GRPID) != NULL) {
2156 2101 argp->flags |= NFSMNT_GRPID;
2157 2102 }
2158 2103 if (nopt(&m, MNTOPT_RSIZE, &argp->rsize)) {
2159 2104 argp->flags |= NFSMNT_RSIZE;
2160 2105 }
2161 2106 if (nopt(&m, MNTOPT_WSIZE, &argp->wsize)) {
2162 2107 argp->flags |= NFSMNT_WSIZE;
2163 2108 }
2164 2109 if (nopt(&m, MNTOPT_TIMEO, &argp->timeo)) {
2165 2110 argp->flags |= NFSMNT_TIMEO;
2166 2111 }
2167 2112 if (nopt(&m, MNTOPT_RETRANS, &argp->retrans)) {
2168 2113 argp->flags |= NFSMNT_RETRANS;
2169 2114 }
2170 2115 if (nopt(&m, MNTOPT_ACTIMEO, &argp->acregmax)) {
2171 2116 argp->flags |= NFSMNT_ACREGMAX;
2172 2117 argp->flags |= NFSMNT_ACDIRMAX;
2173 2118 argp->flags |= NFSMNT_ACDIRMIN;
2174 2119 argp->flags |= NFSMNT_ACREGMIN;
2175 2120 argp->acdirmin = argp->acregmin = argp->acdirmax
2176 2121 = argp->acregmax;
2177 2122 } else {
2178 2123 if (nopt(&m, MNTOPT_ACREGMIN, &argp->acregmin)) {
2179 2124 argp->flags |= NFSMNT_ACREGMIN;
2180 2125 }
2181 2126 if (nopt(&m, MNTOPT_ACREGMAX, &argp->acregmax)) {
2182 2127 argp->flags |= NFSMNT_ACREGMAX;
2183 2128 }
2184 2129 if (nopt(&m, MNTOPT_ACDIRMIN, &argp->acdirmin)) {
2185 2130 argp->flags |= NFSMNT_ACDIRMIN;
2186 2131 }
2187 2132 if (nopt(&m, MNTOPT_ACDIRMAX, &argp->acdirmax)) {
2188 2133 argp->flags |= NFSMNT_ACDIRMAX;
2189 2134 }
2190 2135 }
2191 2136
2192 2137 if (posix) {
2193 2138 argp->pathconf = NULL;
2194 2139 if (error = get_pathconf(cl, dir, remname,
2195 2140 &argp->pathconf, retries)) {
2196 2141 if (secflags & AUTH_F_RPCTIMESYNC)
2197 2142 netbuf_free(syncaddr);
2198 2143 else if (retaddrs)
2199 2144 netdir_free(retaddrs, ND_ADDRLIST);
2200 2145 free_knconf(argp->knconf);
2201 2146 netbuf_free(argp->addr);
2202 2147 freenetconfigent(nconf);
2203 2148 nfs_free_secdata(
2204 2149 argp->nfs_ext_u.nfs_extB.secdata);
2205 2150 if (argp->syncaddr)
2206 2151 netbuf_free(argp->syncaddr);
2207 2152 if (argp->netname)
2208 2153 free(argp->netname);
2209 2154 if (argp->hostname)
2210 2155 free(argp->hostname);
2211 2156 free(argp->fh);
2212 2157 free(argp);
2213 2158 head = prevhead;
2214 2159 tail = prevtail;
2215 2160 if (tail)
2216 2161 tail->nfs_ext_u.nfs_extB.next = NULL;
2217 2162 last_error = NFSERR_IO;
2218 2163
2219 2164 if (error == RET_RETRY && retries-- > 0) {
2220 2165 destroy_auth_client_handle(cl);
2221 2166 DELAY(delay);
2222 2167 goto retry;
2223 2168 }
2224 2169
2225 2170 destroy_auth_client_handle(cl);
2226 2171 skipentry = 1;
2227 2172 mfs->mfs_ignore = 1;
2228 2173 continue;
2229 2174 }
2230 2175 argp->flags |= NFSMNT_POSIX;
2231 2176 if (trace > 4)
2232 2177 trace_prt(1,
2233 2178 " nfsmount: have pathconf for %s\n",
2234 2179 remname);
2235 2180 }
2236 2181
2237 2182 /*
2238 2183 * free loop-specific data structures
2239 2184 */
2240 2185 destroy_auth_client_handle(cl);
2241 2186 freenetconfigent(nconf);
2242 2187 if (secflags & AUTH_F_RPCTIMESYNC)
2243 2188 netbuf_free(syncaddr);
2244 2189 else if (retaddrs)
2245 2190 netdir_free(retaddrs, ND_ADDRLIST);
2246 2191
2247 2192 /*
2248 2193 * Decide whether to use remote host's lockd or local locking.
2249 2194 * If we are using the public fh, we've already turned
2250 2195 * LLOCK on.
2251 2196 */
2252 2197 if (hasmntopt(&m, MNTOPT_LLOCK))
2253 2198 argp->flags |= NFSMNT_LLOCK;
2254 2199 if (!(argp->flags & NFSMNT_LLOCK) && nfsvers == NFS_VERSION &&
2255 2200 remote_lock(host, argp->fh)) {
2256 2201 syslog(loglevel, "No network locking on %s : "
2257 2202 "contact admin to install server change", host);
2258 2203 argp->flags |= NFSMNT_LLOCK;
2259 2204 }
2260 2205
2261 2206 /*
2262 2207 * Build a string for /etc/mnttab.
2263 2208 * If possible, coalesce strings with same 'dir' info.
2264 2209 */
2265 2210 if ((mfs->mfs_flags & MFS_URL) == 0) {
2266 2211 char *tmp;
2267 2212
2268 2213 if (mnttabcnt) {
2269 2214 p = strrchr(mnttabtext, (int)':');
2270 2215 if (!p || strcmp(p+1, dir) != 0) {
2271 2216 mnttabcnt += strlen(remname) + 2;
2272 2217 } else {
2273 2218 *p = '\0';
2274 2219 mnttabcnt += strlen(rhost) + 2;
2275 2220 }
2276 2221 if ((tmp = realloc(mnttabtext,
2277 2222 mnttabcnt)) != NULL) {
2278 2223 mnttabtext = tmp;
2279 2224 strcat(mnttabtext, ",");
2280 2225 } else {
2281 2226 free(mnttabtext);
2282 2227 mnttabtext = NULL;
2283 2228 }
2284 2229 } else {
2285 2230 mnttabcnt = strlen(remname) + 1;
2286 2231 if ((mnttabtext = malloc(mnttabcnt)) != NULL)
2287 2232 mnttabtext[0] = '\0';
2288 2233 }
2289 2234
2290 2235 if (mnttabtext != NULL)
2291 2236 strcat(mnttabtext, remname);
2292 2237
2293 2238 } else {
2294 2239 char *tmp;
2295 2240 int more_cnt = 0;
2296 2241 char sport[16];
2297 2242
2298 2243 more_cnt += strlen("nfs://");
2299 2244 more_cnt += strlen(mfs->mfs_host);
2300 2245
2301 2246 if (mfs->mfs_port != 0) {
2302 2247 (void) sprintf(sport, ":%u", mfs->mfs_port);
2303 2248 } else
2304 2249 sport[0] = '\0';
2305 2250
2306 2251 more_cnt += strlen(sport);
2307 2252 more_cnt += 1; /* "/" */
2308 2253 more_cnt += strlen(mfs->mfs_dir);
2309 2254
2310 2255 if (mnttabcnt) {
2311 2256 more_cnt += 1; /* "," */
2312 2257 mnttabcnt += more_cnt;
2313 2258
2314 2259 if ((tmp = realloc(mnttabtext,
2315 2260 mnttabcnt)) != NULL) {
2316 2261 mnttabtext = tmp;
2317 2262 strcat(mnttabtext, ",");
2318 2263 } else {
2319 2264 free(mnttabtext);
2320 2265 mnttabtext = NULL;
2321 2266 }
2322 2267 } else {
2323 2268 mnttabcnt = more_cnt + 1;
2324 2269 if ((mnttabtext = malloc(mnttabcnt)) != NULL)
2325 2270 mnttabtext[0] = '\0';
2326 2271 }
2327 2272
2328 2273 if (mnttabtext != NULL) {
2329 2274 strcat(mnttabtext, "nfs://");
2330 2275 strcat(mnttabtext, mfs->mfs_host);
2331 2276 strcat(mnttabtext, sport);
2332 2277 strcat(mnttabtext, "/");
2333 2278 strcat(mnttabtext, mfs->mfs_dir);
2334 2279 }
2335 2280 }
2336 2281
2337 2282 if (!mnttabtext) {
2338 2283 syslog(LOG_ERR, "nfsmount: no memory");
2339 2284 last_error = NFSERR_IO;
2340 2285 goto out;
2341 2286 }
2342 2287
2343 2288 /*
2344 2289 * At least one entry, can call mount(2).
2345 2290 */
2346 2291 entries++;
2347 2292
2348 2293 /*
2349 2294 * If replication was defeated, don't do more work
2350 2295 */
2351 2296 if (!replicated)
2352 2297 break;
2353 2298 }
2354 2299
2355 2300
2356 2301 /*
2357 2302 * Did we get through all possibilities without success?
2358 2303 */
2359 2304 if (!entries)
2360 2305 goto out;
2361 2306
2362 2307 /* Make "xattr" the default if "noxattr" is not specified. */
2363 2308 strcpy(mopts, opts);
2364 2309 if (!hasmntopt(&m, MNTOPT_NOXATTR) && !hasmntopt(&m, MNTOPT_XATTR)) {
2365 2310 if (strlen(mopts) > 0)
2366 2311 strcat(mopts, ",");
2367 2312 strcat(mopts, "xattr");
2368 2313 }
2369 2314
2370 2315 /*
2371 2316 * enable services as needed.
2372 2317 */
2373 2318 {
2374 2319 char **sl;
2375 2320
2376 2321 if (strcmp(fstype, MNTTYPE_NFS4) == 0)
2377 2322 sl = service_list_v4;
2378 2323 else
2379 2324 sl = service_list;
2380 2325
2381 2326 (void) _check_services(sl);
2382 2327 }
2383 2328
2384 2329 /*
2385 2330 * Whew; do the mount, at last.
2386 2331 */
2387 2332 if (trace > 1) {
2388 2333 trace_prt(1, " mount %s %s (%s)\n", mnttabtext, mntpnt, mopts);
2389 2334 }
2390 2335
2391 2336 /*
2392 2337 * About to do a nfs mount, make sure the mount_to is set for
2393 2338 * potential ephemeral mounts with NFSv4.
2394 2339 */
2395 2340 set_nfsv4_ephemeral_mount_to();
2396 2341
2397 2342 /*
2398 2343 * If no action list pointer then do the mount, otherwise
2399 2344 * build the actions list pointer with the mount information.
2400 2345 * so the mount can be done in the kernel.
2401 2346 */
2402 2347 if (alp == NULL) {
2403 2348 if (mount(mnttabtext, mntpnt, flags | MS_DATA, fstype,
2404 2349 head, sizeof (*head), mopts, MAX_MNTOPT_STR) < 0) {
2405 2350 if (trace > 1)
2406 2351 trace_prt(1, " Mount of %s on %s: %d\n",
2407 2352 mnttabtext, mntpnt, errno);
2408 2353 if (errno != EBUSY || verbose)
2409 2354 syslog(LOG_ERR,
2410 2355 "Mount of %s on %s: %m", mnttabtext, mntpnt);
2411 2356 last_error = NFSERR_IO;
2412 2357 goto out;
2413 2358 }
2414 2359
2415 2360 last_error = NFS_OK;
2416 2361 if (stat(mntpnt, &stbuf) == 0) {
2417 2362 if (trace > 1) {
2418 2363 trace_prt(1, " mount %s dev=%x rdev=%x OK\n",
2419 2364 mnttabtext, stbuf.st_dev, stbuf.st_rdev);
2420 2365 }
2421 2366 } else {
2422 2367 if (trace > 1) {
2423 2368 trace_prt(1, " mount %s OK\n", mnttabtext);
2424 2369 trace_prt(1, " stat of %s failed\n", mntpnt);
2425 2370 }
2426 2371
2427 2372 }
2428 2373 } else {
2429 2374 alp->action.action = AUTOFS_MOUNT_RQ;
2430 2375 alp->action.action_list_entry_u.mounta.spec =
2431 2376 strdup(mnttabtext);
2432 2377 alp->action.action_list_entry_u.mounta.dir = strdup(mntpnt);
2433 2378 alp->action.action_list_entry_u.mounta.flags =
2434 2379 flags | MS_DATA;
2435 2380 alp->action.action_list_entry_u.mounta.fstype =
2436 2381 strdup(fstype);
2437 2382 alp->action.action_list_entry_u.mounta.dataptr = (char *)head;
2438 2383 alp->action.action_list_entry_u.mounta.datalen =
2439 2384 sizeof (*head);
2440 2385 mntopts = malloc(strlen(mopts) + 1);
2441 2386 strcpy(mntopts, mopts);
2442 2387 mntopts[strlen(mopts)] = '\0';
2443 2388 alp->action.action_list_entry_u.mounta.optptr = mntopts;
2444 2389 alp->action.action_list_entry_u.mounta.optlen =
2445 2390 strlen(mntopts) + 1;
2446 2391 last_error = NFS_OK;
2447 2392 goto ret;
2448 2393 }
2449 2394
2450 2395 out:
2451 2396 argp = head;
2452 2397 while (argp) {
2453 2398 if (argp->pathconf)
2454 2399 free(argp->pathconf);
2455 2400 free_knconf(argp->knconf);
2456 2401 netbuf_free(argp->addr);
2457 2402 if (argp->syncaddr)
2458 2403 netbuf_free(argp->syncaddr);
2459 2404 if (argp->netname) {
2460 2405 free(argp->netname);
2461 2406 }
2462 2407 if (argp->hostname)
2463 2408 free(argp->hostname);
2464 2409 nfs_free_secdata(argp->nfs_ext_u.nfs_extB.secdata);
2465 2410 free(argp->fh);
2466 2411 head = argp;
2467 2412 argp = argp->nfs_ext_u.nfs_extB.next;
2468 2413 free(head);
2469 2414 }
2470 2415 ret:
2471 2416 if (nfs_proto)
2472 2417 free(nfs_proto);
2473 2418 if (mnttabtext)
2474 2419 free(mnttabtext);
2475 2420
2476 2421 for (mfs = mfs_in; mfs; mfs = mfs->mfs_next) {
2477 2422
2478 2423 if (mfs->mfs_flags & MFS_ALLOC_DIR) {
2479 2424 free(mfs->mfs_dir);
2480 2425 mfs->mfs_dir = NULL;
2481 2426 mfs->mfs_flags &= ~MFS_ALLOC_DIR;
2482 2427 }
2483 2428
2484 2429 if (mfs->mfs_args != NULL && alp == NULL) {
2485 2430 free(mfs->mfs_args);
2486 2431 mfs->mfs_args = NULL;
2487 2432 }
2488 2433
2489 2434 if (mfs->mfs_nconf != NULL) {
2490 2435 freenetconfigent(mfs->mfs_nconf);
2491 2436 mfs->mfs_nconf = NULL;
2492 2437 }
2493 2438 }
2494 2439
2495 2440 return (last_error);
2496 2441 }
2497 2442
2498 2443 /*
2499 2444 * get_pathconf(cl, path, fsname, pcnf, cretries)
2500 2445 * ugliness that requires that ppathcnf and pathcnf stay consistent
2501 2446 * cretries is a copy of retries used to determine when to syslog
2502 2447 * on retry situations.
2503 2448 */
2504 2449 static int
2505 2450 get_pathconf(CLIENT *cl, char *path, char *fsname, struct pathcnf **pcnf,
2506 2451 int cretries)
2507 2452 {
2508 2453 struct ppathcnf *p = NULL;
2509 2454 enum clnt_stat rpc_stat;
2510 2455 struct timeval timeout;
2511 2456
2512 2457 p = (struct ppathcnf *)malloc(sizeof (struct ppathcnf));
2513 2458 if (p == NULL) {
2514 2459 syslog(LOG_ERR, "get_pathconf: Out of memory");
2515 2460 return (RET_ERR);
2516 2461 }
2517 2462 memset((caddr_t)p, 0, sizeof (struct ppathcnf));
2518 2463
2519 2464 timeout.tv_sec = 10;
2520 2465 timeout.tv_usec = 0;
2521 2466 rpc_stat = clnt_call(cl, MOUNTPROC_PATHCONF,
2522 2467 xdr_dirpath, (caddr_t)&path, xdr_ppathcnf, (caddr_t)p, timeout);
2523 2468 if (rpc_stat != RPC_SUCCESS) {
2524 2469 if (cretries-- <= 0) {
2525 2470 syslog(LOG_ERR,
2526 2471 "get_pathconf: %s: server not responding: %s",
2527 2472 fsname, clnt_sperror(cl, ""));
2528 2473 }
2529 2474 free(p);
2530 2475 return (RET_RETRY);
2531 2476 }
2532 2477 if (_PC_ISSET(_PC_ERROR, p->pc_mask)) {
2533 2478 syslog(LOG_ERR, "get_pathconf: no info for %s", fsname);
2534 2479 free(p);
2535 2480 return (RET_ERR);
2536 2481 }
2537 2482 *pcnf = (struct pathcnf *)p;
2538 2483 return (RET_OK);
2539 2484 }
2540 2485
2541 2486 void
2542 2487 netbuf_free(nb)
2543 2488 struct netbuf *nb;
2544 2489 {
2545 2490 if (nb == NULL)
2546 2491 return;
2547 2492 if (nb->buf)
2548 2493 free(nb->buf);
2549 2494 free(nb);
2550 2495 }
2551 2496
2552 2497 #define SMALL_HOSTNAME 20
2553 2498 #define SMALL_PROTONAME 10
2554 2499 #define SMALL_PROTOFMLYNAME 10
2555 2500
2556 2501 struct portmap_cache {
2557 2502 int cache_prog;
2558 2503 int cache_vers;
2559 2504 time_t cache_time;
2560 2505 char cache_small_hosts[SMALL_HOSTNAME + 1];
2561 2506 char *cache_hostname;
2562 2507 char *cache_proto;
2563 2508 char *cache_protofmly;
2564 2509 char cache_small_protofmly[SMALL_PROTOFMLYNAME + 1];
2565 2510 char cache_small_proto[SMALL_PROTONAME + 1];
2566 2511 struct netbuf cache_srv_addr;
2567 2512 struct portmap_cache *cache_prev, *cache_next;
2568 2513 };
2569 2514
2570 2515 rwlock_t portmap_cache_lock;
2571 2516 static int portmap_cache_valid_time = 30;
2572 2517 struct portmap_cache *portmap_cache_head, *portmap_cache_tail;
2573 2518
2574 2519 #ifdef MALLOC_DEBUG
2575 2520 void
2576 2521 portmap_cache_flush()
2577 2522 {
2578 2523 struct portmap_cache *next = NULL, *cp;
2579 2524
2580 2525 (void) rw_wrlock(&portmap_cache_lock);
2581 2526 for (cp = portmap_cache_head; cp; cp = cp->cache_next) {
2582 2527 if (cp->cache_hostname != NULL &&
2583 2528 cp->cache_hostname !=
2584 2529 cp->cache_small_hosts)
2585 2530 free(cp->cache_hostname);
2586 2531 if (cp->cache_proto != NULL &&
2587 2532 cp->cache_proto !=
2588 2533 cp->cache_small_proto)
2589 2534 free(cp->cache_proto);
2590 2535 if (cp->cache_srv_addr.buf != NULL)
2591 2536 free(cp->cache_srv_addr.buf);
2592 2537 next = cp->cache_next;
2593 2538 free(cp);
2594 2539 }
2595 2540 portmap_cache_head = NULL;
2596 2541 portmap_cache_tail = NULL;
2597 2542 (void) rw_unlock(&portmap_cache_lock);
2598 2543 }
2599 2544 #endif
2600 2545
2601 2546 /*
2602 2547 * Returns 1 if the entry is found in the cache, 0 otherwise.
2603 2548 */
2604 2549 static int
2605 2550 portmap_cache_lookup(hostname, prog, vers, nconf, addrp)
2606 2551 char *hostname;
2607 2552 rpcprog_t prog;
2608 2553 rpcvers_t vers;
2609 2554 struct netconfig *nconf;
2610 2555 struct netbuf *addrp;
2611 2556 {
2612 2557 struct portmap_cache *cachep, *prev, *next = NULL, *cp;
2613 2558 int retval = 0;
2614 2559
2615 2560 timenow = time(NULL);
2616 2561
2617 2562 (void) rw_rdlock(&portmap_cache_lock);
2618 2563
2619 2564 /*
2620 2565 * Increment the portmap cache counters for # accesses and lookups
2621 2566 * Use a smaller factor (100 vs 1000 for the host cache) since
2622 2567 * initial analysis shows this cache is looked up 10% that of the
2623 2568 * host cache.
2624 2569 */
2625 2570 #ifdef CACHE_DEBUG
2626 2571 portmap_cache_accesses++;
2627 2572 portmap_cache_lookups++;
2628 2573 if ((portmap_cache_lookups%100) == 0)
2629 2574 trace_portmap_cache();
2630 2575 #endif /* CACHE_DEBUG */
2631 2576
2632 2577 for (cachep = portmap_cache_head; cachep;
2633 2578 cachep = cachep->cache_next) {
2634 2579 if (timenow > cachep->cache_time) {
2635 2580 /*
2636 2581 * We stumbled across an entry in the cache which
2637 2582 * has timed out. Free up all the entries that
2638 2583 * were added before it, which will positionally
2639 2584 * be after this entry. And adjust neighboring
2640 2585 * pointers.
2641 2586 * When we drop the lock and re-acquire it, we
2642 2587 * need to start from the beginning.
2643 2588 */
2644 2589 (void) rw_unlock(&portmap_cache_lock);
2645 2590 (void) rw_wrlock(&portmap_cache_lock);
2646 2591 for (cp = portmap_cache_head;
2647 2592 cp && (cp->cache_time >= timenow);
2648 2593 cp = cp->cache_next)
2649 2594 ;
2650 2595 if (cp == NULL)
2651 2596 goto done;
2652 2597 /*
2653 2598 * Adjust the link of the predecessor.
2654 2599 * Make the tail point to the new last entry.
2655 2600 */
2656 2601 prev = cp->cache_prev;
2657 2602 if (prev == NULL) {
2658 2603 portmap_cache_head = NULL;
2659 2604 portmap_cache_tail = NULL;
2660 2605 } else {
2661 2606 prev->cache_next = NULL;
2662 2607 portmap_cache_tail = prev;
2663 2608 }
2664 2609 for (; cp; cp = next) {
2665 2610 if (cp->cache_hostname != NULL &&
2666 2611 cp->cache_hostname !=
2667 2612 cp->cache_small_hosts)
2668 2613 free(cp->cache_hostname);
2669 2614 if (cp->cache_proto != NULL &&
2670 2615 cp->cache_proto !=
2671 2616 cp->cache_small_proto)
2672 2617 free(cp->cache_proto);
2673 2618 if (cp->cache_srv_addr.buf != NULL)
2674 2619 free(cp->cache_srv_addr.buf);
2675 2620 next = cp->cache_next;
2676 2621 free(cp);
2677 2622 }
2678 2623 goto done;
2679 2624 }
2680 2625 if (cachep->cache_hostname == NULL ||
2681 2626 prog != cachep->cache_prog || vers != cachep->cache_vers ||
2682 2627 strcmp(nconf->nc_proto, cachep->cache_proto) != 0 ||
2683 2628 strcmp(nconf->nc_protofmly, cachep->cache_protofmly) != 0 ||
2684 2629 strcmp(hostname, cachep->cache_hostname) != 0)
2685 2630 continue;
2686 2631 /*
2687 2632 * Cache Hit.
2688 2633 */
2689 2634 #ifdef CACHE_DEBUG
2690 2635 portmap_cache_hits++; /* up portmap cache hit counter */
2691 2636 #endif /* CACHE_DEBUG */
2692 2637 addrp->len = cachep->cache_srv_addr.len;
2693 2638 memcpy(addrp->buf, cachep->cache_srv_addr.buf, addrp->len);
2694 2639 retval = 1;
2695 2640 break;
2696 2641 }
2697 2642 done:
2698 2643 (void) rw_unlock(&portmap_cache_lock);
2699 2644 return (retval);
2700 2645 }
2701 2646
2702 2647 static void
2703 2648 portmap_cache_enter(hostname, prog, vers, nconf, addrp)
2704 2649 char *hostname;
2705 2650 rpcprog_t prog;
2706 2651 rpcvers_t vers;
2707 2652 struct netconfig *nconf;
2708 2653 struct netbuf *addrp;
2709 2654 {
2710 2655 struct portmap_cache *cachep;
2711 2656 int protofmlylen;
2712 2657 int protolen, hostnamelen;
2713 2658
2714 2659 timenow = time(NULL);
2715 2660
2716 2661 cachep = malloc(sizeof (struct portmap_cache));
2717 2662 if (cachep == NULL)
2718 2663 return;
2719 2664 memset((char *)cachep, 0, sizeof (*cachep));
2720 2665
2721 2666 hostnamelen = strlen(hostname);
2722 2667 if (hostnamelen <= SMALL_HOSTNAME)
2723 2668 cachep->cache_hostname = cachep->cache_small_hosts;
2724 2669 else {
2725 2670 cachep->cache_hostname = malloc(hostnamelen + 1);
2726 2671 if (cachep->cache_hostname == NULL)
2727 2672 goto nomem;
2728 2673 }
2729 2674 strcpy(cachep->cache_hostname, hostname);
2730 2675 protolen = strlen(nconf->nc_proto);
2731 2676 if (protolen <= SMALL_PROTONAME)
2732 2677 cachep->cache_proto = cachep->cache_small_proto;
2733 2678 else {
2734 2679 cachep->cache_proto = malloc(protolen + 1);
2735 2680 if (cachep->cache_proto == NULL)
2736 2681 goto nomem;
2737 2682 }
2738 2683 protofmlylen = strlen(nconf->nc_protofmly);
2739 2684 if (protofmlylen <= SMALL_PROTOFMLYNAME)
2740 2685 cachep->cache_protofmly = cachep->cache_small_protofmly;
2741 2686 else {
2742 2687 cachep->cache_protofmly = malloc(protofmlylen + 1);
2743 2688 if (cachep->cache_protofmly == NULL)
2744 2689 goto nomem;
2745 2690 }
2746 2691
2747 2692 strcpy(cachep->cache_proto, nconf->nc_proto);
2748 2693 cachep->cache_prog = prog;
2749 2694 cachep->cache_vers = vers;
2750 2695 cachep->cache_time = timenow + portmap_cache_valid_time;
2751 2696 cachep->cache_srv_addr.len = addrp->len;
2752 2697 cachep->cache_srv_addr.buf = malloc(addrp->len);
2753 2698 if (cachep->cache_srv_addr.buf == NULL)
2754 2699 goto nomem;
2755 2700 memcpy(cachep->cache_srv_addr.buf, addrp->buf, addrp->maxlen);
2756 2701 cachep->cache_prev = NULL;
2757 2702 (void) rw_wrlock(&portmap_cache_lock);
2758 2703 /*
2759 2704 * There's a window in which we could have multiple threads making
2760 2705 * the same cache entry. This can be avoided by walking the cache
2761 2706 * once again here to check and see if there are duplicate entries
2762 2707 * (after grabbing the write lock). This isn't fatal and I'm not
2763 2708 * going to bother with this.
2764 2709 */
2765 2710 #ifdef CACHE_DEBUG
2766 2711 portmap_cache_accesses++; /* up portmap cache access counter */
2767 2712 #endif /* CACHE_DEBUG */
2768 2713 cachep->cache_next = portmap_cache_head;
2769 2714 if (portmap_cache_head != NULL)
2770 2715 portmap_cache_head->cache_prev = cachep;
2771 2716 portmap_cache_head = cachep;
2772 2717 (void) rw_unlock(&portmap_cache_lock);
2773 2718 return;
2774 2719
2775 2720 nomem:
2776 2721 syslog(LOG_ERR, "portmap_cache_enter: Memory allocation failed");
2777 2722 if (cachep->cache_srv_addr.buf)
2778 2723 free(cachep->cache_srv_addr.buf);
2779 2724 if (cachep->cache_proto && protolen > SMALL_PROTONAME)
2780 2725 free(cachep->cache_proto);
2781 2726 if (cachep->cache_hostname && hostnamelen > SMALL_HOSTNAME)
2782 2727 free(cachep->cache_hostname);
2783 2728 if (cachep->cache_protofmly && protofmlylen > SMALL_PROTOFMLYNAME)
2784 2729 free(cachep->cache_protofmly);
2785 2730 if (cachep)
2786 2731 free(cachep);
2787 2732 cachep = NULL;
2788 2733 }
2789 2734
2790 2735 static int
2791 2736 get_cached_srv_addr(char *hostname, rpcprog_t prog, rpcvers_t vers,
2792 2737 struct netconfig *nconf, struct netbuf *addrp)
2793 2738 {
2794 2739 if (portmap_cache_lookup(hostname, prog, vers, nconf, addrp))
2795 2740 return (1);
2796 2741 if (rpcb_getaddr(prog, vers, nconf, addrp, hostname) == 0)
2797 2742 return (0);
2798 2743 portmap_cache_enter(hostname, prog, vers, nconf, addrp);
2799 2744 return (1);
2800 2745 }
2801 2746
2802 2747 /*
2803 2748 * Get a network address on "hostname" for program "prog"
2804 2749 * with version "vers". If the port number is specified (non zero)
2805 2750 * then try for a TCP/UDP transport and set the port number of the
2806 2751 * resulting IP address.
2807 2752 *
2808 2753 * If the address of a netconfig pointer was passed and
2809 2754 * if it's not null, use it as the netconfig otherwise
2810 2755 * assign the address of the netconfig that was used to
2811 2756 * establish contact with the service.
2812 2757 *
2813 2758 * tinfo argument is for matching the get_addr() defined in
2814 2759 * ../nfs/mount/mount.c
2815 2760 */
2816 2761
2817 2762 static struct netbuf *
2818 2763 get_addr(char *hostname, rpcprog_t prog, rpcvers_t vers,
2819 2764 struct netconfig **nconfp, char *proto, ushort_t port,
2820 2765 struct t_info *tinfo)
2821 2766
2822 2767 {
2823 2768 enum clnt_stat cstat;
2824 2769
2825 2770 return (get_server_netinfo(SERVER_ADDR, hostname, prog, vers, NULL,
2826 2771 nconfp, proto, port, tinfo, NULL, FALSE, NULL, &cstat));
2827 2772 }
2828 2773
2829 2774 static struct netbuf *
2830 2775 get_pubfh(char *hostname, rpcvers_t vers, mfs_snego_t *mfssnego,
2831 2776 struct netconfig **nconfp, char *proto, ushort_t port,
2832 2777 struct t_info *tinfo, caddr_t *fhp, bool_t get_pubfh, char *fspath)
2833 2778 {
2834 2779 enum clnt_stat cstat;
2835 2780
2836 2781 return (get_server_netinfo(SERVER_FH, hostname, NFS_PROGRAM, vers,
2837 2782 mfssnego, nconfp, proto, port, tinfo, fhp, get_pubfh, fspath,
2838 2783 &cstat));
2839 2784 }
2840 2785
2841 2786 static enum clnt_stat
2842 2787 get_ping(char *hostname, rpcprog_t prog, rpcvers_t vers,
2843 2788 struct netconfig **nconfp, ushort_t port, bool_t direct_to_server)
2844 2789 {
2845 2790 enum clnt_stat cstat;
2846 2791
2847 2792 (void) get_server_netinfo(SERVER_PING, hostname, prog,
2848 2793 vers, NULL, nconfp, NULL, port, NULL, NULL,
2849 2794 direct_to_server, NULL, &cstat);
2850 2795
2851 2796 return (cstat);
2852 2797 }
2853 2798
2854 2799 void *
2855 2800 get_server_netinfo(
2856 2801 enum type_of_stuff type_of_stuff,
2857 2802 char *hostname,
2858 2803 rpcprog_t prog,
2859 2804 rpcvers_t vers,
2860 2805 mfs_snego_t *mfssnego,
2861 2806 struct netconfig **nconfp,
2862 2807 char *proto,
2863 2808 ushort_t port, /* may be zero */
2864 2809 struct t_info *tinfo,
2865 2810 caddr_t *fhp,
2866 2811 bool_t direct_to_server,
2867 2812 char *fspath,
2868 2813 enum clnt_stat *cstatp)
2869 2814 {
2870 2815 struct netbuf *nb = NULL;
2871 2816 struct netconfig *nconf = NULL;
2872 2817 NCONF_HANDLE *nc = NULL;
2873 2818 int error = 0;
2874 2819 int fd = 0;
2875 2820 struct t_bind *tbind = NULL;
2876 2821 int nthtry = FIRST_TRY;
2877 2822
2878 2823 if (nconfp && *nconfp) {
2879 2824 return (get_netconfig_info(type_of_stuff, hostname,
2880 2825 prog, vers, nconf, port, tinfo, tbind, fhp,
2881 2826 direct_to_server, fspath, cstatp, mfssnego));
2882 2827 }
2883 2828
2884 2829 /*
2885 2830 * No nconf passed in.
2886 2831 *
2887 2832 * Try to get a nconf from /etc/netconfig.
2888 2833 * First choice is COTS, second is CLTS unless proto
2889 2834 * is specified. When we retry, we reset the
2890 2835 * netconfig list, so that we search the whole list
2891 2836 * for the next choice.
2892 2837 */
2893 2838 if ((nc = setnetpath()) == NULL)
2894 2839 goto done;
2895 2840
2896 2841 /*
2897 2842 * If proto is specified, then only search for the match,
2898 2843 * otherwise try COTS first, if failed, then try CLTS.
2899 2844 */
2900 2845 if (proto) {
2901 2846 while ((nconf = getnetpath(nc)) != NULL) {
2902 2847 if (strcmp(nconf->nc_proto, proto))
2903 2848 continue;
2904 2849 /*
2905 2850 * If the port number is specified then TCP/UDP
2906 2851 * is needed. Otherwise any cots/clts will do.
2907 2852 */
2908 2853 if (port) {
2909 2854 if ((strcmp(nconf->nc_protofmly, NC_INET) &&
2910 2855 strcmp(nconf->nc_protofmly, NC_INET6)) ||
2911 2856 (strcmp(nconf->nc_proto, NC_TCP) &&
2912 2857 strcmp(nconf->nc_proto, NC_UDP)))
2913 2858 continue;
2914 2859 }
2915 2860 nb = get_netconfig_info(type_of_stuff, hostname,
2916 2861 prog, vers, nconf, port, tinfo, tbind, fhp,
2917 2862 direct_to_server, fspath, cstatp, mfssnego);
2918 2863 if (*cstatp == RPC_SUCCESS)
2919 2864 break;
2920 2865
2921 2866 assert(nb == NULL);
2922 2867
2923 2868 }
2924 2869 if (nconf == NULL)
2925 2870 goto done;
2926 2871 } else {
2927 2872 retry:
2928 2873 while ((nconf = getnetpath(nc)) != NULL) {
2929 2874 if (nconf->nc_flag & NC_VISIBLE) {
2930 2875 if (nthtry == FIRST_TRY) {
2931 2876 if ((nconf->nc_semantics ==
2932 2877 NC_TPI_COTS_ORD) ||
2933 2878 (nconf->nc_semantics ==
2934 2879 NC_TPI_COTS)) {
2935 2880 if (port == 0)
2936 2881 break;
2937 2882 if ((strcmp(nconf->nc_protofmly,
2938 2883 NC_INET) == 0 ||
2939 2884 strcmp(nconf->nc_protofmly,
2940 2885 NC_INET6) == 0) &&
2941 2886 (strcmp(nconf->nc_proto,
2942 2887 NC_TCP) == 0))
2943 2888 break;
2944 2889 }
2945 2890 }
2946 2891 if (nthtry == SECOND_TRY) {
2947 2892 if (nconf->nc_semantics ==
2948 2893 NC_TPI_CLTS) {
2949 2894 if (port == 0)
2950 2895 break;
2951 2896 if ((strcmp(nconf->nc_protofmly,
2952 2897 NC_INET) == 0 ||
2953 2898 strcmp(nconf->nc_protofmly,
2954 2899 NC_INET6) == 0) &&
2955 2900 (strcmp(nconf->nc_proto,
2956 2901 NC_UDP) == 0))
2957 2902 break;
2958 2903 }
2959 2904 }
2960 2905 }
2961 2906 }
2962 2907
2963 2908 if (nconf == NULL) {
2964 2909 if (++nthtry <= MNT_PREF_LISTLEN) {
2965 2910 endnetpath(nc);
2966 2911 if ((nc = setnetpath()) == NULL)
2967 2912 goto done;
2968 2913 goto retry;
2969 2914 } else
2970 2915 goto done;
2971 2916 } else {
2972 2917 nb = get_netconfig_info(type_of_stuff, hostname,
2973 2918 prog, vers, nconf, port, tinfo, tbind, fhp,
2974 2919 direct_to_server, fspath, cstatp, mfssnego);
2975 2920 if (*cstatp != RPC_SUCCESS)
2976 2921 /*
2977 2922 * Continue the same search path in the
2978 2923 * netconfig db until no more matched nconf
2979 2924 * (nconf == NULL).
2980 2925 */
2981 2926 goto retry;
2982 2927 }
2983 2928 }
2984 2929
2985 2930 /*
2986 2931 * Got nconf and nb. Now dup the netconfig structure (nconf)
2987 2932 * and return it thru nconfp.
2988 2933 */
2989 2934 if (nconf != NULL) {
2990 2935 if ((*nconfp = getnetconfigent(nconf->nc_netid)) == NULL) {
2991 2936 syslog(LOG_ERR, "no memory\n");
2992 2937 free(nb);
2993 2938 nb = NULL;
2994 2939 }
2995 2940 } else {
2996 2941 *nconfp = NULL;
2997 2942 }
2998 2943 done:
2999 2944 if (nc)
3000 2945 endnetpath(nc);
3001 2946 return (nb);
3002 2947 }
3003 2948
3004 2949 void *
3005 2950 get_server_fh(char *hostname, rpcprog_t prog, rpcvers_t vers,
3006 2951 mfs_snego_t *mfssnego, struct netconfig *nconf, ushort_t port,
3007 2952 struct t_info *tinfo, struct t_bind *tbind, caddr_t *fhp,
3008 2953 bool_t direct_to_server, char *fspath, enum clnt_stat *cstat)
3009 2954 {
3010 2955 AUTH *ah = NULL;
3011 2956 AUTH *new_ah = NULL;
3012 2957 struct snego_t snego;
3013 2958 enum clnt_stat cs = RPC_TIMEDOUT;
3014 2959 struct timeval tv;
3015 2960 bool_t file_handle = 1;
3016 2961 enum snego_stat sec;
3017 2962 CLIENT *cl = NULL;
3018 2963 int fd = -1;
3019 2964 struct netbuf *nb = NULL;
3020 2965
3021 2966 if (direct_to_server != TRUE)
3022 2967 return (NULL);
3023 2968
3024 2969 if (prog == NFS_PROGRAM && vers == NFS_V4)
3025 2970 if (strncasecmp(nconf->nc_proto, NC_UDP, strlen(NC_UDP)) == 0)
3026 2971 goto done;
3027 2972
3028 2973 if ((fd = t_open(nconf->nc_device, O_RDWR, tinfo)) < 0)
3029 2974 goto done;
3030 2975
3031 2976 /* LINTED pointer alignment */
3032 2977 if ((tbind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR)) == NULL)
3033 2978 goto done;
3034 2979
3035 2980 if (setup_nb_parms(nconf, tbind, tinfo, hostname, fd,
3036 2981 direct_to_server, port, prog, vers, file_handle) < 0) {
3037 2982 goto done;
3038 2983 }
3039 2984
3040 2985 cl = clnt_tli_create(fd, nconf, &tbind->addr, prog, vers, 0, 0);
3041 2986 if (cl == NULL)
3042 2987 goto done;
3043 2988
3044 2989 ah = authsys_create_default();
3045 2990 if (ah != NULL) {
3046 2991 #ifdef MALLOC_DEBUG
3047 2992 drop_alloc("AUTH_HANDLE", cl->cl_auth,
3048 2993 __FILE__, __LINE__);
3049 2994 #endif
3050 2995 AUTH_DESTROY(cl->cl_auth);
3051 2996 cl->cl_auth = ah;
3052 2997 #ifdef MALLOC_DEBUG
3053 2998 add_alloc("AUTH_HANDLE", cl->cl_auth, 0,
3054 2999 __FILE__, __LINE__);
3055 3000 #endif
3056 3001 }
3057 3002
3058 3003 if (!mfssnego->snego_done && vers != NFS_V4) {
3059 3004 /*
3060 3005 * negotiate sec flavor.
3061 3006 */
3062 3007 snego.cnt = 0;
3063 3008 if ((sec = nfs_sec_nego(vers, cl, fspath, &snego)) ==
3064 3009 SNEGO_SUCCESS) {
3065 3010 int jj;
3066 3011
3067 3012 /*
3068 3013 * check if server supports the one
3069 3014 * specified in the sec= option.
3070 3015 */
3071 3016 if (mfssnego->sec_opt) {
3072 3017 for (jj = 0; jj < snego.cnt; jj++) {
3073 3018 if (snego.array[jj] ==
3074 3019 mfssnego->nfs_sec.sc_nfsnum) {
3075 3020 mfssnego->snego_done = TRUE;
3076 3021 break;
3077 3022 }
3078 3023 }
3079 3024 }
3080 3025
3081 3026 /*
3082 3027 * find a common sec flavor
3083 3028 */
3084 3029 if (!mfssnego->snego_done) {
3085 3030 for (jj = 0; jj < snego.cnt; jj++) {
3086 3031 if (!nfs_getseconfig_bynumber(
3087 3032 snego.array[jj],
3088 3033 &mfssnego->nfs_sec)) {
3089 3034 mfssnego->snego_done = TRUE;
3090 3035 break;
3091 3036 }
3092 3037 }
3093 3038 }
3094 3039 if (!mfssnego->snego_done)
3095 3040 goto done;
3096 3041 /*
3097 3042 * Now that the flavor has been
3098 3043 * negotiated, get the fh.
3099 3044 *
3100 3045 * First, create an auth handle using the negotiated
3101 3046 * sec flavor in the next lookup to
3102 3047 * fetch the filehandle.
3103 3048 */
3104 3049 new_ah = nfs_create_ah(cl, hostname,
3105 3050 &mfssnego->nfs_sec);
3106 3051 if (new_ah == NULL)
3107 3052 goto done;
3108 3053 #ifdef MALLOC_DEBUG
3109 3054 drop_alloc("AUTH_HANDLE", cl->cl_auth,
3110 3055 __FILE__, __LINE__);
3111 3056 #endif
3112 3057 AUTH_DESTROY(cl->cl_auth);
3113 3058 cl->cl_auth = new_ah;
3114 3059 #ifdef MALLOC_DEBUG
3115 3060 add_alloc("AUTH_HANDLE", cl->cl_auth, 0,
3116 3061 __FILE__, __LINE__);
3117 3062 #endif
3118 3063 } else if (sec == SNEGO_ARRAY_TOO_SMALL ||
3119 3064 sec == SNEGO_FAILURE) {
3120 3065 goto done;
3121 3066 }
3122 3067 }
3123 3068
3124 3069 switch (vers) {
3125 3070 case NFS_VERSION:
3126 3071 {
3127 3072 wnl_diropargs arg;
3128 3073 wnl_diropres res;
3129 3074
3130 3075 memset((char *)&arg.dir, 0, sizeof (wnl_fh));
3131 3076 memset((char *)&res, 0, sizeof (wnl_diropres));
3132 3077 arg.name = fspath;
3133 3078 if (wnlproc_lookup_2(&arg, &res, cl) !=
3134 3079 RPC_SUCCESS || res.status != WNL_OK)
3135 3080 goto done;
3136 3081 *fhp = malloc(sizeof (wnl_fh));
3137 3082
3138 3083 if (*fhp == NULL) {
3139 3084 syslog(LOG_ERR, "no memory\n");
3140 3085 goto done;
3141 3086 }
3142 3087
3143 3088 memcpy((char *)*fhp,
3144 3089 (char *)&res.wnl_diropres_u.wnl_diropres.file,
3145 3090 sizeof (wnl_fh));
3146 3091 cs = RPC_SUCCESS;
3147 3092 }
3148 3093 break;
3149 3094 case NFS_V3:
3150 3095 {
3151 3096 WNL_LOOKUP3args arg;
3152 3097 WNL_LOOKUP3res res;
3153 3098 nfs_fh3 *fh3p;
3154 3099
3155 3100 memset((char *)&arg.what.dir, 0, sizeof (wnl_fh3));
3156 3101 memset((char *)&res, 0, sizeof (WNL_LOOKUP3res));
3157 3102 arg.what.name = fspath;
3158 3103 if (wnlproc3_lookup_3(&arg, &res, cl) !=
3159 3104 RPC_SUCCESS || res.status != WNL3_OK)
3160 3105 goto done;
3161 3106
3162 3107 fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p));
3163 3108
3164 3109 if (fh3p == NULL) {
3165 3110 syslog(LOG_ERR, "no memory\n");
3166 3111 goto done;
3167 3112 }
3168 3113
3169 3114 fh3p->fh3_length =
3170 3115 res.WNL_LOOKUP3res_u.res_ok.object.data.data_len;
3171 3116 memcpy(fh3p->fh3_u.data,
3172 3117 res.WNL_LOOKUP3res_u.res_ok.object.data.data_val,
3173 3118 fh3p->fh3_length);
3174 3119
3175 3120 *fhp = (caddr_t)fh3p;
3176 3121
3177 3122 cs = RPC_SUCCESS;
3178 3123 }
3179 3124 break;
3180 3125 case NFS_V4:
3181 3126 tv.tv_sec = 10;
3182 3127 tv.tv_usec = 0;
3183 3128 cs = clnt_call(cl, NULLPROC, xdr_void, 0,
3184 3129 xdr_void, 0, tv);
3185 3130 if (cs != RPC_SUCCESS)
3186 3131 goto done;
3187 3132
3188 3133 *fhp = strdup(fspath);
3189 3134 if (fhp == NULL) {
3190 3135 cs = RPC_SYSTEMERROR;
3191 3136 goto done;
3192 3137 }
3193 3138 break;
3194 3139 }
3195 3140 nb = (struct netbuf *)malloc(sizeof (struct netbuf));
3196 3141 if (nb == NULL) {
3197 3142 syslog(LOG_ERR, "no memory\n");
3198 3143 cs = RPC_SYSTEMERROR;
3199 3144 goto done;
3200 3145 }
3201 3146 nb->buf = (char *)malloc(tbind->addr.maxlen);
3202 3147 if (nb->buf == NULL) {
3203 3148 syslog(LOG_ERR, "no memory\n");
3204 3149 free(nb);
3205 3150 nb = NULL;
3206 3151 cs = RPC_SYSTEMERROR;
3207 3152 goto done;
3208 3153 }
3209 3154 (void) memcpy(nb->buf, tbind->addr.buf, tbind->addr.len);
3210 3155 nb->len = tbind->addr.len;
3211 3156 nb->maxlen = tbind->addr.maxlen;
3212 3157 done:
3213 3158 if (cstat != NULL)
3214 3159 *cstat = cs;
3215 3160 destroy_auth_client_handle(cl);
3216 3161 cleanup_tli_parms(tbind, fd);
3217 3162 return (nb);
3218 3163 }
3219 3164
3220 3165 /*
3221 3166 * Sends a null call to the remote host's (NFS program, versp). versp
3222 3167 * may be "NULL" in which case the default maximum version is used.
3223 3168 * Upon return, versp contains the maximum version supported iff versp!= NULL.
3224 3169 */
3225 3170 enum clnt_stat
3226 3171 pingnfs(
3227 3172 char *hostpart,
3228 3173 int attempts,
3229 3174 rpcvers_t *versp,
3230 3175 rpcvers_t versmin,
3231 3176 ushort_t port, /* may be zero */
3232 3177 bool_t usepub,
3233 3178 char *path,
3234 3179 char *proto)
3235 3180 {
3236 3181 CLIENT *cl = NULL;
3237 3182 struct timeval rpc_to_new = {15, 0};
3238 3183 static struct timeval rpc_rtrans_new = {-1, -1};
3239 3184 enum clnt_stat clnt_stat;
3240 3185 int i, j;
3241 3186 rpcvers_t versmax; /* maximum version to try against server */
3242 3187 rpcvers_t outvers; /* version supported by host on last call */
3243 3188 rpcvers_t vers_to_try; /* to try different versions against host */
3244 3189 char *hostname;
3245 3190 struct netconfig *nconf;
3246 3191
3247 3192 hostname = strdup(hostpart);
3248 3193 if (hostname == NULL) {
3249 3194 return (RPC_SYSTEMERROR);
3250 3195 }
3251 3196 unbracket(&hostname);
3252 3197
3253 3198 if (path != NULL && strcmp(hostname, "nfs") == 0 &&
3254 3199 strncmp(path, "//", 2) == 0) {
3255 3200 char *sport;
3256 3201
3257 3202 hostname = strdup(path+2);
3258 3203
3259 3204 if (hostname == NULL)
3260 3205 return (RPC_SYSTEMERROR);
3261 3206
3262 3207 path = strchr(hostname, '/');
3263 3208
3264 3209 /*
3265 3210 * This cannot happen. If it does, give up
3266 3211 * on the ping as this is obviously a corrupt
3267 3212 * entry.
3268 3213 */
3269 3214 if (path == NULL) {
3270 3215 free(hostname);
3271 3216 return (RPC_SUCCESS);
3272 3217 }
3273 3218
3274 3219 /*
3275 3220 * Probable end point of host string.
3276 3221 */
3277 3222 *path = '\0';
3278 3223
3279 3224 sport = strchr(hostname, ':');
3280 3225
3281 3226 if (sport != NULL && sport < path) {
3282 3227
3283 3228 /*
3284 3229 * Actual end point of host string.
3285 3230 */
3286 3231 *sport = '\0';
3287 3232 port = htons((ushort_t)atoi(sport+1));
3288 3233 }
3289 3234
3290 3235 usepub = TRUE;
3291 3236 }
3292 3237
3293 3238 /* Pick up the default versions and then set them appropriately */
3294 3239 if (versp) {
3295 3240 versmax = *versp;
3296 3241 /* use versmin passed in */
3297 3242 } else {
3298 3243 read_default_nfs();
3299 3244 set_versrange(0, &versmax, &versmin);
3300 3245 }
3301 3246
3302 3247 if (proto &&
3303 3248 strncasecmp(proto, NC_UDP, strlen(NC_UDP)) == 0 &&
3304 3249 versmax == NFS_V4) {
3305 3250 if (versmin == NFS_V4) {
3306 3251 if (versp) {
3307 3252 *versp = versmax - 1;
3308 3253 return (RPC_SUCCESS);
3309 3254 }
3310 3255 return (RPC_PROGUNAVAIL);
3311 3256 } else {
3312 3257 versmax--;
3313 3258 }
3314 3259 }
3315 3260
3316 3261 if (versp)
3317 3262 *versp = versmax;
3318 3263
3319 3264 switch (cache_check(hostname, versp, proto)) {
3320 3265 case GOODHOST:
3321 3266 if (hostname != hostpart)
3322 3267 free(hostname);
3323 3268 return (RPC_SUCCESS);
3324 3269 case DEADHOST:
3325 3270 if (hostname != hostpart)
3326 3271 free(hostname);
3327 3272 return (RPC_TIMEDOUT);
3328 3273 case NOHOST:
3329 3274 default:
3330 3275 break;
3331 3276 }
3332 3277
3333 3278 /*
3334 3279 * XXX The retransmission time rpcbrmttime is a global defined
3335 3280 * in the rpc library (rpcb_clnt.c). We use (and like) the default
3336 3281 * value of 15 sec in the rpc library. The code below is to protect
3337 3282 * us in case it changes. This need not be done under a lock since
3338 3283 * any # of threads entering this function will get the same
3339 3284 * retransmission value.
3340 3285 */
3341 3286 if (rpc_rtrans_new.tv_sec == -1 && rpc_rtrans_new.tv_usec == -1) {
3342 3287 __rpc_control(CLCR_GET_RPCB_RMTTIME, (char *)&rpc_rtrans_new);
3343 3288 if (rpc_rtrans_new.tv_sec != 15 && rpc_rtrans_new.tv_sec != 0)
3344 3289 if (trace > 1)
3345 3290 trace_prt(1, "RPC library rttimer changed\n");
3346 3291 }
3347 3292
3348 3293 /*
3349 3294 * XXX Manipulate the total timeout to get the number of
3350 3295 * desired retransmissions. This code is heavily dependant on
3351 3296 * the RPC backoff mechanism in clnt_dg_call (clnt_dg.c).
3352 3297 */
3353 3298 for (i = 0, j = rpc_rtrans_new.tv_sec; i < attempts-1; i++) {
3354 3299 if (j < RPC_MAX_BACKOFF)
3355 3300 j *= 2;
3356 3301 else
3357 3302 j = RPC_MAX_BACKOFF;
3358 3303 rpc_to_new.tv_sec += j;
3359 3304 }
3360 3305
3361 3306 vers_to_try = versmax;
3362 3307
3363 3308 /*
3364 3309 * check the host's version within the timeout
3365 3310 */
3366 3311 if (trace > 1)
3367 3312 trace_prt(1, " ping: %s timeout=%ld request vers=%d min=%d\n",
3368 3313 hostname, rpc_to_new.tv_sec, versmax, versmin);
3369 3314
3370 3315 if (usepub == FALSE) {
3371 3316 do {
3372 3317 /*
3373 3318 * If NFSv4, then we do the same thing as is used
3374 3319 * for public filehandles so that we avoid rpcbind
3375 3320 */
3376 3321 if (vers_to_try == NFS_V4) {
3377 3322 if (trace > 4) {
3378 3323 trace_prt(1, " pingnfs: Trying ping via "
3379 3324 "\"circuit_v\"\n");
3380 3325 }
3381 3326
3382 3327 cl = clnt_create_service_timed(hostname, "nfs",
3383 3328 NFS_PROGRAM, vers_to_try,
3384 3329 port, "circuit_v", &rpc_to_new);
3385 3330 if (cl != NULL) {
3386 3331 outvers = vers_to_try;
3387 3332 break;
3388 3333 }
3389 3334 if (trace > 4) {
3390 3335 trace_prt(1,
3391 3336 " pingnfs: Can't ping via "
3392 3337 "\"circuit_v\" %s: RPC error=%d\n",
3393 3338 hostname, rpc_createerr.cf_stat);
3394 3339 }
3395 3340
3396 3341 } else {
3397 3342 cl = clnt_create_vers_timed(hostname,
3398 3343 NFS_PROGRAM, &outvers, versmin, vers_to_try,
3399 3344 "datagram_v", &rpc_to_new);
3400 3345 if (cl != NULL)
3401 3346 break;
3402 3347 if (trace > 4) {
3403 3348 trace_prt(1,
3404 3349 " pingnfs: Can't ping via "
3405 3350 "\"datagram_v\"%s: RPC error=%d\n",
3406 3351 hostname, rpc_createerr.cf_stat);
3407 3352 }
3408 3353 if (rpc_createerr.cf_stat == RPC_UNKNOWNHOST ||
3409 3354 rpc_createerr.cf_stat == RPC_TIMEDOUT)
3410 3355 break;
3411 3356 if (rpc_createerr.cf_stat ==
3412 3357 RPC_PROGNOTREGISTERED) {
3413 3358 if (trace > 4) {
3414 3359 trace_prt(1,
3415 3360 " pingnfs: Trying ping "
3416 3361 "via \"circuit_v\"\n");
3417 3362 }
3418 3363 cl = clnt_create_vers_timed(hostname,
3419 3364 NFS_PROGRAM, &outvers,
3420 3365 versmin, vers_to_try,
3421 3366 "circuit_v", &rpc_to_new);
3422 3367 if (cl != NULL)
3423 3368 break;
3424 3369 if (trace > 4) {
3425 3370 trace_prt(1,
3426 3371 " pingnfs: Can't ping "
3427 3372 "via \"circuit_v\" %s: "
3428 3373 "RPC error=%d\n",
3429 3374 hostname,
3430 3375 rpc_createerr.cf_stat);
3431 3376 }
3432 3377 }
3433 3378 }
3434 3379
3435 3380 /*
3436 3381 * backoff and return lower version to retry the ping.
3437 3382 * XXX we should be more careful and handle
3438 3383 * RPC_PROGVERSMISMATCH here, because that error is handled
3439 3384 * in clnt_create_vers(). It's not done to stay in sync
3440 3385 * with the nfs mount command.
3441 3386 */
3442 3387 vers_to_try--;
3443 3388 if (vers_to_try < versmin)
3444 3389 break;
3445 3390 if (versp != NULL) { /* recheck the cache */
3446 3391 *versp = vers_to_try;
3447 3392 if (trace > 4) {
3448 3393 trace_prt(1,
3449 3394 " pingnfs: check cache: vers=%d\n",
3450 3395 *versp);
3451 3396 }
3452 3397 switch (cache_check(hostname, versp, proto)) {
3453 3398 case GOODHOST:
3454 3399 if (hostname != hostpart)
3455 3400 free(hostname);
3456 3401 return (RPC_SUCCESS);
3457 3402 case DEADHOST:
3458 3403 if (hostname != hostpart)
3459 3404 free(hostname);
3460 3405 return (RPC_TIMEDOUT);
3461 3406 case NOHOST:
3462 3407 default:
3463 3408 break;
3464 3409 }
3465 3410 }
3466 3411 if (trace > 4) {
3467 3412 trace_prt(1, " pingnfs: Try version=%d\n",
3468 3413 vers_to_try);
3469 3414 }
3470 3415 } while (cl == NULL);
3471 3416
3472 3417
3473 3418 if (cl == NULL) {
3474 3419 if (verbose)
3475 3420 syslog(LOG_ERR, "pingnfs: %s%s",
3476 3421 hostname, clnt_spcreateerror(""));
3477 3422 clnt_stat = rpc_createerr.cf_stat;
3478 3423 } else {
3479 3424 clnt_destroy(cl);
3480 3425 clnt_stat = RPC_SUCCESS;
3481 3426 }
3482 3427
3483 3428 } else {
3484 3429 for (vers_to_try = versmax; vers_to_try >= versmin;
3485 3430 vers_to_try--) {
3486 3431
3487 3432 nconf = NULL;
3488 3433
3489 3434 if (trace > 4) {
3490 3435 trace_prt(1, " pingnfs: Try version=%d "
3491 3436 "using get_ping()\n", vers_to_try);
3492 3437 }
3493 3438
3494 3439 clnt_stat = get_ping(hostname, NFS_PROGRAM,
3495 3440 vers_to_try, &nconf, port, TRUE);
3496 3441
3497 3442 if (nconf != NULL)
3498 3443 freenetconfigent(nconf);
3499 3444
3500 3445 if (clnt_stat == RPC_SUCCESS) {
3501 3446 outvers = vers_to_try;
3502 3447 break;
3503 3448 }
3504 3449 }
3505 3450 }
3506 3451
3507 3452 if (trace > 1)
3508 3453 clnt_stat == RPC_SUCCESS ?
3509 3454 trace_prt(1, " pingnfs OK: nfs version=%d\n", outvers):
3510 3455 trace_prt(1, " pingnfs FAIL: can't get nfs version\n");
3511 3456
3512 3457 if (clnt_stat == RPC_SUCCESS) {
3513 3458 cache_enter(hostname, versmax, outvers, proto, GOODHOST);
3514 3459 if (versp != NULL)
3515 3460 *versp = outvers;
3516 3461 } else
3517 3462 cache_enter(hostname, versmax, versmax, proto, DEADHOST);
3518 3463
3519 3464 if (hostpart != hostname)
3520 3465 free(hostname);
3521 3466
3522 3467 return (clnt_stat);
3523 3468 }
3524 3469
3525 3470 #define MNTTYPE_LOFS "lofs"
3526 3471
3527 3472 int
3528 3473 loopbackmount(fsname, dir, mntopts, overlay)
3529 3474 char *fsname; /* Directory being mounted */
3530 3475 char *dir; /* Directory being mounted on */
3531 3476 char *mntopts;
3532 3477 int overlay;
3533 3478 {
3534 3479 struct mnttab mnt;
3535 3480 int flags = 0;
3536 3481 char fstype[] = MNTTYPE_LOFS;
3537 3482 int dirlen;
3538 3483 struct stat st;
3539 3484 char optbuf[MAX_MNTOPT_STR];
3540 3485
3541 3486 dirlen = strlen(dir);
3542 3487 if (dir[dirlen-1] == ' ')
3543 3488 dirlen--;
3544 3489
3545 3490 if (dirlen == strlen(fsname) &&
3546 3491 strncmp(fsname, dir, dirlen) == 0) {
3547 3492 syslog(LOG_ERR,
3548 3493 "Mount of %s on %s would result in deadlock, aborted\n",
3549 3494 fsname, dir);
3550 3495 return (RET_ERR);
3551 3496 }
3552 3497 mnt.mnt_mntopts = mntopts;
3553 3498 if (hasmntopt(&mnt, MNTOPT_RO) != NULL)
3554 3499 flags |= MS_RDONLY;
3555 3500
3556 3501 (void) strlcpy(optbuf, mntopts, sizeof (optbuf));
3557 3502
3558 3503 if (overlay)
3559 3504 flags |= MS_OVERLAY;
3560 3505
3561 3506 if (trace > 1)
3562 3507 trace_prt(1,
3563 3508 " loopbackmount: fsname=%s, dir=%s, flags=%d\n",
3564 3509 fsname, dir, flags);
3565 3510
3566 3511 if (is_system_labeled()) {
3567 3512 if (create_homedir((const char *)fsname,
3568 3513 (const char *)dir) == 0) {
3569 3514 return (NFSERR_NOENT);
3570 3515 }
3571 3516 }
3572 3517
3573 3518 if (mount(fsname, dir, flags | MS_DATA | MS_OPTIONSTR, fstype,
3574 3519 NULL, 0, optbuf, sizeof (optbuf)) < 0) {
3575 3520 syslog(LOG_ERR, "Mount of %s on %s: %m", fsname, dir);
3576 3521 return (RET_ERR);
3577 3522 }
3578 3523
3579 3524 if (stat(dir, &st) == 0) {
3580 3525 if (trace > 1) {
3581 3526 trace_prt(1,
3582 3527 " loopbackmount of %s on %s dev=%x rdev=%x OK\n",
3583 3528 fsname, dir, st.st_dev, st.st_rdev);
3584 3529 }
3585 3530 } else {
3586 3531 if (trace > 1) {
3587 3532 trace_prt(1,
3588 3533 " loopbackmount of %s on %s OK\n", fsname, dir);
3589 3534 trace_prt(1, " stat of %s failed\n", dir);
3590 3535 }
3591 3536 }
3592 3537
3593 3538 return (0);
3594 3539 }
3595 3540
3596 3541 /*
3597 3542 * Look for the value of a numeric option of the form foo=x. If found, set
3598 3543 * *valp to the value and return non-zero. If not found or the option is
3599 3544 * malformed, return zero.
3600 3545 */
3601 3546
3602 3547 int
3603 3548 nopt(mnt, opt, valp)
3604 3549 struct mnttab *mnt;
3605 3550 char *opt;
3606 3551 int *valp; /* OUT */
3607 3552 {
3608 3553 char *equal;
3609 3554 char *str;
3610 3555
3611 3556 /*
3612 3557 * We should never get a null pointer, but if we do, it's better to
3613 3558 * ignore the option than to dump core.
3614 3559 */
3615 3560
3616 3561 if (valp == NULL) {
3617 3562 syslog(LOG_DEBUG, "null pointer for %s option", opt);
3618 3563 return (0);
3619 3564 }
3620 3565
3621 3566 if (str = hasmntopt(mnt, opt)) {
3622 3567 if (equal = strchr(str, '=')) {
3623 3568 *valp = atoi(&equal[1]);
3624 3569 return (1);
3625 3570 } else {
3626 3571 syslog(LOG_ERR, "Bad numeric option '%s'", str);
3627 3572 }
3628 3573 }
3629 3574 return (0);
3630 3575 }
3631 3576
3632 3577 int
3633 3578 nfsunmount(mnt)
3634 3579 struct mnttab *mnt;
3635 3580 {
3636 3581 struct timeval timeout;
3637 3582 CLIENT *cl;
3638 3583 enum clnt_stat rpc_stat;
3639 3584 char *host, *path;
3640 3585 struct replica *list;
3641 3586 int i, count = 0;
3642 3587 int isv4mount = is_v4_mount(mnt->mnt_mountp);
3643 3588
3644 3589 if (trace > 1)
3645 3590 trace_prt(1, " nfsunmount: umount %s\n", mnt->mnt_mountp);
3646 3591
3647 3592 if (umount(mnt->mnt_mountp) < 0) {
3648 3593 if (trace > 1)
3649 3594 trace_prt(1, " nfsunmount: umount %s FAILED\n",
3650 3595 mnt->mnt_mountp);
3651 3596 if (errno)
3652 3597 return (errno);
3653 3598 }
3654 3599
3655 3600 /*
3656 3601 * If this is a NFSv4 mount, the mount protocol was not used
3657 3602 * so we just return.
3658 3603 */
3659 3604 if (isv4mount) {
3660 3605 if (trace > 1)
3661 3606 trace_prt(1, " nfsunmount: umount %s OK\n",
3662 3607 mnt->mnt_mountp);
3663 3608 return (0);
3664 3609 }
3665 3610
3666 3611 /*
3667 3612 * If mounted with -o public, then no need to contact server
3668 3613 * because mount protocol was not used.
3669 3614 */
3670 3615 if (hasmntopt(mnt, MNTOPT_PUBLIC) != NULL) {
3671 3616 return (0);
3672 3617 }
3673 3618
3674 3619 /*
3675 3620 * The rest of this code is advisory to the server.
3676 3621 * If it fails return success anyway.
3677 3622 */
3678 3623
3679 3624 list = parse_replica(mnt->mnt_special, &count);
3680 3625 if (!list) {
3681 3626 if (count >= 0)
3682 3627 syslog(LOG_ERR,
3683 3628 "Memory allocation failed: %m");
3684 3629 return (ENOMEM);
3685 3630 }
3686 3631
3687 3632 for (i = 0; i < count; i++) {
3688 3633
3689 3634 host = list[i].host;
3690 3635 path = list[i].path;
3691 3636
3692 3637 /*
3693 3638 * Skip file systems mounted using WebNFS, because mount
3694 3639 * protocol was not used.
3695 3640 */
3696 3641 if (strcmp(host, "nfs") == 0 && strncmp(path, "//", 2) == 0)
3697 3642 continue;
3698 3643
3699 3644 cl = clnt_create(host, MOUNTPROG, MOUNTVERS, "datagram_v");
3700 3645 if (cl == NULL)
3701 3646 break;
3702 3647 #ifdef MALLOC_DEBUG
3703 3648 add_alloc("CLNT_HANDLE", cl, 0, __FILE__, __LINE__);
3704 3649 add_alloc("AUTH_HANDLE", cl->cl_auth, 0,
3705 3650 __FILE__, __LINE__);
3706 3651 #endif
3707 3652 if (__clnt_bindresvport(cl) < 0) {
3708 3653 if (verbose)
3709 3654 syslog(LOG_ERR, "umount %s:%s: %s",
3710 3655 host, path,
3711 3656 "Couldn't bind to reserved port");
3712 3657 destroy_auth_client_handle(cl);
3713 3658 continue;
3714 3659 }
3715 3660 #ifdef MALLOC_DEBUG
3716 3661 drop_alloc("AUTH_HANDLE", cl->cl_auth, __FILE__, __LINE__);
3717 3662 #endif
3718 3663 AUTH_DESTROY(cl->cl_auth);
3719 3664 if ((cl->cl_auth = authsys_create_default()) == NULL) {
3720 3665 if (verbose)
3721 3666 syslog(LOG_ERR, "umount %s:%s: %s",
3722 3667 host, path,
3723 3668 "Failed creating default auth handle");
3724 3669 destroy_auth_client_handle(cl);
3725 3670 continue;
3726 3671 }
3727 3672 #ifdef MALLOC_DEBUG
3728 3673 add_alloc("AUTH_HANDLE", cl->cl_auth, 0, __FILE__, __LINE__);
3729 3674 #endif
3730 3675 timeout.tv_usec = 0;
3731 3676 timeout.tv_sec = 5;
3732 3677 rpc_stat = clnt_call(cl, MOUNTPROC_UMNT, xdr_dirpath,
3733 3678 (caddr_t)&path, xdr_void, (char *)NULL, timeout);
3734 3679 if (verbose && rpc_stat != RPC_SUCCESS)
3735 3680 syslog(LOG_ERR, "%s: %s",
3736 3681 host, clnt_sperror(cl, "unmount"));
3737 3682 destroy_auth_client_handle(cl);
3738 3683 }
3739 3684
3740 3685 free_replica(list, count);
3741 3686
3742 3687 if (trace > 1)
3743 3688 trace_prt(1, " nfsunmount: umount %s OK\n", mnt->mnt_mountp);
3744 3689
3745 3690 done:
3746 3691 return (0);
3747 3692 }
3748 3693
3749 3694 /*
3750 3695 * Put a new entry in the cache chain by prepending it to the front.
3751 3696 * If there isn't enough memory then just give up.
3752 3697 */
3753 3698 static void
3754 3699 cache_enter(host, reqvers, outvers, proto, state)
3755 3700 char *host;
3756 3701 rpcvers_t reqvers;
3757 3702 rpcvers_t outvers;
3758 3703 char *proto;
3759 3704 int state;
3760 3705 {
3761 3706 struct cache_entry *entry;
3762 3707 int cache_time = 30; /* sec */
3763 3708
3764 3709 timenow = time(NULL);
3765 3710
3766 3711 entry = (struct cache_entry *)malloc(sizeof (struct cache_entry));
3767 3712 if (entry == NULL)
3768 3713 return;
3769 3714 (void) memset((caddr_t)entry, 0, sizeof (struct cache_entry));
3770 3715 entry->cache_host = strdup(host);
3771 3716 if (entry->cache_host == NULL) {
3772 3717 cache_free(entry);
3773 3718 return;
3774 3719 }
3775 3720 entry->cache_reqvers = reqvers;
3776 3721 entry->cache_outvers = outvers;
3777 3722 entry->cache_proto = (proto == NULL ? NULL : strdup(proto));
3778 3723 entry->cache_state = state;
3779 3724 entry->cache_time = timenow + cache_time;
3780 3725 (void) rw_wrlock(&cache_lock);
3781 3726 #ifdef CACHE_DEBUG
3782 3727 host_cache_accesses++; /* up host cache access counter */
3783 3728 #endif /* CACHE DEBUG */
3784 3729 entry->cache_next = cache_head;
3785 3730 cache_head = entry;
3786 3731 (void) rw_unlock(&cache_lock);
3787 3732 }
3788 3733
3789 3734 static int
3790 3735 cache_check(host, versp, proto)
3791 3736 char *host;
3792 3737 rpcvers_t *versp;
3793 3738 char *proto;
3794 3739 {
3795 3740 int state = NOHOST;
3796 3741 struct cache_entry *ce, *prev;
3797 3742
3798 3743 timenow = time(NULL);
3799 3744
3800 3745 (void) rw_rdlock(&cache_lock);
3801 3746
3802 3747 #ifdef CACHE_DEBUG
3803 3748 /* Increment the lookup and access counters for the host cache */
3804 3749 host_cache_accesses++;
3805 3750 host_cache_lookups++;
3806 3751 if ((host_cache_lookups%1000) == 0)
3807 3752 trace_host_cache();
3808 3753 #endif /* CACHE DEBUG */
3809 3754
3810 3755 for (ce = cache_head; ce; ce = ce->cache_next) {
3811 3756 if (timenow > ce->cache_time) {
3812 3757 (void) rw_unlock(&cache_lock);
3813 3758 (void) rw_wrlock(&cache_lock);
3814 3759 for (prev = NULL, ce = cache_head; ce;
3815 3760 prev = ce, ce = ce->cache_next) {
3816 3761 if (timenow > ce->cache_time) {
3817 3762 cache_free(ce);
3818 3763 if (prev)
3819 3764 prev->cache_next = NULL;
3820 3765 else
3821 3766 cache_head = NULL;
3822 3767 break;
3823 3768 }
3824 3769 }
3825 3770 (void) rw_unlock(&cache_lock);
3826 3771 return (state);
3827 3772 }
3828 3773 if (strcmp(host, ce->cache_host) != 0)
3829 3774 continue;
3830 3775 if ((proto == NULL && ce->cache_proto != NULL) ||
3831 3776 (proto != NULL && ce->cache_proto == NULL))
3832 3777 continue;
3833 3778 if (proto != NULL &&
3834 3779 strcmp(proto, ce->cache_proto) != 0)
3835 3780 continue;
3836 3781
3837 3782 if (versp == NULL ||
3838 3783 (versp != NULL && *versp == ce->cache_reqvers) ||
3839 3784 (versp != NULL && *versp == ce->cache_outvers)) {
3840 3785 if (versp != NULL)
3841 3786 *versp = ce->cache_outvers;
3842 3787 state = ce->cache_state;
3843 3788
3844 3789 /* increment the host cache hit counters */
3845 3790 #ifdef CACHE_DEBUG
3846 3791 if (state == GOODHOST)
3847 3792 goodhost_cache_hits++;
3848 3793 if (state == DEADHOST)
3849 3794 deadhost_cache_hits++;
3850 3795 #endif /* CACHE_DEBUG */
3851 3796 (void) rw_unlock(&cache_lock);
3852 3797 return (state);
3853 3798 }
3854 3799 }
3855 3800 (void) rw_unlock(&cache_lock);
3856 3801 return (state);
3857 3802 }
3858 3803
3859 3804 /*
3860 3805 * Free a cache entry and all entries
3861 3806 * further down the chain since they
3862 3807 * will also be expired.
3863 3808 */
3864 3809 static void
3865 3810 cache_free(entry)
3866 3811 struct cache_entry *entry;
3867 3812 {
3868 3813 struct cache_entry *ce, *next = NULL;
3869 3814
3870 3815 for (ce = entry; ce; ce = next) {
3871 3816 if (ce->cache_host)
3872 3817 free(ce->cache_host);
3873 3818 if (ce->cache_proto)
3874 3819 free(ce->cache_proto);
3875 3820 next = ce->cache_next;
3876 3821 free(ce);
3877 3822 }
3878 3823 }
3879 3824
3880 3825 #ifdef MALLOC_DEBUG
3881 3826 void
3882 3827 cache_flush()
3883 3828 {
3884 3829 (void) rw_wrlock(&cache_lock);
3885 3830 cache_free(cache_head);
3886 3831 cache_head = NULL;
3887 3832 (void) rw_unlock(&cache_lock);
3888 3833 }
3889 3834
3890 3835 void
3891 3836 flush_caches()
3892 3837 {
3893 3838 mutex_lock(&cleanup_lock);
3894 3839 cond_signal(&cleanup_start_cv);
3895 3840 (void) cond_wait(&cleanup_done_cv, &cleanup_lock);
3896 3841 mutex_unlock(&cleanup_lock);
3897 3842 cache_flush();
3898 3843 portmap_cache_flush();
3899 3844 }
3900 3845 #endif
3901 3846
3902 3847 /*
3903 3848 * Returns 1, if port option is NFS_PORT or
3904 3849 * nfsd is running on the port given
3905 3850 * Returns 0, if both port is not NFS_PORT and nfsd is not
3906 3851 * running on the port.
3907 3852 */
3908 3853
3909 3854 static int
3910 3855 is_nfs_port(char *opts)
3911 3856 {
3912 3857 struct mnttab m;
3913 3858 uint_t nfs_port = 0;
3914 3859 struct servent sv;
3915 3860 char buf[256];
3916 3861 int got_port;
3917 3862
3918 3863 m.mnt_mntopts = opts;
3919 3864
3920 3865 /*
3921 3866 * Get port specified in options list, if any.
3922 3867 */
3923 3868 got_port = nopt(&m, MNTOPT_PORT, (int *)&nfs_port);
3924 3869
3925 3870 /*
3926 3871 * if no port specified or it is same as NFS_PORT return nfs
3927 3872 * To use any other daemon the port number should be different
3928 3873 */
3929 3874 if (!got_port || nfs_port == NFS_PORT)
3930 3875 return (1);
3931 3876 /*
3932 3877 * If daemon is nfsd, return nfs
3933 3878 */
3934 3879 if (getservbyport_r(nfs_port, NULL, &sv, buf, 256) == &sv &&
3935 3880 strcmp(sv.s_name, "nfsd") == 0)
3936 3881 return (1);
3937 3882
3938 3883 /*
3939 3884 * daemon is not nfs
3940 3885 */
3941 3886 return (0);
3942 3887 }
3943 3888
3944 3889
3945 3890 /*
3946 3891 * destroy_auth_client_handle(cl)
3947 3892 * destroys the created client handle
3948 3893 */
3949 3894 void
3950 3895 destroy_auth_client_handle(CLIENT *cl)
3951 3896 {
3952 3897 if (cl) {
3953 3898 if (cl->cl_auth) {
3954 3899 #ifdef MALLOC_DEBUG
3955 3900 drop_alloc("AUTH_HANDLE", cl->cl_auth,
3956 3901 __FILE__, __LINE__);
3957 3902 #endif
3958 3903 AUTH_DESTROY(cl->cl_auth);
3959 3904 cl->cl_auth = NULL;
3960 3905 }
3961 3906 #ifdef MALLOC_DEBUG
3962 3907 drop_alloc("CLNT_HANDLE", cl,
3963 3908 __FILE__, __LINE__);
3964 3909 #endif
3965 3910 clnt_destroy(cl);
3966 3911 }
3967 3912 }
3968 3913
3969 3914
3970 3915 /*
3971 3916 * Attempt to figure out which version of NFS to use in pingnfs(). If
3972 3917 * the version number was specified (i.e., non-zero), then use it.
3973 3918 * Otherwise, default to the compiled-in default or the default as set
3974 3919 * by the /etc/default/nfs configuration (as read by read_default().
3975 3920 */
3976 3921 int
3977 3922 set_versrange(rpcvers_t nfsvers, rpcvers_t *vers, rpcvers_t *versmin)
3978 3923 {
3979 3924 switch (nfsvers) {
3980 3925 case 0:
3981 3926 *vers = vers_max_default;
3982 3927 *versmin = vers_min_default;
3983 3928 break;
3984 3929 case NFS_V4:
3985 3930 *vers = NFS_V4;
3986 3931 *versmin = NFS_V4;
3987 3932 break;
3988 3933 case NFS_V3:
3989 3934 *vers = NFS_V3;
3990 3935 *versmin = NFS_V3;
3991 3936 break;
3992 3937 case NFS_VERSION:
3993 3938 *vers = NFS_VERSION; /* version 2 */
3994 3939 *versmin = NFS_VERSMIN; /* version 2 */
3995 3940 break;
3996 3941 default:
3997 3942 return (-1);
3998 3943 }
3999 3944 return (0);
4000 3945 }
4001 3946
4002 3947 #ifdef CACHE_DEBUG
4003 3948 /*
4004 3949 * trace_portmap_cache()
4005 3950 * traces the portmap cache values at desired points
4006 3951 */
4007 3952 static void
4008 3953 trace_portmap_cache()
4009 3954 {
4010 3955 syslog(LOG_ERR, "portmap_cache: accesses=%d lookups=%d hits=%d\n",
4011 3956 portmap_cache_accesses, portmap_cache_lookups,
4012 3957 portmap_cache_hits);
4013 3958 }
4014 3959
4015 3960 /*
4016 3961 * trace_host_cache()
4017 3962 * traces the host cache values at desired points
4018 3963 */
4019 3964 static void
4020 3965 trace_host_cache()
4021 3966 {
4022 3967 syslog(LOG_ERR,
4023 3968 "host_cache: accesses=%d lookups=%d deadhits=%d goodhits=%d\n",
4024 3969 host_cache_accesses, host_cache_lookups, deadhost_cache_hits,
4025 3970 goodhost_cache_hits);
4026 3971 }
4027 3972 #endif /* CACHE_DEBUG */
4028 3973
4029 3974 /*
4030 3975 * Read the NFS SMF properties to determine if the
4031 3976 * client has been configured for a new min/max for the NFS version to
4032 3977 * use.
4033 3978 */
4034 3979
4035 3980 #define SVC_NFS_CLIENT "svc:/network/nfs/client"
4036 3981
4037 3982 static void
4038 3983 read_default_nfs(void)
4039 3984 {
4040 3985 static time_t lastread = 0;
4041 3986 struct stat buf;
4042 3987 char defval[4];
4043 3988 int errno, bufsz;
4044 3989 int tmp, ret = 0;
4045 3990
4046 3991 bufsz = 4;
4047 3992 ret = nfs_smf_get_prop("client_versmin", defval, DEFAULT_INSTANCE,
4048 3993 SCF_TYPE_INTEGER, SVC_NFS_CLIENT, &bufsz);
4049 3994 if (ret == SA_OK) {
4050 3995 errno = 0;
4051 3996 tmp = strtol(defval, (char **)NULL, 10);
4052 3997 if (errno == 0) {
4053 3998 vers_min_default = tmp;
4054 3999 }
4055 4000 }
4056 4001
4057 4002 bufsz = 4;
4058 4003 ret = nfs_smf_get_prop("client_versmax", defval, DEFAULT_INSTANCE,
4059 4004 SCF_TYPE_INTEGER, SVC_NFS_CLIENT, &bufsz);
4060 4005 if (ret == SA_OK) {
4061 4006 errno = 0;
4062 4007 tmp = strtol(defval, (char **)NULL, 10);
4063 4008 if (errno == 0) {
4064 4009 vers_max_default = tmp;
4065 4010 }
4066 4011 }
4067 4012
4068 4013 lastread = buf.st_mtime;
4069 4014
4070 4015 /*
4071 4016 * Quick sanity check on the values picked up from the
4072 4017 * defaults file. Make sure that a mistake wasn't
4073 4018 * made that will confuse things later on.
4074 4019 * If so, reset to compiled-in defaults
4075 4020 */
4076 4021 if (vers_min_default > vers_max_default ||
4077 4022 vers_min_default < NFS_VERSMIN ||
4078 4023 vers_max_default > NFS_VERSMAX) {
4079 4024 if (trace > 1) {
4080 4025 trace_prt(1,
4081 4026 " read_default: version minimum/maximum incorrectly configured\n");
4082 4027 trace_prt(1,
4083 4028 " read_default: config is min=%d, max%d. Resetting to min=%d, max%d\n",
4084 4029 vers_min_default, vers_max_default,
4085 4030 NFS_VERSMIN_DEFAULT,
4086 4031 NFS_VERSMAX_DEFAULT);
4087 4032 }
4088 4033 vers_min_default = NFS_VERSMIN_DEFAULT;
4089 4034 vers_max_default = NFS_VERSMAX_DEFAULT;
4090 4035 }
4091 4036 }
4092 4037
4093 4038 /*
4094 4039 * Find the mnttab entry that corresponds to "name".
4095 4040 * We're not sure what the name represents: either
4096 4041 * a mountpoint name, or a special name (server:/path).
4097 4042 * Return the last entry in the file that matches.
4098 4043 */
4099 4044 static struct extmnttab *
4100 4045 mnttab_find(dirname)
4101 4046 char *dirname;
4102 4047 {
4103 4048 FILE *fp;
4104 4049 struct extmnttab mnt;
4105 4050 struct extmnttab *res = NULL;
4106 4051
4107 4052 fp = fopen(MNTTAB, "r");
4108 4053 if (fp == NULL) {
4109 4054 if (trace > 1)
4110 4055 trace_prt(1, " mnttab_find: unable to open mnttab\n");
4111 4056 return (NULL);
4112 4057 }
4113 4058 while (getextmntent(fp, &mnt, sizeof (struct extmnttab)) == 0) {
4114 4059 if (strcmp(mnt.mnt_mountp, dirname) == 0 ||
4115 4060 strcmp(mnt.mnt_special, dirname) == 0) {
4116 4061 if (res)
4117 4062 fsfreemnttab(res);
4118 4063 res = fsdupmnttab(&mnt);
4119 4064 }
4120 4065 }
4121 4066
4122 4067 resetmnttab(fp);
4123 4068 fclose(fp);
4124 4069 if (res == NULL) {
4125 4070 if (trace > 1)
4126 4071 trace_prt(1, " mnttab_find: unable to find %s\n",
4127 4072 dirname);
4128 4073 }
4129 4074 return (res);
4130 4075 }
4131 4076
4132 4077 /*
4133 4078 * This function's behavior is taken from nfsstat.
4134 4079 * Trying to determine what NFS version was used for the mount.
4135 4080 */
4136 4081 static int
4137 4082 is_v4_mount(char *mntpath)
4138 4083 {
4139 4084 kstat_ctl_t *kc = NULL; /* libkstat cookie */
4140 4085 kstat_t *ksp;
4141 4086 ulong_t fsid;
4142 4087 struct mntinfo_kstat mik;
4143 4088 struct extmnttab *mntp;
4144 4089 uint_t mnt_minor;
4145 4090
4146 4091 if ((mntp = mnttab_find(mntpath)) == NULL)
4147 4092 return (FALSE);
4148 4093
4149 4094 /* save the minor number and free the struct so we don't forget */
4150 4095 mnt_minor = mntp->mnt_minor;
4151 4096 fsfreemnttab(mntp);
4152 4097
4153 4098 if ((kc = kstat_open()) == NULL)
4154 4099 return (FALSE);
4155 4100
4156 4101 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
4157 4102 if (ksp->ks_type != KSTAT_TYPE_RAW)
4158 4103 continue;
4159 4104 if (strcmp(ksp->ks_module, "nfs") != 0)
4160 4105 continue;
4161 4106 if (strcmp(ksp->ks_name, "mntinfo") != 0)
4162 4107 continue;
4163 4108 if (mnt_minor != ksp->ks_instance)
4164 4109 continue;
4165 4110
4166 4111 if (kstat_read(kc, ksp, &mik) == -1)
4167 4112 continue;
4168 4113
4169 4114 (void) kstat_close(kc);
4170 4115 if (mik.mik_vers == 4)
4171 4116 return (TRUE);
4172 4117 else
4173 4118 return (FALSE);
4174 4119 }
4175 4120 (void) kstat_close(kc);
4176 4121
4177 4122 return (FALSE);
4178 4123 }
4179 4124
4180 4125 static int
4181 4126 create_homedir(const char *src, const char *dst) {
4182 4127
4183 4128 struct stat stbuf;
4184 4129 char *dst_username;
4185 4130 struct passwd *pwd, pwds;
4186 4131 char buf_pwd[NSS_BUFLEN_PASSWD];
4187 4132 int homedir_len;
4188 4133 int dst_dir_len;
4189 4134 int src_dir_len;
4190 4135
4191 4136 if (trace > 1)
4192 4137 trace_prt(1, "entered create_homedir\n");
4193 4138
4194 4139 if (stat(src, &stbuf) == 0) {
4195 4140 if (trace > 1)
4196 4141 trace_prt(1, "src exists\n");
4197 4142 return (1);
4198 4143 }
4199 4144
4200 4145 dst_username = strrchr(dst, '/');
4201 4146 if (dst_username) {
4202 4147 dst_username++; /* Skip over slash */
4203 4148 pwd = getpwnam_r(dst_username, &pwds, buf_pwd,
4204 4149 sizeof (buf_pwd));
4205 4150 if (pwd == NULL) {
4206 4151 return (0);
4207 4152 }
4208 4153 } else {
4209 4154 return (0);
4210 4155 }
4211 4156
4212 4157 homedir_len = strlen(pwd->pw_dir);
4213 4158 dst_dir_len = strlen(dst) - homedir_len;
4214 4159 src_dir_len = strlen(src) - homedir_len;
4215 4160
4216 4161 /* Check that the paths are in the same zone */
4217 4162 if (src_dir_len < dst_dir_len ||
4218 4163 (strncmp(dst, src, dst_dir_len) != 0)) {
4219 4164 if (trace > 1)
4220 4165 trace_prt(1, " paths don't match\n");
4221 4166 return (0);
4222 4167 }
4223 4168 /* Check that mountpoint is an auto_home entry */
4224 4169 if (dst_dir_len < 0 ||
4225 4170 (strcmp(pwd->pw_dir, dst + dst_dir_len) != 0)) {
4226 4171 return (0);
4227 4172 }
4228 4173
4229 4174 /* Check that source is an home directory entry */
4230 4175 if (src_dir_len < 0 ||
4231 4176 (strcmp(pwd->pw_dir, src + src_dir_len) != 0)) {
4232 4177 if (trace > 1)
4233 4178 trace_prt(1, " homedir (2) doesn't match %s\n",
4234 4179 src+src_dir_len);
4235 4180 return (0);
4236 4181 }
4237 4182
4238 4183 if (mkdir(src,
4239 4184 S_IRUSR | S_IWUSR | S_IXUSR | S_IXGRP | S_IXOTH) == -1) {
4240 4185 if (trace > 1) {
4241 4186 trace_prt(1, " Couldn't mkdir %s\n", src);
4242 4187 }
4243 4188 return (0);
4244 4189 }
4245 4190
4246 4191 if (chown(src, pwd->pw_uid, pwd->pw_gid) == -1) {
4247 4192 unlink(src);
4248 4193 return (0);
4249 4194 }
4250 4195
4251 4196 /* Created new home directory for the user */
4252 4197 return (1);
4253 4198 }
4254 4199
4255 4200 void
4256 4201 free_nfs_args(struct nfs_args *argp)
4257 4202 {
4258 4203 struct nfs_args *oldp;
4259 4204 while (argp) {
4260 4205 if (argp->pathconf)
4261 4206 free(argp->pathconf);
4262 4207 if (argp->knconf)
4263 4208 free_knconf(argp->knconf);
4264 4209 if (argp->addr)
4265 4210 netbuf_free(argp->addr);
4266 4211 if (argp->syncaddr)
4267 4212 netbuf_free(argp->syncaddr);
4268 4213 if (argp->netname)
4269 4214 free(argp->netname);
4270 4215 if (argp->hostname)
4271 4216 free(argp->hostname);
4272 4217 if (argp->nfs_ext_u.nfs_extB.secdata)
4273 4218 nfs_free_secdata(argp->nfs_ext_u.nfs_extB.secdata);
4274 4219 if (argp->fh)
4275 4220 free(argp->fh);
4276 4221 if (argp->nfs_ext_u.nfs_extA.secdata) {
4277 4222 sec_data_t *sd;
4278 4223 sd = argp->nfs_ext_u.nfs_extA.secdata;
4279 4224 if (sd == NULL)
4280 4225 break;
4281 4226 switch (sd->rpcflavor) {
4282 4227 case AUTH_NONE:
4283 4228 case AUTH_UNIX:
4284 4229 case AUTH_LOOPBACK:
4285 4230 break;
4286 4231 case AUTH_DES:
4287 4232 {
4288 4233 dh_k4_clntdata_t *dhk4;
4289 4234 dhk4 = (dh_k4_clntdata_t *)sd->data;
4290 4235 if (dhk4 == NULL)
4291 4236 break;
4292 4237 if (dhk4->syncaddr.buf)
4293 4238 free(dhk4->syncaddr.buf);
4294 4239 if (dhk4->knconf->knc_protofmly)
4295 4240 free(dhk4->knconf->knc_protofmly);
4296 4241 if (dhk4->knconf->knc_proto)
4297 4242 free(dhk4->knconf->knc_proto);
4298 4243 if (dhk4->knconf)
4299 4244 free(dhk4->knconf);
4300 4245 if (dhk4->netname)
4301 4246 free(dhk4->netname);
4302 4247 free(dhk4);
4303 4248 break;
4304 4249 }
4305 4250 case RPCSEC_GSS:
4306 4251 {
4307 4252 gss_clntdata_t *gss;
4308 4253 gss = (gss_clntdata_t *)sd->data;
4309 4254 if (gss == NULL)
4310 4255 break;
4311 4256 if (gss->mechanism.elements)
4312 4257 free(gss->mechanism.elements);
4313 4258 free(gss);
4314 4259 break;
4315 4260 }
4316 4261 }
4317 4262 }
4318 4263 oldp = argp;
4319 4264 if (argp->nfs_args_ext == NFS_ARGS_EXTB)
4320 4265 argp = argp->nfs_ext_u.nfs_extB.next;
4321 4266 else
4322 4267 argp = NULL;
4323 4268 free(oldp);
4324 4269 }
4325 4270 }
4326 4271
4327 4272 void *
4328 4273 get_netconfig_info(enum type_of_stuff type_of_stuff, char *hostname,
4329 4274 rpcprog_t prog, rpcvers_t vers, struct netconfig *nconf,
4330 4275 ushort_t port, struct t_info *tinfo, struct t_bind *tbind,
4331 4276 caddr_t *fhp, bool_t direct_to_server, char *fspath,
4332 4277 enum clnt_stat *cstat, mfs_snego_t *mfssnego)
4333 4278 {
4334 4279 struct netconfig *nb = NULL;
4335 4280 int ping_server = 0;
4336 4281
4337 4282
4338 4283 if (nconf == NULL)
4339 4284 return (NULL);
4340 4285
4341 4286 switch (type_of_stuff) {
4342 4287 case SERVER_FH:
4343 4288 nb = get_server_fh(hostname, prog, vers, mfssnego,
4344 4289 nconf, port, tinfo, tbind, fhp, direct_to_server,
4345 4290 fspath, cstat);
4346 4291 break;
4347 4292 case SERVER_PING:
4348 4293 ping_server = 1;
4349 4294 case SERVER_ADDR:
4350 4295 nb = get_server_addrorping(hostname, prog, vers,
4351 4296 nconf, port, tinfo, tbind, fhp, direct_to_server,
4352 4297 fspath, cstat, ping_server);
4353 4298 break;
4354 4299 default:
4355 4300 assert(nb != NULL);
4356 4301 }
4357 4302 return (nb);
4358 4303 }
4359 4304
4360 4305 /*
4361 4306 * Get the server address or can we ping it or not.
4362 4307 * Check the portmap cache first for server address.
4363 4308 * If no entries there, ping the server with a NULLPROC rpc.
4364 4309 */
4365 4310 void *
4366 4311 get_server_addrorping(char *hostname, rpcprog_t prog, rpcvers_t vers,
4367 4312 struct netconfig *nconf, ushort_t port, struct t_info *tinfo,
4368 4313 struct t_bind *tbind, caddr_t *fhp, bool_t direct_to_server,
4369 4314 char *fspath, enum clnt_stat *cstat, int ping_server)
4370 4315 {
4371 4316 struct timeval tv;
4372 4317 enum clnt_stat cs = RPC_TIMEDOUT;
4373 4318 struct netbuf *nb = NULL;
4374 4319 CLIENT *cl = NULL;
4375 4320 int fd = -1;
4376 4321
4377 4322 if (prog == NFS_PROGRAM && vers == NFS_V4)
4378 4323 if (strncasecmp(nconf->nc_proto, NC_UDP, strlen(NC_UDP)) == 0)
4379 4324 goto done;
4380 4325
4381 4326 if ((fd = t_open(nconf->nc_device, O_RDWR, tinfo)) < 0) {
4382 4327 goto done;
4383 4328 }
4384 4329
4385 4330 /* LINTED pointer alignment */
4386 4331 if ((tbind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR))
4387 4332 == NULL) {
4388 4333 goto done;
4389 4334 }
4390 4335
4391 4336 if (direct_to_server != TRUE) {
4392 4337 if (!ping_server) {
4393 4338 if (get_cached_srv_addr(hostname, prog, vers,
4394 4339 nconf, &tbind->addr) == 0)
4395 4340 goto done;
4396 4341 } else {
4397 4342 if (port == 0)
4398 4343 goto done;
4399 4344 }
4400 4345 }
4401 4346 if (setup_nb_parms(nconf, tbind, tinfo, hostname,
4402 4347 fd, direct_to_server, port, prog, vers, 0) < 0)
4403 4348 goto done;
4404 4349
4405 4350 if (port || (direct_to_server == TRUE)) {
4406 4351 tv.tv_sec = 10;
4407 4352 tv.tv_usec = 0;
4408 4353 cl = clnt_tli_create(fd, nconf, &tbind->addr,
4409 4354 prog, vers, 0, 0);
4410 4355 if (cl == NULL)
4411 4356 goto done;
4412 4357
4413 4358 cs = clnt_call(cl, NULLPROC, xdr_void, 0,
4414 4359 xdr_void, 0, tv);
4415 4360 if (cs != RPC_SUCCESS) {
4416 4361 syslog(LOG_ERR, "error is %d", cs);
4417 4362 goto done;
4418 4363 }
4419 4364 }
4420 4365 if (!ping_server) {
4421 4366 nb = (struct netbuf *)malloc(sizeof (struct netbuf));
4422 4367 if (nb == NULL) {
4423 4368 syslog(LOG_ERR, "no memory\n");
4424 4369 goto done;
4425 4370 }
4426 4371 nb->buf = (char *)malloc(tbind->addr.maxlen);
4427 4372 if (nb->buf == NULL) {
4428 4373 syslog(LOG_ERR, "no memory\n");
4429 4374 free(nb);
4430 4375 nb = NULL;
4431 4376 goto done;
4432 4377 }
4433 4378 (void) memcpy(nb->buf, tbind->addr.buf, tbind->addr.len);
4434 4379 nb->len = tbind->addr.len;
4435 4380 nb->maxlen = tbind->addr.maxlen;
4436 4381 cs = RPC_SUCCESS;
4437 4382 }
4438 4383 done:
4439 4384 destroy_auth_client_handle(cl);
4440 4385 cleanup_tli_parms(tbind, fd);
4441 4386 *cstat = cs;
4442 4387 return (nb);
4443 4388 }
↓ open down ↓ |
3207 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX