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 #define OPT_FOLLOW 49
952 MNTOPT_FOLLOW,
953 #define OPT_NOFOLLOW 50
954 MNTOPT_NOFOLLOW,
955 NULL
956 };
957
958 static int
convert_int(int * val,char * str)959 convert_int(int *val, char *str)
960 {
961 long lval;
962
963 if (str == NULL || !isdigit(*str))
964 return (-1);
965
966 lval = strtol(str, &str, 10);
967 if (*str != '\0' || lval > INT_MAX)
968 return (-2);
969
970 *val = (int)lval;
971 return (0);
972 }
973
974 static int
set_args(int * mntflags,struct nfs_args * args,char * fshost,struct mnttab * mnt)975 set_args(int *mntflags, struct nfs_args *args, char *fshost, struct mnttab *mnt)
976 {
977 char *saveopt, *optstr, *opts, *newopts, *val;
978 int num;
979 int largefiles = 0;
980 int invalid = 0;
981 int attrpref = 0;
982 int optlen;
983
984 args->flags = NFSMNT_INT; /* default is "intr" */
985 args->flags |= NFSMNT_HOSTNAME;
986 args->flags |= NFSMNT_NEWARGS; /* using extented nfs_args structure */
987 args->hostname = fshost;
988
989 optstr = opts = strdup(mnt->mnt_mntopts);
990 /* sizeof (MNTOPT_XXX) includes one extra byte we may need for "," */
991 optlen = strlen(mnt->mnt_mntopts) + sizeof (MNTOPT_XATTR) + 1;
992 if (optlen > MAX_MNTOPT_STR) {
993 pr_err(gettext("option string too long"));
994 return (RET_ERR);
995 }
996 newopts = malloc(optlen);
997 if (opts == NULL || newopts == NULL) {
998 pr_err(gettext("no memory"));
999 if (opts)
1000 free(opts);
1001 if (newopts)
1002 free(newopts);
1003 return (RET_ERR);
1004 }
1005 newopts[0] = '\0';
1006
1007 while (*opts) {
1008 invalid = 0;
1009 saveopt = opts;
1010 switch (getsubopt(&opts, optlist, &val)) {
1011 case OPT_RO:
1012 *mntflags |= MS_RDONLY;
1013 break;
1014 case OPT_RW:
1015 *mntflags &= ~(MS_RDONLY);
1016 break;
1017 case OPT_QUOTA:
1018 case OPT_NOQUOTA:
1019 break;
1020 case OPT_SOFT:
1021 args->flags |= NFSMNT_SOFT;
1022 args->flags &= ~(NFSMNT_SEMISOFT);
1023 break;
1024 case OPT_SEMISOFT:
1025 args->flags |= NFSMNT_SOFT;
1026 args->flags |= NFSMNT_SEMISOFT;
1027 break;
1028 case OPT_HARD:
1029 args->flags &= ~(NFSMNT_SOFT);
1030 args->flags &= ~(NFSMNT_SEMISOFT);
1031 break;
1032 case OPT_SUID:
1033 *mntflags &= ~(MS_NOSUID);
1034 break;
1035 case OPT_NOSUID:
1036 *mntflags |= MS_NOSUID;
1037 break;
1038 case OPT_GRPID:
1039 args->flags |= NFSMNT_GRPID;
1040 break;
1041 case OPT_REMOUNT:
1042 *mntflags |= MS_REMOUNT;
1043 break;
1044 case OPT_INTR:
1045 args->flags |= NFSMNT_INT;
1046 break;
1047 case OPT_NOINTR:
1048 args->flags &= ~(NFSMNT_INT);
1049 break;
1050 case OPT_NOAC:
1051 args->flags |= NFSMNT_NOAC;
1052 break;
1053 case OPT_PORT:
1054 if (convert_int(&num, val) != 0)
1055 goto badopt;
1056 nfs_port = htons((ushort_t)num);
1057 break;
1058
1059 case OPT_SECURE:
1060 if (nfs_getseconfig_byname("dh", &nfs_sec)) {
1061 pr_err(gettext("can not get \"dh\" from %s\n"),
1062 NFSSEC_CONF);
1063 goto badopt;
1064 }
1065 sec_opt++;
1066 break;
1067
1068 case OPT_NOCTO:
1069 args->flags |= NFSMNT_NOCTO;
1070 break;
1071
1072 case OPT_RSIZE:
1073 if (convert_int(&args->rsize, val) != 0)
1074 goto badopt;
1075 args->flags |= NFSMNT_RSIZE;
1076 break;
1077 case OPT_WSIZE:
1078 if (convert_int(&args->wsize, val) != 0)
1079 goto badopt;
1080 args->flags |= NFSMNT_WSIZE;
1081 break;
1082 case OPT_TIMEO:
1083 if (convert_int(&args->timeo, val) != 0)
1084 goto badopt;
1085 args->flags |= NFSMNT_TIMEO;
1086 break;
1087 case OPT_RETRANS:
1088 if (convert_int(&args->retrans, val) != 0)
1089 goto badopt;
1090 args->flags |= NFSMNT_RETRANS;
1091 break;
1092 case OPT_ACTIMEO:
1093 if (convert_int(&args->acregmax, val) != 0)
1094 goto badopt;
1095 args->acdirmin = args->acregmin = args->acdirmax
1096 = args->acregmax;
1097 args->flags |= NFSMNT_ACDIRMAX;
1098 args->flags |= NFSMNT_ACREGMAX;
1099 args->flags |= NFSMNT_ACDIRMIN;
1100 args->flags |= NFSMNT_ACREGMIN;
1101 break;
1102 case OPT_ACREGMIN:
1103 if (convert_int(&args->acregmin, val) != 0)
1104 goto badopt;
1105 args->flags |= NFSMNT_ACREGMIN;
1106 break;
1107 case OPT_ACREGMAX:
1108 if (convert_int(&args->acregmax, val) != 0)
1109 goto badopt;
1110 args->flags |= NFSMNT_ACREGMAX;
1111 break;
1112 case OPT_ACDIRMIN:
1113 if (convert_int(&args->acdirmin, val) != 0)
1114 goto badopt;
1115 args->flags |= NFSMNT_ACDIRMIN;
1116 break;
1117 case OPT_ACDIRMAX:
1118 if (convert_int(&args->acdirmax, val) != 0)
1119 goto badopt;
1120 args->flags |= NFSMNT_ACDIRMAX;
1121 break;
1122 case OPT_BG:
1123 bg++;
1124 break;
1125 case OPT_FG:
1126 bg = 0;
1127 break;
1128 case OPT_RETRY:
1129 if (convert_int(&retries, val) != 0)
1130 goto badopt;
1131 break;
1132 case OPT_LLOCK:
1133 args->flags |= NFSMNT_LLOCK;
1134 break;
1135 case OPT_POSIX:
1136 posix = 1;
1137 break;
1138 case OPT_VERS:
1139 if (convert_int(&num, val) != 0)
1140 goto badopt;
1141 nfsvers = (rpcvers_t)num;
1142 break;
1143 case OPT_PROTO:
1144 if (val == NULL)
1145 goto badopt;
1146
1147 nfs_proto = (char *)malloc(strlen(val)+1);
1148 if (!nfs_proto) {
1149 pr_err(gettext("no memory"));
1150 return (RET_ERR);
1151 }
1152
1153 (void) strncpy(nfs_proto, val, strlen(val)+1);
1154 break;
1155
1156 case OPT_NOPRINT:
1157 args->flags |= NFSMNT_NOPRINT;
1158 break;
1159
1160 case OPT_LARGEFILES:
1161 largefiles = 1;
1162 break;
1163
1164 case OPT_NOLARGEFILES:
1165 pr_err(gettext("NFS can't support \"nolargefiles\"\n"));
1166 free(optstr);
1167 return (RET_ERR);
1168
1169 case OPT_SEC:
1170 if (val == NULL) {
1171 pr_err(gettext(
1172 "\"sec\" option requires argument\n"));
1173 return (RET_ERR);
1174 }
1175 if (nfs_getseconfig_byname(val, &nfs_sec)) {
1176 pr_err(gettext("can not get \"%s\" from %s\n"),
1177 val, NFSSEC_CONF);
1178 return (RET_ERR);
1179 }
1180 sec_opt++;
1181 break;
1182
1183 case OPT_PUBLIC:
1184 public_opt = TRUE;
1185 break;
1186
1187 case OPT_DIRECTIO:
1188 args->flags |= NFSMNT_DIRECTIO;
1189 break;
1190
1191 case OPT_NODIRECTIO:
1192 args->flags &= ~(NFSMNT_DIRECTIO);
1193 break;
1194
1195 case OPT_XATTR:
1196 case OPT_NOXATTR:
1197 /*
1198 * VFS options; just need to get them into the
1199 * new mount option string and note we've seen them
1200 */
1201 attrpref = 1;
1202 break;
1203 default:
1204 /*
1205 * Note that this could be a valid OPT_* option so
1206 * we can't use "val" but need to use "saveopt".
1207 */
1208 if (fsisstdopt(saveopt))
1209 break;
1210 invalid = 1;
1211 if (!qflg)
1212 (void) fprintf(stderr, gettext(
1213 "mount: %s on %s - WARNING unknown option"
1214 " \"%s\"\n"), mnt->mnt_special,
1215 mnt->mnt_mountp, saveopt);
1216 break;
1217 }
1218 if (!invalid) {
1219 if (newopts[0])
1220 strcat(newopts, ",");
1221 strcat(newopts, saveopt);
1222 }
1223 }
1224 /* Default is to turn extended attrs on */
1225 if (!attrpref) {
1226 if (newopts[0])
1227 strcat(newopts, ",");
1228 strcat(newopts, MNTOPT_XATTR);
1229 }
1230 strcpy(mnt->mnt_mntopts, newopts);
1231 free(newopts);
1232 free(optstr);
1233
1234 /* ensure that only one secure mode is requested */
1235 if (sec_opt > 1) {
1236 pr_err(gettext("Security options conflict\n"));
1237 return (RET_ERR);
1238 }
1239
1240 /* ensure that the user isn't trying to get large files over V2 */
1241 if (nfsvers == NFS_VERSION && largefiles) {
1242 pr_err(gettext("NFS V2 can't support \"largefiles\"\n"));
1243 return (RET_ERR);
1244 }
1245
1246 if (nfsvers == NFS_V4 &&
1247 nfs_proto != NULL &&
1248 strncasecmp(nfs_proto, NC_UDP, strlen(NC_UDP)) == 0) {
1249 pr_err(gettext("NFS V4 does not support %s\n"), nfs_proto);
1250 return (RET_ERR);
1251 }
1252
1253 return (RET_OK);
1254
1255 badopt:
1256 pr_err(gettext("invalid option: \"%s\"\n"), saveopt);
1257 free(optstr);
1258 return (RET_ERR);
1259 }
1260
1261 static int
make_secure(struct nfs_args * args,char * hostname,struct netconfig * nconf,bool_t use_pubfh,rpcvers_t vers)1262 make_secure(struct nfs_args *args, char *hostname, struct netconfig *nconf,
1263 bool_t use_pubfh, rpcvers_t vers)
1264 {
1265 sec_data_t *secdata;
1266 int flags;
1267 struct netbuf *syncaddr = NULL;
1268 struct nd_addrlist *retaddrs = NULL;
1269 char netname[MAXNETNAMELEN+1];
1270
1271 /*
1272 * check to see if any secure mode is requested.
1273 * if not, use default security mode.
1274 */
1275 if (!snego_done && !sec_opt) {
1276 /*
1277 * Get default security mode.
1278 * AUTH_UNIX has been the default choice for a long time.
1279 * The better NFS security service becomes, the better chance
1280 * we will set stronger security service as the default NFS
1281 * security mode.
1282 */
1283 if (nfs_getseconfig_default(&nfs_sec)) {
1284 pr_err(gettext("error getting default"
1285 " security entry\n"));
1286 return (-1);
1287 }
1288 args->flags |= NFSMNT_SECDEFAULT;
1289 }
1290
1291 /*
1292 * Get the network address for the time service on the server.
1293 * If an RPC based time service is not available then try the
1294 * IP time service.
1295 *
1296 * This is for AUTH_DH processing. We will also pass down syncaddr
1297 * and netname for NFS V4 even if AUTH_DH is not requested right now.
1298 * NFS V4 does security negotiation in the kernel via SECINFO.
1299 * These information might be needed later in the kernel.
1300 *
1301 * Eventurally, we want to move this code to nfs_clnt_secdata()
1302 * when autod_nfs.c and mount.c can share the same get_the_addr()
1303 * routine.
1304 */
1305 flags = 0;
1306 syncaddr = NULL;
1307
1308 if (nfs_sec.sc_rpcnum == AUTH_DH || vers == NFS_V4) {
1309 /*
1310 * If using the public fh or nfsv4, we will not contact the
1311 * remote RPCBINDer, since it is possibly behind a firewall.
1312 */
1313 if (use_pubfh == FALSE && vers != NFS_V4)
1314 syncaddr = get_the_addr(hostname, RPCBPROG, RPCBVERS,
1315 nconf, 0, NULL, NULL, FALSE, NULL, NULL);
1316
1317 if (syncaddr != NULL) {
1318 /* for flags in sec_data */
1319 flags |= AUTH_F_RPCTIMESYNC;
1320 } else {
1321 struct nd_hostserv hs;
1322 int error;
1323
1324 hs.h_host = hostname;
1325 hs.h_serv = "timserver";
1326
1327 error = netdir_getbyname(nconf, &hs, &retaddrs);
1328
1329 if (error != ND_OK && (nfs_sec.sc_rpcnum == AUTH_DH)) {
1330 pr_err(gettext("%s: secure: no time service\n"),
1331 hostname);
1332 return (-1);
1333 }
1334
1335 if (error == ND_OK)
1336 syncaddr = retaddrs->n_addrs;
1337
1338 /*
1339 * For NFS_V4 if AUTH_DH is negotiated later in the
1340 * kernel thru SECINFO, it will need syncaddr
1341 * and netname data.
1342 */
1343 if (vers == NFS_V4 && syncaddr &&
1344 host2netname(netname, hostname, NULL)) {
1345 args->syncaddr = malloc(sizeof (struct netbuf));
1346 args->syncaddr->buf = malloc(syncaddr->len);
1347 (void) memcpy(args->syncaddr->buf,
1348 syncaddr->buf, syncaddr->len);
1349 args->syncaddr->len = syncaddr->len;
1350 args->syncaddr->maxlen = syncaddr->maxlen;
1351 args->netname = strdup(netname);
1352 args->flags |= NFSMNT_SECURE;
1353 }
1354 }
1355 }
1356
1357 /*
1358 * For the initial chosen flavor (any flavor defined in nfssec.conf),
1359 * the data will be stored in the sec_data structure via
1360 * nfs_clnt_secdata() and be passed to the kernel via nfs_args_*
1361 * extended data structure.
1362 */
1363 if (!(secdata = nfs_clnt_secdata(&nfs_sec, hostname, args->knconf,
1364 syncaddr, flags))) {
1365 pr_err(gettext("errors constructing security related data\n"));
1366 if (flags & AUTH_F_RPCTIMESYNC) {
1367 free(syncaddr->buf);
1368 free(syncaddr);
1369 } else if (retaddrs)
1370 netdir_free((void *)retaddrs, ND_ADDRLIST);
1371 return (-1);
1372 }
1373
1374 NFS_ARGS_EXTB_secdata(args, secdata);
1375 if (flags & AUTH_F_RPCTIMESYNC) {
1376 free(syncaddr->buf);
1377 free(syncaddr);
1378 } else if (retaddrs)
1379 netdir_free((void *)retaddrs, ND_ADDRLIST);
1380 return (0);
1381 }
1382
1383 /*
1384 * Get the network address on "hostname" for program "prog"
1385 * with version "vers" by using the nconf configuration data
1386 * passed in.
1387 *
1388 * If the address of a netconfig pointer is null then
1389 * information is not sufficient and no netbuf will be returned.
1390 *
1391 * Finally, ping the null procedure of that service.
1392 *
1393 * A similar routine is also defined in ../../autofs/autod_nfs.c.
1394 * This is a potential routine to move to ../lib for common usage.
1395 */
1396 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)1397 get_the_addr(char *hostname, ulong_t prog, ulong_t vers,
1398 struct netconfig *nconf, ushort_t port, struct t_info *tinfo,
1399 caddr_t *fhp, bool_t get_pubfh, char *fspath, err_ret_t *error)
1400 {
1401 struct netbuf *nb = NULL;
1402 struct t_bind *tbind = NULL;
1403 CLIENT *cl = NULL;
1404 struct timeval tv;
1405 int fd = -1;
1406 AUTH *ah = NULL;
1407 AUTH *new_ah = NULL;
1408 struct snego_t snego;
1409
1410 if (nconf == NULL)
1411 return (NULL);
1412
1413 if ((fd = t_open(nconf->nc_device, O_RDWR, tinfo)) == -1)
1414 goto done;
1415
1416 /* LINTED pointer alignment */
1417 if ((tbind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR))
1418 == NULL)
1419 goto done;
1420
1421 /*
1422 * In the case of public filehandle usage or NFSv4 we want to
1423 * avoid use of the rpcbind/portmap protocol
1424 */
1425 if ((get_pubfh == TRUE) || (vers == NFS_V4)) {
1426 struct nd_hostserv hs;
1427 struct nd_addrlist *retaddrs;
1428 int retval;
1429 hs.h_host = hostname;
1430
1431 /* NFS where vers==4 does not support UDP */
1432 if (vers == NFS_V4 &&
1433 strncasecmp(nconf->nc_proto, NC_UDP,
1434 strlen(NC_UDP)) == 0) {
1435 SET_ERR_RET(error, ERR_PROTO_UNSUPP, 0);
1436 goto done;
1437 }
1438
1439 if (port == 0)
1440 hs.h_serv = "nfs";
1441 else
1442 hs.h_serv = NULL;
1443
1444 if ((retval = netdir_getbyname(nconf, &hs, &retaddrs))
1445 != ND_OK) {
1446 /*
1447 * Carefully set the error value here. Want to signify
1448 * that the error was an unknown host.
1449 */
1450 if (retval == ND_NOHOST) {
1451 SET_ERR_RET(error, ERR_NOHOST, retval);
1452 }
1453
1454 goto done;
1455 }
1456 memcpy(tbind->addr.buf, retaddrs->n_addrs->buf,
1457 retaddrs->n_addrs->len);
1458 tbind->addr.len = retaddrs->n_addrs->len;
1459 netdir_free((void *)retaddrs, ND_ADDRLIST);
1460 (void) netdir_options(nconf, ND_SET_RESERVEDPORT, fd, NULL);
1461
1462 } else {
1463 if (rpcb_getaddr(prog, vers, nconf, &tbind->addr,
1464 hostname) == FALSE) {
1465 goto done;
1466 }
1467 }
1468
1469 if (port) {
1470 /* LINTED pointer alignment */
1471 if (strcmp(nconf->nc_protofmly, NC_INET) == 0)
1472 ((struct sockaddr_in *)tbind->addr.buf)->sin_port
1473 = port;
1474 else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0)
1475 ((struct sockaddr_in6 *)tbind->addr.buf)->sin6_port
1476 = port;
1477
1478 }
1479
1480 cl = clnt_tli_create(fd, nconf, &tbind->addr, prog, vers, 0, 0);
1481 if (cl == NULL) {
1482 /*
1483 * clnt_tli_create() returns either RPC_SYSTEMERROR,
1484 * RPC_UNKNOWNPROTO or RPC_TLIERROR. The RPC_TLIERROR translates
1485 * to "Misc. TLI error". This is not too helpful. Most likely
1486 * the connection to the remote server timed out, so this
1487 * error is at least less perplexing.
1488 * See: usr/src/cmd/rpcinfo/rpcinfo.c
1489 */
1490 if (rpc_createerr.cf_stat == RPC_TLIERROR) {
1491 SET_ERR_RET(error, ERR_RPCERROR, RPC_PMAPFAILURE);
1492 } else {
1493 SET_ERR_RET(error, ERR_RPCERROR, rpc_createerr.cf_stat);
1494 }
1495 goto done;
1496 }
1497
1498 ah = authsys_create_default();
1499 if (ah != NULL)
1500 cl->cl_auth = ah;
1501
1502 tv.tv_sec = 5;
1503 tv.tv_usec = 0;
1504
1505 (void) clnt_control(cl, CLSET_TIMEOUT, (char *)&tv);
1506
1507 if ((get_pubfh == TRUE) && (vers != NFS_V4)) {
1508 enum snego_stat sec;
1509
1510 if (!snego_done) {
1511 /*
1512 * negotiate sec flavor.
1513 */
1514 snego.cnt = 0;
1515 if ((sec = nfs_sec_nego(vers, cl, fspath, &snego)) ==
1516 SNEGO_SUCCESS) {
1517 int jj;
1518
1519 /*
1520 * check if server supports the one
1521 * specified in the sec= option.
1522 */
1523 if (sec_opt) {
1524 for (jj = 0; jj < snego.cnt; jj++) {
1525 if (snego.array[jj] ==
1526 nfs_sec.sc_nfsnum) {
1527 snego_done = TRUE;
1528 break;
1529 }
1530 }
1531 }
1532
1533 /*
1534 * find a common sec flavor
1535 */
1536 if (!snego_done) {
1537 if (sec_opt) {
1538 pr_err(gettext(
1539 "Server does not support"
1540 " the security flavor"
1541 " specified.\n"));
1542 }
1543
1544 for (jj = 0; jj < snego.cnt; jj++) {
1545 if (!nfs_getseconfig_bynumber(
1546 snego.array[jj],
1547 &nfs_sec)) {
1548 snego_done = TRUE;
1549 #define EMSG80SUX "Security flavor %d was negotiated and will be used.\n"
1550 if (sec_opt)
1551 pr_err(gettext(
1552 EMSG80SUX),
1553 nfs_sec.
1554 sc_nfsnum);
1555 break;
1556 }
1557 }
1558 }
1559
1560 if (!snego_done)
1561 return (NULL);
1562
1563 /*
1564 * Now that the flavor has been
1565 * negotiated, get the fh.
1566 *
1567 * First, create an auth handle using the
1568 * negotiated sec flavor in the next lookup to
1569 * fetch the filehandle.
1570 */
1571 new_ah = nfs_create_ah(cl, hostname, &nfs_sec);
1572 if (new_ah == NULL)
1573 goto done;
1574 cl->cl_auth = new_ah;
1575 } else if (sec == SNEGO_ARRAY_TOO_SMALL || sec ==
1576 SNEGO_FAILURE) {
1577 goto done;
1578 }
1579
1580 /*
1581 * Note that if sec == SNEGO_DEF_VALID
1582 * default sec flavor is acceptable.
1583 * Use it to get the filehandle.
1584 */
1585 }
1586
1587 if (vers == NFS_VERSION) {
1588 wnl_diropargs arg;
1589 wnl_diropres res;
1590
1591 memset((char *)&arg.dir, 0, sizeof (wnl_fh));
1592 arg.name = fspath;
1593 memset((char *)&res, 0, sizeof (wnl_diropres));
1594 if (wnlproc_lookup_2(&arg, &res, cl) !=
1595 RPC_SUCCESS || res.status != WNL_OK)
1596 goto done;
1597
1598 *fhp = malloc(sizeof (wnl_fh));
1599
1600 if (*fhp == NULL) {
1601 pr_err(gettext("no memory\n"));
1602 goto done;
1603 }
1604
1605 memcpy((char *)*fhp,
1606 (char *)&res.wnl_diropres_u.wnl_diropres.file,
1607 sizeof (wnl_fh));
1608 } else {
1609 WNL_LOOKUP3args arg;
1610 WNL_LOOKUP3res res;
1611 nfs_fh3 *fh3p;
1612
1613 memset((char *)&arg.what.dir, 0, sizeof (wnl_fh3));
1614 arg.what.name = fspath;
1615 memset((char *)&res, 0, sizeof (WNL_LOOKUP3res));
1616 if (wnlproc3_lookup_3(&arg, &res, cl) !=
1617 RPC_SUCCESS || res.status != WNL3_OK)
1618 goto done;
1619
1620 fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p));
1621
1622 if (fh3p == NULL) {
1623 pr_err(gettext("no memory\n"));
1624 goto done;
1625 }
1626
1627 fh3p->fh3_length =
1628 res.WNL_LOOKUP3res_u.res_ok.object.data.data_len;
1629 memcpy(fh3p->fh3_u.data,
1630 res.WNL_LOOKUP3res_u.res_ok.object.data.data_val,
1631 fh3p->fh3_length);
1632
1633 *fhp = (caddr_t)fh3p;
1634 }
1635 } else {
1636 struct rpc_err r_err;
1637 enum clnt_stat rc;
1638
1639 /*
1640 * NULL procedures need not have an argument or
1641 * result param.
1642 */
1643 if (vers == NFS_VERSION)
1644 rc = wnlproc_null_2(NULL, NULL, cl);
1645 else if (vers == NFS_V3)
1646 rc = wnlproc3_null_3(NULL, NULL, cl);
1647 else
1648 rc = wnlproc4_null_4(NULL, NULL, cl);
1649
1650 if (rc != RPC_SUCCESS) {
1651 clnt_geterr(cl, &r_err);
1652 if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
1653 switch (r_err.re_status) {
1654 case RPC_TLIERROR:
1655 case RPC_CANTRECV:
1656 case RPC_CANTSEND:
1657 r_err.re_status = RPC_PROGVERSMISMATCH;
1658 }
1659 }
1660 SET_ERR_RET(error, ERR_RPCERROR, r_err.re_status);
1661 goto done;
1662 }
1663 }
1664
1665 /*
1666 * Make a copy of the netbuf to return
1667 */
1668 nb = (struct netbuf *)malloc(sizeof (*nb));
1669 if (nb == NULL) {
1670 pr_err(gettext("no memory\n"));
1671 goto done;
1672 }
1673 *nb = tbind->addr;
1674 nb->buf = (char *)malloc(nb->maxlen);
1675 if (nb->buf == NULL) {
1676 pr_err(gettext("no memory\n"));
1677 free(nb);
1678 nb = NULL;
1679 goto done;
1680 }
1681 (void) memcpy(nb->buf, tbind->addr.buf, tbind->addr.len);
1682
1683 done:
1684 if (cl) {
1685 if (ah != NULL) {
1686 if (new_ah != NULL)
1687 AUTH_DESTROY(ah);
1688 AUTH_DESTROY(cl->cl_auth);
1689 cl->cl_auth = NULL;
1690 }
1691 clnt_destroy(cl);
1692 cl = NULL;
1693 }
1694 if (tbind) {
1695 t_free((char *)tbind, T_BIND);
1696 tbind = NULL;
1697 }
1698 if (fd >= 0)
1699 (void) t_close(fd);
1700 return (nb);
1701 }
1702
1703 static int
check_nconf(struct netconfig * nconf,int nthtry,int * valid_proto)1704 check_nconf(struct netconfig *nconf, int nthtry, int *valid_proto)
1705 {
1706 int try_test = 0;
1707 int valid_family;
1708 char *proto = NULL;
1709
1710
1711 if (nthtry == FIRST_TRY) {
1712 try_test = ((nconf->nc_semantics == NC_TPI_COTS_ORD) ||
1713 (nconf->nc_semantics == NC_TPI_COTS));
1714 proto = NC_TCP;
1715 } else if (nthtry == SECOND_TRY) {
1716 try_test = (nconf->nc_semantics == NC_TPI_CLTS);
1717 proto = NC_UDP;
1718 }
1719
1720 if (proto &&
1721 (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
1722 strcmp(nconf->nc_protofmly, NC_INET6) == 0) &&
1723 (strcmp(nconf->nc_proto, proto) == 0))
1724 *valid_proto = TRUE;
1725 else
1726 *valid_proto = FALSE;
1727
1728 return (try_test);
1729 }
1730
1731 /*
1732 * Get a network address on "hostname" for program "prog"
1733 * with version "vers". If the port number is specified (non zero)
1734 * then try for a TCP/UDP transport and set the port number of the
1735 * resulting IP address.
1736 *
1737 * If the address of a netconfig pointer was passed and
1738 * if it's not null, use it as the netconfig otherwise
1739 * assign the address of the netconfig that was used to
1740 * establish contact with the service.
1741 *
1742 * A similar routine is also defined in ../../autofs/autod_nfs.c.
1743 * This is a potential routine to move to ../lib for common usage.
1744 *
1745 * "error" refers to a more descriptive term when get_addr fails
1746 * and returns NULL: ERR_PROTO_NONE if no error introduced by
1747 * -o proto option, ERR_NETPATH if error found in NETPATH
1748 * environment variable, ERR_PROTO_INVALID if an unrecognized
1749 * protocol is specified by user, and ERR_PROTO_UNSUPP for a
1750 * recognized but invalid protocol (eg. ticlts, ticots, etc.).
1751 * "error" is ignored if get_addr returns non-NULL result.
1752 *
1753 */
1754 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)1755 get_addr(char *hostname, ulong_t prog, ulong_t vers, struct netconfig **nconfp,
1756 char *proto, ushort_t port, struct t_info *tinfo, caddr_t *fhp,
1757 bool_t get_pubfh, char *fspath, err_ret_t *error)
1758 {
1759 struct netbuf *nb = NULL;
1760 struct netconfig *nconf = NULL;
1761 NCONF_HANDLE *nc = NULL;
1762 int nthtry = FIRST_TRY;
1763 err_ret_t errsave_nohost, errsave_rpcerr;
1764
1765 SET_ERR_RET(&errsave_nohost, ERR_PROTO_NONE, 0);
1766 SET_ERR_RET(&errsave_rpcerr, ERR_PROTO_NONE, 0);
1767
1768 SET_ERR_RET(error, ERR_PROTO_NONE, 0);
1769
1770 if (nconfp && *nconfp)
1771 return (get_the_addr(hostname, prog, vers, *nconfp, port,
1772 tinfo, fhp, get_pubfh, fspath, error));
1773 /*
1774 * No nconf passed in.
1775 *
1776 * Try to get a nconf from /etc/netconfig filtered by
1777 * the NETPATH environment variable.
1778 * First search for COTS, second for CLTS unless proto
1779 * is specified. When we retry, we reset the
1780 * netconfig list so that we would search the whole list
1781 * all over again.
1782 */
1783
1784 if ((nc = setnetpath()) == NULL) {
1785 /* should only return an error if problems with NETPATH */
1786 /* In which case you are hosed */
1787 SET_ERR_RET(error, ERR_NETPATH, 0);
1788 goto done;
1789 }
1790
1791 /*
1792 * If proto is specified, then only search for the match,
1793 * otherwise try COTS first, if failed, try CLTS.
1794 */
1795 if (proto) {
1796 /* no matching proto name */
1797 SET_ERR_RET(error, ERR_PROTO_INVALID, 0);
1798
1799 while (nconf = getnetpath(nc)) {
1800 if (strcmp(nconf->nc_netid, proto))
1801 continue;
1802
1803 /* may be unsupported */
1804 SET_ERR_RET(error, ERR_PROTO_UNSUPP, 0);
1805
1806 if ((port != 0) &&
1807 ((strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
1808 strcmp(nconf->nc_protofmly, NC_INET6) == 0) &&
1809 (strcmp(nconf->nc_proto, NC_TCP) != 0 &&
1810 strcmp(nconf->nc_proto, NC_UDP) != 0))) {
1811 continue;
1812 } else {
1813 nb = get_the_addr(hostname, prog,
1814 vers, nconf, port, tinfo,
1815 fhp, get_pubfh, fspath, error);
1816
1817 if (nb != NULL)
1818 break;
1819
1820 /* nb is NULL - deal with errors */
1821 if (error) {
1822 if (error->error_type == ERR_NOHOST)
1823 SET_ERR_RET(&errsave_nohost,
1824 error->error_type,
1825 error->error_value);
1826 if (error->error_type == ERR_RPCERROR)
1827 SET_ERR_RET(&errsave_rpcerr,
1828 error->error_type,
1829 error->error_value);
1830 }
1831 /*
1832 * continue with same protocol
1833 * selection
1834 */
1835 continue;
1836 }
1837 } /* end of while */
1838
1839 if (nconf == NULL)
1840 goto done;
1841
1842 if ((nb = get_the_addr(hostname, prog, vers, nconf, port,
1843 tinfo, fhp, get_pubfh, fspath, error)) == NULL)
1844 goto done;
1845 } else {
1846 retry:
1847 SET_ERR_RET(error, ERR_NETPATH, 0);
1848 while (nconf = getnetpath(nc)) {
1849 SET_ERR_RET(error, ERR_PROTO_NONE, 0);
1850
1851 if (nconf->nc_flag & NC_VISIBLE) {
1852 int valid_proto;
1853
1854 if (check_nconf(nconf,
1855 nthtry, &valid_proto)) {
1856 if (port == 0)
1857 break;
1858
1859 if (valid_proto == TRUE)
1860 break;
1861 }
1862 }
1863 } /* while */
1864 if (nconf == NULL) {
1865 if (++nthtry <= MNT_PREF_LISTLEN) {
1866 endnetpath(nc);
1867 if ((nc = setnetpath()) == NULL)
1868 goto done;
1869 goto retry;
1870 } else
1871 goto done;
1872 } else {
1873 if ((nb = get_the_addr(hostname, prog, vers, nconf,
1874 port, tinfo, fhp, get_pubfh, fspath, error))
1875 == NULL) {
1876 /* nb is NULL - deal with errors */
1877 if (error) {
1878 if (error->error_type == ERR_NOHOST)
1879 SET_ERR_RET(&errsave_nohost,
1880 error->error_type,
1881 error->error_value);
1882 if (error->error_type == ERR_RPCERROR)
1883 SET_ERR_RET(&errsave_rpcerr,
1884 error->error_type,
1885 error->error_value);
1886 }
1887 /*
1888 * Continue the same search path in the
1889 * netconfig db until no more matched
1890 * nconf (nconf == NULL).
1891 */
1892 goto retry;
1893 }
1894 }
1895 }
1896 SET_ERR_RET(error, ERR_PROTO_NONE, 0);
1897
1898 /*
1899 * Got nconf and nb. Now dup the netconfig structure (nconf)
1900 * and return it thru nconfp.
1901 */
1902 *nconfp = getnetconfigent(nconf->nc_netid);
1903 if (*nconfp == NULL) {
1904 syslog(LOG_ERR, "no memory\n");
1905 free(nb);
1906 nb = NULL;
1907 }
1908 done:
1909 if (nc)
1910 endnetpath(nc);
1911
1912 if (nb == NULL) {
1913 /*
1914 * Check the saved errors. The RPC error has *
1915 * precedence over the no host error.
1916 */
1917 if (errsave_nohost.error_type != ERR_PROTO_NONE)
1918 SET_ERR_RET(error, errsave_nohost.error_type,
1919 errsave_nohost.error_value);
1920
1921 if (errsave_rpcerr.error_type != ERR_PROTO_NONE)
1922 SET_ERR_RET(error, errsave_rpcerr.error_type,
1923 errsave_rpcerr.error_value);
1924 }
1925
1926 return (nb);
1927 }
1928
1929 /*
1930 * Get a file handle usinging multi-component lookup with the public
1931 * file handle.
1932 */
1933 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)1934 get_fh_via_pub(struct nfs_args *args, char *fshost, char *fspath, bool_t url,
1935 bool_t loud, int *versp, struct netconfig **nconfp, ushort_t port)
1936 {
1937 uint_t vers_min;
1938 uint_t vers_max;
1939 int r;
1940 char *path;
1941
1942 if (nfsvers != 0) {
1943 vers_max = vers_min = nfsvers;
1944 } else {
1945 vers_max = vers_max_default;
1946 vers_min = vers_min_default;
1947 }
1948
1949 if (url == FALSE) {
1950 path = malloc(strlen(fspath) + 2);
1951 if (path == NULL) {
1952 if (loud == TRUE)
1953 pr_err(gettext("no memory\n"));
1954 return (RET_ERR);
1955 }
1956
1957 path[0] = (char)WNL_NATIVEPATH;
1958 (void) strcpy(&path[1], fspath);
1959
1960 } else {
1961 path = fspath;
1962 }
1963
1964 for (nfsvers_to_use = vers_max; nfsvers_to_use >= vers_min;
1965 nfsvers_to_use--) {
1966 /*
1967 * getaddr_nfs will also fill in the fh for us.
1968 */
1969 r = getaddr_nfs(args, fshost, nconfp,
1970 TRUE, path, port, NULL, FALSE);
1971
1972 if (r == RET_OK) {
1973 /*
1974 * Since we are using the public fh, and NLM is
1975 * not firewall friendly, use local locking.
1976 * Not the case for v4.
1977 */
1978 *versp = nfsvers_to_use;
1979 switch (nfsvers_to_use) {
1980 case NFS_V4:
1981 fstype = MNTTYPE_NFS4;
1982 break;
1983 case NFS_V3:
1984 fstype = MNTTYPE_NFS3;
1985 /* fall through to pick up llock option */
1986 default:
1987 args->flags |= NFSMNT_LLOCK;
1988 break;
1989 }
1990 if (fspath != path)
1991 free(path);
1992
1993 return (r);
1994 }
1995 }
1996
1997 if (fspath != path)
1998 free(path);
1999
2000 if (loud == TRUE) {
2001 pr_err(gettext("Could not use public filehandle in request to"
2002 " server %s\n"), fshost);
2003 }
2004
2005 return (r);
2006 }
2007
2008 /*
2009 * get fhandle of remote path from server's mountd
2010 */
2011 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)2012 get_fh(struct nfs_args *args, char *fshost, char *fspath, int *versp,
2013 bool_t loud_on_mnt_err, struct netconfig **nconfp, ushort_t port)
2014 {
2015 static struct fhstatus fhs;
2016 static struct mountres3 mountres3;
2017 static struct pathcnf p;
2018 nfs_fh3 *fh3p;
2019 struct timeval timeout = { 25, 0};
2020 CLIENT *cl;
2021 enum clnt_stat rpc_stat;
2022 rpcvers_t outvers = 0;
2023 rpcvers_t vers_to_try;
2024 rpcvers_t vers_min;
2025 static int printed = 0;
2026 int count, i, *auths;
2027 char *msg;
2028
2029 switch (nfsvers) {
2030 case 2: /* version 2 specified try that only */
2031 vers_to_try = MOUNTVERS_POSIX;
2032 vers_min = MOUNTVERS;
2033 break;
2034 case 3: /* version 3 specified try that only */
2035 vers_to_try = MOUNTVERS3;
2036 vers_min = MOUNTVERS3;
2037 break;
2038 case 4: /* version 4 specified try that only */
2039 /*
2040 * This assignment is in the wrong version sequence.
2041 * The above are MOUNT program and this is NFS
2042 * program. However, it happens to work out since the
2043 * two don't collide for NFSv4.
2044 */
2045 vers_to_try = NFS_V4;
2046 vers_min = NFS_V4;
2047 break;
2048 default: /* no version specified, start with default */
2049 /*
2050 * If the retry version is set, use that. This will
2051 * be set if the last mount attempt returned any other
2052 * besides an RPC error.
2053 */
2054 if (nfsretry_vers)
2055 vers_to_try = nfsretry_vers;
2056 else {
2057 vers_to_try = vers_max_default;
2058 vers_min = vers_min_default;
2059 }
2060
2061 break;
2062 }
2063
2064 /*
2065 * In the case of version 4, just NULL proc the server since
2066 * there is no MOUNT program. If this fails, then decrease
2067 * vers_to_try and continue on with regular MOUNT program
2068 * processing.
2069 */
2070 if (vers_to_try == NFS_V4) {
2071 int savevers = nfsvers_to_use;
2072 err_ret_t error;
2073 int retval;
2074 SET_ERR_RET(&error, ERR_PROTO_NONE, 0);
2075
2076 /* Let's hope for the best */
2077 nfsvers_to_use = NFS_V4;
2078 retval = getaddr_nfs(args, fshost, nconfp, FALSE,
2079 fspath, port, &error, vers_min == NFS_V4);
2080
2081 if (retval == RET_OK) {
2082 *versp = nfsvers_to_use = NFS_V4;
2083 fstype = MNTTYPE_NFS4;
2084 args->fh = strdup(fspath);
2085 if (args->fh == NULL) {
2086 pr_err(gettext("no memory\n"));
2087 *versp = nfsvers_to_use = savevers;
2088 return (RET_ERR);
2089 }
2090 return (RET_OK);
2091 }
2092 nfsvers_to_use = savevers;
2093
2094 vers_to_try--;
2095 /* If no more versions to try, let the user know. */
2096 if (vers_to_try < vers_min)
2097 return (retval);
2098
2099 /*
2100 * If we are here, there are more versions to try but
2101 * there has been an error of some sort. If it is not
2102 * an RPC error (e.g. host unknown), we just stop and
2103 * return the error since the other versions would see
2104 * the same error as well.
2105 */
2106 if (retval == RET_ERR && error.error_type != ERR_RPCERROR)
2107 return (retval);
2108 }
2109
2110 while ((cl = clnt_create_vers(fshost, MOUNTPROG, &outvers,
2111 vers_min, vers_to_try, "datagram_v")) == NULL) {
2112 if (rpc_createerr.cf_stat == RPC_UNKNOWNHOST) {
2113 pr_err(gettext("%s: %s\n"), fshost,
2114 clnt_spcreateerror(""));
2115 return (RET_ERR);
2116 }
2117
2118 /*
2119 * We don't want to downgrade version on lost packets
2120 */
2121 if ((rpc_createerr.cf_stat == RPC_TIMEDOUT) ||
2122 (rpc_createerr.cf_stat == RPC_PMAPFAILURE)) {
2123 pr_err(gettext("%s: %s\n"), fshost,
2124 clnt_spcreateerror(""));
2125 return (RET_RETRY);
2126 }
2127
2128 /*
2129 * back off and try the previous version - patch to the
2130 * problem of version numbers not being contigous and
2131 * clnt_create_vers failing (SunOS4.1 clients & SGI servers)
2132 * The problem happens with most non-Sun servers who
2133 * don't support mountd protocol #2. So, in case the
2134 * call fails, we re-try the call anyway.
2135 */
2136 vers_to_try--;
2137 if (vers_to_try < vers_min) {
2138 if (rpc_createerr.cf_stat == RPC_PROGVERSMISMATCH) {
2139 if (nfsvers == 0) {
2140 pr_err(gettext(
2141 "%s:%s: no applicable versions of NFS supported\n"),
2142 fshost, fspath);
2143 } else {
2144 pr_err(gettext(
2145 "%s:%s: NFS Version %d not supported\n"),
2146 fshost, fspath, nfsvers);
2147 }
2148 return (RET_ERR);
2149 }
2150 if (!printed) {
2151 pr_err(gettext("%s: %s\n"), fshost,
2152 clnt_spcreateerror(""));
2153 printed = 1;
2154 }
2155 return (RET_RETRY);
2156 }
2157 }
2158 if (posix && outvers < MOUNTVERS_POSIX) {
2159 pr_err(gettext("%s: %s: no pathconf info\n"),
2160 fshost, clnt_sperror(cl, ""));
2161 clnt_destroy(cl);
2162 return (RET_ERR);
2163 }
2164
2165 if (__clnt_bindresvport(cl) < 0) {
2166 pr_err(gettext("Couldn't bind to reserved port\n"));
2167 clnt_destroy(cl);
2168 return (RET_RETRY);
2169 }
2170
2171 if ((cl->cl_auth = authsys_create_default()) == NULL) {
2172 pr_err(
2173 gettext("Couldn't create default authentication handle\n"));
2174 clnt_destroy(cl);
2175 return (RET_RETRY);
2176 }
2177
2178 switch (outvers) {
2179 case MOUNTVERS:
2180 case MOUNTVERS_POSIX:
2181 *versp = nfsvers_to_use = NFS_VERSION;
2182 rpc_stat = clnt_call(cl, MOUNTPROC_MNT, xdr_dirpath,
2183 (caddr_t)&fspath, xdr_fhstatus, (caddr_t)&fhs, timeout);
2184 if (rpc_stat != RPC_SUCCESS) {
2185 pr_err(gettext("%s:%s: server not responding %s\n"),
2186 fshost, fspath, clnt_sperror(cl, ""));
2187 clnt_destroy(cl);
2188 return (RET_RETRY);
2189 }
2190
2191 if ((errno = fhs.fhs_status) != MNT_OK) {
2192 if (loud_on_mnt_err) {
2193 if (errno == EACCES) {
2194 pr_err(gettext(
2195 "%s:%s: access denied\n"),
2196 fshost, fspath);
2197 } else {
2198 pr_err(gettext("%s:%s: %s\n"), fshost,
2199 fspath, errno >= 0 ?
2200 strerror(errno) : "invalid error "
2201 "returned by server");
2202 }
2203 }
2204 clnt_destroy(cl);
2205 return (RET_MNTERR);
2206 }
2207 args->fh = malloc(sizeof (fhs.fhstatus_u.fhs_fhandle));
2208 if (args->fh == NULL) {
2209 pr_err(gettext("no memory\n"));
2210 return (RET_ERR);
2211 }
2212 memcpy((caddr_t)args->fh, (caddr_t)&fhs.fhstatus_u.fhs_fhandle,
2213 sizeof (fhs.fhstatus_u.fhs_fhandle));
2214 if (!errno && posix) {
2215 rpc_stat = clnt_call(cl, MOUNTPROC_PATHCONF,
2216 xdr_dirpath, (caddr_t)&fspath, xdr_ppathcnf,
2217 (caddr_t)&p, timeout);
2218 if (rpc_stat != RPC_SUCCESS) {
2219 pr_err(gettext(
2220 "%s:%s: server not responding %s\n"),
2221 fshost, fspath, clnt_sperror(cl, ""));
2222 free(args->fh);
2223 clnt_destroy(cl);
2224 return (RET_RETRY);
2225 }
2226 if (_PC_ISSET(_PC_ERROR, p.pc_mask)) {
2227 pr_err(gettext(
2228 "%s:%s: no pathconf info\n"),
2229 fshost, fspath);
2230 free(args->fh);
2231 clnt_destroy(cl);
2232 return (RET_ERR);
2233 }
2234 args->flags |= NFSMNT_POSIX;
2235 args->pathconf = malloc(sizeof (p));
2236 if (args->pathconf == NULL) {
2237 pr_err(gettext("no memory\n"));
2238 free(args->fh);
2239 clnt_destroy(cl);
2240 return (RET_ERR);
2241 }
2242 memcpy((caddr_t)args->pathconf, (caddr_t)&p,
2243 sizeof (p));
2244 }
2245 break;
2246
2247 case MOUNTVERS3:
2248 *versp = nfsvers_to_use = NFS_V3;
2249 rpc_stat = clnt_call(cl, MOUNTPROC_MNT, xdr_dirpath,
2250 (caddr_t)&fspath, xdr_mountres3, (caddr_t)&mountres3,
2251 timeout);
2252 if (rpc_stat != RPC_SUCCESS) {
2253 pr_err(gettext("%s:%s: server not responding %s\n"),
2254 fshost, fspath, clnt_sperror(cl, ""));
2255 clnt_destroy(cl);
2256 return (RET_RETRY);
2257 }
2258
2259 /*
2260 * Assume here that most of the MNT3ERR_*
2261 * codes map into E* errors.
2262 */
2263 if ((errno = mountres3.fhs_status) != MNT_OK) {
2264 if (loud_on_mnt_err) {
2265 switch (errno) {
2266 case MNT3ERR_NAMETOOLONG:
2267 msg = "path name is too long";
2268 break;
2269 case MNT3ERR_NOTSUPP:
2270 msg = "operation not supported";
2271 break;
2272 case MNT3ERR_SERVERFAULT:
2273 msg = "server fault";
2274 break;
2275 default:
2276 if (errno >= 0)
2277 msg = strerror(errno);
2278 else
2279 msg = "invalid error returned "
2280 "by server";
2281 break;
2282 }
2283 pr_err(gettext("%s:%s: %s\n"), fshost,
2284 fspath, msg);
2285 }
2286 clnt_destroy(cl);
2287 return (RET_MNTERR);
2288 }
2289
2290 fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p));
2291 if (fh3p == NULL) {
2292 pr_err(gettext("no memory\n"));
2293 return (RET_ERR);
2294 }
2295 fh3p->fh3_length =
2296 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len;
2297 (void) memcpy(fh3p->fh3_u.data,
2298 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val,
2299 fh3p->fh3_length);
2300 args->fh = (caddr_t)fh3p;
2301 fstype = MNTTYPE_NFS3;
2302
2303 /*
2304 * Check the security flavor to be used.
2305 *
2306 * If "secure" or "sec=flavor" is a mount
2307 * option, check if the server supports the "flavor".
2308 * If the server does not support the flavor, return
2309 * error.
2310 *
2311 * If no mount option is given then look for default auth
2312 * (default auth entry in /etc/nfssec.conf) in the auth list
2313 * returned from server. If default auth not found, then use
2314 * the first supported security flavor (by the client) in the
2315 * auth list returned from the server.
2316 *
2317 */
2318 auths =
2319 mountres3.mountres3_u.mountinfo.auth_flavors
2320 .auth_flavors_val;
2321 count =
2322 mountres3.mountres3_u.mountinfo.auth_flavors
2323 .auth_flavors_len;
2324
2325 if (count <= 0) {
2326 pr_err(gettext(
2327 "server %s did not return any security mode\n"),
2328 fshost);
2329 clnt_destroy(cl);
2330 return (RET_ERR);
2331 }
2332
2333 if (sec_opt) {
2334 for (i = 0; i < count; i++) {
2335 if (auths[i] == nfs_sec.sc_nfsnum)
2336 break;
2337 }
2338 if (i == count)
2339 goto autherr;
2340 } else {
2341 seconfig_t default_sec;
2342
2343 /*
2344 * Get client configured default auth.
2345 */
2346 nfs_sec.sc_nfsnum = -1;
2347 default_sec.sc_nfsnum = -1;
2348 (void) nfs_getseconfig_default(&default_sec);
2349
2350 /*
2351 * Look for clients default auth in servers list.
2352 */
2353 if (default_sec.sc_nfsnum != -1) {
2354 for (i = 0; i < count; i++) {
2355 if (auths[i] == default_sec.sc_nfsnum) {
2356 sec_opt++;
2357 nfs_sec = default_sec;
2358 break;
2359 }
2360 }
2361 }
2362
2363 /*
2364 * Could not find clients default auth in servers list.
2365 * Pick the first auth from servers list that is
2366 * also supported on the client.
2367 */
2368 if (nfs_sec.sc_nfsnum == -1) {
2369 for (i = 0; i < count; i++) {
2370 if (!nfs_getseconfig_bynumber(auths[i],
2371 &nfs_sec)) {
2372 sec_opt++;
2373 break;
2374
2375 }
2376 }
2377 }
2378
2379 if (i == count)
2380 goto autherr;
2381 }
2382 break;
2383 default:
2384 pr_err(gettext("%s:%s: Unknown MOUNT version %d\n"),
2385 fshost, fspath, outvers);
2386 clnt_destroy(cl);
2387 return (RET_ERR);
2388 }
2389
2390 clnt_destroy(cl);
2391 return (RET_OK);
2392
2393 autherr:
2394 pr_err(gettext(
2395 "security mode does not match the server exporting %s:%s\n"),
2396 fshost, fspath);
2397 clnt_destroy(cl);
2398 return (RET_ERR);
2399 }
2400
2401 /*
2402 * Fill in the address for the server's NFS service and
2403 * fill in a knetconfig structure for the transport that
2404 * the service is available on.
2405 */
2406 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)2407 getaddr_nfs(struct nfs_args *args, char *fshost, struct netconfig **nconfp,
2408 bool_t get_pubfh, char *fspath, ushort_t port, err_ret_t *error,
2409 bool_t print_rpcerror)
2410 {
2411 struct stat sb;
2412 struct netconfig *nconf;
2413 struct knetconfig *knconfp;
2414 static int printed = 0;
2415 struct t_info tinfo;
2416 err_ret_t addr_error;
2417
2418 SET_ERR_RET(error, ERR_PROTO_NONE, 0);
2419 SET_ERR_RET(&addr_error, ERR_PROTO_NONE, 0);
2420
2421 if (nfs_proto) {
2422 /*
2423 * If a proto is specified and its rdma try this. The kernel
2424 * will later do the reachablity test and fail form there
2425 * if rdma transport is not available to kernel rpc
2426 */
2427 if (strcmp(nfs_proto, "rdma") == 0) {
2428 args->addr = get_addr(fshost, NFS_PROGRAM,
2429 nfsvers_to_use, nconfp, NULL, port, &tinfo,
2430 &args->fh, get_pubfh, fspath, &addr_error);
2431
2432 args->flags |= NFSMNT_DORDMA;
2433 } else {
2434 args->addr = get_addr(fshost, NFS_PROGRAM,
2435 nfsvers_to_use, nconfp, nfs_proto, port, &tinfo,
2436 &args->fh, get_pubfh, fspath, &addr_error);
2437 }
2438 } else {
2439 args->addr = get_addr(fshost, NFS_PROGRAM, nfsvers_to_use,
2440 nconfp, nfs_proto, port, &tinfo, &args->fh, get_pubfh,
2441 fspath, &addr_error);
2442 /*
2443 * If no proto is specified set this flag.
2444 * Kernel mount code will try to use RDMA if its on the
2445 * system, otherwise it will keep on using the protocol
2446 * selected here, through the above get_addr call.
2447 */
2448 if (nfs_proto == NULL)
2449 args->flags |= NFSMNT_TRYRDMA;
2450 }
2451
2452 if (args->addr == NULL) {
2453 /*
2454 * We could have failed because the server had no public
2455 * file handle support. So don't print a message and don't
2456 * retry.
2457 */
2458 if (get_pubfh == TRUE)
2459 return (RET_ERR);
2460
2461 if (!printed) {
2462 switch (addr_error.error_type) {
2463 case 0:
2464 printed = 1;
2465 break;
2466 case ERR_RPCERROR:
2467 if (!print_rpcerror)
2468 /* no error print at this time */
2469 break;
2470 pr_err(gettext("%s NFS service not"
2471 " available %s\n"), fshost,
2472 clnt_sperrno(addr_error.error_value));
2473 printed = 1;
2474 break;
2475 case ERR_NETPATH:
2476 pr_err(gettext("%s: Error in NETPATH.\n"),
2477 fshost);
2478 printed = 1;
2479 break;
2480 case ERR_PROTO_INVALID:
2481 pr_err(gettext("%s: NFS service does not"
2482 " recognize protocol: %s.\n"), fshost,
2483 nfs_proto);
2484 printed = 1;
2485 break;
2486 case ERR_PROTO_UNSUPP:
2487 if (nfsvers || nfsvers_to_use == NFS_VERSMIN) {
2488 /*
2489 * Don't set "printed" here. Since we
2490 * have to keep checking here till we
2491 * exhaust transport errors on all vers.
2492 *
2493 * Print this message if:
2494 * 1. After we have tried all versions
2495 * of NFS and none support the asked
2496 * transport.
2497 *
2498 * 2. If a version is specified and it
2499 * does'nt support the asked
2500 * transport.
2501 *
2502 * Otherwise we decrement the version
2503 * and retry below.
2504 */
2505 pr_err(gettext("%s: NFS service does"
2506 " not support protocol: %s.\n"),
2507 fshost, nfs_proto);
2508 }
2509 break;
2510 case ERR_NOHOST:
2511 pr_err("%s: %s\n", fshost, "Unknown host");
2512 printed = 1;
2513 break;
2514 default:
2515 /* case ERR_PROTO_NONE falls through */
2516 pr_err(gettext("%s: NFS service not responding"
2517 "\n"), fshost);
2518 printed = 1;
2519 break;
2520 }
2521 }
2522 SET_ERR_RET(error,
2523 addr_error.error_type, addr_error.error_value);
2524 if (addr_error.error_type == ERR_PROTO_NONE)
2525 return (RET_RETRY);
2526 else if (addr_error.error_type == ERR_RPCERROR &&
2527 !IS_UNRECOVERABLE_RPC(addr_error.error_value)) {
2528 return (RET_RETRY);
2529 } else if (nfsvers == 0 && addr_error.error_type ==
2530 ERR_PROTO_UNSUPP && nfsvers_to_use != NFS_VERSMIN) {
2531 /*
2532 * If no version is specified, and the error is due
2533 * to an unsupported transport, then decrement the
2534 * version and retry.
2535 */
2536 return (RET_RETRY);
2537 } else
2538 return (RET_ERR);
2539 }
2540 nconf = *nconfp;
2541
2542 if (stat(nconf->nc_device, &sb) < 0) {
2543 pr_err(gettext("getaddr_nfs: couldn't stat: %s: %s\n"),
2544 nconf->nc_device, strerror(errno));
2545 return (RET_ERR);
2546 }
2547
2548 knconfp = (struct knetconfig *)malloc(sizeof (*knconfp));
2549 if (!knconfp) {
2550 pr_err(gettext("no memory\n"));
2551 return (RET_ERR);
2552 }
2553 knconfp->knc_semantics = nconf->nc_semantics;
2554 knconfp->knc_protofmly = nconf->nc_protofmly;
2555 knconfp->knc_proto = nconf->nc_proto;
2556 knconfp->knc_rdev = sb.st_rdev;
2557
2558 /* make sure we don't overload the transport */
2559 if (tinfo.tsdu > 0 && tinfo.tsdu < NFS_MAXDATA + NFS_RPC_HDR) {
2560 args->flags |= (NFSMNT_RSIZE | NFSMNT_WSIZE);
2561 if (args->rsize == 0 || args->rsize > tinfo.tsdu - NFS_RPC_HDR)
2562 args->rsize = tinfo.tsdu - NFS_RPC_HDR;
2563 if (args->wsize == 0 || args->wsize > tinfo.tsdu - NFS_RPC_HDR)
2564 args->wsize = tinfo.tsdu - NFS_RPC_HDR;
2565 }
2566
2567 args->flags |= NFSMNT_KNCONF;
2568 args->knconf = knconfp;
2569 return (RET_OK);
2570 }
2571
2572 static int
retry(struct mnttab * mntp,int ro)2573 retry(struct mnttab *mntp, int ro)
2574 {
2575 int delay = 5;
2576 int count = retries;
2577 int r;
2578
2579 /*
2580 * Please see comments on nfsretry_vers in the beginning of this file
2581 * and in main() routine.
2582 */
2583
2584 if (bg) {
2585 if (fork() > 0)
2586 return (RET_OK);
2587 backgrounded = 1;
2588 pr_err(gettext("backgrounding: %s\n"), mntp->mnt_mountp);
2589 } else {
2590 if (!nfsretry_vers)
2591 pr_err(gettext("retrying: %s\n"), mntp->mnt_mountp);
2592 }
2593
2594 while (count--) {
2595 if ((r = mount_nfs(mntp, ro, NULL)) == RET_OK) {
2596 pr_err(gettext("%s: mounted OK\n"), mntp->mnt_mountp);
2597 return (RET_OK);
2598 }
2599 if (r != RET_RETRY)
2600 break;
2601
2602 if (count > 0) {
2603 (void) sleep(delay);
2604 delay *= 2;
2605 if (delay > 120)
2606 delay = 120;
2607 }
2608 }
2609
2610 if (!nfsretry_vers)
2611 pr_err(gettext("giving up on: %s\n"), mntp->mnt_mountp);
2612
2613 return (RET_ERR);
2614 }
2615
2616 /*
2617 * Read the NFS SMF Parameters to determine if the
2618 * client has been configured for a new min/max for the NFS version to
2619 * use.
2620 */
2621 static void
read_default(void)2622 read_default(void)
2623 {
2624 char value[4];
2625 int errno;
2626 int tmp = 0, bufsz = 0, ret = 0;
2627
2628 /* Maximum number of bytes expected. */
2629 bufsz = 4;
2630 ret = nfs_smf_get_prop("client_versmin", value, DEFAULT_INSTANCE,
2631 SCF_TYPE_INTEGER, SVC_NFS_CLIENT, &bufsz);
2632 if (ret == SA_OK) {
2633 errno = 0;
2634 tmp = strtol(value, (char **)NULL, 10);
2635 if (errno == 0) {
2636 vers_min_default = tmp;
2637 }
2638 }
2639
2640 /* Maximum number of bytes expected. */
2641 bufsz = 4;
2642 ret = nfs_smf_get_prop("client_versmax", value, DEFAULT_INSTANCE,
2643 SCF_TYPE_INTEGER, SVC_NFS_CLIENT, &bufsz);
2644 if (ret == SA_OK) {
2645 errno = 0;
2646 tmp = strtol(value, (char **)NULL, 10);
2647 if (errno == 0) {
2648 vers_max_default = tmp;
2649 }
2650 }
2651 }
2652
2653 static void
sigusr1(int s)2654 sigusr1(int s)
2655 {
2656 }
2657