krb5_boolean KRB5_LIB_FUNCTION krb5_address_search(krb5_context context, const krb5_address *addr, const krb5_addresses *addrlist) { int i; for (i = 0; i < addrlist->len; ++i) if (krb5_address_compare (context, addr, &addrlist->val[i])) return TRUE; return FALSE; }
static krb5_error_code compare_addrs(krb5_context context, krb5_address *a, krb5_address *b, const char *message) { char a_str[64], b_str[64]; size_t len; if(krb5_address_compare (context, a, b)) return 0; krb5_print_address (a, a_str, sizeof(a_str), &len); krb5_print_address (b, b_str, sizeof(b_str), &len); krb5_set_error_message(context, KRB5KRB_AP_ERR_BADADDR, "%s: %s != %s", message, b_str, a_str); return KRB5KRB_AP_ERR_BADADDR; }
/* * if addr is listed in addrlist, or addrlist is null, return TRUE. * if not listed, return FALSE */ krb5_boolean krb5_address_search(krb5_context context, const krb5_address *addr, krb5_address *const *addrlist) { /* * Treat an address list containing only a NetBIOS address * as empty, because we presently have no way of associating * a client with its NetBIOS address. */ if (address_count(addrlist) == 1 && addrlist[0]->addrtype == ADDRTYPE_NETBIOS) return TRUE; if (!addrlist) return TRUE; for (; *addrlist; addrlist++) { if (krb5_address_compare(context, addr, *addrlist)) return TRUE; } return FALSE; }
krb5_error_code KRB5_LIB_FUNCTION krb5_rd_safe(krb5_context context, krb5_auth_context auth_context, const krb5_data *inbuf, krb5_data *outbuf, krb5_replay_data *outdata) { krb5_error_code ret; KRB_SAFE safe; size_t len; krb5_data_zero(outbuf); if ((auth_context->flags & (KRB5_AUTH_CONTEXT_RET_TIME | KRB5_AUTH_CONTEXT_RET_SEQUENCE))) { if (outdata == NULL) { krb5_set_error_message(context, KRB5_RC_REQUIRED, N_("rd_safe: need outdata " "to return data", "")); return KRB5_RC_REQUIRED; /* XXX better error, MIT returns this */ } /* if these fields are not present in the safe-part, silently return zero */ memset(outdata, 0, sizeof(*outdata)); } ret = decode_KRB_SAFE (inbuf->data, inbuf->length, &safe, &len); if (ret) return ret; if (safe.pvno != 5) { ret = KRB5KRB_AP_ERR_BADVERSION; krb5_clear_error_message (context); goto failure; } if (safe.msg_type != krb_safe) { ret = KRB5KRB_AP_ERR_MSG_TYPE; krb5_clear_error_message (context); goto failure; } if (!krb5_checksum_is_keyed(context, safe.cksum.cksumtype) || !krb5_checksum_is_collision_proof(context, safe.cksum.cksumtype)) { ret = KRB5KRB_AP_ERR_INAPP_CKSUM; krb5_clear_error_message (context); goto failure; } /* check sender address */ if (safe.safe_body.s_address && auth_context->remote_address && !krb5_address_compare (context, auth_context->remote_address, safe.safe_body.s_address)) { ret = KRB5KRB_AP_ERR_BADADDR; krb5_clear_error_message (context); goto failure; } /* check receiver address */ if (safe.safe_body.r_address && auth_context->local_address && !krb5_address_compare (context, auth_context->local_address, safe.safe_body.r_address)) { ret = KRB5KRB_AP_ERR_BADADDR; krb5_clear_error_message (context); goto failure; } /* check timestamp */ if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_TIME) { krb5_timestamp sec; krb5_timeofday (context, &sec); if (safe.safe_body.timestamp == NULL || safe.safe_body.usec == NULL || abs(*safe.safe_body.timestamp - sec) > context->max_skew) { ret = KRB5KRB_AP_ERR_SKEW; krb5_clear_error_message (context); goto failure; } } /* XXX - check replay cache */ /* check sequence number. since MIT krb5 cannot generate a sequence number of zero but instead generates no sequence number, we accept that */ if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) { if ((safe.safe_body.seq_number == NULL && auth_context->remote_seqnumber != 0) || (safe.safe_body.seq_number != NULL && *safe.safe_body.seq_number != auth_context->remote_seqnumber)) { ret = KRB5KRB_AP_ERR_BADORDER; krb5_clear_error_message (context); goto failure; } auth_context->remote_seqnumber++; } ret = verify_checksum (context, auth_context, &safe); if (ret) goto failure; outbuf->length = safe.safe_body.user_data.length; outbuf->data = malloc(outbuf->length); if (outbuf->data == NULL && outbuf->length != 0) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); krb5_data_zero(outbuf); goto failure; } memcpy (outbuf->data, safe.safe_body.user_data.data, outbuf->length); if ((auth_context->flags & (KRB5_AUTH_CONTEXT_RET_TIME | KRB5_AUTH_CONTEXT_RET_SEQUENCE))) { if(safe.safe_body.timestamp) outdata->timestamp = *safe.safe_body.timestamp; if(safe.safe_body.usec) outdata->usec = *safe.safe_body.usec; if(safe.safe_body.seq_number) outdata->seq = *safe.safe_body.seq_number; } failure: free_KRB_SAFE (&safe); return ret; }
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; }
/* * 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; }
krb5_boolean KRB5_CALLCONV krb5_creds_compare (krb5_context in_context, krb5_creds *in_creds, krb5_creds *in_compare_creds) { /* Set to 0 when we hit the first mismatch and then fall through */ int equal = 1; if (equal) { equal = krb5_principal_compare (in_context, in_creds->client, in_compare_creds->client); } if (equal) { equal = krb5_principal_compare (in_context, in_creds->server, in_compare_creds->server); } if (equal) { equal = (in_creds->keyblock.enctype == in_compare_creds->keyblock.enctype && in_creds->keyblock.length == in_compare_creds->keyblock.length && (!in_creds->keyblock.length || !memcmp (in_creds->keyblock.contents, in_compare_creds->keyblock.contents, in_creds->keyblock.length))); } if (equal) { equal = (in_creds->times.authtime == in_compare_creds->times.authtime && in_creds->times.starttime == in_compare_creds->times.starttime && in_creds->times.endtime == in_compare_creds->times.endtime && in_creds->times.renew_till == in_compare_creds->times.renew_till); } if (equal) { equal = (in_creds->is_skey == in_compare_creds->is_skey); } if (equal) { equal = (in_creds->ticket_flags == in_compare_creds->ticket_flags); } if (equal) { krb5_address **addresses = in_creds->addresses; krb5_address **compare_addresses = in_compare_creds->addresses; unsigned int i; if (addresses && compare_addresses) { for (i = 0; (equal && addresses[i] && compare_addresses[i]); i++) { equal = krb5_address_compare (in_context, addresses[i], compare_addresses[i]); } if (equal) { equal = (!addresses[i] && !compare_addresses[i]); } } else { if (equal) { equal = (!addresses && !compare_addresses); } } } if (equal) { equal = (in_creds->ticket.length == in_compare_creds->ticket.length && (!in_creds->ticket.length || !memcmp (in_creds->ticket.data, in_compare_creds->ticket.data, in_creds->ticket.length))); } if (equal) { equal = (in_creds->second_ticket.length == in_compare_creds->second_ticket.length && (!in_creds->second_ticket.length || !memcmp (in_creds->second_ticket.data, in_compare_creds->second_ticket.data, in_creds->second_ticket.length))); } if (equal) { krb5_authdata **authdata = in_creds->authdata; krb5_authdata **compare_authdata = in_compare_creds->authdata; unsigned int i; if (authdata && compare_authdata) { for (i = 0; (equal && authdata[i] && compare_authdata[i]); i++) { equal = (authdata[i]->ad_type == compare_authdata[i]->ad_type && authdata[i]->length == compare_authdata[i]->length && (!authdata[i]->length || !memcmp (authdata[i]->contents, compare_authdata[i]->contents, authdata[i]->length))); } if (equal) { equal = (!authdata[i] && !compare_authdata[i]); } } else { if (equal) { equal = (!authdata && !compare_authdata); } } } return equal; }
krb5_error_code KRB5_LIB_FUNCTION krb5_rd_priv(krb5_context context, krb5_auth_context auth_context, const krb5_data *inbuf, krb5_data *outbuf, krb5_replay_data *outdata) { krb5_error_code ret; KRB_PRIV priv; EncKrbPrivPart part; size_t len; krb5_data plain; krb5_keyblock *key; krb5_crypto crypto; if (outbuf) krb5_data_zero(outbuf); if ((auth_context->flags & (KRB5_AUTH_CONTEXT_RET_TIME | KRB5_AUTH_CONTEXT_RET_SEQUENCE)) && outdata == NULL) return KRB5_RC_REQUIRED; /* XXX better error, MIT returns this */ memset(&priv, 0, sizeof(priv)); ret = decode_KRB_PRIV (inbuf->data, inbuf->length, &priv, &len); if (ret) goto failure; if (priv.pvno != 5) { krb5_clear_error_string (context); ret = KRB5KRB_AP_ERR_BADVERSION; goto failure; } if (priv.msg_type != krb_priv) { krb5_clear_error_string (context); ret = KRB5KRB_AP_ERR_MSG_TYPE; goto failure; } if (auth_context->remote_subkey) key = auth_context->remote_subkey; else if (auth_context->local_subkey) key = auth_context->local_subkey; else key = auth_context->keyblock; ret = krb5_crypto_init(context, key, 0, &crypto); if (ret) goto failure; ret = krb5_decrypt_EncryptedData(context, crypto, KRB5_KU_KRB_PRIV, &priv.enc_part, &plain); krb5_crypto_destroy(context, crypto); if (ret) goto failure; ret = decode_EncKrbPrivPart (plain.data, plain.length, &part, &len); krb5_data_free (&plain); if (ret) goto failure; /* check sender address */ if (part.s_address && auth_context->remote_address && !krb5_address_compare (context, auth_context->remote_address, part.s_address)) { krb5_clear_error_string (context); ret = KRB5KRB_AP_ERR_BADADDR; goto failure_part; } /* check receiver address */ if (part.r_address && auth_context->local_address && !krb5_address_compare (context, auth_context->local_address, part.r_address)) { krb5_clear_error_string (context); ret = KRB5KRB_AP_ERR_BADADDR; goto failure_part; } /* check timestamp */ if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_TIME) { krb5_timestamp sec; krb5_timeofday (context, &sec); if (part.timestamp == NULL || part.usec == NULL || abs(*part.timestamp - sec) > context->max_skew) { krb5_clear_error_string (context); ret = KRB5KRB_AP_ERR_SKEW; goto failure_part; } } /* XXX - check replay cache */ /* check sequence number. since MIT krb5 cannot generate a sequence number of zero but instead generates no sequence number, we accept that */ if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) { if ((part.seq_number == NULL && auth_context->remote_seqnumber != 0) || (part.seq_number != NULL && *part.seq_number != auth_context->remote_seqnumber)) { krb5_clear_error_string (context); ret = KRB5KRB_AP_ERR_BADORDER; goto failure_part; } auth_context->remote_seqnumber++; } ret = krb5_data_copy (outbuf, part.user_data.data, part.user_data.length); if (ret) goto failure_part; if ((auth_context->flags & (KRB5_AUTH_CONTEXT_RET_TIME | KRB5_AUTH_CONTEXT_RET_SEQUENCE))) { /* if these fields are not present in the priv-part, silently return zero */ memset(outdata, 0, sizeof(*outdata)); if(part.timestamp) outdata->timestamp = *part.timestamp; if(part.usec) outdata->usec = *part.usec; if(part.seq_number) outdata->seq = *part.seq_number; } failure_part: free_EncKrbPrivPart (&part); failure: free_KRB_PRIV (&priv); return ret; }