X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=utils%2Fmount%2Fnetwork.c;h=5b515c30d76d26a79839331d5db7dd2b7840f6e3;hp=e3ad5c26a71da5d915fe45f28ae5d32e8dbc9827;hb=17962b82afb68ca8e6b0d3f432d36c6c7c4980ea;hpb=e9ab22a79e385babb16623a9260bda358291c80d diff --git a/utils/mount/network.c b/utils/mount/network.c index e3ad5c2..5b515c3 100644 --- a/utils/mount/network.c +++ b/utils/mount/network.c @@ -37,11 +37,13 @@ #include #include #include +#include #include #include #include #include +#include "sockaddr.h" #include "xcommon.h" #include "mount.h" #include "nls.h" @@ -51,14 +53,13 @@ #include "parse_opt.h" #include "network.h" #include "conffile.h" +#include "nfslib.h" #define PMAP_TIMEOUT (10) #define CONNECT_TIMEOUT (20) #define MOUNT_TIMEOUT (30) -#if SIZEOF_SOCKLEN_T - 0 == 0 -#define socklen_t unsigned int -#endif +#define SAFE_SOCKADDR(x) (struct sockaddr *)(char *)(x) extern int nfs_mount_data_version; extern char *progname; @@ -84,6 +85,7 @@ static const char *nfs_nfs_pgmtbl[] = { static const char *nfs_transport_opttbl[] = { "udp", "tcp", + "rdma", "proto", NULL, }; @@ -428,12 +430,12 @@ static int get_socket(struct sockaddr_in *saddr, unsigned int p_prot, if (bindresvport(so, &laddr) < 0) goto err_bindresvport; } else { - cc = bind(so, (struct sockaddr *)&laddr, namelen); + cc = bind(so, SAFE_SOCKADDR(&laddr), namelen); if (cc < 0) goto err_bind; } if (type == SOCK_STREAM || (conn && type == SOCK_DGRAM)) { - cc = connect_to(so, (struct sockaddr *)saddr, namelen, + cc = connect_to(so, SAFE_SOCKADDR(saddr), namelen, timeout); if (cc < 0) goto err_connect; @@ -540,8 +542,8 @@ static int nfs_probe_port(const struct sockaddr *sap, const socklen_t salen, struct pmap *pmap, const unsigned long *versions, const unsigned int *protos) { - struct sockaddr_storage address; - struct sockaddr *saddr = (struct sockaddr *)&address; + union nfs_sockaddr address; + struct sockaddr *saddr = &address.sa; const unsigned long prog = pmap->pm_prog, *p_vers; const unsigned int prot = (u_int)pmap->pm_prot, *p_prot; const u_short port = (u_short) pmap->pm_port; @@ -756,11 +758,12 @@ int nfs_probe_bothports(const struct sockaddr *mnt_saddr, */ int probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server) { - return nfs_probe_bothports((struct sockaddr *)&mnt_server->saddr, - sizeof(mnt_server->saddr), + struct sockaddr *mnt_addr = SAFE_SOCKADDR(&mnt_server->saddr); + struct sockaddr *nfs_addr = SAFE_SOCKADDR(&nfs_server->saddr); + + return nfs_probe_bothports(mnt_addr, sizeof(mnt_server->saddr), &mnt_server->pmap, - (struct sockaddr *)&nfs_server->saddr, - sizeof(nfs_server->saddr), + nfs_addr, sizeof(nfs_server->saddr), &nfs_server->pmap); } @@ -772,7 +775,7 @@ static int nfs_probe_statd(void) }; rpcprog_t program = nfs_getrpcbyname(NSMPROG, nfs_ns_pgmtbl); - return nfs_getport_ping((struct sockaddr *)&addr, sizeof(addr), + return nfs_getport_ping(SAFE_SOCKADDR(&addr), sizeof(addr), program, (rpcvers_t)1, IPPROTO_UDP); } @@ -831,8 +834,8 @@ int start_statd(void) int nfs_advise_umount(const struct sockaddr *sap, const socklen_t salen, const struct pmap *pmap, const dirpath *argp) { - struct sockaddr_storage address; - struct sockaddr *saddr = (struct sockaddr *)&address; + union nfs_sockaddr address; + struct sockaddr *saddr = &address.sa; struct pmap mnt_pmap = *pmap; struct timeval timeout = { .tv_sec = MOUNT_TIMEOUT >> 3, @@ -859,7 +862,14 @@ int nfs_advise_umount(const struct sockaddr *sap, const socklen_t salen, return 0; } - client->cl_auth = authunix_create_default(); + client->cl_auth = nfs_authsys_create(); + if (client->cl_auth == NULL) { + if (verbose) + nfs_error(_("%s: Failed to create RPC auth handle"), + progname); + CLNT_DESTROY(client); + return 0; + } res = CLNT_CALL(client, MOUNTPROC_UMNT, (xdrproc_t)xdr_dirpath, (caddr_t)argp, @@ -894,7 +904,7 @@ int nfs_advise_umount(const struct sockaddr *sap, const socklen_t salen, */ int nfs_call_umount(clnt_addr_t *mnt_server, dirpath *argp) { - struct sockaddr *sap = (struct sockaddr *)&mnt_server->saddr; + struct sockaddr *sap = SAFE_SOCKADDR(&mnt_server->saddr); socklen_t salen = sizeof(mnt_server->saddr); struct pmap *pmap = &mnt_server->pmap; CLIENT *clnt; @@ -959,8 +969,10 @@ CLIENT *mnt_openclnt(clnt_addr_t *mnt_server, int *msock) } if (clnt) { /* try to mount hostname:dirname */ - clnt->cl_auth = authunix_create_default(); - return clnt; + clnt->cl_auth = nfs_authsys_create(); + if (clnt->cl_auth) + return clnt; + CLNT_DESTROY(clnt); } return NULL; } @@ -1002,11 +1014,11 @@ int clnt_ping(struct sockaddr_in *saddr, const unsigned long prog, struct sockaddr_in *caddr) { CLIENT *clnt = NULL; - int sock, stat; + int sock, status; static char clnt_res; struct sockaddr dissolve; - rpc_createerr.cf_stat = stat = 0; + rpc_createerr.cf_stat = status = 0; sock = get_socket(saddr, prot, CONNECT_TIMEOUT, FALSE, TRUE); if (sock == RPC_ANYSOCK) { if (rpc_createerr.cf_error.re_errno == ETIMEDOUT) { @@ -1049,18 +1061,18 @@ int clnt_ping(struct sockaddr_in *saddr, const unsigned long prog, return 0; } memset(&clnt_res, 0, sizeof(clnt_res)); - stat = clnt_call(clnt, NULLPROC, + status = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void, (caddr_t)NULL, (xdrproc_t)xdr_void, (caddr_t)&clnt_res, TIMEOUT); - if (stat) { + if (status) { clnt_geterr(clnt, &rpc_createerr.cf_error); - rpc_createerr.cf_stat = stat; + rpc_createerr.cf_stat = status; } clnt_destroy(clnt); close(sock); - if (stat == RPC_SUCCESS) + if (status == RPC_SUCCESS) return 1; else return 0; @@ -1094,13 +1106,13 @@ static int nfs_ca_sockname(const struct sockaddr *sap, const socklen_t salen, switch (sap->sa_family) { case AF_INET: - if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) { + if (bind(sock, SAFE_SOCKADDR(&sin), sizeof(sin)) < 0) { close(sock); return 0; } break; case AF_INET6: - if (bind(sock, (struct sockaddr *)&sin6, sizeof(sin6)) < 0) { + if (bind(sock, SAFE_SOCKADDR(&sin6), sizeof(sin6)) < 0) { close(sock); return 0; } @@ -1205,6 +1217,8 @@ nfs_nfs_program(struct mount_options *options, unsigned long *program) return 1; } case PO_BAD_VALUE: + nfs_error(_("%s: invalid value for 'nfsprog=' option"), + progname); return 0; } @@ -1244,9 +1258,12 @@ nfs_nfs_version(struct mount_options *options, unsigned long *version) } return 0; case PO_NOT_FOUND: - nfs_error(_("%s: option parsing error\n"), + nfs_error(_("%s: parsing error on 'vers=' option\n"), progname); + return 0; case PO_BAD_VALUE: + nfs_error(_("%s: invalid value for 'vers=' option"), + progname); return 0; } case 4: /* nfsvers */ @@ -1258,9 +1275,12 @@ nfs_nfs_version(struct mount_options *options, unsigned long *version) } return 0; case PO_NOT_FOUND: - nfs_error(_("%s: option parsing error\n"), + nfs_error(_("%s: parsing error on 'nfsvers=' option\n"), progname); + return 0; case PO_BAD_VALUE: + nfs_error(_("%s: invalid value for 'nfsvers=' option"), + progname); return 0; } } @@ -1275,7 +1295,8 @@ nfs_nfs_version(struct mount_options *options, unsigned long *version) /* * Returns TRUE if @protocol contains a valid value for this option, - * or FALSE if the option was specified with an invalid value. + * or FALSE if the option was specified with an invalid value. On + * error, errno is set. */ int nfs_nfs_protocol(struct mount_options *options, unsigned long *protocol) @@ -1290,10 +1311,20 @@ nfs_nfs_protocol(struct mount_options *options, unsigned long *protocol) case 1: /* tcp */ *protocol = IPPROTO_TCP; return 1; - case 2: /* proto */ + case 2: /* rdma */ + *protocol = NFSPROTO_RDMA; + return 1; + case 3: /* proto */ option = po_get(options, "proto"); - if (option != NULL) - return nfs_get_proto(option, &family, protocol); + if (option != NULL) { + if (!nfs_get_proto(option, &family, protocol)) { + errno = EPROTONOSUPPORT; + nfs_error(_("%s: Failed to find '%s' protocol"), + progname, option); + return 0; + } + return 1; + } } /* @@ -1323,6 +1354,8 @@ nfs_nfs_port(struct mount_options *options, unsigned long *port) return 1; } case PO_BAD_VALUE: + nfs_error(_("%s: invalid value for 'port=' option"), + progname); return 0; } @@ -1334,38 +1367,65 @@ nfs_nfs_port(struct mount_options *options, unsigned long *port) return 1; } +#ifdef IPV6_SUPPORTED +sa_family_t config_default_family = AF_UNSPEC; + +static int +nfs_verify_family(sa_family_t UNUSED(family)) +{ + return 1; +} +#else /* IPV6_SUPPORTED */ +sa_family_t config_default_family = AF_INET; + +static int +nfs_verify_family(sa_family_t family) +{ + if (family != AF_INET) + return 0; + + return 1; +} +#endif /* IPV6_SUPPORTED */ + /* * Returns TRUE and fills in @family if a valid NFS protocol option - * is found, or FALSE if the option was specified with an invalid value. + * is found, or FALSE if the option was specified with an invalid value + * or if the protocol family isn't supported. On error, errno is set. */ int nfs_nfs_proto_family(struct mount_options *options, sa_family_t *family) { unsigned long protocol; char *option; - -#ifdef HAVE_LIBTIRPC - *family = AF_UNSPEC; -#else - *family = AF_INET; -#endif + sa_family_t tmp_family = config_default_family; switch (po_rightmost(options, nfs_transport_opttbl)) { case 0: /* udp */ - return 1; case 1: /* tcp */ + case 2: /* rdma */ + /* for compatibility; these are always AF_INET */ + *family = AF_INET; return 1; - case 2: /* proto */ + case 3: /* proto */ option = po_get(options, "proto"); - if (option != NULL) - return nfs_get_proto(option, family, &protocol); + if (option != NULL && + !nfs_get_proto(option, &tmp_family, &protocol)) { + + nfs_error(_("%s: Failed to find '%s' protocol"), + progname, option); + errno = EPROTONOSUPPORT; + return 0; + } } - /* - * NFS transport protocol wasn't specified. Return the - * default address family. - */ + if (!nfs_verify_family(tmp_family)) + goto out_err; + *family = tmp_family; return 1; +out_err: + errno = EAFNOSUPPORT; + return 0; } /* @@ -1389,6 +1449,8 @@ nfs_mount_program(struct mount_options *options, unsigned long *program) return 1; } case PO_BAD_VALUE: + nfs_error(_("%s: invalid value for 'mountprog=' option"), + progname); return 0; } @@ -1418,6 +1480,8 @@ nfs_mount_version(struct mount_options *options, unsigned long *version) return 1; } case PO_BAD_VALUE: + nfs_error(_("%s: invalid value for 'mountvers=' option"), + progname); return 0; } @@ -1431,7 +1495,8 @@ nfs_mount_version(struct mount_options *options, unsigned long *version) /* * Returns TRUE if @protocol contains a valid value for this option, - * or FALSE if the option was specified with an invalid value. + * or FALSE if the option was specified with an invalid value. On + * error, errno is set. */ static int nfs_mount_protocol(struct mount_options *options, unsigned long *protocol) @@ -1440,8 +1505,15 @@ nfs_mount_protocol(struct mount_options *options, unsigned long *protocol) char *option; option = po_get(options, "mountproto"); - if (option != NULL) - return nfs_get_proto(option, &family, protocol); + if (option != NULL) { + if (!nfs_get_proto(option, &family, protocol)) { + errno = EPROTONOSUPPORT; + nfs_error(_("%s: Failed to find '%s' protocol"), + progname, option); + return 0; + } + return 1; + } /* * MNT transport protocol wasn't specified. If the NFS @@ -1449,7 +1521,11 @@ nfs_mount_protocol(struct mount_options *options, unsigned long *protocol) * set @protocol to zero. The pmap protocol value will * be filled in later by an rpcbind query in this case. */ - return nfs_nfs_protocol(options, protocol); + if (!nfs_nfs_protocol(options, protocol)) + return 0; + if (*protocol == NFSPROTO_RDMA) + *protocol = IPPROTO_TCP; + return 1; } /* @@ -1470,6 +1546,8 @@ nfs_mount_port(struct mount_options *options, unsigned long *port) return 1; } case PO_BAD_VALUE: + nfs_error(_("%s: invalid value for 'mountport=' option"), + progname); return 0; } @@ -1483,23 +1561,29 @@ nfs_mount_port(struct mount_options *options, unsigned long *port) /* * Returns TRUE and fills in @family if a valid MNT protocol option - * is found, or FALSE if the option was specified with an invalid value. + * is found, or FALSE if the option was specified with an invalid value + * or if the protocol family isn't supported. On error, errno is set. */ int nfs_mount_proto_family(struct mount_options *options, sa_family_t *family) { unsigned long protocol; char *option; - -#ifdef HAVE_LIBTIRPC - *family = AF_UNSPEC; -#else - *family = AF_INET; -#endif + sa_family_t tmp_family = config_default_family; option = po_get(options, "mountproto"); - if (option != NULL) - return nfs_get_proto(option, family, &protocol); + if (option != NULL) { + if (!nfs_get_proto(option, &tmp_family, &protocol)) { + nfs_error(_("%s: Failed to find '%s' protocol"), + progname, option); + errno = EPROTONOSUPPORT; + goto out_err; + } + if (!nfs_verify_family(tmp_family)) + goto out_err; + *family = tmp_family; + return 1; + } /* * MNT transport protocol wasn't specified. If the NFS @@ -1508,6 +1592,9 @@ int nfs_mount_proto_family(struct mount_options *options, * NFS. */ return nfs_nfs_proto_family(options, family); +out_err: + errno = EAFNOSUPPORT; + return 0; } /**