/* Dispatch routine for set/change password */ void dispatch(void *handle, struct sockaddr *local_saddr, const krb5_fulladdr *remote_faddr, krb5_data *request, int is_tcp, verto_ctx *vctx, loop_respond_fn respond, void *arg) { krb5_error_code ret; krb5_keytab kt = NULL; kadm5_server_handle_t server_handle = (kadm5_server_handle_t)handle; krb5_fulladdr local_faddr; krb5_address **local_kaddrs = NULL, local_kaddr_buf; krb5_data *response = NULL; if (local_saddr == NULL) { ret = krb5_os_localaddr(server_handle->context, &local_kaddrs); if (ret != 0) goto egress; local_faddr.address = local_kaddrs[0]; local_faddr.port = 0; } else { local_faddr.address = &local_kaddr_buf; init_addr(&local_faddr, local_saddr); } ret = krb5_kt_resolve(server_handle->context, "KDB:", &kt); if (ret != 0) { krb5_klog_syslog(LOG_ERR, _("chpw: Couldn't open admin keytab %s"), krb5_get_error_message(server_handle->context, ret)); goto egress; } response = k5alloc(sizeof(krb5_data), &ret); if (response == NULL) goto egress; ret = process_chpw_request(server_handle->context, handle, server_handle->params.realm, kt, &local_faddr, remote_faddr, request, response); egress: if (ret) krb5_free_data(server_handle->context, response); krb5_free_addresses(server_handle->context, local_kaddrs); krb5_kt_close(server_handle->context, kt); (*respond)(arg, ret, ret == 0 ? response : NULL); }
krb5_get_init_creds_opt *kim_options_init_cred_options (kim_options in_options) { kim_error err = KIM_NO_ERROR; krb5_address **addresses = NULL; if (!err && !in_options) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err && !in_options->init_cred_context) { err = krb5_error (NULL, krb5_init_context (&in_options->init_cred_context)); } if (!err && !in_options->addressless) { err = krb5_error (in_options->init_cred_context, krb5_os_localaddr (in_options->init_cred_context, &addresses)); } if (!err && !in_options->init_cred_options) { err = krb5_error (in_options->init_cred_context, krb5_get_init_creds_opt_alloc (in_options->init_cred_context, &in_options->init_cred_options)); } if (!err) { krb5_get_init_creds_opt_set_tkt_life (in_options->init_cred_options, in_options->lifetime); if (in_options->renewal_lifetime || in_options->renewable) krb5_get_init_creds_opt_set_renew_life (in_options->init_cred_options, in_options->renewal_lifetime); krb5_get_init_creds_opt_set_forwardable (in_options->init_cred_options, in_options->forwardable); krb5_get_init_creds_opt_set_proxiable (in_options->init_cred_options, in_options->proxiable); krb5_get_init_creds_opt_set_address_list (in_options->init_cred_options, addresses); addresses = NULL; } if (addresses) { krb5_free_addresses (in_options->init_cred_context, addresses); } return !check_error (err) ? in_options->init_cred_options : NULL; }
/* * Solaris Kerberos: * Try to determine if this is the master KDC for a given realm */ kadm5_ret_t kadm5_is_master(krb5_context context, const char *realm, krb5_boolean *is_master) { kadm5_ret_t ret; char *admin_host = NULL; krb5_address **tmp_addr, **master_addr = NULL; krb5_address **local_addr = NULL; if (is_master) *is_master = FALSE; else return (KADM5_FAILURE); /* Locate the master KDC */ if (ret = kadm5_get_master(context, realm, &admin_host)) return (ret); if (ret = krb5_os_hostaddr(context, admin_host, &master_addr)) { free(admin_host); return (ret); } /* Get the local addresses */ if (ret = krb5_os_localaddr(context, &local_addr)) { krb5_free_addresses(context, master_addr); free(admin_host); return (ret); } /* Compare them */ for (tmp_addr = master_addr; *tmp_addr; tmp_addr++) { if (krb5_address_search(context, *tmp_addr, local_addr)) { *is_master = TRUE; break; } } krb5_free_addresses(context, local_addr); krb5_free_addresses(context, master_addr); free(admin_host); return (KADM5_OK); }
static krb5_error_code krb5_rd_priv_basic(krb5_context context, const krb5_data *inbuf, const krb5_keyblock *keyblock, const krb5_address *local_addr, const krb5_address *remote_addr, krb5_pointer i_vector, krb5_replay_data *replaydata, krb5_data *outbuf) { krb5_error_code retval; krb5_priv * privmsg; krb5_data scratch; krb5_priv_enc_part * privmsg_enc_part; size_t blocksize; krb5_data ivdata; if (!krb5_is_krb_priv(inbuf)) return KRB5KRB_AP_ERR_MSG_TYPE; /* decode private message */ if ((retval = decode_krb5_priv(inbuf, &privmsg))) return retval; if (i_vector) { if ((retval = krb5_c_block_size(context, keyblock->enctype, &blocksize))) goto cleanup_privmsg; ivdata.length = blocksize; ivdata.data = i_vector; } scratch.length = privmsg->enc_part.ciphertext.length; if (!(scratch.data = malloc(scratch.length))) { retval = ENOMEM; goto cleanup_privmsg; } if ((retval = krb5_c_decrypt(context, keyblock, KRB5_KEYUSAGE_KRB_PRIV_ENCPART, i_vector?&ivdata:0, &privmsg->enc_part, &scratch))) goto cleanup_scratch; /* now decode the decrypted stuff */ if ((retval = decode_krb5_enc_priv_part(&scratch, &privmsg_enc_part))) goto cleanup_scratch; if (!krb5_address_compare(context,remote_addr,privmsg_enc_part->s_address)){ retval = KRB5KRB_AP_ERR_BADADDR; goto cleanup_data; } if (privmsg_enc_part->r_address) { if (local_addr) { if (!krb5_address_compare(context, local_addr, privmsg_enc_part->r_address)) { retval = KRB5KRB_AP_ERR_BADADDR; goto cleanup_data; } } else { krb5_address **our_addrs; if ((retval = krb5_os_localaddr(context, &our_addrs))) { goto cleanup_data; } if (!krb5_address_search(context, privmsg_enc_part->r_address, our_addrs)) { krb5_free_addresses(context, our_addrs); retval = KRB5KRB_AP_ERR_BADADDR; goto cleanup_data; } krb5_free_addresses(context, our_addrs); } } replaydata->timestamp = privmsg_enc_part->timestamp; replaydata->usec = privmsg_enc_part->usec; replaydata->seq = privmsg_enc_part->seq_number; /* everything is ok - return data to the user */ *outbuf = privmsg_enc_part->user_data; retval = 0; cleanup_data:; if (retval == 0) privmsg_enc_part->user_data.data = 0; krb5_free_priv_enc_part(context, privmsg_enc_part); cleanup_scratch:; memset(scratch.data, 0, scratch.length); free(scratch.data); cleanup_privmsg:; free(privmsg->enc_part.ciphertext.data); free(privmsg); return retval; }
/* returns boolean */ static int k5_kinit(struct k_opts *opts, struct k5_data *k5, struct user_info *u_info) { char *doing; int notix = 1; krb5_keytab keytab = 0; krb5_creds my_creds; krb5_error_code code = 0; krb5_get_init_creds_opt options; krb5_address **addresses; krb5_get_init_creds_opt_init(&options); g_memset(&my_creds, 0, sizeof(my_creds)); /* From this point on, we can goto cleanup because my_creds is initialized. */ if (opts->lifetime) { krb5_get_init_creds_opt_set_tkt_life(&options, opts->lifetime); } if (opts->rlife) { krb5_get_init_creds_opt_set_renew_life(&options, opts->rlife); } if (opts->forwardable) { krb5_get_init_creds_opt_set_forwardable(&options, 1); } if (opts->not_forwardable) { krb5_get_init_creds_opt_set_forwardable(&options, 0); } if (opts->proxiable) { krb5_get_init_creds_opt_set_proxiable(&options, 1); } if (opts->not_proxiable) { krb5_get_init_creds_opt_set_proxiable(&options, 0); } if (opts->addresses) { addresses = NULL; code = krb5_os_localaddr(k5->ctx, &addresses); if (code != 0) { g_printf("krb5_os_localaddr failed in k5_kinit\n"); goto cleanup; } krb5_get_init_creds_opt_set_address_list(&options, addresses); } if (opts->no_addresses) { krb5_get_init_creds_opt_set_address_list(&options, NULL); } if ((opts->action == INIT_KT) && opts->keytab_name) { code = krb5_kt_resolve(k5->ctx, opts->keytab_name, &keytab); if (code != 0) { g_printf("krb5_kt_resolve failed in k5_kinit\n"); goto cleanup; } } switch (opts->action) { case INIT_PW: code = krb5_get_init_creds_password(k5->ctx, &my_creds, k5->me, 0, kinit_prompter, u_info, opts->starttime, opts->service_name, &options); break; case INIT_KT: code = krb5_get_init_creds_keytab(k5->ctx, &my_creds, k5->me, keytab, opts->starttime, opts->service_name, &options); break; case VALIDATE: code = krb5_get_validated_creds(k5->ctx, &my_creds, k5->me, k5->cc, opts->service_name); break; case RENEW: code = krb5_get_renewed_creds(k5->ctx, &my_creds, k5->me, k5->cc, opts->service_name); break; } if (code != 0) { doing = 0; switch (opts->action) { case INIT_PW: case INIT_KT: doing = "getting initial credentials"; break; case VALIDATE: doing = "validating credentials"; break; case RENEW: doing = "renewing credentials"; break; } if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) { g_printf("sesman: Password incorrect while %s in k5_kinit\n", doing); } else { g_printf("sesman: error while %s in k5_kinit\n", doing); } goto cleanup; } if (!opts->lifetime) { /* We need to figure out what lifetime to use for Kerberos 4. */ opts->lifetime = my_creds.times.endtime - my_creds.times.authtime; } code = krb5_cc_initialize(k5->ctx, k5->cc, k5->me); if (code != 0) { g_printf("krb5_cc_initialize failed in k5_kinit\n"); goto cleanup; } code = krb5_cc_store_cred(k5->ctx, k5->cc, &my_creds); if (code != 0) { g_printf("krb5_cc_store_cred failed in k5_kinit\n"); goto cleanup; } notix = 0; cleanup: if (my_creds.client == k5->me) { my_creds.client = 0; } krb5_free_cred_contents(k5->ctx, &my_creds); if (keytab) { krb5_kt_close(k5->ctx, keytab); } return notix ? 0 : 1; }
/* * Verify the sender and receiver addresses from a KRB-SAFE or KRB-PRIV message * against the auth context. msg_r_addr may be NULL, but msg_s_addr must not * be. The auth context's remote addr must be set. */ krb5_error_code k5_privsafe_check_addrs(krb5_context context, krb5_auth_context ac, krb5_address *msg_s_addr, krb5_address *msg_r_addr) { krb5_error_code ret = 0; krb5_address **our_addrs = NULL; const krb5_address *local_addr, *remote_addr; krb5_address local_fulladdr, remote_fulladdr; local_fulladdr.contents = remote_fulladdr.contents = NULL; /* Determine the remote comparison address. */ if (ac->remote_port != NULL) { ret = krb5_make_fulladdr(context, ac->remote_addr, ac->remote_port, &remote_fulladdr); if (ret) goto cleanup; remote_addr = &remote_fulladdr; } else remote_addr = ac->remote_addr; /* Determine the local comparison address (possibly NULL). */ if (ac->local_addr != NULL) { if (ac->local_port != NULL) { ret = krb5_make_fulladdr(context, ac->local_addr, ac->local_port, &local_fulladdr); if (ret) goto cleanup; local_addr = &local_fulladdr; } else local_addr = ac->local_addr; } else local_addr = NULL; /* Check the remote address against the message's sender address. */ if (!krb5_address_compare(context, remote_addr, msg_s_addr)) { ret = KRB5KRB_AP_ERR_BADADDR; goto cleanup; } /* Receiver address is optional; only check it if supplied. */ if (msg_r_addr == NULL) goto cleanup; /* Check the message's receiver address against the local address, or * against all local addresses if no specific local address is set. */ if (local_addr != NULL) { if (!krb5_address_compare(context, local_addr, msg_r_addr)) { ret = KRB5KRB_AP_ERR_BADADDR; goto cleanup; } } else { ret = krb5_os_localaddr(context, &our_addrs); if (ret) goto cleanup; if (!krb5_address_search(context, msg_r_addr, our_addrs)) { ret = KRB5KRB_AP_ERR_BADADDR; goto cleanup; } } cleanup: free(local_fulladdr.contents); free(remote_fulladdr.contents); krb5_free_addresses(context, our_addrs); return ret; }
static int kpasswd_sendto_msg_callback(SOCKET fd, void *data, krb5_data *message) { krb5_error_code code = 0; struct sockaddr_storage local_addr; krb5_address local_kaddr; struct sendto_callback_context *ctx = data; GETSOCKNAME_ARG3_TYPE addrlen; krb5_data output; memset (message, 0, sizeof(krb5_data)); /* * We need the local addr from the connection socket */ addrlen = sizeof(local_addr); if (getsockname(fd, ss2sa(&local_addr), &addrlen) < 0) { code = SOCKET_ERRNO; goto cleanup; } /* some brain-dead OS's don't return useful information from * the getsockname call. Namely, windows and solaris. */ if (local_addr.ss_family == AF_INET && ss2sin(&local_addr)->sin_addr.s_addr != 0) { local_kaddr.addrtype = ADDRTYPE_INET; local_kaddr.length = sizeof(ss2sin(&local_addr)->sin_addr); local_kaddr.contents = (krb5_octet *) &ss2sin(&local_addr)->sin_addr; } else if (local_addr.ss_family == AF_INET6 && memcmp(ss2sin6(&local_addr)->sin6_addr.s6_addr, in6addr_any.s6_addr, sizeof(in6addr_any.s6_addr)) != 0) { local_kaddr.addrtype = ADDRTYPE_INET6; local_kaddr.length = sizeof(ss2sin6(&local_addr)->sin6_addr); local_kaddr.contents = (krb5_octet *) &ss2sin6(&local_addr)->sin6_addr; } else { krb5_address **addrs; code = krb5_os_localaddr(ctx->context, &addrs); if (code) goto cleanup; local_kaddr.magic = addrs[0]->magic; local_kaddr.addrtype = addrs[0]->addrtype; local_kaddr.length = addrs[0]->length; local_kaddr.contents = k5memdup(addrs[0]->contents, addrs[0]->length, &code); krb5_free_addresses(ctx->context, addrs); if (local_kaddr.contents == NULL) goto cleanup; } /* * TBD: Does this tamper w/ the auth context in such a way * to break us? Yes - provide 1 per conn-state / host... */ if ((code = krb5_auth_con_setaddrs(ctx->context, ctx->auth_context, &local_kaddr, NULL))) goto cleanup; ctx->auth_context->remote_seq_number = ctx->remote_seq_num; ctx->auth_context->local_seq_number = ctx->local_seq_num; if (ctx->set_password_for) code = krb5int_mk_setpw_req(ctx->context, ctx->auth_context, &ctx->ap_req, ctx->set_password_for, ctx->newpw, &output); else code = krb5int_mk_chpw_req(ctx->context, ctx->auth_context, &ctx->ap_req, ctx->newpw, &output); if (code) goto cleanup; message->length = output.length; message->data = output.data; cleanup: return code; }
int Condor_Auth_Kerberos :: authenticate_client_kerberos() { krb5_error_code code; krb5_flags flags; krb5_data request; int reply, rc = FALSE; request.data = 0; request.length = 0; //------------------------------------------ // Set up the flags //------------------------------------------ flags = AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY; //------------------------------------------ // Load local addresses //------------------------------------------ assert(creds_); if (creds_->addresses == NULL) { dprintf ( D_SECURITY, "KERBEROS: creds_->addresses == NULL\n"); if ((code = krb5_os_localaddr(krb_context_, &(creds_->addresses)))) { goto error; } } dprintf_krb5_principal ( D_FULLDEBUG, "KERBEROS: creds_->client is '%s'\n", creds_->client); dprintf_krb5_principal ( D_FULLDEBUG, "KERBEROS: creds_->server is '%s'\n", creds_->server); //------------------------------------------ // Let's create the KRB_AP_REQ message //------------------------------------------ if ((code = krb5_mk_req_extended(krb_context_, &auth_context_, flags, 0, creds_, &request))) { goto error; } // Send out the request if ((reply = send_request(&request)) != KERBEROS_MUTUAL) { dprintf( D_ALWAYS, "KERBEROS: Could not authenticate!\n" ); return FALSE; } //------------------------------------------ // Now, mutual authenticate //------------------------------------------ reply = client_mutual_authenticate(); switch (reply) { case KERBEROS_DENY: dprintf( D_ALWAYS, "KERBEROS: Authentication failed\n" ); return FALSE; break; // unreachable case KERBEROS_FORWARD: // We need to forward the credentials // We could do a fast forwarding (i.e stashing, if client/server // are located on the same machine. However, I want to keep the // forwarding mechanism clean, so, we use krb5_fwd_tgt_creds // regardless of where client/server are located // This is an implict GRANT //if (forward_tgt_creds(creds_, 0)) { // dprintf(D_ALWAYS,"KERBEROS: Unable to forward credentials\n"); //return FALSE; // } case KERBEROS_GRANT: break; default: dprintf( D_ALWAYS, "KERBEROS: Response is invalid\n" ); break; } //------------------------------------------ // Success, do some cleanup //------------------------------------------ setRemoteAddress(); //------------------------------------------ // Store the session key for encryption //------------------------------------------ if ((code = krb5_copy_keyblock(krb_context_, &(creds_->keyblock), &sessionKey_))) { goto error; } rc = TRUE; goto cleanup; error: dprintf( D_ALWAYS, "KERBEROS: %s\n", error_message(code) ); // Abort mySock_->encode(); reply = KERBEROS_ABORT; if (!mySock_->code(reply) || !mySock_->end_of_message()) { dprintf( D_ALWAYS, "KERBEROS: Failed to send ABORT message.\n"); } rc = FALSE; cleanup: if (creds_) { krb5_free_creds(krb_context_, creds_); } if (request.data) { free(request.data); } return rc; }
static krb5_error_code process_chpw_request(krb5_context context, void *server_handle, char *realm, int s, krb5_keytab keytab, struct sockaddr_in *sin, krb5_data *req, krb5_data *rep) { krb5_error_code ret; char *ptr; int plen, vno; krb5_address local_kaddr, remote_kaddr; int allocated_mem = 0; krb5_data ap_req, ap_rep; krb5_auth_context auth_context; krb5_principal changepw; krb5_ticket *ticket; krb5_data cipher, clear; struct sockaddr local_addr, remote_addr; int addrlen; krb5_replay_data replay; krb5_error krberror; int numresult; char strresult[1024]; ret = 0; rep->length = 0; auth_context = NULL; changepw = NULL; ap_rep.length = 0; ap_rep.data = NULL; ticket = NULL; clear.length = 0; clear.data = NULL; cipher.length = 0; cipher.data = NULL; if (req->length < 4) { /* * either this, or the server is printing bad messages, * or the caller passed in garbage */ ret = KRB5KRB_AP_ERR_MODIFIED; numresult = KRB5_KPASSWD_MALFORMED; (void) strlcpy(strresult, "Request was truncated", sizeof (strresult)); goto chpwfail; } ptr = req->data; /* * Verify length */ plen = (*ptr++ & 0xff); plen = (plen<<8) | (*ptr++ & 0xff); if (plen != req->length) return (KRB5KRB_AP_ERR_MODIFIED); /* * Verify version number */ vno = (*ptr++ & 0xff); vno = (vno<<8) | (*ptr++ & 0xff); if (vno != 1) { ret = KRB5KDC_ERR_BAD_PVNO; numresult = KRB5_KPASSWD_MALFORMED; (void) snprintf(strresult, sizeof (strresult), "Request contained unknown protocol version number %d", vno); goto chpwfail; } /* * Read, check ap-req length */ ap_req.length = (*ptr++ & 0xff); ap_req.length = (ap_req.length<<8) | (*ptr++ & 0xff); if (ptr + ap_req.length >= req->data + req->length) { ret = KRB5KRB_AP_ERR_MODIFIED; numresult = KRB5_KPASSWD_MALFORMED; (void) strlcpy(strresult, "Request was truncated in AP-REQ", sizeof (strresult)); goto chpwfail; } /* * Verify ap_req */ ap_req.data = ptr; ptr += ap_req.length; if (ret = krb5_auth_con_init(context, &auth_context)) { krb5_klog_syslog(LOG_ERR, gettext("Change password request failed. " "Failed initializing auth context: %s"), error_message(ret)); numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Failed initializing auth context", sizeof (strresult)); goto chpwfail; } if (ret = krb5_auth_con_setflags(context, auth_context, KRB5_AUTH_CONTEXT_DO_SEQUENCE)) { krb5_klog_syslog(LOG_ERR, gettext("Change password request failed. " "Failed setting auth " "context flags: %s"), error_message(ret)); numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Failed initializing auth context", sizeof (strresult)); goto chpwfail; } if (ret = krb5_build_principal(context, &changepw, strlen(realm), realm, "kadmin", "changepw", NULL)) { krb5_klog_syslog(LOG_ERR, gettext("Change password request failed " "Failed to build kadmin/changepw " "principal: %s"), error_message(ret)); numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Failed building kadmin/changepw principal", sizeof (strresult)); goto chpwfail; } ret = krb5_rd_req(context, &auth_context, &ap_req, changepw, keytab, NULL, &ticket); if (ret) { char kt_name[MAX_KEYTAB_NAME_LEN]; if (krb5_kt_get_name(context, keytab, kt_name, sizeof (kt_name))) strncpy(kt_name, "default keytab", sizeof (kt_name)); switch (ret) { case KRB5_KT_NOTFOUND: krb5_klog_syslog(LOG_ERR, gettext("Change password request failed because " "keytab entry \"kadmin/changepw\" " "is missing from \"%s\""), kt_name); break; case ENOENT: krb5_klog_syslog(LOG_ERR, gettext("Change password request failed because " "keytab file \"%s\" does not exist"), kt_name); break; default: krb5_klog_syslog(LOG_ERR, gettext("Change password request failed. " "Failed to parse Kerberos AP_REQ message: %s"), error_message(ret)); } numresult = KRB5_KPASSWD_AUTHERROR; (void) strlcpy(strresult, "Failed reading application request", sizeof (strresult)); goto chpwfail; } /* * Set up address info */ addrlen = sizeof (local_addr); if (getsockname(s, &local_addr, &addrlen) < 0) { ret = errno; numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Failed getting server internet address", sizeof (strresult)); goto chpwfail; } /* * Some brain-dead OS's don't return useful information from * the getsockname call. Namely, windows and solaris. */ if (((struct sockaddr_in *)&local_addr)->sin_addr.s_addr != 0) { local_kaddr.addrtype = ADDRTYPE_INET; local_kaddr.length = sizeof (((struct sockaddr_in *) &local_addr)->sin_addr); /* CSTYLED */ local_kaddr.contents = (krb5_octet *) &(((struct sockaddr_in *)&local_addr)->sin_addr); } else { krb5_address **addrs; krb5_os_localaddr(context, &addrs); local_kaddr.magic = addrs[0]->magic; local_kaddr.addrtype = addrs[0]->addrtype; local_kaddr.length = addrs[0]->length; if ((local_kaddr.contents = malloc(addrs[0]->length)) == 0) { ret = errno; numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Malloc failed for local_kaddr", sizeof (strresult)); goto chpwfail; } (void) memcpy(local_kaddr.contents, addrs[0]->contents, addrs[0]->length); allocated_mem++; krb5_free_addresses(context, addrs); } addrlen = sizeof (remote_addr); if (getpeername(s, &remote_addr, &addrlen) < 0) { ret = errno; numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Failed getting client internet address", sizeof (strresult)); goto chpwfail; } remote_kaddr.addrtype = ADDRTYPE_INET; remote_kaddr.length = sizeof (((struct sockaddr_in *) &remote_addr)->sin_addr); /* CSTYLED */ remote_kaddr.contents = (krb5_octet *) &(((struct sockaddr_in *)&remote_addr)->sin_addr); remote_kaddr.addrtype = ADDRTYPE_INET; remote_kaddr.length = sizeof (sin->sin_addr); remote_kaddr.contents = (krb5_octet *) &sin->sin_addr; /* * mk_priv requires that the local address be set. * getsockname is used for this. rd_priv requires that the * remote address be set. recvfrom is used for this. If * rd_priv is given a local address, and the message has the * recipient addr in it, this will be checked. However, there * is simply no way to know ahead of time what address the * message will be delivered *to*. Therefore, it is important * that either no recipient address is in the messages when * mk_priv is called, or that no local address is passed to * rd_priv. Both is a better idea, and I have done that. In * summary, when mk_priv is called, *only* a local address is * specified. when rd_priv is called, *only* a remote address * is specified. Are we having fun yet? */ if (ret = krb5_auth_con_setaddrs(context, auth_context, NULL, &remote_kaddr)) { numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Failed storing client internet address", sizeof (strresult)); goto chpwfail; } /* * Verify that this is an AS_REQ ticket */ if (!(ticket->enc_part2->flags & TKT_FLG_INITIAL)) { numresult = KRB5_KPASSWD_AUTHERROR; (void) strlcpy(strresult, "Ticket must be derived from a password", sizeof (strresult)); goto chpwfail; } /* * Construct the ap-rep */ if (ret = krb5_mk_rep(context, auth_context, &ap_rep)) { numresult = KRB5_KPASSWD_AUTHERROR; (void) strlcpy(strresult, "Failed replying to application request", sizeof (strresult)); goto chpwfail; } /* * Decrypt the new password */ cipher.length = (req->data + req->length) - ptr; cipher.data = ptr; if (ret = krb5_rd_priv(context, auth_context, &cipher, &clear, &replay)) { numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Failed decrypting request", sizeof (strresult)); goto chpwfail; } /* * Change the password */ if ((ptr = (char *)malloc(clear.length + 1)) == NULL) { ret = errno; numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Malloc failed for ptr", sizeof (strresult)); goto chpwfail; } (void) memcpy(ptr, clear.data, clear.length); ptr[clear.length] = '\0'; ret = (kadm5_ret_t)kadm5_chpass_principal_util(server_handle, ticket->enc_part2->client, ptr, NULL, strresult, sizeof (strresult)); /* * Zap the password */ (void) memset(clear.data, 0, clear.length); (void) memset(ptr, 0, clear.length); if (clear.data != NULL) { krb5_xfree(clear.data); clear.data = NULL; } free(ptr); clear.length = 0; if (ret) { if ((ret != KADM5_PASS_Q_TOOSHORT) && (ret != KADM5_PASS_REUSE) && (ret != KADM5_PASS_Q_CLASS) && (ret != KADM5_PASS_Q_DICT) && (ret != KADM5_PASS_TOOSOON)) numresult = KRB5_KPASSWD_HARDERROR; else numresult = KRB5_KPASSWD_SOFTERROR; /* * strresult set by kadb5_chpass_principal_util() */ goto chpwfail; } /* * Success! */ numresult = KRB5_KPASSWD_SUCCESS; (void) strlcpy(strresult, "", sizeof (strresult)); chpwfail: clear.length = 2 + strlen(strresult); if (clear.data != NULL) { krb5_xfree(clear.data); clear.data = NULL; } if ((clear.data = (char *)malloc(clear.length)) == NULL) { ret = errno; numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Malloc failed for clear.data", sizeof (strresult)); } cipher.length = 0; if (ap_rep.length) { if (ret = krb5_auth_con_setaddrs(context, auth_context, &local_kaddr, NULL)) { numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Failed storing client and server internet addresses", sizeof (strresult)); } else { if (ret = krb5_mk_priv(context, auth_context, &clear, &cipher, &replay)) { numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Failed encrypting reply", sizeof (strresult)); } } } ptr = clear.data; *ptr++ = (numresult>>8) & 0xff; *ptr++ = numresult & 0xff; (void) memcpy(ptr, strresult, strlen(strresult)); /* * If no KRB-PRIV was constructed, then we need a KRB-ERROR. * If this fails, just bail. There's nothing else we can do. */ if (cipher.length == 0) { /* * Clear out ap_rep now, so that it won't be inserted * in the reply */ if (ap_rep.length) { if (ap_rep.data != NULL) krb5_xfree(ap_rep.data); ap_rep.data = NULL; ap_rep.length = 0; } krberror.ctime = 0; krberror.cusec = 0; krberror.susec = 0; if (ret = krb5_timeofday(context, &krberror.stime)) goto bailout; /* * This is really icky. but it's what all the other callers * to mk_error do. */ krberror.error = ret; krberror.error -= ERROR_TABLE_BASE_krb5; if (krberror.error < 0 || krberror.error > 128) krberror.error = KRB_ERR_GENERIC; krberror.client = NULL; if (ret = krb5_build_principal(context, &krberror.server, strlen(realm), realm, "kadmin", "changepw", NULL)) { goto bailout; } krberror.text.length = 0; krberror.e_data = clear; ret = krb5_mk_error(context, &krberror, &cipher); krb5_free_principal(context, krberror.server); if (ret) goto bailout; } /* * Construct the reply */ rep->length = 6 + ap_rep.length + cipher.length; if ((rep->data = (char *)malloc(rep->length)) == NULL) { ret = errno; goto bailout; } ptr = rep->data; /* * Length */ *ptr++ = (rep->length>>8) & 0xff; *ptr++ = rep->length & 0xff; /* * Version == 0x0001 big-endian */ *ptr++ = 0; *ptr++ = 1; /* * ap_rep length, big-endian */ *ptr++ = (ap_rep.length>>8) & 0xff; *ptr++ = ap_rep.length & 0xff; /* * ap-rep data */ if (ap_rep.length) { (void) memcpy(ptr, ap_rep.data, ap_rep.length); ptr += ap_rep.length; } /* * krb-priv or krb-error */ (void) memcpy(ptr, cipher.data, cipher.length); bailout: if (auth_context) krb5_auth_con_free(context, auth_context); if (changepw) krb5_free_principal(context, changepw); if (ap_rep.data != NULL) krb5_xfree(ap_rep.data); if (ticket) krb5_free_ticket(context, ticket); if (clear.data != NULL) krb5_xfree(clear.data); if (cipher.data != NULL) krb5_xfree(cipher.data); if (allocated_mem) krb5_xfree(local_kaddr.contents); return (ret); }