1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 /*
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
32 * All Rights Reserved
33 *
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
36 * contributors.
37 */
38
39 /*
40 * nfs mount
41 */
42
43 #define NFSCLIENT
44 #include <locale.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <memory.h>
48 #include <stdarg.h>
49 #include <unistd.h>
50 #include <ctype.h>
51 #include <stdlib.h>
52 #include <signal.h>
53 #include <sys/param.h>
54 #include <rpc/rpc.h>
55 #include <errno.h>
56 #include <sys/stat.h>
57 #include <netdb.h>
58 #include <sys/mount.h>
59 #include <sys/mntent.h>
60 #include <sys/mnttab.h>
61 #include <nfs/nfs.h>
62 #include <nfs/mount.h>
63 #include <rpcsvc/mount.h>
64 #include <sys/pathconf.h>
65 #include <netdir.h>
66 #include <netconfig.h>
67 #include <sys/sockio.h>
68 #include <net/if.h>
69 #include <syslog.h>
70 #include <fslib.h>
71 #include <deflt.h>
72 #include <sys/wait.h>
73 #include "replica.h"
74 #include <netinet/in.h>
75 #include <nfs/nfs_sec.h>
76 #include <rpcsvc/daemon_utils.h>
77 #include <priv.h>
78 #include <tsol/label.h>
79 #include "nfs_subr.h"
80 #include "webnfs.h"
81 #include <rpcsvc/nfs4_prot.h>
82 #include <limits.h>
83 #include <libscf.h>
84 #include <libshare.h>
85 #include "smfcfg.h"
86
87 #include <nfs/nfssys.h>
88 extern int _nfssys(enum nfssys_op, void *);
89
90 #ifndef NFS_VERSMAX
91 #define NFS_VERSMAX 4
92 #endif
93 #ifndef NFS_VERSMIN
94 #define NFS_VERSMIN 2
95 #endif
96
97 #define RET_OK 0
98 #define RET_RETRY 32
99 #define RET_ERR 33
100 #define RET_MNTERR 1000
101 #define ERR_PROTO_NONE 0
102 #define ERR_PROTO_INVALID 901
103 #define ERR_PROTO_UNSUPP 902
104 #define ERR_NETPATH 903
105 #define ERR_NOHOST 904
106 #define ERR_RPCERROR 905
107
108 typedef struct err_ret {
109 int error_type;
110 int error_value;
111 } err_ret_t;
112
113 #define SET_ERR_RET(errst, etype, eval) \
114 if (errst) { \
115 (errst)->error_type = etype; \
116 (errst)->error_value = eval; \
117 }
118
119 /* number of transports to try */
120 #define MNT_PREF_LISTLEN 2
121 #define FIRST_TRY 1
122 #define SECOND_TRY 2
123
124 #define BIGRETRY 10000
125
126 /* maximum length of RPC header for NFS messages */
127 #define NFS_RPC_HDR 432
128
129 #define NFS_ARGS_EXTB_secdata(args, secdata) \
130 { (args)->nfs_args_ext = NFS_ARGS_EXTB, \
131 (args)->nfs_ext_u.nfs_extB.secdata = secdata; }
132
133 extern int __clnt_bindresvport(CLIENT *);
134 extern char *nfs_get_qop_name();
135 extern AUTH * nfs_create_ah();
136 extern enum snego_stat nfs_sec_nego();
137
138 static void usage(void);
139 static int retry(struct mnttab *, int);
140 static int set_args(int *, struct nfs_args *, char *, struct mnttab *);
141 static int get_fh_via_pub(struct nfs_args *, char *, char *, bool_t, bool_t,
142 int *, struct netconfig **, ushort_t);
143 static int get_fh(struct nfs_args *, char *, char *, int *, bool_t,
144 struct netconfig **, ushort_t);
145 static int make_secure(struct nfs_args *, char *, struct netconfig *,
146 bool_t, rpcvers_t);
147 static int mount_nfs(struct mnttab *, int, err_ret_t *);
148 static int getaddr_nfs(struct nfs_args *, char *, struct netconfig **,
149 bool_t, char *, ushort_t, err_ret_t *, bool_t);
150 static void pr_err(const char *fmt, ...);
151 static void usage(void);
152 static struct netbuf *get_addr(char *, rpcprog_t, rpcvers_t,
153 struct netconfig **, char *, ushort_t, struct t_info *,
154 caddr_t *, bool_t, char *, err_ret_t *);
155
156 static struct netbuf *get_the_addr(char *, rpcprog_t, rpcvers_t,
157 struct netconfig *, ushort_t, struct t_info *, caddr_t *,
158 bool_t, char *, err_ret_t *);
159
160 extern int self_check(char *);
161
162 static void read_default(void);
163
164 static char typename[64];
165
166 static int bg = 0;
167 static int backgrounded = 0;
168 static int posix = 0;
169 static int retries = BIGRETRY;
170 static ushort_t nfs_port = 0;
171 static char *nfs_proto = NULL;
172
173 static int mflg = 0;
174 static int Oflg = 0; /* Overlay mounts */
175 static int qflg = 0; /* quiet - don't print warnings on bad options */
176
177 static char *fstype = MNTTYPE_NFS;
178
179 static seconfig_t nfs_sec;
180 static int sec_opt = 0; /* any security option ? */
181 static bool_t snego_done;
182 static void sigusr1(int);
183
184 extern void set_nfsv4_ephemeral_mount_to(void);
185
186 /*
187 * list of support services needed
188 */
189 static char *service_list[] = { STATD, LOCKD, NULL };
190 static char *service_list_v4[] = { STATD, LOCKD, NFS4CBD, NFSMAPID, NULL };
191
192 /*
193 * These two variables control the NFS version number to be used.
194 *
195 * nfsvers defaults to 0 which means to use the highest number that
196 * both the client and the server support. It can also be set to
197 * a particular value, either 2, 3, or 4 to indicate the version
198 * number of choice. If the server (or the client) do not support
199 * the version indicated, then the mount attempt will be failed.
200 *
201 * nfsvers_to_use is the actual version number found to use. It
202 * is determined in get_fh by pinging the various versions of the
203 * NFS service on the server to see which responds positively.
204 *
205 * nfsretry_vers is the version number set when we retry the mount
206 * command with the version decremented from nfsvers_to_use.
207 * nfsretry_vers is set from nfsvers_to_use when we retry the mount
208 * for errors other than RPC errors; it helps un know why we are
209 * retrying. It is an indication that the retry is due to
210 * non-RPC errors.
211 */
212 static rpcvers_t nfsvers = 0;
213 static rpcvers_t nfsvers_to_use = 0;
214 static rpcvers_t nfsretry_vers = 0;
215
216 /*
217 * There are the defaults (range) for the client when determining
218 * which NFS version to use when probing the server (see above).
219 * These will only be used when the vers mount option is not used and
220 * these may be reset if NFS SMF is configured to do so.
221 */
222 static rpcvers_t vers_max_default = NFS_VERSMAX_DEFAULT;
223 static rpcvers_t vers_min_default = NFS_VERSMIN_DEFAULT;
224
225 /*
226 * This variable controls whether to try the public file handle.
227 */
228 static bool_t public_opt;
229
230 int
main(int argc,char * argv[])231 main(int argc, char *argv[])
232 {
233 struct mnttab mnt;
234 extern char *optarg;
235 extern int optind;
236 char optbuf[MAX_MNTOPT_STR];
237 int ro = 0;
238 int r;
239 int c;
240 char *myname;
241 err_ret_t retry_error;
242
243 (void) setlocale(LC_ALL, "");
244 #if !defined(TEXT_DOMAIN)
245 #define TEXT_DOMAIN "SYS_TEST"
246 #endif
247 (void) textdomain(TEXT_DOMAIN);
248
249 myname = strrchr(argv[0], '/');
250 myname = myname ? myname + 1 : argv[0];
251 (void) snprintf(typename, sizeof (typename), "%s %s",
252 MNTTYPE_NFS, myname);
253 argv[0] = typename;
254
255 mnt.mnt_mntopts = optbuf;
256 (void) strcpy(optbuf, "rw");
257
258 /*
259 * Set options
260 */
261 while ((c = getopt(argc, argv, "ro:mOq")) != EOF) {
262 switch (c) {
263 case 'r':
264 ro++;
265 break;
266 case 'o':
267 if (strlen(optarg) >= MAX_MNTOPT_STR) {
268 pr_err(gettext("option string too long"));
269 return (RET_ERR);
270 }
271 (void) strcpy(mnt.mnt_mntopts, optarg);
272 #ifdef LATER /* XXX */
273 if (strstr(optarg, MNTOPT_REMOUNT)) {
274 /*
275 * If remount is specified, only rw is allowed.
276 */
277 if ((strcmp(optarg, MNTOPT_REMOUNT) != 0) &&
278 (strcmp(optarg, "remount,rw") != 0) &&
279 (strcmp(optarg, "rw,remount") != 0)) {
280 pr_err(gettext("Invalid options\n"));
281 exit(RET_ERR);
282 }
283 }
284 #endif /* LATER */ /* XXX */
285 break;
286 case 'm':
287 mflg++;
288 break;
289 case 'O':
290 Oflg++;
291 break;
292 case 'q':
293 qflg++;
294 break;
295 default:
296 usage();
297 exit(RET_ERR);
298 }
299 }
300 if (argc - optind != 2) {
301 usage();
302 exit(RET_ERR);
303 }
304
305 mnt.mnt_special = argv[optind];
306 mnt.mnt_mountp = argv[optind+1];
307
308 if (!priv_ineffect(PRIV_SYS_MOUNT) ||
309 !priv_ineffect(PRIV_NET_PRIVADDR)) {
310 pr_err(gettext("insufficient privileges\n"));
311 exit(RET_ERR);
312 }
313
314 /*
315 * On a labeled system, allow read-down nfs mounts if privileged
316 * (PRIV_NET_MAC_AWARE) to do so. Otherwise, ignore the error
317 * and "mount equal label only" behavior will result.
318 */
319 if (is_system_labeled())
320 (void) setpflags(NET_MAC_AWARE, 1);
321
322 /*
323 * Read the NFS SMF defaults to see if the min/max versions have
324 * been set and therefore would override the encoded defaults.
325 * Then check to make sure that if they were set that the
326 * values are reasonable.
327 */
328 read_default();
329 if (vers_min_default > vers_max_default ||
330 vers_min_default < NFS_VERSMIN ||
331 vers_max_default > NFS_VERSMAX) {
332 pr_err("%s\n%s %s\n",
333 gettext("Incorrect configuration of client\'s"),
334 gettext("client_versmin or client_versmax"),
335 gettext("is either out of range or overlaps."));
336 }
337
338 SET_ERR_RET(&retry_error, ERR_PROTO_NONE, 0);
339 r = mount_nfs(&mnt, ro, &retry_error);
340 if (r == RET_RETRY && retries) {
341 /*
342 * Check the error code from the last mount attempt if it was
343 * an RPC error, then retry as is. Otherwise we retry with the
344 * nfsretry_vers set. It is set by decrementing nfsvers_to_use.
345 * If we are retrying with nfsretry_vers then we don't print any
346 * retry messages, since we are not retrying due to an RPC
347 * error.
348 */
349 if (retry_error.error_type) {
350 if (retry_error.error_type != ERR_RPCERROR) {
351 nfsretry_vers = nfsvers_to_use =
352 nfsvers_to_use - 1;
353 if (nfsretry_vers < NFS_VERSMIN)
354 return (r);
355 }
356 }
357
358 r = retry(&mnt, ro);
359 }
360 /*
361 * exit(r);
362 */
363 return (r);
364 }
365
366 static void
pr_err(const char * fmt,...)367 pr_err(const char *fmt, ...)
368 {
369 va_list ap;
370
371 va_start(ap, fmt);
372 if (backgrounded != 0) {
373 (void) vsyslog(LOG_ERR, fmt, ap);
374 } else {
375 (void) fprintf(stderr, "%s: ", typename);
376 (void) vfprintf(stderr, fmt, ap);
377 (void) fflush(stderr);
378 }
379 va_end(ap);
380 }
381
382 static void
usage()383 usage()
384 {
385 (void) fprintf(stderr,
386 gettext("Usage: nfs mount [-r] [-o opts] [server:]path dir\n"));
387 exit(RET_ERR);
388 }
389
390 static int
mount_nfs(struct mnttab * mntp,int ro,err_ret_t * retry_error)391 mount_nfs(struct mnttab *mntp, int ro, err_ret_t *retry_error)
392 {
393 struct nfs_args *args = NULL, *argp = NULL, *prev_argp = NULL;
394 struct netconfig *nconf = NULL;
395 struct replica *list = NULL;
396 int mntflags = 0;
397 int i, r, n;
398 int oldvers = 0, vers = 0;
399 int last_error = RET_OK;
400 int replicated = 0;
401 char *p;
402 bool_t url;
403 bool_t use_pubfh;
404 char *special = NULL;
405 char *oldpath = NULL;
406 char *newpath = NULL;
407 char *service;
408 pid_t pi;
409 struct flock f;
410 char *saveopts = NULL;
411 char **sl = NULL;
412
413 mntp->mnt_fstype = MNTTYPE_NFS;
414
415 if (ro) {
416 mntflags |= MS_RDONLY;
417 /* convert "rw"->"ro" */
418 if (p = strstr(mntp->mnt_mntopts, "rw")) {
419 if (*(p+2) == ',' || *(p+2) == '\0')
420 *(p+1) = 'o';
421 }
422 }
423
424 if (Oflg)
425 mntflags |= MS_OVERLAY;
426
427 list = parse_replica(mntp->mnt_special, &n);
428 if (list == NULL) {
429 if (n < 0)
430 pr_err(gettext("nfs file system; use [host:]path\n"));
431 else
432 pr_err(gettext("no memory\n"));
433 return (RET_ERR);
434 }
435
436 replicated = (n > 1);
437
438 /*
439 * There are some free() calls at the bottom of this loop, so be
440 * careful about adding continue statements.
441 */
442 for (i = 0; i < n; i++) {
443 char *path;
444 char *host;
445 ushort_t port;
446
447 argp = (struct nfs_args *)malloc(sizeof (*argp));
448 if (argp == NULL) {
449 pr_err(gettext("no memory\n"));
450 last_error = RET_ERR;
451 goto out;
452 }
453 memset(argp, 0, sizeof (*argp));
454
455 memset(&nfs_sec, 0, sizeof (nfs_sec));
456 sec_opt = 0;
457 use_pubfh = FALSE;
458 url = FALSE;
459 port = 0;
460 snego_done = FALSE;
461
462 /*
463 * Looking for resources of the form
464 * nfs://server_host[:port_number]/path_name
465 */
466 if (strcmp(list[i].host, "nfs") == 0 && strncmp(list[i].path,
467 "//", 2) == 0) {
468 char *sport, *cb;
469 url = TRUE;
470 oldpath = strdup(list[i].path);
471 if (oldpath == NULL) {
472 pr_err(gettext("memory allocation failure\n"));
473 last_error = RET_ERR;
474 goto out;
475 }
476 host = list[i].path+2;
477 path = strchr(host, '/');
478
479 if (path == NULL) {
480 pr_err(gettext(
481 "illegal nfs url syntax\n"));
482 last_error = RET_ERR;
483 goto out;
484 }
485
486 *path = '\0';
487 if (*host == '[') {
488 cb = strchr(host, ']');
489 if (cb == NULL) {
490 pr_err(gettext(
491 "illegal nfs url syntax\n"));
492 last_error = RET_ERR;
493 goto out;
494 } else {
495 *cb = '\0';
496 host++;
497 cb++;
498 if (*cb == ':')
499 port = htons((ushort_t)
500 atoi(cb+1));
501 }
502 } else {
503 sport = strchr(host, ':');
504
505 if (sport != NULL && sport < path) {
506 *sport = '\0';
507 port = htons((ushort_t)atoi(sport+1));
508 }
509 }
510
511 path++;
512 if (*path == '\0')
513 path = ".";
514
515 } else {
516 host = list[i].host;
517 path = list[i].path;
518 }
519
520 if (r = set_args(&mntflags, argp, host, mntp)) {
521 last_error = r;
522 goto out;
523 }
524
525 if (public_opt == TRUE)
526 use_pubfh = TRUE;
527
528 if (port == 0) {
529 port = nfs_port;
530 } else if (nfs_port != 0 && nfs_port != port) {
531 pr_err(gettext(
532 "port (%u) in nfs URL not the same"
533 " as port (%u) in port option\n"),
534 (unsigned int)ntohs(port),
535 (unsigned int)ntohs(nfs_port));
536 last_error = RET_ERR;
537 goto out;
538 }
539
540
541 if (replicated && !(mntflags & MS_RDONLY)) {
542 pr_err(gettext(
543 "replicated mounts must be read-only\n"));
544 last_error = RET_ERR;
545 goto out;
546 }
547
548 if (replicated && (argp->flags & NFSMNT_SOFT)) {
549 pr_err(gettext(
550 "replicated mounts must not be soft\n"));
551 last_error = RET_ERR;
552 goto out;
553 }
554
555 oldvers = vers;
556 nconf = NULL;
557
558 r = RET_ERR;
559
560 /*
561 * If -o public was specified, and/or a URL was specified,
562 * then try the public file handle method.
563 */
564 if ((use_pubfh == TRUE) || (url == TRUE)) {
565 r = get_fh_via_pub(argp, host, path, url, use_pubfh,
566 &vers, &nconf, port);
567
568 if (r != RET_OK) {
569 /*
570 * If -o public was specified, then return the
571 * error now.
572 */
573 if (use_pubfh == TRUE) {
574 last_error = r;
575 goto out;
576 }
577 } else
578 use_pubfh = TRUE;
579 argp->flags |= NFSMNT_PUBLIC;
580 }
581
582 if ((r != RET_OK) || (vers == NFS_V4)) {
583 bool_t loud_on_mnt_err;
584
585 /*
586 * This can happen if -o public is not specified,
587 * special is a URL, and server doesn't support
588 * public file handle.
589 */
590 if (url) {
591 URLparse(path);
592 }
593
594 /*
595 * If the path portion of the URL didn't have
596 * a leading / then there is good possibility
597 * that a mount without a leading slash will
598 * fail.
599 */
600 if (url == TRUE && *path != '/')
601 loud_on_mnt_err = FALSE;
602 else
603 loud_on_mnt_err = TRUE;
604
605 r = get_fh(argp, host, path, &vers,
606 loud_on_mnt_err, &nconf, port);
607
608 if (r != RET_OK) {
609
610 /*
611 * If there was no leading / and the path was
612 * derived from a URL, then try again
613 * with a leading /.
614 */
615 if ((r == RET_MNTERR) &&
616 (loud_on_mnt_err == FALSE)) {
617
618 newpath = malloc(strlen(path)+2);
619
620 if (newpath == NULL) {
621 pr_err(gettext("memory "
622 "allocation failure\n"));
623 last_error = RET_ERR;
624 goto out;
625 }
626
627 strcpy(newpath, "/");
628 strcat(newpath, path);
629
630 r = get_fh(argp, host, newpath, &vers,
631 TRUE, &nconf, port);
632
633 if (r == RET_OK)
634 path = newpath;
635 }
636
637 /*
638 * map exit code back to RET_ERR.
639 */
640 if (r == RET_MNTERR)
641 r = RET_ERR;
642
643 if (r != RET_OK) {
644
645 if (replicated) {
646 if (argp->fh)
647 free(argp->fh);
648 if (argp->pathconf)
649 free(argp->pathconf);
650 free(argp);
651 goto cont;
652 }
653
654 last_error = r;
655 goto out;
656 }
657 }
658 }
659
660 if (oldvers && vers != oldvers) {
661 pr_err(
662 gettext("replicas must have the same version\n"));
663 last_error = RET_ERR;
664 goto out;
665 }
666
667 /*
668 * decide whether to use remote host's
669 * lockd or do local locking
670 */
671 if (!(argp->flags & NFSMNT_LLOCK) && vers == NFS_VERSION &&
672 remote_lock(host, argp->fh)) {
673 (void) fprintf(stderr, gettext(
674 "WARNING: No network locking on %s:%s:"),
675 host, path);
676 (void) fprintf(stderr, gettext(
677 " contact admin to install server change\n"));
678 argp->flags |= NFSMNT_LLOCK;
679 }
680
681 if (self_check(host))
682 argp->flags |= NFSMNT_LOOPBACK;
683
684 if (use_pubfh == FALSE) {
685 /*
686 * Call to get_fh() above may have obtained the
687 * netconfig info and NULL proc'd the server.
688 * This would be the case with v4
689 */
690 if (!(argp->flags & NFSMNT_KNCONF)) {
691 nconf = NULL;
692 if (r = getaddr_nfs(argp, host, &nconf,
693 FALSE, path, port, retry_error,
694 TRUE)) {
695 last_error = r;
696 goto out;
697 }
698 }
699 }
700
701 if (make_secure(argp, host, nconf, use_pubfh, vers) < 0) {
702 last_error = RET_ERR;
703 goto out;
704 }
705
706 if ((url == TRUE) && (use_pubfh == FALSE)) {
707 /*
708 * Convert the special from
709 * nfs://host/path
710 * to
711 * host:path
712 */
713 if (convert_special(&special, host, oldpath, path,
714 mntp->mnt_special) == -1) {
715 (void) fprintf(stderr, gettext(
716 "could not convert URL nfs:%s to %s:%s\n"),
717 oldpath, host, path);
718 last_error = RET_ERR;
719 goto out;
720 } else {
721 mntp->mnt_special = special;
722 }
723 }
724
725 if (prev_argp == NULL)
726 args = argp;
727 else
728 prev_argp->nfs_ext_u.nfs_extB.next = argp;
729 prev_argp = argp;
730
731 cont:
732 if (oldpath != NULL) {
733 free(oldpath);
734 oldpath = NULL;
735 }
736
737 if (newpath != NULL) {
738 free(newpath);
739 newpath = NULL;
740 }
741 }
742
743 argp = NULL;
744
745 if (args == NULL) {
746 last_error = RET_RETRY;
747 goto out;
748 }
749
750 /* Determine which services are appropriate for the NFS version */
751 if (strcmp(fstype, MNTTYPE_NFS4) == 0)
752 sl = service_list_v4;
753 else
754 sl = service_list;
755
756 /*
757 * enable services as needed.
758 */
759 _check_services(sl);
760
761 mntflags |= MS_DATA | MS_OPTIONSTR;
762
763 if (mflg)
764 mntflags |= MS_NOMNTTAB;
765
766 if (!qflg)
767 saveopts = strdup(mntp->mnt_mntopts);
768
769 /*
770 * And make sure that we have the ephemeral mount_to
771 * set for this zone.
772 */
773 set_nfsv4_ephemeral_mount_to();
774
775 if (mount(mntp->mnt_special, mntp->mnt_mountp, mntflags, fstype, args,
776 sizeof (*args), mntp->mnt_mntopts, MAX_MNTOPT_STR) < 0) {
777 if (errno != ENOENT) {
778 pr_err(gettext("mount: %s: %s\n"),
779 mntp->mnt_mountp, strerror(errno));
780 } else {
781 struct stat sb;
782 if (stat(mntp->mnt_mountp, &sb) < 0 && errno == ENOENT)
783 pr_err(gettext("mount: %s: %s\n"),
784 mntp->mnt_mountp, strerror(ENOENT));
785 else
786 pr_err("%s: %s\n", mntp->mnt_special,
787 strerror(ENOENT));
788 }
789
790 last_error = RET_ERR;
791 goto out;
792 }
793
794 if (!qflg && saveopts != NULL) {
795 cmp_requested_to_actual_options(saveopts, mntp->mnt_mntopts,
796 mntp->mnt_special, mntp->mnt_mountp);
797 }
798
799 out:
800 if (saveopts != NULL)
801 free(saveopts);
802 if (special != NULL)
803 free(special);
804 if (oldpath != NULL)
805 free(oldpath);
806 if (newpath != NULL)
807 free(newpath);
808
809 free_replica(list, n);
810
811 if (argp != NULL) {
812 /*
813 * If we had a new entry which was not added to the
814 * list yet, then add it now that it can be freed.
815 */
816 if (prev_argp == NULL)
817 args = argp;
818 else
819 prev_argp->nfs_ext_u.nfs_extB.next = argp;
820 }
821 argp = args;
822 while (argp != NULL) {
823 if (argp->fh)
824 free(argp->fh);
825 if (argp->pathconf)
826 free(argp->pathconf);
827 if (argp->knconf)
828 free(argp->knconf);
829 if (argp->addr) {
830 free(argp->addr->buf);
831 free(argp->addr);
832 }
833 nfs_free_secdata(argp->nfs_ext_u.nfs_extB.secdata);
834 if (argp->syncaddr) {
835 free(argp->syncaddr->buf);
836 free(argp->syncaddr);
837 }
838 if (argp->netname)
839 free(argp->netname);
840 prev_argp = argp;
841 argp = argp->nfs_ext_u.nfs_extB.next;
842 free(prev_argp);
843 }
844
845 return (last_error);
846 }
847
848 /*
849 * These options are duplicated in uts/common/fs/nfs/nfs_dlinet.c
850 * Changes must be made to both lists.
851 */
852 static char *optlist[] = {
853 #define OPT_RO 0
854 MNTOPT_RO,
855 #define OPT_RW 1
856 MNTOPT_RW,
857 #define OPT_QUOTA 2
858 MNTOPT_QUOTA,
859 #define OPT_NOQUOTA 3
860 MNTOPT_NOQUOTA,
861 #define OPT_SOFT 4
862 MNTOPT_SOFT,
863 #define OPT_HARD 5
864 MNTOPT_HARD,
865 #define OPT_SUID 6
866 MNTOPT_SUID,
867 #define OPT_NOSUID 7
868 MNTOPT_NOSUID,
869 #define OPT_GRPID 8
870 MNTOPT_GRPID,
871 #define OPT_REMOUNT 9
872 MNTOPT_REMOUNT,
873 #define OPT_NOSUB 10
874 MNTOPT_NOSUB,
875 #define OPT_INTR 11
876 MNTOPT_INTR,
877 #define OPT_NOINTR 12
878 MNTOPT_NOINTR,
879 #define OPT_PORT 13
880 MNTOPT_PORT,
881 #define OPT_SECURE 14
882 MNTOPT_SECURE,
883 #define OPT_RSIZE 15
884 MNTOPT_RSIZE,
885 #define OPT_WSIZE 16
886 MNTOPT_WSIZE,
887 #define OPT_TIMEO 17
888 MNTOPT_TIMEO,
889 #define OPT_RETRANS 18
890 MNTOPT_RETRANS,
891 #define OPT_ACTIMEO 19
892 MNTOPT_ACTIMEO,
893 #define OPT_ACREGMIN 20
894 MNTOPT_ACREGMIN,
895 #define OPT_ACREGMAX 21
896 MNTOPT_ACREGMAX,
897 #define OPT_ACDIRMIN 22
898 MNTOPT_ACDIRMIN,
899 #define OPT_ACDIRMAX 23
900 MNTOPT_ACDIRMAX,
901 #define OPT_BG 24
902 MNTOPT_BG,
903 #define OPT_FG 25
904 MNTOPT_FG,
905 #define OPT_RETRY 26
906 MNTOPT_RETRY,
907 #define OPT_NOAC 27
908 MNTOPT_NOAC,
909 #define OPT_NOCTO 28
910 MNTOPT_NOCTO,
911 #define OPT_LLOCK 29
912 MNTOPT_LLOCK,
913 #define OPT_POSIX 30
914 MNTOPT_POSIX,
915 #define OPT_VERS 31
916 MNTOPT_VERS,
917 #define OPT_PROTO 32
918 MNTOPT_PROTO,
919 #define OPT_SEMISOFT 33
920 MNTOPT_SEMISOFT,
921 #define OPT_NOPRINT 34
922 MNTOPT_NOPRINT,
923 #define OPT_SEC 35
924 MNTOPT_SEC,
925 #define OPT_LARGEFILES 36
926 MNTOPT_LARGEFILES,
927 #define OPT_NOLARGEFILES 37
928 MNTOPT_NOLARGEFILES,
929 #define OPT_PUBLIC 38
930 MNTOPT_PUBLIC,
931 #define OPT_DIRECTIO 39
932 MNTOPT_FORCEDIRECTIO,
933 #define OPT_NODIRECTIO 40
934 MNTOPT_NOFORCEDIRECTIO,
935 #define OPT_XATTR 41
936 MNTOPT_XATTR,
937 #define OPT_NOXATTR 42
938 MNTOPT_NOXATTR,
939 #define OPT_DEVICES 43
940 MNTOPT_DEVICES,
941 #define OPT_NODEVICES 44
942 MNTOPT_NODEVICES,
943 #define OPT_SETUID 45
944 MNTOPT_SETUID,
945 #define OPT_NOSETUID 46
946 MNTOPT_NOSETUID,
947 #define OPT_EXEC 47
948 MNTOPT_EXEC,
949 #define OPT_NOEXEC 48
950 MNTOPT_NOEXEC,
951 NULL
952 };
953
954 static int
convert_int(int * val,char * str)955 convert_int(int *val, char *str)
956 {
957 long lval;
958
959 if (str == NULL || !isdigit(*str))
960 return (-1);
961
962 lval = strtol(str, &str, 10);
963 if (*str != '\0' || lval > INT_MAX)
964 return (-2);
965
966 *val = (int)lval;
967 return (0);
968 }
969
970 static int
set_args(int * mntflags,struct nfs_args * args,char * fshost,struct mnttab * mnt)971 set_args(int *mntflags, struct nfs_args *args, char *fshost, struct mnttab *mnt)
972 {
973 char *saveopt, *optstr, *opts, *newopts, *val;
974 int num;
975 int largefiles = 0;
976 int invalid = 0;
977 int attrpref = 0;
978 int optlen;
979
980 args->flags = NFSMNT_INT; /* default is "intr" */
981 args->flags |= NFSMNT_HOSTNAME;
982 args->flags |= NFSMNT_NEWARGS; /* using extented nfs_args structure */
983 args->hostname = fshost;
984
985 optstr = opts = strdup(mnt->mnt_mntopts);
986 /* sizeof (MNTOPT_XXX) includes one extra byte we may need for "," */
987 optlen = strlen(mnt->mnt_mntopts) + sizeof (MNTOPT_XATTR) + 1;
988 if (optlen > MAX_MNTOPT_STR) {
989 pr_err(gettext("option string too long"));
990 return (RET_ERR);
991 }
992 newopts = malloc(optlen);
993 if (opts == NULL || newopts == NULL) {
994 pr_err(gettext("no memory"));
995 if (opts)
996 free(opts);
997 if (newopts)
998 free(newopts);
999 return (RET_ERR);
1000 }
1001 newopts[0] = '\0';
1002
1003 while (*opts) {
1004 invalid = 0;
1005 saveopt = opts;
1006 switch (getsubopt(&opts, optlist, &val)) {
1007 case OPT_RO:
1008 *mntflags |= MS_RDONLY;
1009 break;
1010 case OPT_RW:
1011 *mntflags &= ~(MS_RDONLY);
1012 break;
1013 case OPT_QUOTA:
1014 case OPT_NOQUOTA:
1015 break;
1016 case OPT_SOFT:
1017 args->flags |= NFSMNT_SOFT;
1018 args->flags &= ~(NFSMNT_SEMISOFT);
1019 break;
1020 case OPT_SEMISOFT:
1021 args->flags |= NFSMNT_SOFT;
1022 args->flags |= NFSMNT_SEMISOFT;
1023 break;
1024 case OPT_HARD:
1025 args->flags &= ~(NFSMNT_SOFT);
1026 args->flags &= ~(NFSMNT_SEMISOFT);
1027 break;
1028 case OPT_SUID:
1029 *mntflags &= ~(MS_NOSUID);
1030 break;
1031 case OPT_NOSUID:
1032 *mntflags |= MS_NOSUID;
1033 break;
1034 case OPT_GRPID:
1035 args->flags |= NFSMNT_GRPID;
1036 break;
1037 case OPT_REMOUNT:
1038 *mntflags |= MS_REMOUNT;
1039 break;
1040 case OPT_INTR:
1041 args->flags |= NFSMNT_INT;
1042 break;
1043 case OPT_NOINTR:
1044 args->flags &= ~(NFSMNT_INT);
1045 break;
1046 case OPT_NOAC:
1047 args->flags |= NFSMNT_NOAC;
1048 break;
1049 case OPT_PORT:
1050 if (convert_int(&num, val) != 0)
1051 goto badopt;
1052 nfs_port = htons((ushort_t)num);
1053 break;
1054
1055 case OPT_SECURE:
1056 if (nfs_getseconfig_byname("dh", &nfs_sec)) {
1057 pr_err(gettext("can not get \"dh\" from %s\n"),
1058 NFSSEC_CONF);
1059 goto badopt;
1060 }
1061 sec_opt++;
1062 break;
1063
1064 case OPT_NOCTO:
1065 args->flags |= NFSMNT_NOCTO;
1066 break;
1067
1068 case OPT_RSIZE:
1069 if (convert_int(&args->rsize, val) != 0)
1070 goto badopt;
1071 args->flags |= NFSMNT_RSIZE;
1072 break;
1073 case OPT_WSIZE:
1074 if (convert_int(&args->wsize, val) != 0)
1075 goto badopt;
1076 args->flags |= NFSMNT_WSIZE;
1077 break;
1078 case OPT_TIMEO:
1079 if (convert_int(&args->timeo, val) != 0)
1080 goto badopt;
1081 args->flags |= NFSMNT_TIMEO;
1082 break;
1083 case OPT_RETRANS:
1084 if (convert_int(&args->retrans, val) != 0)
1085 goto badopt;
1086 args->flags |= NFSMNT_RETRANS;
1087 break;
1088 case OPT_ACTIMEO:
1089 if (convert_int(&args->acregmax, val) != 0)
1090 goto badopt;
1091 args->acdirmin = args->acregmin = args->acdirmax
1092 = args->acregmax;
1093 args->flags |= NFSMNT_ACDIRMAX;
1094 args->flags |= NFSMNT_ACREGMAX;
1095 args->flags |= NFSMNT_ACDIRMIN;
1096 args->flags |= NFSMNT_ACREGMIN;
1097 break;
1098 case OPT_ACREGMIN:
1099 if (convert_int(&args->acregmin, val) != 0)
1100 goto badopt;
1101 args->flags |= NFSMNT_ACREGMIN;
1102 break;
1103 case OPT_ACREGMAX:
1104 if (convert_int(&args->acregmax, val) != 0)
1105 goto badopt;
1106 args->flags |= NFSMNT_ACREGMAX;
1107 break;
1108 case OPT_ACDIRMIN:
1109 if (convert_int(&args->acdirmin, val) != 0)
1110 goto badopt;
1111 args->flags |= NFSMNT_ACDIRMIN;
1112 break;
1113 case OPT_ACDIRMAX:
1114 if (convert_int(&args->acdirmax, val) != 0)
1115 goto badopt;
1116 args->flags |= NFSMNT_ACDIRMAX;
1117 break;
1118 case OPT_BG:
1119 bg++;
1120 break;
1121 case OPT_FG:
1122 bg = 0;
1123 break;
1124 case OPT_RETRY:
1125 if (convert_int(&retries, val) != 0)
1126 goto badopt;
1127 break;
1128 case OPT_LLOCK:
1129 args->flags |= NFSMNT_LLOCK;
1130 break;
1131 case OPT_POSIX:
1132 posix = 1;
1133 break;
1134 case OPT_VERS:
1135 if (convert_int(&num, val) != 0)
1136 goto badopt;
1137 nfsvers = (rpcvers_t)num;
1138 break;
1139 case OPT_PROTO:
1140 if (val == NULL)
1141 goto badopt;
1142
1143 nfs_proto = (char *)malloc(strlen(val)+1);
1144 if (!nfs_proto) {
1145 pr_err(gettext("no memory"));
1146 return (RET_ERR);
1147 }
1148
1149 (void) strncpy(nfs_proto, val, strlen(val)+1);
1150 break;
1151
1152 case OPT_NOPRINT:
1153 args->flags |= NFSMNT_NOPRINT;
1154 break;
1155
1156 case OPT_LARGEFILES:
1157 largefiles = 1;
1158 break;
1159
1160 case OPT_NOLARGEFILES:
1161 pr_err(gettext("NFS can't support \"nolargefiles\"\n"));
1162 free(optstr);
1163 return (RET_ERR);
1164
1165 case OPT_SEC:
1166 if (val == NULL) {
1167 pr_err(gettext(
1168 "\"sec\" option requires argument\n"));
1169 return (RET_ERR);
1170 }
1171 if (nfs_getseconfig_byname(val, &nfs_sec)) {
1172 pr_err(gettext("can not get \"%s\" from %s\n"),
1173 val, NFSSEC_CONF);
1174 return (RET_ERR);
1175 }
1176 sec_opt++;
1177 break;
1178
1179 case OPT_PUBLIC:
1180 public_opt = TRUE;
1181 break;
1182
1183 case OPT_DIRECTIO:
1184 args->flags |= NFSMNT_DIRECTIO;
1185 break;
1186
1187 case OPT_NODIRECTIO:
1188 args->flags &= ~(NFSMNT_DIRECTIO);
1189 break;
1190
1191 case OPT_XATTR:
1192 case OPT_NOXATTR:
1193 /*
1194 * VFS options; just need to get them into the
1195 * new mount option string and note we've seen them
1196 */
1197 attrpref = 1;
1198 break;
1199 default:
1200 /*
1201 * Note that this could be a valid OPT_* option so
1202 * we can't use "val" but need to use "saveopt".
1203 */
1204 if (fsisstdopt(saveopt))
1205 break;
1206 invalid = 1;
1207 if (!qflg)
1208 (void) fprintf(stderr, gettext(
1209 "mount: %s on %s - WARNING unknown option"
1210 " \"%s\"\n"), mnt->mnt_special,
1211 mnt->mnt_mountp, saveopt);
1212 break;
1213 }
1214 if (!invalid) {
1215 if (newopts[0])
1216 strcat(newopts, ",");
1217 strcat(newopts, saveopt);
1218 }
1219 }
1220 /* Default is to turn extended attrs on */
1221 if (!attrpref) {
1222 if (newopts[0])
1223 strcat(newopts, ",");
1224 strcat(newopts, MNTOPT_XATTR);
1225 }
1226 strcpy(mnt->mnt_mntopts, newopts);
1227 free(newopts);
1228 free(optstr);
1229
1230 /* ensure that only one secure mode is requested */
1231 if (sec_opt > 1) {
1232 pr_err(gettext("Security options conflict\n"));
1233 return (RET_ERR);
1234 }
1235
1236 /* ensure that the user isn't trying to get large files over V2 */
1237 if (nfsvers == NFS_VERSION && largefiles) {
1238 pr_err(gettext("NFS V2 can't support \"largefiles\"\n"));
1239 return (RET_ERR);
1240 }
1241
1242 if (nfsvers == NFS_V4 &&
1243 nfs_proto != NULL &&
1244 strncasecmp(nfs_proto, NC_UDP, strlen(NC_UDP)) == 0) {
1245 pr_err(gettext("NFS V4 does not support %s\n"), nfs_proto);
1246 return (RET_ERR);
1247 }
1248
1249 return (RET_OK);
1250
1251 badopt:
1252 pr_err(gettext("invalid option: \"%s\"\n"), saveopt);
1253 free(optstr);
1254 return (RET_ERR);
1255 }
1256
1257 static int
make_secure(struct nfs_args * args,char * hostname,struct netconfig * nconf,bool_t use_pubfh,rpcvers_t vers)1258 make_secure(struct nfs_args *args, char *hostname, struct netconfig *nconf,
1259 bool_t use_pubfh, rpcvers_t vers)
1260 {
1261 sec_data_t *secdata;
1262 int flags;
1263 struct netbuf *syncaddr = NULL;
1264 struct nd_addrlist *retaddrs = NULL;
1265 char netname[MAXNETNAMELEN+1];
1266
1267 /*
1268 * check to see if any secure mode is requested.
1269 * if not, use default security mode.
1270 */
1271 if (!snego_done && !sec_opt) {
1272 /*
1273 * Get default security mode.
1274 * AUTH_UNIX has been the default choice for a long time.
1275 * The better NFS security service becomes, the better chance
1276 * we will set stronger security service as the default NFS
1277 * security mode.
1278 */
1279 if (nfs_getseconfig_default(&nfs_sec)) {
1280 pr_err(gettext("error getting default"
1281 " security entry\n"));
1282 return (-1);
1283 }
1284 args->flags |= NFSMNT_SECDEFAULT;
1285 }
1286
1287 /*
1288 * Get the network address for the time service on the server.
1289 * If an RPC based time service is not available then try the
1290 * IP time service.
1291 *
1292 * This is for AUTH_DH processing. We will also pass down syncaddr
1293 * and netname for NFS V4 even if AUTH_DH is not requested right now.
1294 * NFS V4 does security negotiation in the kernel via SECINFO.
1295 * These information might be needed later in the kernel.
1296 *
1297 * Eventurally, we want to move this code to nfs_clnt_secdata()
1298 * when autod_nfs.c and mount.c can share the same get_the_addr()
1299 * routine.
1300 */
1301 flags = 0;
1302 syncaddr = NULL;
1303
1304 if (nfs_sec.sc_rpcnum == AUTH_DH || vers == NFS_V4) {
1305 /*
1306 * If using the public fh or nfsv4, we will not contact the
1307 * remote RPCBINDer, since it is possibly behind a firewall.
1308 */
1309 if (use_pubfh == FALSE && vers != NFS_V4)
1310 syncaddr = get_the_addr(hostname, RPCBPROG, RPCBVERS,
1311 nconf, 0, NULL, NULL, FALSE, NULL, NULL);
1312
1313 if (syncaddr != NULL) {
1314 /* for flags in sec_data */
1315 flags |= AUTH_F_RPCTIMESYNC;
1316 } else {
1317 struct nd_hostserv hs;
1318 int error;
1319
1320 hs.h_host = hostname;
1321 hs.h_serv = "timserver";
1322
1323 error = netdir_getbyname(nconf, &hs, &retaddrs);
1324
1325 if (error != ND_OK && (nfs_sec.sc_rpcnum == AUTH_DH)) {
1326 pr_err(gettext("%s: secure: no time service\n"),
1327 hostname);
1328 return (-1);
1329 }
1330
1331 if (error == ND_OK)
1332 syncaddr = retaddrs->n_addrs;
1333
1334 /*
1335 * For NFS_V4 if AUTH_DH is negotiated later in the
1336 * kernel thru SECINFO, it will need syncaddr
1337 * and netname data.
1338 */
1339 if (vers == NFS_V4 && syncaddr &&
1340 host2netname(netname, hostname, NULL)) {
1341 args->syncaddr = malloc(sizeof (struct netbuf));
1342 args->syncaddr->buf = malloc(syncaddr->len);
1343 (void) memcpy(args->syncaddr->buf,
1344 syncaddr->buf, syncaddr->len);
1345 args->syncaddr->len = syncaddr->len;
1346 args->syncaddr->maxlen = syncaddr->maxlen;
1347 args->netname = strdup(netname);
1348 args->flags |= NFSMNT_SECURE;
1349 }
1350 }
1351 }
1352
1353 /*
1354 * For the initial chosen flavor (any flavor defined in nfssec.conf),
1355 * the data will be stored in the sec_data structure via
1356 * nfs_clnt_secdata() and be passed to the kernel via nfs_args_*
1357 * extended data structure.
1358 */
1359 if (!(secdata = nfs_clnt_secdata(&nfs_sec, hostname, args->knconf,
1360 syncaddr, flags))) {
1361 pr_err(gettext("errors constructing security related data\n"));
1362 if (flags & AUTH_F_RPCTIMESYNC) {
1363 free(syncaddr->buf);
1364 free(syncaddr);
1365 } else if (retaddrs)
1366 netdir_free((void *)retaddrs, ND_ADDRLIST);
1367 return (-1);
1368 }
1369
1370 NFS_ARGS_EXTB_secdata(args, secdata);
1371 if (flags & AUTH_F_RPCTIMESYNC) {
1372 free(syncaddr->buf);
1373 free(syncaddr);
1374 } else if (retaddrs)
1375 netdir_free((void *)retaddrs, ND_ADDRLIST);
1376 return (0);
1377 }
1378
1379 /*
1380 * Get the network address on "hostname" for program "prog"
1381 * with version "vers" by using the nconf configuration data
1382 * passed in.
1383 *
1384 * If the address of a netconfig pointer is null then
1385 * information is not sufficient and no netbuf will be returned.
1386 *
1387 * Finally, ping the null procedure of that service.
1388 *
1389 * A similar routine is also defined in ../../autofs/autod_nfs.c.
1390 * This is a potential routine to move to ../lib for common usage.
1391 */
1392 static struct netbuf *
get_the_addr(char * hostname,ulong_t prog,ulong_t vers,struct netconfig * nconf,ushort_t port,struct t_info * tinfo,caddr_t * fhp,bool_t get_pubfh,char * fspath,err_ret_t * error)1393 get_the_addr(char *hostname, ulong_t prog, ulong_t vers,
1394 struct netconfig *nconf, ushort_t port, struct t_info *tinfo,
1395 caddr_t *fhp, bool_t get_pubfh, char *fspath, err_ret_t *error)
1396 {
1397 struct netbuf *nb = NULL;
1398 struct t_bind *tbind = NULL;
1399 CLIENT *cl = NULL;
1400 struct timeval tv;
1401 int fd = -1;
1402 AUTH *ah = NULL;
1403 AUTH *new_ah = NULL;
1404 struct snego_t snego;
1405
1406 if (nconf == NULL)
1407 return (NULL);
1408
1409 if ((fd = t_open(nconf->nc_device, O_RDWR, tinfo)) == -1)
1410 goto done;
1411
1412 /* LINTED pointer alignment */
1413 if ((tbind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR))
1414 == NULL)
1415 goto done;
1416
1417 /*
1418 * In the case of public filehandle usage or NFSv4 we want to
1419 * avoid use of the rpcbind/portmap protocol
1420 */
1421 if ((get_pubfh == TRUE) || (vers == NFS_V4)) {
1422 struct nd_hostserv hs;
1423 struct nd_addrlist *retaddrs;
1424 int retval;
1425 hs.h_host = hostname;
1426
1427 /* NFS where vers==4 does not support UDP */
1428 if (vers == NFS_V4 &&
1429 strncasecmp(nconf->nc_proto, NC_UDP,
1430 strlen(NC_UDP)) == 0) {
1431 SET_ERR_RET(error, ERR_PROTO_UNSUPP, 0);
1432 goto done;
1433 }
1434
1435 if (port == 0)
1436 hs.h_serv = "nfs";
1437 else
1438 hs.h_serv = NULL;
1439
1440 if ((retval = netdir_getbyname(nconf, &hs, &retaddrs))
1441 != ND_OK) {
1442 /*
1443 * Carefully set the error value here. Want to signify
1444 * that the error was an unknown host.
1445 */
1446 if (retval == ND_NOHOST) {
1447 SET_ERR_RET(error, ERR_NOHOST, retval);
1448 }
1449
1450 goto done;
1451 }
1452 memcpy(tbind->addr.buf, retaddrs->n_addrs->buf,
1453 retaddrs->n_addrs->len);
1454 tbind->addr.len = retaddrs->n_addrs->len;
1455 netdir_free((void *)retaddrs, ND_ADDRLIST);
1456 (void) netdir_options(nconf, ND_SET_RESERVEDPORT, fd, NULL);
1457
1458 } else {
1459 if (rpcb_getaddr(prog, vers, nconf, &tbind->addr,
1460 hostname) == FALSE) {
1461 goto done;
1462 }
1463 }
1464
1465 if (port) {
1466 /* LINTED pointer alignment */
1467 if (strcmp(nconf->nc_protofmly, NC_INET) == 0)
1468 ((struct sockaddr_in *)tbind->addr.buf)->sin_port
1469 = port;
1470 else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0)
1471 ((struct sockaddr_in6 *)tbind->addr.buf)->sin6_port
1472 = port;
1473
1474 }
1475
1476 cl = clnt_tli_create(fd, nconf, &tbind->addr, prog, vers, 0, 0);
1477 if (cl == NULL) {
1478 /*
1479 * clnt_tli_create() returns either RPC_SYSTEMERROR,
1480 * RPC_UNKNOWNPROTO or RPC_TLIERROR. The RPC_TLIERROR translates
1481 * to "Misc. TLI error". This is not too helpful. Most likely
1482 * the connection to the remote server timed out, so this
1483 * error is at least less perplexing.
1484 * See: usr/src/cmd/rpcinfo/rpcinfo.c
1485 */
1486 if (rpc_createerr.cf_stat == RPC_TLIERROR) {
1487 SET_ERR_RET(error, ERR_RPCERROR, RPC_PMAPFAILURE);
1488 } else {
1489 SET_ERR_RET(error, ERR_RPCERROR, rpc_createerr.cf_stat);
1490 }
1491 goto done;
1492 }
1493
1494 ah = authsys_create_default();
1495 if (ah != NULL)
1496 cl->cl_auth = ah;
1497
1498 tv.tv_sec = 5;
1499 tv.tv_usec = 0;
1500
1501 (void) clnt_control(cl, CLSET_TIMEOUT, (char *)&tv);
1502
1503 if ((get_pubfh == TRUE) && (vers != NFS_V4)) {
1504 enum snego_stat sec;
1505
1506 if (!snego_done) {
1507 /*
1508 * negotiate sec flavor.
1509 */
1510 snego.cnt = 0;
1511 if ((sec = nfs_sec_nego(vers, cl, fspath, &snego)) ==
1512 SNEGO_SUCCESS) {
1513 int jj;
1514
1515 /*
1516 * check if server supports the one
1517 * specified in the sec= option.
1518 */
1519 if (sec_opt) {
1520 for (jj = 0; jj < snego.cnt; jj++) {
1521 if (snego.array[jj] ==
1522 nfs_sec.sc_nfsnum) {
1523 snego_done = TRUE;
1524 break;
1525 }
1526 }
1527 }
1528
1529 /*
1530 * find a common sec flavor
1531 */
1532 if (!snego_done) {
1533 if (sec_opt) {
1534 pr_err(gettext(
1535 "Server does not support"
1536 " the security flavor"
1537 " specified.\n"));
1538 }
1539
1540 for (jj = 0; jj < snego.cnt; jj++) {
1541 if (!nfs_getseconfig_bynumber(
1542 snego.array[jj],
1543 &nfs_sec)) {
1544 snego_done = TRUE;
1545 #define EMSG80SUX "Security flavor %d was negotiated and will be used.\n"
1546 if (sec_opt)
1547 pr_err(gettext(
1548 EMSG80SUX),
1549 nfs_sec.
1550 sc_nfsnum);
1551 break;
1552 }
1553 }
1554 }
1555
1556 if (!snego_done)
1557 return (NULL);
1558
1559 /*
1560 * Now that the flavor has been
1561 * negotiated, get the fh.
1562 *
1563 * First, create an auth handle using the
1564 * negotiated sec flavor in the next lookup to
1565 * fetch the filehandle.
1566 */
1567 new_ah = nfs_create_ah(cl, hostname, &nfs_sec);
1568 if (new_ah == NULL)
1569 goto done;
1570 cl->cl_auth = new_ah;
1571 } else if (sec == SNEGO_ARRAY_TOO_SMALL || sec ==
1572 SNEGO_FAILURE) {
1573 goto done;
1574 }
1575
1576 /*
1577 * Note that if sec == SNEGO_DEF_VALID
1578 * default sec flavor is acceptable.
1579 * Use it to get the filehandle.
1580 */
1581 }
1582
1583 if (vers == NFS_VERSION) {
1584 wnl_diropargs arg;
1585 wnl_diropres res;
1586
1587 memset((char *)&arg.dir, 0, sizeof (wnl_fh));
1588 arg.name = fspath;
1589 memset((char *)&res, 0, sizeof (wnl_diropres));
1590 if (wnlproc_lookup_2(&arg, &res, cl) !=
1591 RPC_SUCCESS || res.status != WNL_OK)
1592 goto done;
1593
1594 *fhp = malloc(sizeof (wnl_fh));
1595
1596 if (*fhp == NULL) {
1597 pr_err(gettext("no memory\n"));
1598 goto done;
1599 }
1600
1601 memcpy((char *)*fhp,
1602 (char *)&res.wnl_diropres_u.wnl_diropres.file,
1603 sizeof (wnl_fh));
1604 } else {
1605 WNL_LOOKUP3args arg;
1606 WNL_LOOKUP3res res;
1607 nfs_fh3 *fh3p;
1608
1609 memset((char *)&arg.what.dir, 0, sizeof (wnl_fh3));
1610 arg.what.name = fspath;
1611 memset((char *)&res, 0, sizeof (WNL_LOOKUP3res));
1612 if (wnlproc3_lookup_3(&arg, &res, cl) !=
1613 RPC_SUCCESS || res.status != WNL3_OK)
1614 goto done;
1615
1616 fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p));
1617
1618 if (fh3p == NULL) {
1619 pr_err(gettext("no memory\n"));
1620 goto done;
1621 }
1622
1623 fh3p->fh3_length =
1624 res.WNL_LOOKUP3res_u.res_ok.object.data.data_len;
1625 memcpy(fh3p->fh3_u.data,
1626 res.WNL_LOOKUP3res_u.res_ok.object.data.data_val,
1627 fh3p->fh3_length);
1628
1629 *fhp = (caddr_t)fh3p;
1630 }
1631 } else {
1632 struct rpc_err r_err;
1633 enum clnt_stat rc;
1634
1635 /*
1636 * NULL procedures need not have an argument or
1637 * result param.
1638 */
1639 if (vers == NFS_VERSION)
1640 rc = wnlproc_null_2(NULL, NULL, cl);
1641 else if (vers == NFS_V3)
1642 rc = wnlproc3_null_3(NULL, NULL, cl);
1643 else
1644 rc = wnlproc4_null_4(NULL, NULL, cl);
1645
1646 if (rc != RPC_SUCCESS) {
1647 clnt_geterr(cl, &r_err);
1648 if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
1649 switch (r_err.re_status) {
1650 case RPC_TLIERROR:
1651 case RPC_CANTRECV:
1652 case RPC_CANTSEND:
1653 r_err.re_status = RPC_PROGVERSMISMATCH;
1654 }
1655 }
1656 SET_ERR_RET(error, ERR_RPCERROR, r_err.re_status);
1657 goto done;
1658 }
1659 }
1660
1661 /*
1662 * Make a copy of the netbuf to return
1663 */
1664 nb = (struct netbuf *)malloc(sizeof (*nb));
1665 if (nb == NULL) {
1666 pr_err(gettext("no memory\n"));
1667 goto done;
1668 }
1669 *nb = tbind->addr;
1670 nb->buf = (char *)malloc(nb->maxlen);
1671 if (nb->buf == NULL) {
1672 pr_err(gettext("no memory\n"));
1673 free(nb);
1674 nb = NULL;
1675 goto done;
1676 }
1677 (void) memcpy(nb->buf, tbind->addr.buf, tbind->addr.len);
1678
1679 done:
1680 if (cl) {
1681 if (ah != NULL) {
1682 if (new_ah != NULL)
1683 AUTH_DESTROY(ah);
1684 AUTH_DESTROY(cl->cl_auth);
1685 cl->cl_auth = NULL;
1686 }
1687 clnt_destroy(cl);
1688 cl = NULL;
1689 }
1690 if (tbind) {
1691 t_free((char *)tbind, T_BIND);
1692 tbind = NULL;
1693 }
1694 if (fd >= 0)
1695 (void) t_close(fd);
1696 return (nb);
1697 }
1698
1699 static int
check_nconf(struct netconfig * nconf,int nthtry,int * valid_proto)1700 check_nconf(struct netconfig *nconf, int nthtry, int *valid_proto)
1701 {
1702 int try_test = 0;
1703 int valid_family;
1704 char *proto = NULL;
1705
1706
1707 if (nthtry == FIRST_TRY) {
1708 try_test = ((nconf->nc_semantics == NC_TPI_COTS_ORD) ||
1709 (nconf->nc_semantics == NC_TPI_COTS));
1710 proto = NC_TCP;
1711 } else if (nthtry == SECOND_TRY) {
1712 try_test = (nconf->nc_semantics == NC_TPI_CLTS);
1713 proto = NC_UDP;
1714 }
1715
1716 if (proto &&
1717 (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
1718 strcmp(nconf->nc_protofmly, NC_INET6) == 0) &&
1719 (strcmp(nconf->nc_proto, proto) == 0))
1720 *valid_proto = TRUE;
1721 else
1722 *valid_proto = FALSE;
1723
1724 return (try_test);
1725 }
1726
1727 /*
1728 * Get a network address on "hostname" for program "prog"
1729 * with version "vers". If the port number is specified (non zero)
1730 * then try for a TCP/UDP transport and set the port number of the
1731 * resulting IP address.
1732 *
1733 * If the address of a netconfig pointer was passed and
1734 * if it's not null, use it as the netconfig otherwise
1735 * assign the address of the netconfig that was used to
1736 * establish contact with the service.
1737 *
1738 * A similar routine is also defined in ../../autofs/autod_nfs.c.
1739 * This is a potential routine to move to ../lib for common usage.
1740 *
1741 * "error" refers to a more descriptive term when get_addr fails
1742 * and returns NULL: ERR_PROTO_NONE if no error introduced by
1743 * -o proto option, ERR_NETPATH if error found in NETPATH
1744 * environment variable, ERR_PROTO_INVALID if an unrecognized
1745 * protocol is specified by user, and ERR_PROTO_UNSUPP for a
1746 * recognized but invalid protocol (eg. ticlts, ticots, etc.).
1747 * "error" is ignored if get_addr returns non-NULL result.
1748 *
1749 */
1750 static struct netbuf *
get_addr(char * hostname,ulong_t prog,ulong_t vers,struct netconfig ** nconfp,char * proto,ushort_t port,struct t_info * tinfo,caddr_t * fhp,bool_t get_pubfh,char * fspath,err_ret_t * error)1751 get_addr(char *hostname, ulong_t prog, ulong_t vers, struct netconfig **nconfp,
1752 char *proto, ushort_t port, struct t_info *tinfo, caddr_t *fhp,
1753 bool_t get_pubfh, char *fspath, err_ret_t *error)
1754 {
1755 struct netbuf *nb = NULL;
1756 struct netconfig *nconf = NULL;
1757 NCONF_HANDLE *nc = NULL;
1758 int nthtry = FIRST_TRY;
1759 err_ret_t errsave_nohost, errsave_rpcerr;
1760
1761 SET_ERR_RET(&errsave_nohost, ERR_PROTO_NONE, 0);
1762 SET_ERR_RET(&errsave_rpcerr, ERR_PROTO_NONE, 0);
1763
1764 SET_ERR_RET(error, ERR_PROTO_NONE, 0);
1765
1766 if (nconfp && *nconfp)
1767 return (get_the_addr(hostname, prog, vers, *nconfp, port,
1768 tinfo, fhp, get_pubfh, fspath, error));
1769 /*
1770 * No nconf passed in.
1771 *
1772 * Try to get a nconf from /etc/netconfig filtered by
1773 * the NETPATH environment variable.
1774 * First search for COTS, second for CLTS unless proto
1775 * is specified. When we retry, we reset the
1776 * netconfig list so that we would search the whole list
1777 * all over again.
1778 */
1779
1780 if ((nc = setnetpath()) == NULL) {
1781 /* should only return an error if problems with NETPATH */
1782 /* In which case you are hosed */
1783 SET_ERR_RET(error, ERR_NETPATH, 0);
1784 goto done;
1785 }
1786
1787 /*
1788 * If proto is specified, then only search for the match,
1789 * otherwise try COTS first, if failed, try CLTS.
1790 */
1791 if (proto) {
1792 /* no matching proto name */
1793 SET_ERR_RET(error, ERR_PROTO_INVALID, 0);
1794
1795 while (nconf = getnetpath(nc)) {
1796 if (strcmp(nconf->nc_netid, proto))
1797 continue;
1798
1799 /* may be unsupported */
1800 SET_ERR_RET(error, ERR_PROTO_UNSUPP, 0);
1801
1802 if ((port != 0) &&
1803 ((strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
1804 strcmp(nconf->nc_protofmly, NC_INET6) == 0) &&
1805 (strcmp(nconf->nc_proto, NC_TCP) != 0 &&
1806 strcmp(nconf->nc_proto, NC_UDP) != 0))) {
1807 continue;
1808 } else {
1809 nb = get_the_addr(hostname, prog,
1810 vers, nconf, port, tinfo,
1811 fhp, get_pubfh, fspath, error);
1812
1813 if (nb != NULL)
1814 break;
1815
1816 /* nb is NULL - deal with errors */
1817 if (error) {
1818 if (error->error_type == ERR_NOHOST)
1819 SET_ERR_RET(&errsave_nohost,
1820 error->error_type,
1821 error->error_value);
1822 if (error->error_type == ERR_RPCERROR)
1823 SET_ERR_RET(&errsave_rpcerr,
1824 error->error_type,
1825 error->error_value);
1826 }
1827 /*
1828 * continue with same protocol
1829 * selection
1830 */
1831 continue;
1832 }
1833 } /* end of while */
1834
1835 if (nconf == NULL)
1836 goto done;
1837
1838 if ((nb = get_the_addr(hostname, prog, vers, nconf, port,
1839 tinfo, fhp, get_pubfh, fspath, error)) == NULL)
1840 goto done;
1841 } else {
1842 retry:
1843 SET_ERR_RET(error, ERR_NETPATH, 0);
1844 while (nconf = getnetpath(nc)) {
1845 SET_ERR_RET(error, ERR_PROTO_NONE, 0);
1846
1847 if (nconf->nc_flag & NC_VISIBLE) {
1848 int valid_proto;
1849
1850 if (check_nconf(nconf,
1851 nthtry, &valid_proto)) {
1852 if (port == 0)
1853 break;
1854
1855 if (valid_proto == TRUE)
1856 break;
1857 }
1858 }
1859 } /* while */
1860 if (nconf == NULL) {
1861 if (++nthtry <= MNT_PREF_LISTLEN) {
1862 endnetpath(nc);
1863 if ((nc = setnetpath()) == NULL)
1864 goto done;
1865 goto retry;
1866 } else
1867 goto done;
1868 } else {
1869 if ((nb = get_the_addr(hostname, prog, vers, nconf,
1870 port, tinfo, fhp, get_pubfh, fspath, error))
1871 == NULL) {
1872 /* nb is NULL - deal with errors */
1873 if (error) {
1874 if (error->error_type == ERR_NOHOST)
1875 SET_ERR_RET(&errsave_nohost,
1876 error->error_type,
1877 error->error_value);
1878 if (error->error_type == ERR_RPCERROR)
1879 SET_ERR_RET(&errsave_rpcerr,
1880 error->error_type,
1881 error->error_value);
1882 }
1883 /*
1884 * Continue the same search path in the
1885 * netconfig db until no more matched
1886 * nconf (nconf == NULL).
1887 */
1888 goto retry;
1889 }
1890 }
1891 }
1892 SET_ERR_RET(error, ERR_PROTO_NONE, 0);
1893
1894 /*
1895 * Got nconf and nb. Now dup the netconfig structure (nconf)
1896 * and return it thru nconfp.
1897 */
1898 *nconfp = getnetconfigent(nconf->nc_netid);
1899 if (*nconfp == NULL) {
1900 syslog(LOG_ERR, "no memory\n");
1901 free(nb);
1902 nb = NULL;
1903 }
1904 done:
1905 if (nc)
1906 endnetpath(nc);
1907
1908 if (nb == NULL) {
1909 /*
1910 * Check the saved errors. The RPC error has *
1911 * precedence over the no host error.
1912 */
1913 if (errsave_nohost.error_type != ERR_PROTO_NONE)
1914 SET_ERR_RET(error, errsave_nohost.error_type,
1915 errsave_nohost.error_value);
1916
1917 if (errsave_rpcerr.error_type != ERR_PROTO_NONE)
1918 SET_ERR_RET(error, errsave_rpcerr.error_type,
1919 errsave_rpcerr.error_value);
1920 }
1921
1922 return (nb);
1923 }
1924
1925 /*
1926 * Get a file handle usinging multi-component lookup with the public
1927 * file handle.
1928 */
1929 static int
get_fh_via_pub(struct nfs_args * args,char * fshost,char * fspath,bool_t url,bool_t loud,int * versp,struct netconfig ** nconfp,ushort_t port)1930 get_fh_via_pub(struct nfs_args *args, char *fshost, char *fspath, bool_t url,
1931 bool_t loud, int *versp, struct netconfig **nconfp, ushort_t port)
1932 {
1933 uint_t vers_min;
1934 uint_t vers_max;
1935 int r;
1936 char *path;
1937
1938 if (nfsvers != 0) {
1939 vers_max = vers_min = nfsvers;
1940 } else {
1941 vers_max = vers_max_default;
1942 vers_min = vers_min_default;
1943 }
1944
1945 if (url == FALSE) {
1946 path = malloc(strlen(fspath) + 2);
1947 if (path == NULL) {
1948 if (loud == TRUE)
1949 pr_err(gettext("no memory\n"));
1950 return (RET_ERR);
1951 }
1952
1953 path[0] = (char)WNL_NATIVEPATH;
1954 (void) strcpy(&path[1], fspath);
1955
1956 } else {
1957 path = fspath;
1958 }
1959
1960 for (nfsvers_to_use = vers_max; nfsvers_to_use >= vers_min;
1961 nfsvers_to_use--) {
1962 /*
1963 * getaddr_nfs will also fill in the fh for us.
1964 */
1965 r = getaddr_nfs(args, fshost, nconfp,
1966 TRUE, path, port, NULL, FALSE);
1967
1968 if (r == RET_OK) {
1969 /*
1970 * Since we are using the public fh, and NLM is
1971 * not firewall friendly, use local locking.
1972 * Not the case for v4.
1973 */
1974 *versp = nfsvers_to_use;
1975 switch (nfsvers_to_use) {
1976 case NFS_V4:
1977 fstype = MNTTYPE_NFS4;
1978 break;
1979 case NFS_V3:
1980 fstype = MNTTYPE_NFS3;
1981 /* fall through to pick up llock option */
1982 default:
1983 args->flags |= NFSMNT_LLOCK;
1984 break;
1985 }
1986 if (fspath != path)
1987 free(path);
1988
1989 return (r);
1990 }
1991 }
1992
1993 if (fspath != path)
1994 free(path);
1995
1996 if (loud == TRUE) {
1997 pr_err(gettext("Could not use public filehandle in request to"
1998 " server %s\n"), fshost);
1999 }
2000
2001 return (r);
2002 }
2003
2004 /*
2005 * get fhandle of remote path from server's mountd
2006 */
2007 static int
get_fh(struct nfs_args * args,char * fshost,char * fspath,int * versp,bool_t loud_on_mnt_err,struct netconfig ** nconfp,ushort_t port)2008 get_fh(struct nfs_args *args, char *fshost, char *fspath, int *versp,
2009 bool_t loud_on_mnt_err, struct netconfig **nconfp, ushort_t port)
2010 {
2011 static struct fhstatus fhs;
2012 static struct mountres3 mountres3;
2013 static struct pathcnf p;
2014 nfs_fh3 *fh3p;
2015 struct timeval timeout = { 25, 0};
2016 CLIENT *cl;
2017 enum clnt_stat rpc_stat;
2018 rpcvers_t outvers = 0;
2019 rpcvers_t vers_to_try;
2020 rpcvers_t vers_min;
2021 static int printed = 0;
2022 int count, i, *auths;
2023 char *msg;
2024
2025 switch (nfsvers) {
2026 case 2: /* version 2 specified try that only */
2027 vers_to_try = MOUNTVERS_POSIX;
2028 vers_min = MOUNTVERS;
2029 break;
2030 case 3: /* version 3 specified try that only */
2031 vers_to_try = MOUNTVERS3;
2032 vers_min = MOUNTVERS3;
2033 break;
2034 case 4: /* version 4 specified try that only */
2035 /*
2036 * This assignment is in the wrong version sequence.
2037 * The above are MOUNT program and this is NFS
2038 * program. However, it happens to work out since the
2039 * two don't collide for NFSv4.
2040 */
2041 vers_to_try = NFS_V4;
2042 vers_min = NFS_V4;
2043 break;
2044 default: /* no version specified, start with default */
2045 /*
2046 * If the retry version is set, use that. This will
2047 * be set if the last mount attempt returned any other
2048 * besides an RPC error.
2049 */
2050 if (nfsretry_vers)
2051 vers_to_try = nfsretry_vers;
2052 else {
2053 vers_to_try = vers_max_default;
2054 vers_min = vers_min_default;
2055 }
2056
2057 break;
2058 }
2059
2060 /*
2061 * In the case of version 4, just NULL proc the server since
2062 * there is no MOUNT program. If this fails, then decrease
2063 * vers_to_try and continue on with regular MOUNT program
2064 * processing.
2065 */
2066 if (vers_to_try == NFS_V4) {
2067 int savevers = nfsvers_to_use;
2068 err_ret_t error;
2069 int retval;
2070 SET_ERR_RET(&error, ERR_PROTO_NONE, 0);
2071
2072 /* Let's hope for the best */
2073 nfsvers_to_use = NFS_V4;
2074 retval = getaddr_nfs(args, fshost, nconfp, FALSE,
2075 fspath, port, &error, vers_min == NFS_V4);
2076
2077 if (retval == RET_OK) {
2078 *versp = nfsvers_to_use = NFS_V4;
2079 fstype = MNTTYPE_NFS4;
2080 args->fh = strdup(fspath);
2081 if (args->fh == NULL) {
2082 pr_err(gettext("no memory\n"));
2083 *versp = nfsvers_to_use = savevers;
2084 return (RET_ERR);
2085 }
2086 return (RET_OK);
2087 }
2088 nfsvers_to_use = savevers;
2089
2090 vers_to_try--;
2091 /* If no more versions to try, let the user know. */
2092 if (vers_to_try < vers_min)
2093 return (retval);
2094
2095 /*
2096 * If we are here, there are more versions to try but
2097 * there has been an error of some sort. If it is not
2098 * an RPC error (e.g. host unknown), we just stop and
2099 * return the error since the other versions would see
2100 * the same error as well.
2101 */
2102 if (retval == RET_ERR && error.error_type != ERR_RPCERROR)
2103 return (retval);
2104 }
2105
2106 while ((cl = clnt_create_vers(fshost, MOUNTPROG, &outvers,
2107 vers_min, vers_to_try, "datagram_v")) == NULL) {
2108 if (rpc_createerr.cf_stat == RPC_UNKNOWNHOST) {
2109 pr_err(gettext("%s: %s\n"), fshost,
2110 clnt_spcreateerror(""));
2111 return (RET_ERR);
2112 }
2113
2114 /*
2115 * We don't want to downgrade version on lost packets
2116 */
2117 if ((rpc_createerr.cf_stat == RPC_TIMEDOUT) ||
2118 (rpc_createerr.cf_stat == RPC_PMAPFAILURE)) {
2119 pr_err(gettext("%s: %s\n"), fshost,
2120 clnt_spcreateerror(""));
2121 return (RET_RETRY);
2122 }
2123
2124 /*
2125 * back off and try the previous version - patch to the
2126 * problem of version numbers not being contigous and
2127 * clnt_create_vers failing (SunOS4.1 clients & SGI servers)
2128 * The problem happens with most non-Sun servers who
2129 * don't support mountd protocol #2. So, in case the
2130 * call fails, we re-try the call anyway.
2131 */
2132 vers_to_try--;
2133 if (vers_to_try < vers_min) {
2134 if (rpc_createerr.cf_stat == RPC_PROGVERSMISMATCH) {
2135 if (nfsvers == 0) {
2136 pr_err(gettext(
2137 "%s:%s: no applicable versions of NFS supported\n"),
2138 fshost, fspath);
2139 } else {
2140 pr_err(gettext(
2141 "%s:%s: NFS Version %d not supported\n"),
2142 fshost, fspath, nfsvers);
2143 }
2144 return (RET_ERR);
2145 }
2146 if (!printed) {
2147 pr_err(gettext("%s: %s\n"), fshost,
2148 clnt_spcreateerror(""));
2149 printed = 1;
2150 }
2151 return (RET_RETRY);
2152 }
2153 }
2154 if (posix && outvers < MOUNTVERS_POSIX) {
2155 pr_err(gettext("%s: %s: no pathconf info\n"),
2156 fshost, clnt_sperror(cl, ""));
2157 clnt_destroy(cl);
2158 return (RET_ERR);
2159 }
2160
2161 if (__clnt_bindresvport(cl) < 0) {
2162 pr_err(gettext("Couldn't bind to reserved port\n"));
2163 clnt_destroy(cl);
2164 return (RET_RETRY);
2165 }
2166
2167 if ((cl->cl_auth = authsys_create_default()) == NULL) {
2168 pr_err(
2169 gettext("Couldn't create default authentication handle\n"));
2170 clnt_destroy(cl);
2171 return (RET_RETRY);
2172 }
2173
2174 switch (outvers) {
2175 case MOUNTVERS:
2176 case MOUNTVERS_POSIX:
2177 *versp = nfsvers_to_use = NFS_VERSION;
2178 rpc_stat = clnt_call(cl, MOUNTPROC_MNT, xdr_dirpath,
2179 (caddr_t)&fspath, xdr_fhstatus, (caddr_t)&fhs, timeout);
2180 if (rpc_stat != RPC_SUCCESS) {
2181 pr_err(gettext("%s:%s: server not responding %s\n"),
2182 fshost, fspath, clnt_sperror(cl, ""));
2183 clnt_destroy(cl);
2184 return (RET_RETRY);
2185 }
2186
2187 if ((errno = fhs.fhs_status) != MNT_OK) {
2188 if (loud_on_mnt_err) {
2189 if (errno == EACCES) {
2190 pr_err(gettext(
2191 "%s:%s: access denied\n"),
2192 fshost, fspath);
2193 } else {
2194 pr_err(gettext("%s:%s: %s\n"), fshost,
2195 fspath, errno >= 0 ?
2196 strerror(errno) : "invalid error "
2197 "returned by server");
2198 }
2199 }
2200 clnt_destroy(cl);
2201 return (RET_MNTERR);
2202 }
2203 args->fh = malloc(sizeof (fhs.fhstatus_u.fhs_fhandle));
2204 if (args->fh == NULL) {
2205 pr_err(gettext("no memory\n"));
2206 return (RET_ERR);
2207 }
2208 memcpy((caddr_t)args->fh, (caddr_t)&fhs.fhstatus_u.fhs_fhandle,
2209 sizeof (fhs.fhstatus_u.fhs_fhandle));
2210 if (!errno && posix) {
2211 rpc_stat = clnt_call(cl, MOUNTPROC_PATHCONF,
2212 xdr_dirpath, (caddr_t)&fspath, xdr_ppathcnf,
2213 (caddr_t)&p, timeout);
2214 if (rpc_stat != RPC_SUCCESS) {
2215 pr_err(gettext(
2216 "%s:%s: server not responding %s\n"),
2217 fshost, fspath, clnt_sperror(cl, ""));
2218 free(args->fh);
2219 clnt_destroy(cl);
2220 return (RET_RETRY);
2221 }
2222 if (_PC_ISSET(_PC_ERROR, p.pc_mask)) {
2223 pr_err(gettext(
2224 "%s:%s: no pathconf info\n"),
2225 fshost, fspath);
2226 free(args->fh);
2227 clnt_destroy(cl);
2228 return (RET_ERR);
2229 }
2230 args->flags |= NFSMNT_POSIX;
2231 args->pathconf = malloc(sizeof (p));
2232 if (args->pathconf == NULL) {
2233 pr_err(gettext("no memory\n"));
2234 free(args->fh);
2235 clnt_destroy(cl);
2236 return (RET_ERR);
2237 }
2238 memcpy((caddr_t)args->pathconf, (caddr_t)&p,
2239 sizeof (p));
2240 }
2241 break;
2242
2243 case MOUNTVERS3:
2244 *versp = nfsvers_to_use = NFS_V3;
2245 rpc_stat = clnt_call(cl, MOUNTPROC_MNT, xdr_dirpath,
2246 (caddr_t)&fspath, xdr_mountres3, (caddr_t)&mountres3,
2247 timeout);
2248 if (rpc_stat != RPC_SUCCESS) {
2249 pr_err(gettext("%s:%s: server not responding %s\n"),
2250 fshost, fspath, clnt_sperror(cl, ""));
2251 clnt_destroy(cl);
2252 return (RET_RETRY);
2253 }
2254
2255 /*
2256 * Assume here that most of the MNT3ERR_*
2257 * codes map into E* errors.
2258 */
2259 if ((errno = mountres3.fhs_status) != MNT_OK) {
2260 if (loud_on_mnt_err) {
2261 switch (errno) {
2262 case MNT3ERR_NAMETOOLONG:
2263 msg = "path name is too long";
2264 break;
2265 case MNT3ERR_NOTSUPP:
2266 msg = "operation not supported";
2267 break;
2268 case MNT3ERR_SERVERFAULT:
2269 msg = "server fault";
2270 break;
2271 default:
2272 if (errno >= 0)
2273 msg = strerror(errno);
2274 else
2275 msg = "invalid error returned "
2276 "by server";
2277 break;
2278 }
2279 pr_err(gettext("%s:%s: %s\n"), fshost,
2280 fspath, msg);
2281 }
2282 clnt_destroy(cl);
2283 return (RET_MNTERR);
2284 }
2285
2286 fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p));
2287 if (fh3p == NULL) {
2288 pr_err(gettext("no memory\n"));
2289 return (RET_ERR);
2290 }
2291 fh3p->fh3_length =
2292 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len;
2293 (void) memcpy(fh3p->fh3_u.data,
2294 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val,
2295 fh3p->fh3_length);
2296 args->fh = (caddr_t)fh3p;
2297 fstype = MNTTYPE_NFS3;
2298
2299 /*
2300 * Check the security flavor to be used.
2301 *
2302 * If "secure" or "sec=flavor" is a mount
2303 * option, check if the server supports the "flavor".
2304 * If the server does not support the flavor, return
2305 * error.
2306 *
2307 * If no mount option is given then look for default auth
2308 * (default auth entry in /etc/nfssec.conf) in the auth list
2309 * returned from server. If default auth not found, then use
2310 * the first supported security flavor (by the client) in the
2311 * auth list returned from the server.
2312 *
2313 */
2314 auths =
2315 mountres3.mountres3_u.mountinfo.auth_flavors
2316 .auth_flavors_val;
2317 count =
2318 mountres3.mountres3_u.mountinfo.auth_flavors
2319 .auth_flavors_len;
2320
2321 if (count <= 0) {
2322 pr_err(gettext(
2323 "server %s did not return any security mode\n"),
2324 fshost);
2325 clnt_destroy(cl);
2326 return (RET_ERR);
2327 }
2328
2329 if (sec_opt) {
2330 for (i = 0; i < count; i++) {
2331 if (auths[i] == nfs_sec.sc_nfsnum)
2332 break;
2333 }
2334 if (i == count)
2335 goto autherr;
2336 } else {
2337 seconfig_t default_sec;
2338
2339 /*
2340 * Get client configured default auth.
2341 */
2342 nfs_sec.sc_nfsnum = -1;
2343 default_sec.sc_nfsnum = -1;
2344 (void) nfs_getseconfig_default(&default_sec);
2345
2346 /*
2347 * Look for clients default auth in servers list.
2348 */
2349 if (default_sec.sc_nfsnum != -1) {
2350 for (i = 0; i < count; i++) {
2351 if (auths[i] == default_sec.sc_nfsnum) {
2352 sec_opt++;
2353 nfs_sec = default_sec;
2354 break;
2355 }
2356 }
2357 }
2358
2359 /*
2360 * Could not find clients default auth in servers list.
2361 * Pick the first auth from servers list that is
2362 * also supported on the client.
2363 */
2364 if (nfs_sec.sc_nfsnum == -1) {
2365 for (i = 0; i < count; i++) {
2366 if (!nfs_getseconfig_bynumber(auths[i],
2367 &nfs_sec)) {
2368 sec_opt++;
2369 break;
2370
2371 }
2372 }
2373 }
2374
2375 if (i == count)
2376 goto autherr;
2377 }
2378 break;
2379 default:
2380 pr_err(gettext("%s:%s: Unknown MOUNT version %d\n"),
2381 fshost, fspath, outvers);
2382 clnt_destroy(cl);
2383 return (RET_ERR);
2384 }
2385
2386 clnt_destroy(cl);
2387 return (RET_OK);
2388
2389 autherr:
2390 pr_err(gettext(
2391 "security mode does not match the server exporting %s:%s\n"),
2392 fshost, fspath);
2393 clnt_destroy(cl);
2394 return (RET_ERR);
2395 }
2396
2397 /*
2398 * Fill in the address for the server's NFS service and
2399 * fill in a knetconfig structure for the transport that
2400 * the service is available on.
2401 */
2402 static int
getaddr_nfs(struct nfs_args * args,char * fshost,struct netconfig ** nconfp,bool_t get_pubfh,char * fspath,ushort_t port,err_ret_t * error,bool_t print_rpcerror)2403 getaddr_nfs(struct nfs_args *args, char *fshost, struct netconfig **nconfp,
2404 bool_t get_pubfh, char *fspath, ushort_t port, err_ret_t *error,
2405 bool_t print_rpcerror)
2406 {
2407 struct stat sb;
2408 struct netconfig *nconf;
2409 struct knetconfig *knconfp;
2410 static int printed = 0;
2411 struct t_info tinfo;
2412 err_ret_t addr_error;
2413
2414 SET_ERR_RET(error, ERR_PROTO_NONE, 0);
2415 SET_ERR_RET(&addr_error, ERR_PROTO_NONE, 0);
2416
2417 if (nfs_proto) {
2418 /*
2419 * If a proto is specified and its rdma try this. The kernel
2420 * will later do the reachablity test and fail form there
2421 * if rdma transport is not available to kernel rpc
2422 */
2423 if (strcmp(nfs_proto, "rdma") == 0) {
2424 args->addr = get_addr(fshost, NFS_PROGRAM,
2425 nfsvers_to_use, nconfp, NULL, port, &tinfo,
2426 &args->fh, get_pubfh, fspath, &addr_error);
2427
2428 args->flags |= NFSMNT_DORDMA;
2429 } else {
2430 args->addr = get_addr(fshost, NFS_PROGRAM,
2431 nfsvers_to_use, nconfp, nfs_proto, port, &tinfo,
2432 &args->fh, get_pubfh, fspath, &addr_error);
2433 }
2434 } else {
2435 args->addr = get_addr(fshost, NFS_PROGRAM, nfsvers_to_use,
2436 nconfp, nfs_proto, port, &tinfo, &args->fh, get_pubfh,
2437 fspath, &addr_error);
2438 /*
2439 * If no proto is specified set this flag.
2440 * Kernel mount code will try to use RDMA if its on the
2441 * system, otherwise it will keep on using the protocol
2442 * selected here, through the above get_addr call.
2443 */
2444 if (nfs_proto == NULL)
2445 args->flags |= NFSMNT_TRYRDMA;
2446 }
2447
2448 if (args->addr == NULL) {
2449 /*
2450 * We could have failed because the server had no public
2451 * file handle support. So don't print a message and don't
2452 * retry.
2453 */
2454 if (get_pubfh == TRUE)
2455 return (RET_ERR);
2456
2457 if (!printed) {
2458 switch (addr_error.error_type) {
2459 case 0:
2460 printed = 1;
2461 break;
2462 case ERR_RPCERROR:
2463 if (!print_rpcerror)
2464 /* no error print at this time */
2465 break;
2466 pr_err(gettext("%s NFS service not"
2467 " available %s\n"), fshost,
2468 clnt_sperrno(addr_error.error_value));
2469 printed = 1;
2470 break;
2471 case ERR_NETPATH:
2472 pr_err(gettext("%s: Error in NETPATH.\n"),
2473 fshost);
2474 printed = 1;
2475 break;
2476 case ERR_PROTO_INVALID:
2477 pr_err(gettext("%s: NFS service does not"
2478 " recognize protocol: %s.\n"), fshost,
2479 nfs_proto);
2480 printed = 1;
2481 break;
2482 case ERR_PROTO_UNSUPP:
2483 if (nfsvers || nfsvers_to_use == NFS_VERSMIN) {
2484 /*
2485 * Don't set "printed" here. Since we
2486 * have to keep checking here till we
2487 * exhaust transport errors on all vers.
2488 *
2489 * Print this message if:
2490 * 1. After we have tried all versions
2491 * of NFS and none support the asked
2492 * transport.
2493 *
2494 * 2. If a version is specified and it
2495 * does'nt support the asked
2496 * transport.
2497 *
2498 * Otherwise we decrement the version
2499 * and retry below.
2500 */
2501 pr_err(gettext("%s: NFS service does"
2502 " not support protocol: %s.\n"),
2503 fshost, nfs_proto);
2504 }
2505 break;
2506 case ERR_NOHOST:
2507 pr_err("%s: %s\n", fshost, "Unknown host");
2508 printed = 1;
2509 break;
2510 default:
2511 /* case ERR_PROTO_NONE falls through */
2512 pr_err(gettext("%s: NFS service not responding"
2513 "\n"), fshost);
2514 printed = 1;
2515 break;
2516 }
2517 }
2518 SET_ERR_RET(error,
2519 addr_error.error_type, addr_error.error_value);
2520 if (addr_error.error_type == ERR_PROTO_NONE)
2521 return (RET_RETRY);
2522 else if (addr_error.error_type == ERR_RPCERROR &&
2523 !IS_UNRECOVERABLE_RPC(addr_error.error_value)) {
2524 return (RET_RETRY);
2525 } else if (nfsvers == 0 && addr_error.error_type ==
2526 ERR_PROTO_UNSUPP && nfsvers_to_use != NFS_VERSMIN) {
2527 /*
2528 * If no version is specified, and the error is due
2529 * to an unsupported transport, then decrement the
2530 * version and retry.
2531 */
2532 return (RET_RETRY);
2533 } else
2534 return (RET_ERR);
2535 }
2536 nconf = *nconfp;
2537
2538 if (stat(nconf->nc_device, &sb) < 0) {
2539 pr_err(gettext("getaddr_nfs: couldn't stat: %s: %s\n"),
2540 nconf->nc_device, strerror(errno));
2541 return (RET_ERR);
2542 }
2543
2544 knconfp = (struct knetconfig *)malloc(sizeof (*knconfp));
2545 if (!knconfp) {
2546 pr_err(gettext("no memory\n"));
2547 return (RET_ERR);
2548 }
2549 knconfp->knc_semantics = nconf->nc_semantics;
2550 knconfp->knc_protofmly = nconf->nc_protofmly;
2551 knconfp->knc_proto = nconf->nc_proto;
2552 knconfp->knc_rdev = sb.st_rdev;
2553
2554 /* make sure we don't overload the transport */
2555 if (tinfo.tsdu > 0 && tinfo.tsdu < NFS_MAXDATA + NFS_RPC_HDR) {
2556 args->flags |= (NFSMNT_RSIZE | NFSMNT_WSIZE);
2557 if (args->rsize == 0 || args->rsize > tinfo.tsdu - NFS_RPC_HDR)
2558 args->rsize = tinfo.tsdu - NFS_RPC_HDR;
2559 if (args->wsize == 0 || args->wsize > tinfo.tsdu - NFS_RPC_HDR)
2560 args->wsize = tinfo.tsdu - NFS_RPC_HDR;
2561 }
2562
2563 args->flags |= NFSMNT_KNCONF;
2564 args->knconf = knconfp;
2565 return (RET_OK);
2566 }
2567
2568 static int
retry(struct mnttab * mntp,int ro)2569 retry(struct mnttab *mntp, int ro)
2570 {
2571 int delay = 5;
2572 int count = retries;
2573 int r;
2574
2575 /*
2576 * Please see comments on nfsretry_vers in the beginning of this file
2577 * and in main() routine.
2578 */
2579
2580 if (bg) {
2581 if (fork() > 0)
2582 return (RET_OK);
2583 backgrounded = 1;
2584 pr_err(gettext("backgrounding: %s\n"), mntp->mnt_mountp);
2585 } else {
2586 if (!nfsretry_vers)
2587 pr_err(gettext("retrying: %s\n"), mntp->mnt_mountp);
2588 }
2589
2590 while (count--) {
2591 if ((r = mount_nfs(mntp, ro, NULL)) == RET_OK) {
2592 pr_err(gettext("%s: mounted OK\n"), mntp->mnt_mountp);
2593 return (RET_OK);
2594 }
2595 if (r != RET_RETRY)
2596 break;
2597
2598 if (count > 0) {
2599 (void) sleep(delay);
2600 delay *= 2;
2601 if (delay > 120)
2602 delay = 120;
2603 }
2604 }
2605
2606 if (!nfsretry_vers)
2607 pr_err(gettext("giving up on: %s\n"), mntp->mnt_mountp);
2608
2609 return (RET_ERR);
2610 }
2611
2612 /*
2613 * Read the NFS SMF Parameters to determine if the
2614 * client has been configured for a new min/max for the NFS version to
2615 * use.
2616 */
2617 static void
read_default(void)2618 read_default(void)
2619 {
2620 char value[4];
2621 int errno;
2622 int tmp = 0, bufsz = 0, ret = 0;
2623
2624 /* Maximum number of bytes expected. */
2625 bufsz = 4;
2626 ret = nfs_smf_get_prop("client_versmin", value, DEFAULT_INSTANCE,
2627 SCF_TYPE_INTEGER, SVC_NFS_CLIENT, &bufsz);
2628 if (ret == SA_OK) {
2629 errno = 0;
2630 tmp = strtol(value, (char **)NULL, 10);
2631 if (errno == 0) {
2632 vers_min_default = tmp;
2633 }
2634 }
2635
2636 /* Maximum number of bytes expected. */
2637 bufsz = 4;
2638 ret = nfs_smf_get_prop("client_versmax", value, DEFAULT_INSTANCE,
2639 SCF_TYPE_INTEGER, SVC_NFS_CLIENT, &bufsz);
2640 if (ret == SA_OK) {
2641 errno = 0;
2642 tmp = strtol(value, (char **)NULL, 10);
2643 if (errno == 0) {
2644 vers_max_default = tmp;
2645 }
2646 }
2647 }
2648
2649 static void
sigusr1(int s)2650 sigusr1(int s)
2651 {
2652 }
2653