X-Git-Url: https://git.decadent.org.uk/gitweb/?a=blobdiff_plain;f=utils%2Fgssd%2Fgssd_proc.c;h=6a68cdf6d1744fb19f57bc4a0b22ee82d2c1b5f0;hb=59189376db057ae08a710cb2b258426230f687d7;hp=295c37dfaa5ba515ef5ac9ffd6c5a2b9219050f7;hpb=336f8bca825416082d62ef38314f3e0b7e8f5cc2;p=nfs-utils.git diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c index 295c37d..6a68cdf 100644 --- a/utils/gssd/gssd_proc.c +++ b/utils/gssd/gssd_proc.c @@ -102,12 +102,68 @@ struct pollfd * pollarray; int pollsize; /* the size of pollaray (in pollfd's) */ +/* + * convert a presentation address string to a sockaddr_storage struct. Returns + * true on success and false on failure. + */ +static int +addrstr_to_sockaddr(struct sockaddr *sa, const char *addr, const int port) +{ + struct sockaddr_in *s4 = (struct sockaddr_in *) sa; + + if (inet_pton(AF_INET, addr, &s4->sin_addr)) { + s4->sin_family = AF_INET; + s4->sin_port = htons(port); + } else { + printerr(0, "ERROR: unable to convert %s to address\n", addr); + return 0; + } + + return 1; +} + +/* + * convert a sockaddr to a hostname + */ +static char * +sockaddr_to_hostname(const struct sockaddr *sa, const char *addr) +{ + socklen_t addrlen; + int err; + char *hostname; + char hbuf[NI_MAXHOST]; + + switch (sa->sa_family) { + case AF_INET: + addrlen = sizeof(struct sockaddr_in); + break; + default: + printerr(0, "ERROR: unrecognized addr family %d\n", + sa->sa_family); + return NULL; + } + + err = getnameinfo(sa, addrlen, hbuf, sizeof(hbuf), NULL, 0, + NI_NAMEREQD); + if (err) { + printerr(0, "ERROR: unable to resolve %s to hostname: %s\n", + addr, err == EAI_SYSTEM ? strerror(err) : + gai_strerror(err)); + return NULL; + } + + hostname = strdup(hbuf); + + return hostname; +} + /* XXX buffer problems: */ static int read_service_info(char *info_file_name, char **servicename, char **servername, - int *prog, int *vers, char **protocol, int *port) { + int *prog, int *vers, char **protocol, + struct sockaddr *addr) { #define INFOBUFLEN 256 - char buf[INFOBUFLEN]; + char buf[INFOBUFLEN + 1]; static char dummy[128]; int nbytes; static char service[128]; @@ -117,10 +173,9 @@ read_service_info(char *info_file_name, char **servicename, char **servername, char protoname[16]; char cb_port[128]; char *p; - in_addr_t inaddr; int fd = -1; - struct hostent *ent = NULL; int numfields; + int port = 0; *servicename = *servername = *protocol = NULL; @@ -132,6 +187,7 @@ read_service_info(char *info_file_name, char **servicename, char **servername, if ((nbytes = read(fd, buf, INFOBUFLEN)) == -1) goto fail; close(fd); + buf[nbytes] = '\0'; numfields = sscanf(buf,"RPC server: %127s\n" "service: %127s %15s version %15s\n" @@ -159,21 +215,26 @@ read_service_info(char *info_file_name, char **servicename, char **servername, if((*prog != 100003) || ((*vers != 2) && (*vers != 3) && (*vers != 4))) goto fail; - /* create service name */ - inaddr = inet_addr(address); - if (!(ent = gethostbyaddr(&inaddr, sizeof(inaddr), AF_INET))) { - printerr(0, "ERROR: can't resolve server %s name\n", address); - goto fail; + if (cb_port[0] != '\0') { + port = atoi(cb_port); + if (port < 0 || port > 65535) + goto fail; } - if (!(*servername = calloc(strlen(ent->h_name) + 1, 1))) + + if (!addrstr_to_sockaddr(addr, address, port)) goto fail; - memcpy(*servername, ent->h_name, strlen(ent->h_name)); - snprintf(buf, INFOBUFLEN, "%s@%s", service, ent->h_name); + + *servername = sockaddr_to_hostname(addr, address); + if (*servername == NULL) + goto fail; + + nbytes = snprintf(buf, INFOBUFLEN, "%s@%s", service, *servername); + if (nbytes > INFOBUFLEN) + goto fail; + if (!(*servicename = calloc(strlen(buf) + 1, 1))) goto fail; memcpy(*servicename, buf, strlen(buf)); - if (cb_port[0] != '\0') - *port = atoi(cb_port); if (!(*protocol = strdup(protoname))) goto fail; @@ -181,9 +242,10 @@ read_service_info(char *info_file_name, char **servicename, char **servername, fail: printerr(0, "ERROR: failed to read service info\n"); if (fd != -1) close(fd); - if (*servername) free(*servername); - if (*servicename) free(*servicename); - if (*protocol) free(*protocol); + free(*servername); + free(*servicename); + free(*protocol); + *servicename = *servername = *protocol = NULL; return -1; } @@ -199,10 +261,10 @@ destroy_client(struct clnt_info *clp) if (clp->dir_fd != -1) close(clp->dir_fd); if (clp->krb5_fd != -1) close(clp->krb5_fd); if (clp->spkm3_fd != -1) close(clp->spkm3_fd); - if (clp->dirname) free(clp->dirname); - if (clp->servicename) free(clp->servicename); - if (clp->servername) free(clp->servername); - if (clp->protocol) free(clp->protocol); + free(clp->dirname); + free(clp->servicename); + free(clp->servername); + free(clp->protocol); free(clp); } @@ -249,7 +311,7 @@ process_clnt_dir_files(struct clnt_info * clp) if ((clp->servicename == NULL) && read_service_info(info_file_name, &clp->servicename, &clp->servername, &clp->prog, &clp->vers, - &clp->protocol, &clp->port)) + &clp->protocol, (struct sockaddr *) &clp->addr)) return -1; return 0; } @@ -501,6 +563,7 @@ int create_auth_rpc_client(struct clnt_info *clp, struct addrinfo ai_hints, *a = NULL; char service[64]; char *at_sign; + struct sockaddr_in *addr = (struct sockaddr_in *) &clp->addr; /* Create the context as the user (not as root) */ save_uid = geteuid(); @@ -597,8 +660,10 @@ int create_auth_rpc_client(struct clnt_info *clp, clp->servername, uid); goto out_fail; } - if (clp->port) - ((struct sockaddr_in *)a->ai_addr)->sin_port = htons(clp->port); + + if (addr->sin_port != 0) + ((struct sockaddr_in *) a->ai_addr)->sin_port = addr->sin_port; + if (a->ai_protocol == IPPROTO_TCP) { if ((rpc_clnt = clnttcp_create( (struct sockaddr_in *) a->ai_addr,