108 #define SET_ERR_RET(errst, etype, eval) \
109 if (errst) { \
110 (errst)->error_type = etype; \
111 (errst)->error_value = eval; \
112 }
113
114 /* number of transports to try */
115 #define MNT_PREF_LISTLEN 2
116 #define FIRST_TRY 1
117 #define SECOND_TRY 2
118
119 #define BIGRETRY 10000
120
121 /* maximum length of RPC header for NFS messages */
122 #define NFS_RPC_HDR 432
123
124 #define NFS_ARGS_EXTB_secdata(args, secdata) \
125 { (args)->nfs_args_ext = NFS_ARGS_EXTB, \
126 (args)->nfs_ext_u.nfs_extB.secdata = secdata; }
127
128 extern int __clnt_bindresvport();
129 extern char *nfs_get_qop_name();
130 extern AUTH * nfs_create_ah();
131 extern enum snego_stat nfs_sec_nego();
132
133 static void usage(void);
134 static int retry(struct mnttab *, int);
135 static int set_args(int *, struct nfs_args *, char *, struct mnttab *);
136 static int get_fh_via_pub(struct nfs_args *, char *, char *, bool_t, bool_t,
137 int *, struct netconfig **, ushort_t);
138 static int get_fh(struct nfs_args *, char *, char *, int *, bool_t,
139 struct netconfig **, ushort_t);
140 static int make_secure(struct nfs_args *, char *, struct netconfig *,
141 bool_t, rpcvers_t);
142 static int mount_nfs(struct mnttab *, int, err_ret_t *);
143 static int getaddr_nfs(struct nfs_args *, char *, struct netconfig **,
144 bool_t, char *, ushort_t, err_ret_t *, bool_t);
145 static void pr_err(const char *fmt, ...);
146 static void usage(void);
147 static struct netbuf *get_addr(char *, rpcprog_t, rpcvers_t,
148 struct netconfig **, char *, ushort_t, struct t_info *,
1235 sec_data_t *secdata;
1236 int flags;
1237 struct netbuf *syncaddr = NULL;
1238 struct nd_addrlist *retaddrs = NULL;
1239 char netname[MAXNETNAMELEN+1];
1240
1241 /*
1242 * check to see if any secure mode is requested.
1243 * if not, use default security mode.
1244 */
1245 if (!snego_done && !sec_opt) {
1246 /*
1247 * Get default security mode.
1248 * AUTH_UNIX has been the default choice for a long time.
1249 * The better NFS security service becomes, the better chance
1250 * we will set stronger security service as the default NFS
1251 * security mode.
1252 *
1253 */
1254 if (nfs_getseconfig_default(&nfs_sec)) {
1255 pr_err(gettext("error getting default security entry\n"));
1256 return (-1);
1257 }
1258 args->flags |= NFSMNT_SECDEFAULT;
1259 }
1260
1261 /*
1262 * Get the network address for the time service on the server.
1263 * If an RPC based time service is not available then try the
1264 * IP time service.
1265 *
1266 * This is for AUTH_DH processing. We will also pass down syncaddr
1267 * and netname for NFS V4 even if AUTH_DH is not requested right now.
1268 * NFS V4 does security negotiation in the kernel via SECINFO.
1269 * These information might be needed later in the kernel.
1270 *
1271 * Eventurally, we want to move this code to nfs_clnt_secdata()
1272 * when autod_nfs.c and mount.c can share the same get_the_addr()
1273 * routine.
1274 */
1275 flags = 0;
1298 error = netdir_getbyname(nconf, &hs, &retaddrs);
1299
1300 if (error != ND_OK && (nfs_sec.sc_rpcnum == AUTH_DH)) {
1301 pr_err(gettext("%s: secure: no time service\n"),
1302 hostname);
1303 return (-1);
1304 }
1305
1306 if (error == ND_OK)
1307 syncaddr = retaddrs->n_addrs;
1308
1309 /*
1310 * For NFS_V4 if AUTH_DH is negotiated later in the
1311 * kernel thru SECINFO, it will need syncaddr
1312 * and netname data.
1313 */
1314 if (vers == NFS_V4 && syncaddr &&
1315 host2netname(netname, hostname, NULL)) {
1316 args->syncaddr = malloc(sizeof (struct netbuf));
1317 args->syncaddr->buf = malloc(syncaddr->len);
1318 (void) memcpy(args->syncaddr->buf, syncaddr->buf,
1319 syncaddr->len);
1320 args->syncaddr->len = syncaddr->len;
1321 args->syncaddr->maxlen = syncaddr->maxlen;
1322 args->netname = strdup(netname);
1323 args->flags |= NFSMNT_SECURE;
1324 }
1325 }
1326 }
1327
1328 /*
1329 * For the initial chosen flavor (any flavor defined in nfssec.conf),
1330 * the data will be stored in the sec_data structure via
1331 * nfs_clnt_secdata() and be passed to the kernel via nfs_args_*
1332 * extended data structure.
1333 */
1334 if (!(secdata = nfs_clnt_secdata(&nfs_sec, hostname, args->knconf,
1335 syncaddr, flags))) {
1336 pr_err(gettext("errors constructing security related data\n"));
1337 if (flags & AUTH_F_RPCTIMESYNC) {
1338 free(syncaddr->buf);
1339 free(syncaddr);
1428 retaddrs->n_addrs->len);
1429 tbind->addr.len = retaddrs->n_addrs->len;
1430 netdir_free((void *)retaddrs, ND_ADDRLIST);
1431 (void) netdir_options(nconf, ND_SET_RESERVEDPORT, fd, NULL);
1432
1433 } else {
1434 if (rpcb_getaddr(prog, vers, nconf, &tbind->addr,
1435 hostname) == FALSE) {
1436 goto done;
1437 }
1438 }
1439
1440 if (port) {
1441 /* LINTED pointer alignment */
1442 if (strcmp(nconf->nc_protofmly, NC_INET) == 0)
1443 ((struct sockaddr_in *)tbind->addr.buf)->sin_port
1444 = port;
1445 else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0)
1446 ((struct sockaddr_in6 *)tbind->addr.buf)->sin6_port
1447 = port;
1448
1449 }
1450
1451 cl = clnt_tli_create(fd, nconf, &tbind->addr, prog, vers, 0, 0);
1452 if (cl == NULL) {
1453 /*
1454 * clnt_tli_create() returns either RPC_SYSTEMERROR,
1455 * RPC_UNKNOWNPROTO or RPC_TLIERROR. The RPC_TLIERROR translates
1456 * to "Misc. TLI error". This is not too helpful. Most likely
1457 * the connection to the remote server timed out, so this
1458 * error is at least less perplexing.
1459 * See: usr/src/cmd/rpcinfo/rpcinfo.c
1460 */
1461 if (rpc_createerr.cf_stat == RPC_TLIERROR) {
1462 SET_ERR_RET(error, ERR_RPCERROR, RPC_PMAPFAILURE);
1463 } else {
1464 SET_ERR_RET(error, ERR_RPCERROR, rpc_createerr.cf_stat);
1465 }
1466 goto done;
1467 }
1468
1469 ah = authsys_create_default();
1470 if (ah != NULL)
1471 cl->cl_auth = ah;
1472
1473 tv.tv_sec = 5;
1474 tv.tv_usec = 0;
1475
1476 (void) clnt_control(cl, CLSET_TIMEOUT, (char *)&tv);
1477
1478 if ((get_pubfh == TRUE) && (vers != NFS_V4)) {
1479 enum snego_stat sec;
1480
1481 if (!snego_done) {
1482 /*
1483 * negotiate sec flavor.
1484 */
1485 snego.cnt = 0;
1486 if ((sec = nfs_sec_nego(vers, cl, fspath, &snego)) ==
1487 SNEGO_SUCCESS) {
1488 int jj;
1489
1490 /*
1491 * check if server supports the one
1492 * specified in the sec= option.
1493 */
1494 if (sec_opt) {
1495 for (jj = 0; jj < snego.cnt; jj++) {
1496 if (snego.array[jj] == nfs_sec.sc_nfsnum) {
1497 snego_done = TRUE;
1498 break;
1499 }
1500 }
1501 }
1502
1503 /*
1504 * find a common sec flavor
1505 */
1506 if (!snego_done) {
1507 if (sec_opt) {
1508 pr_err(gettext(
1509 "Server does not support the security"
1510 " flavor specified.\n"));
1511 }
1512 for (jj = 0; jj < snego.cnt; jj++) {
1513 if (!nfs_getseconfig_bynumber(snego.array[jj],
1514 &nfs_sec)) {
1515 snego_done = TRUE;
1516 if (sec_opt) {
1517 pr_err(gettext(
1518 "Security flavor %d was negotiated and"
1519 " will be used.\n"),
1520 nfs_sec.sc_nfsnum);
1521 }
1522 break;
1523 }
1524 }
1525 }
1526 if (!snego_done)
1527 return (NULL);
1528
1529 /*
1530 * Now that the flavor has been
1531 * negotiated, get the fh.
1532 *
1533 * First, create an auth handle using the negotiated
1534 * sec flavor in the next lookup to
1535 * fetch the filehandle.
1536 */
1537 new_ah = nfs_create_ah(cl, hostname, &nfs_sec);
1538 if (new_ah == NULL)
1539 goto done;
1540 cl->cl_auth = new_ah;
1541 } else if (sec == SNEGO_ARRAY_TOO_SMALL || sec ==
1542 SNEGO_FAILURE) {
1543 goto done;
1544 }
1545 /*
1546 * Note that if sec == SNEGO_DEF_VALID
1547 * default sec flavor is acceptable.
1548 * Use it to get the filehandle.
1549 */
1550 }
1551
1552 if (vers == NFS_VERSION) {
1553 wnl_diropargs arg;
1554 wnl_diropres *res;
1555
1556 memset((char *)&arg.dir, 0, sizeof (wnl_fh));
1557 arg.name = fspath;
1558 res = wnlproc_lookup_2(&arg, cl);
1559
1560 if (res == NULL || res->status != NFS_OK)
1561 goto done;
1562 *fhp = malloc(sizeof (wnl_fh));
1563
1564 if (*fhp == NULL) {
1568
1569 memcpy((char *)*fhp,
1570 (char *)&res->wnl_diropres_u.wnl_diropres.file,
1571 sizeof (wnl_fh));
1572 } else {
1573 WNL_LOOKUP3args arg;
1574 WNL_LOOKUP3res *res;
1575 nfs_fh3 *fh3p;
1576
1577 memset((char *)&arg.what.dir, 0, sizeof (wnl_fh3));
1578 arg.what.name = fspath;
1579 res = wnlproc3_lookup_3(&arg, cl);
1580
1581 if (res == NULL || res->status != NFS3_OK)
1582 goto done;
1583
1584 fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p));
1585
1586 if (fh3p == NULL) {
1587 pr_err(gettext("no memory\n"));
1588 CLNT_FREERES(cl, xdr_WNL_LOOKUP3res, (char *)res);
1589 goto done;
1590 }
1591
1592 fh3p->fh3_length =
1593 res->WNL_LOOKUP3res_u.res_ok.object.data.data_len;
1594 memcpy(fh3p->fh3_u.data,
1595 res->WNL_LOOKUP3res_u.res_ok.object.data.data_val,
1596 fh3p->fh3_length);
1597
1598 *fhp = (caddr_t)fh3p;
1599
1600 CLNT_FREERES(cl, xdr_WNL_LOOKUP3res, (char *)res);
1601 }
1602 } else {
1603 void *res;
1604 struct rpc_err r_err;
1605
1606 if (vers == NFS_VERSION)
1607 res = wnlproc_null_2(NULL, cl);
1608 else if (vers == NFS_V3)
1725
1726 /*
1727 * If proto is specified, then only search for the match,
1728 * otherwise try COTS first, if failed, try CLTS.
1729 */
1730 if (proto) {
1731 /* no matching proto name */
1732 SET_ERR_RET(error, ERR_PROTO_INVALID, 0);
1733
1734 while (nconf = getnetpath(nc)) {
1735 if (strcmp(nconf->nc_netid, proto))
1736 continue;
1737
1738 /* may be unsupported */
1739 SET_ERR_RET(error, ERR_PROTO_UNSUPP, 0);
1740
1741 if ((port != 0) &&
1742 ((strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
1743 strcmp(nconf->nc_protofmly, NC_INET6) == 0) &&
1744 (strcmp(nconf->nc_proto, NC_TCP) != 0 &&
1745 strcmp(nconf->nc_proto, NC_UDP) != 0)))
1746
1747 continue;
1748
1749 else {
1750 nb = get_the_addr(hostname, prog,
1751 vers, nconf, port, tinfo,
1752 fhp, get_pubfh, fspath, error);
1753
1754 if (nb != NULL)
1755 break;
1756
1757 /* nb is NULL - deal with errors */
1758 if (error) {
1759 if (error->error_type == ERR_NOHOST)
1760 SET_ERR_RET(&errsave_nohost,
1761 error->error_type,
1762 error->error_value);
1763 if (error->error_type == ERR_RPCERROR)
1764 SET_ERR_RET(&errsave_rpcerr,
1765 error->error_type,
1766 error->error_value);
1767 }
1768 /*
1769 * continue with same protocol
1770 * selection
1771 */
1772 continue;
1773 }
1774 } /* end of while */
1775
1776 if (nconf == NULL)
1777 goto done;
1778
1779 if ((nb = get_the_addr(hostname, prog, vers, nconf, port,
1780 tinfo, fhp, get_pubfh, fspath, error)) == NULL)
1781 goto done;
1782
1783
1784 } else {
1785 retry:
1786 SET_ERR_RET(error, ERR_NETPATH, 0);
1787 while (nconf = getnetpath(nc)) {
1788 SET_ERR_RET(error, ERR_PROTO_NONE, 0);
1789 if (nconf->nc_flag & NC_VISIBLE) {
1790 if (nthtry == FIRST_TRY) {
1791 if ((nconf->nc_semantics ==
1792 NC_TPI_COTS_ORD) ||
1793 (nconf->nc_semantics ==
1794 NC_TPI_COTS)) {
1795
1796 if (port == 0)
1797 break;
1798
1799 if ((strcmp(nconf->nc_protofmly,
1800 NC_INET) == 0 ||
1801 strcmp(nconf->
1802 nc_protofmly,
1803 NC_INET6) == 0) &&
1804 (strcmp(nconf->nc_proto,
1805 NC_TCP) == 0))
1806
1807 break;
1808 }
1809 }
1810 if (nthtry == SECOND_TRY) {
1811 if (nconf->nc_semantics ==
1812 NC_TPI_CLTS) {
1813 if (port == 0)
1814 break;
1815 if ((strcmp(nconf->nc_protofmly,
1816 NC_INET) == 0 ||
1817 strcmp(nconf->
1818 nc_protofmly, NC_INET6)
1819 == 0) &&
1820 (strcmp(
1821 nconf->nc_proto,
1822 NC_UDP) == 0))
1823 break;
1824 }
1825 }
1826 }
1827 } /* while */
1828 if (nconf == NULL) {
1829 if (++nthtry <= MNT_PREF_LISTLEN) {
1830 endnetpath(nc);
1831 if ((nc = setnetpath()) == NULL)
1832 goto done;
1833 goto retry;
1834 } else
1835 goto done;
1836 } else {
1837 if ((nb = get_the_addr(hostname, prog, vers, nconf,
1838 port, tinfo, fhp, get_pubfh, fspath, error))
1839 == NULL) {
1840 /* nb is NULL - deal with errors */
1841 if (error) {
1842 if (error->error_type == ERR_NOHOST)
1843 SET_ERR_RET(&errsave_nohost,
1844 error->error_type,
1845 error->error_value);
1846 if (error->error_type == ERR_RPCERROR)
1847 SET_ERR_RET(&errsave_rpcerr,
1848 error->error_type,
1849 error->error_value);
1850 }
1851 /*
1852 * Continue the same search path in the
1853 * netconfig db until no more matched
1854 * nconf (nconf == NULL).
1855 */
1856 goto retry;
1857 }
1858 }
1859 }
2024 vers_min = vers_min_default;
2025 }
2026
2027 break;
2028 }
2029
2030 /*
2031 * In the case of version 4, just NULL proc the server since
2032 * there is no MOUNT program. If this fails, then decrease
2033 * vers_to_try and continue on with regular MOUNT program
2034 * processing.
2035 */
2036 if (vers_to_try == NFS_V4) {
2037 int savevers = nfsvers_to_use;
2038 err_ret_t error;
2039 int retval;
2040 SET_ERR_RET(&error, ERR_PROTO_NONE, 0);
2041
2042 /* Let's hope for the best */
2043 nfsvers_to_use = NFS_V4;
2044 retval =
2045 getaddr_nfs(args, fshost, nconfp, FALSE,
2046 fspath, port, &error, vers_min == NFS_V4);
2047
2048 if (retval == RET_OK) {
2049 *versp = nfsvers_to_use = NFS_V4;
2050 fstype = MNTTYPE_NFS4;
2051 args->fh = strdup(fspath);
2052 if (args->fh == NULL) {
2053 pr_err(gettext("no memory\n"));
2054 *versp = nfsvers_to_use = savevers;
2055 return (RET_ERR);
2056 }
2057 return (RET_OK);
2058 }
2059 nfsvers_to_use = savevers;
2060
2061 vers_to_try--;
2062 /* If no more versions to try, let the user know. */
2063 if (vers_to_try < vers_min) {
2064 return (retval);
2065 }
2142 clnt_destroy(cl);
2143 return (RET_RETRY);
2144 }
2145
2146 switch (outvers) {
2147 case MOUNTVERS:
2148 case MOUNTVERS_POSIX:
2149 *versp = nfsvers_to_use = NFS_VERSION;
2150 rpc_stat = clnt_call(cl, MOUNTPROC_MNT, xdr_dirpath,
2151 (caddr_t)&fspath, xdr_fhstatus, (caddr_t)&fhs, timeout);
2152 if (rpc_stat != RPC_SUCCESS) {
2153 pr_err(gettext("%s:%s: server not responding %s\n"),
2154 fshost, fspath, clnt_sperror(cl, ""));
2155 clnt_destroy(cl);
2156 return (RET_RETRY);
2157 }
2158
2159 if ((errno = fhs.fhs_status) != MNT_OK) {
2160 if (loud_on_mnt_err) {
2161 if (errno == EACCES) {
2162 pr_err(gettext("%s:%s: access denied\n"),
2163 fshost, fspath);
2164 } else {
2165 pr_err(gettext("%s:%s: %s\n"), fshost, fspath,
2166 strerror(errno));
2167 }
2168 }
2169 clnt_destroy(cl);
2170 return (RET_MNTERR);
2171 }
2172 args->fh = malloc(sizeof (fhs.fhstatus_u.fhs_fhandle));
2173 if (args->fh == NULL) {
2174 pr_err(gettext("no memory\n"));
2175 return (RET_ERR);
2176 }
2177 memcpy((caddr_t)args->fh, (caddr_t)&fhs.fhstatus_u.fhs_fhandle,
2178 sizeof (fhs.fhstatus_u.fhs_fhandle));
2179 if (!errno && posix) {
2180 rpc_stat = clnt_call(cl, MOUNTPROC_PATHCONF,
2181 xdr_dirpath, (caddr_t)&fspath, xdr_ppathcnf,
2182 (caddr_t)&p, timeout);
2183 if (rpc_stat != RPC_SUCCESS) {
2184 pr_err(gettext(
2185 "%s:%s: server not responding %s\n"),
2186 fshost, fspath, clnt_sperror(cl, ""));
2195 free(args->fh);
2196 clnt_destroy(cl);
2197 return (RET_ERR);
2198 }
2199 args->flags |= NFSMNT_POSIX;
2200 args->pathconf = malloc(sizeof (p));
2201 if (args->pathconf == NULL) {
2202 pr_err(gettext("no memory\n"));
2203 free(args->fh);
2204 clnt_destroy(cl);
2205 return (RET_ERR);
2206 }
2207 memcpy((caddr_t)args->pathconf, (caddr_t)&p,
2208 sizeof (p));
2209 }
2210 break;
2211
2212 case MOUNTVERS3:
2213 *versp = nfsvers_to_use = NFS_V3;
2214 rpc_stat = clnt_call(cl, MOUNTPROC_MNT, xdr_dirpath,
2215 (caddr_t)&fspath,
2216 xdr_mountres3, (caddr_t)&mountres3, timeout);
2217 if (rpc_stat != RPC_SUCCESS) {
2218 pr_err(gettext("%s:%s: server not responding %s\n"),
2219 fshost, fspath, clnt_sperror(cl, ""));
2220 clnt_destroy(cl);
2221 return (RET_RETRY);
2222 }
2223
2224 /*
2225 * Assume here that most of the MNT3ERR_*
2226 * codes map into E* errors.
2227 */
2228 if ((errno = mountres3.fhs_status) != MNT_OK) {
2229 if (loud_on_mnt_err) {
2230 switch (errno) {
2231 case MNT3ERR_NAMETOOLONG:
2232 msg = "path name is too long";
2233 break;
2234 case MNT3ERR_NOTSUPP:
2235 msg = "operation not supported";
2236 break;
2237 case MNT3ERR_SERVERFAULT:
2238 msg = "server fault";
2239 break;
2240 default:
2241 msg = strerror(errno);
2242 break;
2243 }
2244 pr_err(gettext("%s:%s: %s\n"), fshost, fspath, msg);
2245 }
2246 clnt_destroy(cl);
2247 return (RET_MNTERR);
2248 }
2249
2250 fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p));
2251 if (fh3p == NULL) {
2252 pr_err(gettext("no memory\n"));
2253 return (RET_ERR);
2254 }
2255 fh3p->fh3_length =
2256 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len;
2257 (void) memcpy(fh3p->fh3_u.data,
2258 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val,
2259 fh3p->fh3_length);
2260 args->fh = (caddr_t)fh3p;
2261 fstype = MNTTYPE_NFS3;
2262
2263 /*
2264 * Check the security flavor to be used.
2265 *
2266 * If "secure" or "sec=flavor" is a mount
2267 * option, check if the server supports the "flavor".
2268 * If the server does not support the flavor, return
2269 * error.
2270 *
2271 * If no mount option is given then use the first supported
2272 * security flavor (by the client) in the auth list returned
2273 * from the server.
2274 *
2275 */
2276 auths =
2277 mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_val;
2278 count =
2279 mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_len;
2280
2281 if (sec_opt) {
2282 for (i = 0; i < count; i++) {
2283 if (auths[i] == nfs_sec.sc_nfsnum)
2284 break;
2285 }
2286 if (i >= count) {
2287 goto autherr;
2288 }
2289 } else {
2290 if (count > 0) {
2291 for (i = 0; i < count; i++) {
2292 if (!nfs_getseconfig_bynumber(auths[i], &nfs_sec)) {
2293 sec_opt++;
2294 break;
2295 }
2296 }
2297 if (i >= count) {
2298 goto autherr;
2299 }
2300 }
2301 }
2302 break;
2303 default:
2304 pr_err(gettext("%s:%s: Unknown MOUNT version %d\n"),
2305 fshost, fspath, outvers);
2306 clnt_destroy(cl);
2307 return (RET_ERR);
2308 }
2309
2310 clnt_destroy(cl);
2311 return (RET_OK);
2312
2313 autherr:
2314 pr_err(gettext(
2315 "security mode does not match the server exporting %s:%s\n"),
2316 fshost, fspath);
2317 clnt_destroy(cl);
2318 return (RET_ERR);
2319 }
2320
2321 /*
2367 */
2368 if (nfs_proto == NULL)
2369 args->flags |= NFSMNT_TRYRDMA;
2370 }
2371
2372 if (args->addr == NULL) {
2373 /*
2374 * We could have failed because the server had no public
2375 * file handle support. So don't print a message and don't
2376 * retry.
2377 */
2378 if (get_pubfh == TRUE)
2379 return (RET_ERR);
2380
2381 if (!printed) {
2382 switch (addr_error.error_type) {
2383 case 0:
2384 printed = 1;
2385 break;
2386 case ERR_RPCERROR:
2387 if (!print_rpcerror)
2388 /* no error print at this time */
2389 break;
2390 pr_err(gettext("%s NFS service not"
2391 " available %s\n"), fshost,
2392 clnt_sperrno(addr_error.error_value));
2393 printed = 1;
2394 break;
2395 case ERR_NETPATH:
2396 pr_err(gettext("%s: Error in NETPATH.\n"),
2397 fshost);
2398 printed = 1;
2399 break;
2400 case ERR_PROTO_INVALID:
2401 pr_err(gettext("%s: NFS service does not"
2402 " recognize protocol: %s.\n"), fshost,
2403 nfs_proto);
2404 printed = 1;
2405 break;
2406 case ERR_PROTO_UNSUPP:
2407 if (nfsvers || nfsvers_to_use == NFS_VERSMIN) {
2408 /*
2422 * Otherwise we decrement the version
2423 * and retry below.
2424 */
2425 pr_err(gettext("%s: NFS service does"
2426 " not support protocol: %s.\n"),
2427 fshost, nfs_proto);
2428 }
2429 break;
2430 case ERR_NOHOST:
2431 pr_err("%s: %s\n", fshost, "Unknown host");
2432 printed = 1;
2433 break;
2434 default:
2435 /* case ERR_PROTO_NONE falls through */
2436 pr_err(gettext("%s: NFS service not responding"
2437 "\n"), fshost);
2438 printed = 1;
2439 break;
2440 }
2441 }
2442 SET_ERR_RET(error,
2443 addr_error.error_type, addr_error.error_value);
2444 if (addr_error.error_type == ERR_PROTO_NONE)
2445 return (RET_RETRY);
2446 else if (addr_error.error_type == ERR_RPCERROR &&
2447 ! IS_UNRECOVERABLE_RPC(addr_error.error_value)) {
2448 return (RET_RETRY);
2449 } else if (nfsvers == 0 && addr_error.error_type ==
2450 ERR_PROTO_UNSUPP && nfsvers_to_use != NFS_VERSMIN) {
2451 /*
2452 * If no version is specified, and the error is due
2453 * to an unsupported transport, then decrement the
2454 * version and retry.
2455 */
2456 return (RET_RETRY);
2457 } else
2458 return (RET_ERR);
2459 }
2460 nconf = *nconfp;
2461
|
108 #define SET_ERR_RET(errst, etype, eval) \
109 if (errst) { \
110 (errst)->error_type = etype; \
111 (errst)->error_value = eval; \
112 }
113
114 /* number of transports to try */
115 #define MNT_PREF_LISTLEN 2
116 #define FIRST_TRY 1
117 #define SECOND_TRY 2
118
119 #define BIGRETRY 10000
120
121 /* maximum length of RPC header for NFS messages */
122 #define NFS_RPC_HDR 432
123
124 #define NFS_ARGS_EXTB_secdata(args, secdata) \
125 { (args)->nfs_args_ext = NFS_ARGS_EXTB, \
126 (args)->nfs_ext_u.nfs_extB.secdata = secdata; }
127
128 extern int __clnt_bindresvport(CLIENT *);
129 extern char *nfs_get_qop_name();
130 extern AUTH * nfs_create_ah();
131 extern enum snego_stat nfs_sec_nego();
132
133 static void usage(void);
134 static int retry(struct mnttab *, int);
135 static int set_args(int *, struct nfs_args *, char *, struct mnttab *);
136 static int get_fh_via_pub(struct nfs_args *, char *, char *, bool_t, bool_t,
137 int *, struct netconfig **, ushort_t);
138 static int get_fh(struct nfs_args *, char *, char *, int *, bool_t,
139 struct netconfig **, ushort_t);
140 static int make_secure(struct nfs_args *, char *, struct netconfig *,
141 bool_t, rpcvers_t);
142 static int mount_nfs(struct mnttab *, int, err_ret_t *);
143 static int getaddr_nfs(struct nfs_args *, char *, struct netconfig **,
144 bool_t, char *, ushort_t, err_ret_t *, bool_t);
145 static void pr_err(const char *fmt, ...);
146 static void usage(void);
147 static struct netbuf *get_addr(char *, rpcprog_t, rpcvers_t,
148 struct netconfig **, char *, ushort_t, struct t_info *,
1235 sec_data_t *secdata;
1236 int flags;
1237 struct netbuf *syncaddr = NULL;
1238 struct nd_addrlist *retaddrs = NULL;
1239 char netname[MAXNETNAMELEN+1];
1240
1241 /*
1242 * check to see if any secure mode is requested.
1243 * if not, use default security mode.
1244 */
1245 if (!snego_done && !sec_opt) {
1246 /*
1247 * Get default security mode.
1248 * AUTH_UNIX has been the default choice for a long time.
1249 * The better NFS security service becomes, the better chance
1250 * we will set stronger security service as the default NFS
1251 * security mode.
1252 *
1253 */
1254 if (nfs_getseconfig_default(&nfs_sec)) {
1255 pr_err(gettext("error getting default"
1256 " security entry\n"));
1257 return (-1);
1258 }
1259 args->flags |= NFSMNT_SECDEFAULT;
1260 }
1261
1262 /*
1263 * Get the network address for the time service on the server.
1264 * If an RPC based time service is not available then try the
1265 * IP time service.
1266 *
1267 * This is for AUTH_DH processing. We will also pass down syncaddr
1268 * and netname for NFS V4 even if AUTH_DH is not requested right now.
1269 * NFS V4 does security negotiation in the kernel via SECINFO.
1270 * These information might be needed later in the kernel.
1271 *
1272 * Eventurally, we want to move this code to nfs_clnt_secdata()
1273 * when autod_nfs.c and mount.c can share the same get_the_addr()
1274 * routine.
1275 */
1276 flags = 0;
1299 error = netdir_getbyname(nconf, &hs, &retaddrs);
1300
1301 if (error != ND_OK && (nfs_sec.sc_rpcnum == AUTH_DH)) {
1302 pr_err(gettext("%s: secure: no time service\n"),
1303 hostname);
1304 return (-1);
1305 }
1306
1307 if (error == ND_OK)
1308 syncaddr = retaddrs->n_addrs;
1309
1310 /*
1311 * For NFS_V4 if AUTH_DH is negotiated later in the
1312 * kernel thru SECINFO, it will need syncaddr
1313 * and netname data.
1314 */
1315 if (vers == NFS_V4 && syncaddr &&
1316 host2netname(netname, hostname, NULL)) {
1317 args->syncaddr = malloc(sizeof (struct netbuf));
1318 args->syncaddr->buf = malloc(syncaddr->len);
1319 (void) memcpy(args->syncaddr->buf,
1320 syncaddr->buf, syncaddr->len);
1321 args->syncaddr->len = syncaddr->len;
1322 args->syncaddr->maxlen = syncaddr->maxlen;
1323 args->netname = strdup(netname);
1324 args->flags |= NFSMNT_SECURE;
1325 }
1326 }
1327 }
1328
1329 /*
1330 * For the initial chosen flavor (any flavor defined in nfssec.conf),
1331 * the data will be stored in the sec_data structure via
1332 * nfs_clnt_secdata() and be passed to the kernel via nfs_args_*
1333 * extended data structure.
1334 */
1335 if (!(secdata = nfs_clnt_secdata(&nfs_sec, hostname, args->knconf,
1336 syncaddr, flags))) {
1337 pr_err(gettext("errors constructing security related data\n"));
1338 if (flags & AUTH_F_RPCTIMESYNC) {
1339 free(syncaddr->buf);
1340 free(syncaddr);
1429 retaddrs->n_addrs->len);
1430 tbind->addr.len = retaddrs->n_addrs->len;
1431 netdir_free((void *)retaddrs, ND_ADDRLIST);
1432 (void) netdir_options(nconf, ND_SET_RESERVEDPORT, fd, NULL);
1433
1434 } else {
1435 if (rpcb_getaddr(prog, vers, nconf, &tbind->addr,
1436 hostname) == FALSE) {
1437 goto done;
1438 }
1439 }
1440
1441 if (port) {
1442 /* LINTED pointer alignment */
1443 if (strcmp(nconf->nc_protofmly, NC_INET) == 0)
1444 ((struct sockaddr_in *)tbind->addr.buf)->sin_port
1445 = port;
1446 else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0)
1447 ((struct sockaddr_in6 *)tbind->addr.buf)->sin6_port
1448 = port;
1449 }
1450
1451 cl = clnt_tli_create(fd, nconf, &tbind->addr, prog, vers, 0, 0);
1452 if (cl == NULL) {
1453 /*
1454 * clnt_tli_create() returns either RPC_SYSTEMERROR,
1455 * RPC_UNKNOWNPROTO or RPC_TLIERROR. The RPC_TLIERROR translates
1456 * to "Misc. TLI error". This is not too helpful. Most likely
1457 * the connection to the remote server timed out, so this
1458 * error is at least less perplexing.
1459 * See: usr/src/cmd/rpcinfo/rpcinfo.c
1460 */
1461 if (rpc_createerr.cf_stat == RPC_TLIERROR) {
1462 SET_ERR_RET(error, ERR_RPCERROR, RPC_PMAPFAILURE);
1463 } else {
1464 SET_ERR_RET(error, ERR_RPCERROR, rpc_createerr.cf_stat);
1465 }
1466 goto done;
1467 }
1468
1469 ah = authsys_create_default();
1470 if (ah != NULL)
1471 cl->cl_auth = ah;
1472
1473 tv.tv_sec = 5;
1474 tv.tv_usec = 0;
1475
1476 (void) clnt_control(cl, CLSET_TIMEOUT, (char *)&tv);
1477
1478 if ((get_pubfh == TRUE) && (vers != NFS_V4)) {
1479 enum snego_stat sec;
1480
1481 if (!snego_done) {
1482 /*
1483 * negotiate sec flavor.
1484 */
1485 snego.cnt = 0;
1486 if ((sec = nfs_sec_nego(vers, cl,
1487 fspath, &snego)) == SNEGO_SUCCESS) {
1488 int jj;
1489
1490 /*
1491 * check if server supports the one
1492 * specified in the sec= option.
1493 */
1494 if (sec_opt) {
1495 for (jj = 0; jj < snego.cnt; jj++) {
1496 if (snego.array[jj] ==
1497 nfs_sec.sc_nfsnum) {
1498 snego_done = TRUE;
1499 break;
1500 }
1501 }
1502 }
1503
1504 /*
1505 * find a common sec flavor
1506 */
1507 if (!snego_done) {
1508 if (sec_opt) {
1509 pr_err(gettext(
1510 "Server does not support"
1511 " the security"
1512 " flavor specified.\n"));
1513 }
1514
1515 for (jj = 0; jj < snego.cnt; jj++) {
1516 if (!nfs_getseconfig_bynumber(
1517 snego.array[jj],
1518 &nfs_sec)) {
1519 snego_done = TRUE;
1520 if (sec_opt) {
1521 pr_err(gettext(
1522 "Security flavor %d was negotiated and will be used.\n"),
1523 nfs_sec.
1524 sc_nfsnum);
1525 }
1526
1527 break;
1528 }
1529 }
1530
1531 if (!snego_done)
1532 return (NULL);
1533 }
1534
1535 /*
1536 * Now that the flavor has been
1537 * negotiated, get the fh.
1538 *
1539 * First, create an auth handle using
1540 * the negotiated sec flavor in the
1541 * next lookup to fetch the filehandle.
1542 */
1543 new_ah = nfs_create_ah(cl, hostname, &nfs_sec);
1544 if (new_ah == NULL)
1545 goto done;
1546 cl->cl_auth = new_ah;
1547 } else if (sec == SNEGO_ARRAY_TOO_SMALL || sec ==
1548 SNEGO_FAILURE) {
1549 goto done;
1550 }
1551
1552 /*
1553 * Note that if sec == SNEGO_DEF_VALID
1554 * default sec flavor is acceptable.
1555 * Use it to get the filehandle.
1556 */
1557 }
1558
1559 if (vers == NFS_VERSION) {
1560 wnl_diropargs arg;
1561 wnl_diropres *res;
1562
1563 memset((char *)&arg.dir, 0, sizeof (wnl_fh));
1564 arg.name = fspath;
1565 res = wnlproc_lookup_2(&arg, cl);
1566
1567 if (res == NULL || res->status != NFS_OK)
1568 goto done;
1569 *fhp = malloc(sizeof (wnl_fh));
1570
1571 if (*fhp == NULL) {
1575
1576 memcpy((char *)*fhp,
1577 (char *)&res->wnl_diropres_u.wnl_diropres.file,
1578 sizeof (wnl_fh));
1579 } else {
1580 WNL_LOOKUP3args arg;
1581 WNL_LOOKUP3res *res;
1582 nfs_fh3 *fh3p;
1583
1584 memset((char *)&arg.what.dir, 0, sizeof (wnl_fh3));
1585 arg.what.name = fspath;
1586 res = wnlproc3_lookup_3(&arg, cl);
1587
1588 if (res == NULL || res->status != NFS3_OK)
1589 goto done;
1590
1591 fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p));
1592
1593 if (fh3p == NULL) {
1594 pr_err(gettext("no memory\n"));
1595 CLNT_FREERES(cl, xdr_WNL_LOOKUP3res,
1596 (char *)res);
1597 goto done;
1598 }
1599
1600 fh3p->fh3_length =
1601 res->WNL_LOOKUP3res_u.res_ok.object.data.data_len;
1602 memcpy(fh3p->fh3_u.data,
1603 res->WNL_LOOKUP3res_u.res_ok.object.data.data_val,
1604 fh3p->fh3_length);
1605
1606 *fhp = (caddr_t)fh3p;
1607
1608 CLNT_FREERES(cl, xdr_WNL_LOOKUP3res, (char *)res);
1609 }
1610 } else {
1611 void *res;
1612 struct rpc_err r_err;
1613
1614 if (vers == NFS_VERSION)
1615 res = wnlproc_null_2(NULL, cl);
1616 else if (vers == NFS_V3)
1733
1734 /*
1735 * If proto is specified, then only search for the match,
1736 * otherwise try COTS first, if failed, try CLTS.
1737 */
1738 if (proto) {
1739 /* no matching proto name */
1740 SET_ERR_RET(error, ERR_PROTO_INVALID, 0);
1741
1742 while (nconf = getnetpath(nc)) {
1743 if (strcmp(nconf->nc_netid, proto))
1744 continue;
1745
1746 /* may be unsupported */
1747 SET_ERR_RET(error, ERR_PROTO_UNSUPP, 0);
1748
1749 if ((port != 0) &&
1750 ((strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
1751 strcmp(nconf->nc_protofmly, NC_INET6) == 0) &&
1752 (strcmp(nconf->nc_proto, NC_TCP) != 0 &&
1753 strcmp(nconf->nc_proto, NC_UDP) != 0))) {
1754 continue;
1755 } else {
1756 nb = get_the_addr(hostname, prog,
1757 vers, nconf, port, tinfo,
1758 fhp, get_pubfh, fspath, error);
1759
1760 if (nb != NULL)
1761 break;
1762
1763 /* nb is NULL - deal with errors */
1764 if (error) {
1765 if (error->error_type == ERR_NOHOST)
1766 SET_ERR_RET(&errsave_nohost,
1767 error->error_type,
1768 error->error_value);
1769 if (error->error_type == ERR_RPCERROR)
1770 SET_ERR_RET(&errsave_rpcerr,
1771 error->error_type,
1772 error->error_value);
1773 }
1774 /*
1775 * continue with same protocol
1776 * selection
1777 */
1778 continue;
1779 }
1780 } /* end of while */
1781
1782 if (nconf == NULL)
1783 goto done;
1784
1785 if ((nb = get_the_addr(hostname, prog, vers, nconf, port,
1786 tinfo, fhp, get_pubfh, fspath, error)) == NULL)
1787 goto done;
1788 } else {
1789 retry:
1790 SET_ERR_RET(error, ERR_NETPATH, 0);
1791 while (nconf = getnetpath(nc)) {
1792 SET_ERR_RET(error, ERR_PROTO_NONE, 0);
1793 if (nconf->nc_flag & NC_VISIBLE) {
1794 if (nthtry == FIRST_TRY) {
1795 if ((nconf->nc_semantics ==
1796 NC_TPI_COTS_ORD) ||
1797 (nconf->nc_semantics ==
1798 NC_TPI_COTS)) {
1799
1800 if (port == 0)
1801 break;
1802
1803 if ((strcmp(nconf->nc_protofmly,
1804 NC_INET) == 0 ||
1805 strcmp(nconf->nc_protofmly,
1806 NC_INET6) == 0) &&
1807 (strcmp(nconf->nc_proto,
1808 NC_TCP) == 0))
1809 break;
1810 }
1811 }
1812 if (nthtry == SECOND_TRY) {
1813 if (nconf->nc_semantics ==
1814 NC_TPI_CLTS) {
1815 if (port == 0)
1816 break;
1817 if ((strcmp(nconf->nc_protofmly,
1818 NC_INET) == 0 ||
1819 strcmp(nconf->nc_protofmly,
1820 NC_INET6) == 0) &&
1821 (strcmp(nconf->nc_proto,
1822 NC_UDP) == 0))
1823 break;
1824 }
1825 }
1826 }
1827 } /* while */
1828
1829 if (nconf == NULL) {
1830 if (++nthtry <= MNT_PREF_LISTLEN) {
1831 endnetpath(nc);
1832 if ((nc = setnetpath()) == NULL)
1833 goto done;
1834 goto retry;
1835 } else
1836 goto done;
1837 } else {
1838 if ((nb = get_the_addr(hostname, prog, vers, nconf,
1839 port, tinfo, fhp, get_pubfh, fspath, error))
1840 == NULL) {
1841
1842 /* nb is NULL - deal with errors */
1843 if (error) {
1844 if (error->error_type == ERR_NOHOST)
1845 SET_ERR_RET(&errsave_nohost,
1846 error->error_type,
1847 error->error_value);
1848 if (error->error_type == ERR_RPCERROR)
1849 SET_ERR_RET(&errsave_rpcerr,
1850 error->error_type,
1851 error->error_value);
1852 }
1853 /*
1854 * Continue the same search path in the
1855 * netconfig db until no more matched
1856 * nconf (nconf == NULL).
1857 */
1858 goto retry;
1859 }
1860 }
1861 }
2026 vers_min = vers_min_default;
2027 }
2028
2029 break;
2030 }
2031
2032 /*
2033 * In the case of version 4, just NULL proc the server since
2034 * there is no MOUNT program. If this fails, then decrease
2035 * vers_to_try and continue on with regular MOUNT program
2036 * processing.
2037 */
2038 if (vers_to_try == NFS_V4) {
2039 int savevers = nfsvers_to_use;
2040 err_ret_t error;
2041 int retval;
2042 SET_ERR_RET(&error, ERR_PROTO_NONE, 0);
2043
2044 /* Let's hope for the best */
2045 nfsvers_to_use = NFS_V4;
2046 retval = getaddr_nfs(args, fshost, nconfp, FALSE,
2047 fspath, port, &error, vers_min == NFS_V4);
2048
2049 if (retval == RET_OK) {
2050 *versp = nfsvers_to_use = NFS_V4;
2051 fstype = MNTTYPE_NFS4;
2052 args->fh = strdup(fspath);
2053 if (args->fh == NULL) {
2054 pr_err(gettext("no memory\n"));
2055 *versp = nfsvers_to_use = savevers;
2056 return (RET_ERR);
2057 }
2058 return (RET_OK);
2059 }
2060 nfsvers_to_use = savevers;
2061
2062 vers_to_try--;
2063 /* If no more versions to try, let the user know. */
2064 if (vers_to_try < vers_min) {
2065 return (retval);
2066 }
2143 clnt_destroy(cl);
2144 return (RET_RETRY);
2145 }
2146
2147 switch (outvers) {
2148 case MOUNTVERS:
2149 case MOUNTVERS_POSIX:
2150 *versp = nfsvers_to_use = NFS_VERSION;
2151 rpc_stat = clnt_call(cl, MOUNTPROC_MNT, xdr_dirpath,
2152 (caddr_t)&fspath, xdr_fhstatus, (caddr_t)&fhs, timeout);
2153 if (rpc_stat != RPC_SUCCESS) {
2154 pr_err(gettext("%s:%s: server not responding %s\n"),
2155 fshost, fspath, clnt_sperror(cl, ""));
2156 clnt_destroy(cl);
2157 return (RET_RETRY);
2158 }
2159
2160 if ((errno = fhs.fhs_status) != MNT_OK) {
2161 if (loud_on_mnt_err) {
2162 if (errno == EACCES) {
2163 pr_err(gettext(
2164 "%s:%s: access denied\n"),
2165 fshost, fspath);
2166 } else {
2167 pr_err(gettext("%s:%s: %s\n"),
2168 fshost, fspath, strerror(errno));
2169 }
2170 }
2171 clnt_destroy(cl);
2172 return (RET_MNTERR);
2173 }
2174 args->fh = malloc(sizeof (fhs.fhstatus_u.fhs_fhandle));
2175 if (args->fh == NULL) {
2176 pr_err(gettext("no memory\n"));
2177 return (RET_ERR);
2178 }
2179 memcpy((caddr_t)args->fh, (caddr_t)&fhs.fhstatus_u.fhs_fhandle,
2180 sizeof (fhs.fhstatus_u.fhs_fhandle));
2181 if (!errno && posix) {
2182 rpc_stat = clnt_call(cl, MOUNTPROC_PATHCONF,
2183 xdr_dirpath, (caddr_t)&fspath, xdr_ppathcnf,
2184 (caddr_t)&p, timeout);
2185 if (rpc_stat != RPC_SUCCESS) {
2186 pr_err(gettext(
2187 "%s:%s: server not responding %s\n"),
2188 fshost, fspath, clnt_sperror(cl, ""));
2197 free(args->fh);
2198 clnt_destroy(cl);
2199 return (RET_ERR);
2200 }
2201 args->flags |= NFSMNT_POSIX;
2202 args->pathconf = malloc(sizeof (p));
2203 if (args->pathconf == NULL) {
2204 pr_err(gettext("no memory\n"));
2205 free(args->fh);
2206 clnt_destroy(cl);
2207 return (RET_ERR);
2208 }
2209 memcpy((caddr_t)args->pathconf, (caddr_t)&p,
2210 sizeof (p));
2211 }
2212 break;
2213
2214 case MOUNTVERS3:
2215 *versp = nfsvers_to_use = NFS_V3;
2216 rpc_stat = clnt_call(cl, MOUNTPROC_MNT, xdr_dirpath,
2217 (caddr_t)&fspath, xdr_mountres3,
2218 (caddr_t)&mountres3, timeout);
2219 if (rpc_stat != RPC_SUCCESS) {
2220 pr_err(gettext("%s:%s: server not responding %s\n"),
2221 fshost, fspath, clnt_sperror(cl, ""));
2222 clnt_destroy(cl);
2223 return (RET_RETRY);
2224 }
2225
2226 /*
2227 * Assume here that most of the MNT3ERR_*
2228 * codes map into E* errors.
2229 */
2230 if ((errno = mountres3.fhs_status) != MNT_OK) {
2231 if (loud_on_mnt_err) {
2232 switch (errno) {
2233 case MNT3ERR_NAMETOOLONG:
2234 msg = "path name is too long";
2235 break;
2236 case MNT3ERR_NOTSUPP:
2237 msg = "operation not supported";
2238 break;
2239 case MNT3ERR_SERVERFAULT:
2240 msg = "server fault";
2241 break;
2242 default:
2243 msg = strerror(errno);
2244 break;
2245 }
2246
2247 pr_err(gettext("%s:%s: %s\n"),
2248 fshost, fspath, msg);
2249 }
2250
2251 clnt_destroy(cl);
2252 return (RET_MNTERR);
2253 }
2254
2255 fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p));
2256 if (fh3p == NULL) {
2257 pr_err(gettext("no memory\n"));
2258 return (RET_ERR);
2259 }
2260 fh3p->fh3_length =
2261 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len;
2262 (void) memcpy(fh3p->fh3_u.data,
2263 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val,
2264 fh3p->fh3_length);
2265 args->fh = (caddr_t)fh3p;
2266 fstype = MNTTYPE_NFS3;
2267
2268 /*
2269 * Check the security flavor to be used.
2270 *
2271 * If "secure" or "sec=flavor" is a mount
2272 * option, check if the server supports the "flavor".
2273 * If the server does not support the flavor, return
2274 * error.
2275 *
2276 * If no mount option is given then use the first supported
2277 * security flavor (by the client) in the auth list returned
2278 * from the server.
2279 *
2280 */
2281 auths =
2282 mountres3.mountres3_u.mountinfo.auth_flavors.
2283 auth_flavors_val;
2284 count =
2285 mountres3.mountres3_u.mountinfo.auth_flavors.
2286 auth_flavors_len;
2287
2288 if (sec_opt) {
2289 for (i = 0; i < count; i++) {
2290 if (auths[i] == nfs_sec.sc_nfsnum)
2291 break;
2292 }
2293 if (i >= count)
2294 goto autherr;
2295 } else {
2296 if (count > 0) {
2297 for (i = 0; i < count; i++) {
2298 if (!nfs_getseconfig_bynumber(auths[i],
2299 &nfs_sec)) {
2300 sec_opt++;
2301 break;
2302 }
2303 }
2304
2305 if (i >= count)
2306 goto autherr;
2307 }
2308 }
2309 break;
2310 default:
2311 pr_err(gettext("%s:%s: Unknown MOUNT version %d\n"),
2312 fshost, fspath, outvers);
2313 clnt_destroy(cl);
2314 return (RET_ERR);
2315 }
2316
2317 clnt_destroy(cl);
2318 return (RET_OK);
2319
2320 autherr:
2321 pr_err(gettext(
2322 "security mode does not match the server exporting %s:%s\n"),
2323 fshost, fspath);
2324 clnt_destroy(cl);
2325 return (RET_ERR);
2326 }
2327
2328 /*
2374 */
2375 if (nfs_proto == NULL)
2376 args->flags |= NFSMNT_TRYRDMA;
2377 }
2378
2379 if (args->addr == NULL) {
2380 /*
2381 * We could have failed because the server had no public
2382 * file handle support. So don't print a message and don't
2383 * retry.
2384 */
2385 if (get_pubfh == TRUE)
2386 return (RET_ERR);
2387
2388 if (!printed) {
2389 switch (addr_error.error_type) {
2390 case 0:
2391 printed = 1;
2392 break;
2393 case ERR_RPCERROR:
2394 /* no error print at this time */
2395 if (!print_rpcerror)
2396 break;
2397 pr_err(gettext("%s NFS service not"
2398 " available %s\n"), fshost,
2399 clnt_sperrno(addr_error.error_value));
2400 printed = 1;
2401 break;
2402 case ERR_NETPATH:
2403 pr_err(gettext("%s: Error in NETPATH.\n"),
2404 fshost);
2405 printed = 1;
2406 break;
2407 case ERR_PROTO_INVALID:
2408 pr_err(gettext("%s: NFS service does not"
2409 " recognize protocol: %s.\n"), fshost,
2410 nfs_proto);
2411 printed = 1;
2412 break;
2413 case ERR_PROTO_UNSUPP:
2414 if (nfsvers || nfsvers_to_use == NFS_VERSMIN) {
2415 /*
2429 * Otherwise we decrement the version
2430 * and retry below.
2431 */
2432 pr_err(gettext("%s: NFS service does"
2433 " not support protocol: %s.\n"),
2434 fshost, nfs_proto);
2435 }
2436 break;
2437 case ERR_NOHOST:
2438 pr_err("%s: %s\n", fshost, "Unknown host");
2439 printed = 1;
2440 break;
2441 default:
2442 /* case ERR_PROTO_NONE falls through */
2443 pr_err(gettext("%s: NFS service not responding"
2444 "\n"), fshost);
2445 printed = 1;
2446 break;
2447 }
2448 }
2449
2450 SET_ERR_RET(error,
2451 addr_error.error_type, addr_error.error_value);
2452 if (addr_error.error_type == ERR_PROTO_NONE)
2453 return (RET_RETRY);
2454 else if (addr_error.error_type == ERR_RPCERROR &&
2455 ! IS_UNRECOVERABLE_RPC(addr_error.error_value)) {
2456 return (RET_RETRY);
2457 } else if (nfsvers == 0 && addr_error.error_type ==
2458 ERR_PROTO_UNSUPP && nfsvers_to_use != NFS_VERSMIN) {
2459 /*
2460 * If no version is specified, and the error is due
2461 * to an unsupported transport, then decrement the
2462 * version and retry.
2463 */
2464 return (RET_RETRY);
2465 } else
2466 return (RET_ERR);
2467 }
2468 nconf = *nconfp;
2469
|