X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=utils%2Fgssd%2Fgssd_proc.c;h=50a27e418f2add809d2a63fdd29a3716c2fd53c2;hp=33a31c3c3c5b1c018ea8a7408bba34863569053b;hb=76be349d5dd07f55797cb9920cc275667258f10f;hpb=dd31301d485b4244b1b35049f6917df907997da9 diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c index 33a31c3..50a27e4 100644 --- a/utils/gssd/gssd_proc.c +++ b/utils/gssd/gssd_proc.c @@ -108,7 +108,7 @@ 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. + * true on success or false on failure. * * Note that we do not populate the sin6_scope_id field here for IPv6 addrs. * gssd nececessarily relies on hostname resolution and DNS AAAA records @@ -120,26 +120,43 @@ int pollsize; /* the size of pollaray (in pollfd's) */ * not really feasible at present. */ static int -addrstr_to_sockaddr(struct sockaddr *sa, const char *addr, const int port) +addrstr_to_sockaddr(struct sockaddr *sa, const char *node, const char *port) { - struct sockaddr_in *s4 = (struct sockaddr_in *) sa; -#ifdef IPV6_SUPPORTED - struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) sa; -#endif /* IPV6_SUPPORTED */ + int rc; + struct addrinfo *res; + struct addrinfo hints = { .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV }; - if (inet_pton(AF_INET, addr, &s4->sin_addr)) { - s4->sin_family = AF_INET; - s4->sin_port = htons(port); -#ifdef IPV6_SUPPORTED - } else if (inet_pton(AF_INET6, addr, &s6->sin6_addr)) { - s6->sin6_family = AF_INET6; - s6->sin6_port = htons(port); +#ifndef IPV6_SUPPORTED + hints.ai_family = AF_INET; #endif /* IPV6_SUPPORTED */ - } else { - printerr(0, "ERROR: unable to convert %s to address\n", addr); + + rc = getaddrinfo(node, port, &hints, &res); + if (rc) { + printerr(0, "ERROR: unable to convert %s|%s to sockaddr: %s\n", + node, port, rc == EAI_SYSTEM ? strerror(errno) : + gai_strerror(rc)); return 0; } +#ifdef IPV6_SUPPORTED + /* + * getnameinfo ignores the scopeid. If the address turns out to have + * a non-zero scopeid, we can't use it -- the resolved host might be + * completely different from the one intended. + */ + if (res->ai_addr->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)res->ai_addr; + if (sin6->sin6_scope_id) { + printerr(0, "ERROR: address %s has non-zero " + "sin6_scope_id!\n", node); + freeaddrinfo(res); + return 0; + } + } +#endif /* IPV6_SUPPORTED */ + + memcpy(sa, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); return 1; } @@ -197,11 +214,10 @@ read_service_info(char *info_file_name, char **servicename, char **servername, char program[16]; char version[16]; char protoname[16]; - char cb_port[128]; + char port[128]; char *p; int fd = -1; int numfields; - int port = 0; *servicename = *servername = *protocol = NULL; @@ -230,9 +246,9 @@ read_service_info(char *info_file_name, char **servicename, char **servername, goto fail; } - cb_port[0] = '\0'; + port[0] = '\0'; if ((p = strstr(buf, "port")) != NULL) - sscanf(p, "port: %127s\n", cb_port); + sscanf(p, "port: %127s\n", port); /* check service, program, and version */ if (memcmp(service, "nfs", 3) != 0) @@ -249,12 +265,6 @@ read_service_info(char *info_file_name, char **servicename, char **servername, goto fail; } - if (cb_port[0] != '\0') { - port = atoi(cb_port); - if (port < 0 || port > 65535) - goto fail; - } - if (!addrstr_to_sockaddr(addr, address, port)) goto fail; @@ -590,6 +600,67 @@ update_client_list(void) return retval; } +/* Encryption types supported by the kernel rpcsec_gss code */ +int num_krb5_enctypes = 0; +krb5_enctype *krb5_enctypes = NULL; + +/* + * Parse the supported encryption type information + */ +static int +parse_enctypes(char *enctypes) +{ + int n = 0; + char *curr, *comma; + int i; + static char *cached_types; + + if (cached_types && strcmp(cached_types, enctypes) == 0) + return 0; + free(cached_types); + + if (krb5_enctypes != NULL) { + free(krb5_enctypes); + krb5_enctypes = NULL; + num_krb5_enctypes = 0; + } + + /* count the number of commas */ + for (curr = enctypes; curr && *curr != '\0'; curr = ++comma) { + comma = strchr(curr, ','); + if (comma != NULL) + n++; + else + break; + } + /* If no more commas and we're not at the end, there's one more value */ + if (*curr != '\0') + n++; + + /* Empty string, return an error */ + if (n == 0) + return ENOENT; + + /* Allocate space for enctypes array */ + if ((krb5_enctypes = (int *) calloc(n, sizeof(int))) == NULL) { + return ENOMEM; + } + + /* Now parse each value into the array */ + for (curr = enctypes, i = 0; curr && *curr != '\0'; curr = ++comma) { + krb5_enctypes[i++] = atoi(curr); + comma = strchr(curr, ','); + if (comma == NULL) + break; + } + + num_krb5_enctypes = n; + if (cached_types = malloc(strlen(enctypes)+1)) + strcpy(cached_types, enctypes); + + return 0; +} + static int do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd, gss_buffer_desc *context_token) @@ -894,6 +965,7 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, char **ccname; char **dirname; int create_resp = -1; + int err, downcall_err = -EACCES; printerr(1, "handling krb5 upcall (%s)\n", clp->dirname); @@ -934,7 +1006,10 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, service == NULL)) { /* Tell krb5 gss which credentials cache to use */ for (dirname = ccachesearch; *dirname != NULL; dirname++) { - if (gssd_setup_krb5_user_gss_ccache(uid, clp->servername, *dirname) == 0) + err = gssd_setup_krb5_user_gss_ccache(uid, clp->servername, *dirname); + if (err == -EKEYEXPIRED) + downcall_err = -EKEYEXPIRED; + else if (!err) create_resp = create_auth_rpc_client(clp, &rpc_clnt, &auth, uid, AUTHTYPE_KRB5); if (create_resp == 0) @@ -1024,7 +1099,7 @@ out: return; out_return_error: - do_error_downcall(fd, uid, -1); + do_error_downcall(fd, uid, downcall_err); goto out; } @@ -1114,11 +1189,12 @@ handle_gssd_upcall(struct clnt_info *clp) { uid_t uid; char *lbuf = NULL; - int lbuflen = 0; + int lbuflen = 0, code; char *p; char *mech = NULL; char *target = NULL; char *service = NULL; + char *enctypes = NULL; printerr(1, "handling gssd upcall (%s)\n", clp->dirname); @@ -1162,6 +1238,23 @@ handle_gssd_upcall(struct clnt_info *clp) goto out; } + /* read supported encryption types if supplied */ + if ((p = strstr(lbuf, "enctypes=")) != NULL) { + enctypes = malloc(lbuflen); + if (!enctypes) + goto out; + if (sscanf(p, "enctypes=%s", enctypes) != 1) { + printerr(0, "WARNING: handle_gssd_upcall: " + "failed to parse target name " + "in upcall string '%s'\n", lbuf); + goto out; + } + if (parse_enctypes(enctypes) != 0) { + printerr(0, "WARNING: handle_gssd_upcall: " + "parsing encryption types failed: errno %d\n", code); + } + } + /* read target name */ if ((p = strstr(lbuf, "target=")) != NULL) { target = malloc(lbuflen); @@ -1208,6 +1301,7 @@ handle_gssd_upcall(struct clnt_info *clp) out: free(lbuf); free(mech); + free(enctypes); free(target); free(service); return;