static krb5_error_code gethostlist(krb5_context context, const char *realm, unsigned int type, char ***hostlist) { krb5_error_code ret; int nhost = 0; krb5_krbhst_handle handle; char host[MAXHOSTNAMELEN]; krb5_krbhst_info *hostinfo; ret = krb5_krbhst_init(context, realm, type, &handle); if (ret) return ret; while(krb5_krbhst_next(context, handle, &hostinfo) == 0) nhost++; if(nhost == 0) return KRB5_KDC_UNREACH; *hostlist = calloc(nhost + 1, sizeof(**hostlist)); if(*hostlist == NULL) { krb5_krbhst_free(context, handle); return ENOMEM; } krb5_krbhst_reset(context, handle); nhost = 0; while(krb5_krbhst_next_as_string(context, handle, host, sizeof(host)) == 0) { if(((*hostlist)[nhost++] = strdup(host)) == NULL) { krb5_free_krbhst(context, *hostlist); krb5_krbhst_free(context, handle); return ENOMEM; } } (*hostlist)[nhost++] = NULL; krb5_krbhst_free(context, handle); return 0; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_sendto (krb5_context context, const krb5_data *send_data, krb5_krbhst_handle handle, krb5_data *receive) { krb5_error_code ret; krb5_socket_t fd; size_t i; krb5_data_zero(receive); for (i = 0; i < context->max_retries; ++i) { krb5_krbhst_info *hi; while (krb5_krbhst_next(context, handle, &hi) == 0) { struct addrinfo *ai, *a; _krb5_debug(context, 2, "trying to communicate with host %s in realm %s", hi->hostname, _krb5_krbhst_get_realm(handle)); if (context->send_to_kdc) { struct send_to_kdc *s = context->send_to_kdc; ret = (*s->func)(context, s->data, hi, context->kdc_timeout, send_data, receive); if (ret == 0 && receive->length != 0) goto out; continue; } ret = send_via_plugin(context, hi, context->kdc_timeout, send_data, receive); if (ret == 0 && receive->length != 0) goto out; else if (ret != KRB5_PLUGIN_NO_HANDLE) continue; if(hi->proto == KRB5_KRBHST_HTTP && context->http_proxy) { if (send_via_proxy (context, hi, send_data, receive) == 0) { ret = 0; goto out; } continue; } ret = krb5_krbhst_get_addrinfo(context, hi, &ai); if (ret) continue; for (a = ai; a != NULL; a = a->ai_next) { fd = socket (a->ai_family, a->ai_socktype | SOCK_CLOEXEC, a->ai_protocol); if (rk_IS_BAD_SOCKET(fd)) continue; rk_cloexec(fd); if (timed_connect (fd, a, context->kdc_timeout) < 0) { rk_closesocket (fd); continue; } switch (hi->proto) { case KRB5_KRBHST_HTTP : ret = send_and_recv_http(fd, context->kdc_timeout, "", send_data, receive); break; case KRB5_KRBHST_TCP : ret = send_and_recv_tcp (fd, context->kdc_timeout, send_data, receive); break; case KRB5_KRBHST_UDP : ret = send_and_recv_udp (fd, context->kdc_timeout, send_data, receive); break; } rk_closesocket (fd); if(ret == 0 && receive->length != 0) goto out; } } krb5_krbhst_reset(context, handle); } krb5_clear_error_message (context); ret = KRB5_KDC_UNREACH; out: _krb5_debug(context, 2, "result of trying to talk to realm %s = %d", _krb5_krbhst_get_realm(handle), ret); return ret; }
static krb5_error_code change_password_loop (krb5_context context, krb5_creds *creds, krb5_principal targprinc, char *newpw, int *result_code, krb5_data *result_code_string, krb5_data *result_string, struct kpwd_proc *proc) { krb5_error_code ret; krb5_auth_context auth_context = NULL; krb5_krbhst_handle handle = NULL; krb5_krbhst_info *hi; int sock; int i; int done = 0; krb5_realm realm = creds->client->realm; ret = krb5_auth_con_init (context, &auth_context); if (ret) return ret; krb5_auth_con_setflags (context, auth_context, KRB5_AUTH_CONTEXT_DO_SEQUENCE); ret = krb5_krbhst_init (context, realm, KRB5_KRBHST_CHANGEPW, &handle); if (ret) goto out; while (!done && (ret = krb5_krbhst_next(context, handle, &hi)) == 0) { struct addrinfo *ai, *a; int is_stream; switch (hi->proto) { case KRB5_KRBHST_UDP: if ((proc->flags & SUPPORT_UDP) == 0) continue; is_stream = 0; break; case KRB5_KRBHST_TCP: if ((proc->flags & SUPPORT_TCP) == 0) continue; is_stream = 1; break; default: continue; } ret = krb5_krbhst_get_addrinfo(context, hi, &ai); if (ret) continue; for (a = ai; !done && a != NULL; a = a->ai_next) { int replied = 0; sock = socket (a->ai_family, a->ai_socktype, a->ai_protocol); if (sock < 0) continue; ret = connect(sock, a->ai_addr, a->ai_addrlen); if (ret < 0) { close (sock); goto out; } ret = krb5_auth_con_genaddrs (context, auth_context, sock, KRB5_AUTH_CONTEXT_GENERATE_LOCAL_ADDR); if (ret) { close (sock); goto out; } for (i = 0; !done && i < 5; ++i) { fd_set fdset; struct timeval tv; if (!replied) { replied = 0; ret = (*proc->send_req) (context, &auth_context, creds, targprinc, is_stream, sock, newpw, hi->hostname); if (ret) { close(sock); goto out; } } if (sock >= FD_SETSIZE) { krb5_set_error_string(context, "fd %d too large", sock); ret = ERANGE; close (sock); goto out; } FD_ZERO(&fdset); FD_SET(sock, &fdset); tv.tv_usec = 0; tv.tv_sec = 1 + (1 << i); ret = select (sock + 1, &fdset, NULL, NULL, &tv); if (ret < 0 && errno != EINTR) { close(sock); goto out; } if (ret == 1) { ret = (*proc->process_rep) (context, auth_context, is_stream, sock, result_code, result_code_string, result_string, hi->hostname); if (ret == 0) done = 1; else if (i > 0 && ret == KRB5KRB_AP_ERR_MUT_FAIL) replied = 1; } else { ret = KRB5_KDC_UNREACH; } } close (sock); } } out: krb5_krbhst_free (context, handle); krb5_auth_con_free (context, auth_context); if (done) return 0; else { if (ret == KRB5_KDC_UNREACH) { krb5_set_error_string(context, "unable to reach any changepw server " " in realm %s", realm); *result_code = KRB5_KPASSWD_HARDERROR; } return ret; } }
krb5_error_code KRB5_LIB_FUNCTION krb5_sendto (krb5_context context, const krb5_data *send_data, krb5_krbhst_handle handle, krb5_data *receive) { krb5_error_code ret; int fd; int i; krb5_data_zero(receive); for (i = 0; i < context->max_retries; ++i) { krb5_krbhst_info *hi; while (krb5_krbhst_next(context, handle, &hi) == 0) { struct addrinfo *ai, *a; if (context->send_to_kdc) { struct send_to_kdc *s = context->send_to_kdc; ret = (*s->func)(context, s->data, hi, send_data, receive); if (ret == 0 && receive->length != 0) goto out; continue; } if(hi->proto == KRB5_KRBHST_HTTP && context->http_proxy) { if (send_via_proxy (context, hi, send_data, receive) == 0) { ret = 0; goto out; } continue; } ret = krb5_krbhst_get_addrinfo(context, hi, &ai); if (ret) continue; for (a = ai; a != NULL; a = a->ai_next) { fd = socket (a->ai_family, a->ai_socktype, a->ai_protocol); if (fd < 0) continue; if (connect (fd, a->ai_addr, a->ai_addrlen) < 0) { close (fd); continue; } switch (hi->proto) { case KRB5_KRBHST_HTTP : ret = send_and_recv_http(fd, context->kdc_timeout, "", send_data, receive); break; case KRB5_KRBHST_TCP : ret = send_and_recv_tcp (fd, context->kdc_timeout, send_data, receive); break; case KRB5_KRBHST_UDP : ret = send_and_recv_udp (fd, context->kdc_timeout, send_data, receive); break; } close (fd); if(ret == 0 && receive->length != 0) goto out; } } krb5_krbhst_reset(context, handle); } krb5_clear_error_string (context); ret = KRB5_KDC_UNREACH; out: return ret; }