static int arange_copy (krb5_context context, const krb5_address *inaddr, krb5_address *outaddr) { krb5_error_code ret; struct arange *i, *o; outaddr->addr_type = KRB5_ADDRESS_ARANGE; ret = krb5_data_alloc(&outaddr->address, sizeof(*o)); if(ret) return ret; i = inaddr->address.data; o = outaddr->address.data; ret = krb5_copy_address(context, &i->low, &o->low); if(ret) { krb5_data_free(&outaddr->address); return ret; } ret = krb5_copy_address(context, &i->high, &o->high); if(ret) { krb5_free_address(context, &o->low); krb5_data_free(&outaddr->address); return ret; } return 0; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_auth_con_getaddrs(krb5_context context, krb5_auth_context auth_context, krb5_address **local_addr, krb5_address **remote_addr) { if(*local_addr) krb5_free_address (context, *local_addr); *local_addr = malloc (sizeof(**local_addr)); if (*local_addr == NULL) { krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); return ENOMEM; } krb5_copy_address(context, auth_context->local_address, *local_addr); if(*remote_addr) krb5_free_address (context, *remote_addr); *remote_addr = malloc (sizeof(**remote_addr)); if (*remote_addr == NULL) { krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); krb5_free_address (context, *local_addr); *local_addr = NULL; return ENOMEM; } krb5_copy_address(context, auth_context->remote_address, *remote_addr); return 0; }
krb5_error_code KRB5_LIB_FUNCTION krb5_append_addresses(krb5_context context, krb5_addresses *dest, const krb5_addresses *source) { krb5_address *tmp; krb5_error_code ret; int i; if(source->len > 0) { tmp = realloc(dest->val, (dest->len + source->len) * sizeof(*tmp)); if(tmp == NULL) { krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", "")); return ENOMEM; } dest->val = tmp; for(i = 0; i < source->len; i++) { /* skip duplicates */ if(krb5_address_search(context, &source->val[i], dest)) continue; ret = krb5_copy_address(context, &source->val[i], &dest->val[dest->len]); if(ret) return ret; dest->len++; } } return 0; }
krb5_error_code KRB5_LIB_FUNCTION krb5_auth_con_setaddrs(krb5_context context, krb5_auth_context auth_context, krb5_address *local_addr, krb5_address *remote_addr) { if (local_addr) { if (auth_context->local_address) krb5_free_address (context, auth_context->local_address); else auth_context->local_address = malloc(sizeof(krb5_address)); krb5_copy_address(context, local_addr, auth_context->local_address); } if (remote_addr) { if (auth_context->remote_address) krb5_free_address (context, auth_context->remote_address); else auth_context->remote_address = malloc(sizeof(krb5_address)); krb5_copy_address(context, remote_addr, auth_context->remote_address); } return 0; }
krb5_error_code KRB5_LIB_FUNCTION krb5_copy_addresses(krb5_context context, const krb5_addresses *inaddr, krb5_addresses *outaddr) { int i; ALLOC_SEQ(outaddr, inaddr->len); if(inaddr->len > 0 && outaddr->val == NULL) return ENOMEM; for(i = 0; i < inaddr->len; i++) krb5_copy_address(context, &inaddr->val[i], &outaddr->val[i]); return 0; }
krb5_error_code KRB5_LIB_FUNCTION krb5_get_forwarded_creds (krb5_context context, krb5_auth_context auth_context, krb5_ccache ccache, krb5_flags flags, const char *hostname, krb5_creds *in_creds, krb5_data *out_data) { krb5_error_code ret; krb5_creds *out_creds; krb5_addresses addrs, *paddrs; KRB_CRED cred; KrbCredInfo *krb_cred_info; EncKrbCredPart enc_krb_cred_part; size_t len; unsigned char *buf; size_t buf_size; krb5_kdc_flags kdc_flags; krb5_crypto crypto; struct addrinfo *ai; int save_errno; krb5_creds *ticket; char *realm; if (in_creds->client && in_creds->client->realm) realm = in_creds->client->realm; else realm = in_creds->server->realm; addrs.len = 0; addrs.val = NULL; paddrs = &addrs; /* * If tickets are address-less, forward address-less tickets. */ ret = _krb5_get_krbtgt (context, ccache, realm, &ticket); if(ret == 0) { if (ticket->addresses.len == 0) paddrs = NULL; krb5_free_creds (context, ticket); } if (paddrs != NULL) { ret = getaddrinfo (hostname, NULL, NULL, &ai); if (ret) { save_errno = errno; krb5_set_error_string(context, "resolving %s: %s", hostname, gai_strerror(ret)); return krb5_eai_to_heim_errno(ret, save_errno); } ret = add_addrs (context, &addrs, ai); freeaddrinfo (ai); if (ret) return ret; } kdc_flags.b = int2KDCOptions(flags); ret = krb5_get_kdc_cred (context, ccache, kdc_flags, paddrs, NULL, in_creds, &out_creds); krb5_free_addresses (context, &addrs); if (ret) { return ret; } memset (&cred, 0, sizeof(cred)); cred.pvno = 5; cred.msg_type = krb_cred; ALLOC_SEQ(&cred.tickets, 1); if (cred.tickets.val == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto out2; } ret = decode_Ticket(out_creds->ticket.data, out_creds->ticket.length, cred.tickets.val, &len); if (ret) goto out3; memset (&enc_krb_cred_part, 0, sizeof(enc_krb_cred_part)); ALLOC_SEQ(&enc_krb_cred_part.ticket_info, 1); if (enc_krb_cred_part.ticket_info.val == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto out4; } if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_TIME) { krb5_timestamp sec; int32_t usec; krb5_us_timeofday (context, &sec, &usec); ALLOC(enc_krb_cred_part.timestamp, 1); if (enc_krb_cred_part.timestamp == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto out4; } *enc_krb_cred_part.timestamp = sec; ALLOC(enc_krb_cred_part.usec, 1); if (enc_krb_cred_part.usec == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto out4; } *enc_krb_cred_part.usec = usec; } else { enc_krb_cred_part.timestamp = NULL; enc_krb_cred_part.usec = NULL; } if (auth_context->local_address && auth_context->local_port) { krb5_boolean noaddr; krb5_const_realm realm; realm = krb5_principal_get_realm(context, out_creds->server); krb5_appdefault_boolean(context, NULL, realm, "no-addresses", paddrs == NULL, &noaddr); if (!noaddr) { ret = krb5_make_addrport (context, &enc_krb_cred_part.s_address, auth_context->local_address, auth_context->local_port); if (ret) goto out4; } } if (auth_context->remote_address) { if (auth_context->remote_port) { krb5_boolean noaddr; krb5_const_realm realm; realm = krb5_principal_get_realm(context, out_creds->server); /* Is this correct, and should we use the paddrs == NULL trick here as well? Having an address-less ticket may indicate that we don't know our own global address, but it does not necessary mean that we don't know the server's. */ krb5_appdefault_boolean(context, NULL, realm, "no-addresses", FALSE, &noaddr); if (!noaddr) { ret = krb5_make_addrport (context, &enc_krb_cred_part.r_address, auth_context->remote_address, auth_context->remote_port); if (ret) goto out4; } } else { ALLOC(enc_krb_cred_part.r_address, 1); if (enc_krb_cred_part.r_address == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto out4; } ret = krb5_copy_address (context, auth_context->remote_address, enc_krb_cred_part.r_address); if (ret) goto out4; } } /* fill ticket_info.val[0] */ enc_krb_cred_part.ticket_info.len = 1; krb_cred_info = enc_krb_cred_part.ticket_info.val; copy_EncryptionKey (&out_creds->session, &krb_cred_info->key); ALLOC(krb_cred_info->prealm, 1); copy_Realm (&out_creds->client->realm, krb_cred_info->prealm); ALLOC(krb_cred_info->pname, 1); copy_PrincipalName(&out_creds->client->name, krb_cred_info->pname); ALLOC(krb_cred_info->flags, 1); *krb_cred_info->flags = out_creds->flags.b; ALLOC(krb_cred_info->authtime, 1); *krb_cred_info->authtime = out_creds->times.authtime; ALLOC(krb_cred_info->starttime, 1); *krb_cred_info->starttime = out_creds->times.starttime; ALLOC(krb_cred_info->endtime, 1); *krb_cred_info->endtime = out_creds->times.endtime; ALLOC(krb_cred_info->renew_till, 1); *krb_cred_info->renew_till = out_creds->times.renew_till; ALLOC(krb_cred_info->srealm, 1); copy_Realm (&out_creds->server->realm, krb_cred_info->srealm); ALLOC(krb_cred_info->sname, 1); copy_PrincipalName (&out_creds->server->name, krb_cred_info->sname); ALLOC(krb_cred_info->caddr, 1); copy_HostAddresses (&out_creds->addresses, krb_cred_info->caddr); krb5_free_creds (context, out_creds); /* encode EncKrbCredPart */ ASN1_MALLOC_ENCODE(EncKrbCredPart, buf, buf_size, &enc_krb_cred_part, &len, ret); free_EncKrbCredPart (&enc_krb_cred_part); if (ret) { free_KRB_CRED(&cred); return ret; } if(buf_size != len) krb5_abortx(context, "internal error in ASN.1 encoder"); if (auth_context->flags & KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED) { cred.enc_part.etype = ENCTYPE_NULL; cred.enc_part.kvno = NULL; cred.enc_part.cipher.data = buf; cred.enc_part.cipher.length = buf_size; } else { krb5_keyblock *key; if (auth_context->local_subkey) key = auth_context->local_subkey; else if (auth_context->remote_subkey) key = auth_context->remote_subkey; else key = auth_context->keyblock; ret = krb5_crypto_init(context, key, 0, &crypto); if (ret) { free(buf); free_KRB_CRED(&cred); return ret; } ret = krb5_encrypt_EncryptedData (context, crypto, KRB5_KU_KRB_CRED, buf, len, 0, &cred.enc_part); free(buf); krb5_crypto_destroy(context, crypto); if (ret) { free_KRB_CRED(&cred); return ret; } } ASN1_MALLOC_ENCODE(KRB_CRED, buf, buf_size, &cred, &len, ret); free_KRB_CRED (&cred); if (ret) return ret; if(buf_size != len) krb5_abortx(context, "internal error in ASN.1 encoder"); out_data->length = len; out_data->data = buf; return 0; out4: free_EncKrbCredPart(&enc_krb_cred_part); out3: free_KRB_CRED(&cred); out2: krb5_free_creds (context, out_creds); return ret; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_get_forwarded_creds (krb5_context context, krb5_auth_context auth_context, krb5_ccache ccache, krb5_flags flags, const char *hostname, krb5_creds *in_creds, krb5_data *out_data) { krb5_error_code ret; krb5_creds *out_creds; krb5_addresses addrs, *paddrs; KRB_CRED cred; KrbCredInfo *krb_cred_info; EncKrbCredPart enc_krb_cred_part; size_t len; unsigned char *buf; size_t buf_size; krb5_kdc_flags kdc_flags; krb5_crypto crypto; struct addrinfo *ai; krb5_creds *ticket; paddrs = NULL; addrs.len = 0; addrs.val = NULL; ret = krb5_get_credentials(context, 0, ccache, in_creds, &ticket); if(ret == 0) { if (ticket->addresses.len) paddrs = &addrs; krb5_free_creds (context, ticket); } else { krb5_boolean noaddr; krb5_appdefault_boolean(context, NULL, krb5_principal_get_realm(context, in_creds->client), "no-addresses", KRB5_ADDRESSLESS_DEFAULT, &noaddr); if (!noaddr) paddrs = &addrs; } /* * If tickets have addresses, get the address of the remote host. */ if (paddrs != NULL) { ret = getaddrinfo (hostname, NULL, NULL, &ai); if (ret) { krb5_error_code ret2 = krb5_eai_to_heim_errno(ret, errno); krb5_set_error_message(context, ret2, N_("resolving host %s failed: %s", "hostname, error"), hostname, gai_strerror(ret)); return ret2; } ret = add_addrs (context, &addrs, ai); freeaddrinfo (ai); if (ret) return ret; } kdc_flags.b = int2KDCOptions(flags); ret = krb5_get_kdc_cred (context, ccache, kdc_flags, paddrs, NULL, in_creds, &out_creds); krb5_free_addresses (context, &addrs); if (ret) return ret; memset (&cred, 0, sizeof(cred)); cred.pvno = 5; cred.msg_type = krb_cred; ALLOC_SEQ(&cred.tickets, 1); if (cred.tickets.val == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto out2; } ret = decode_Ticket(out_creds->ticket.data, out_creds->ticket.length, cred.tickets.val, &len); if (ret) goto out3; memset (&enc_krb_cred_part, 0, sizeof(enc_krb_cred_part)); ALLOC_SEQ(&enc_krb_cred_part.ticket_info, 1); if (enc_krb_cred_part.ticket_info.val == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto out4; } if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_TIME) { krb5_timestamp sec; int32_t usec; krb5_us_timeofday (context, &sec, &usec); ALLOC(enc_krb_cred_part.timestamp, 1); if (enc_krb_cred_part.timestamp == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto out4; } *enc_krb_cred_part.timestamp = sec; ALLOC(enc_krb_cred_part.usec, 1); if (enc_krb_cred_part.usec == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto out4; } *enc_krb_cred_part.usec = usec; } else { enc_krb_cred_part.timestamp = NULL; enc_krb_cred_part.usec = NULL; } if (auth_context->local_address && auth_context->local_port && paddrs) { ret = krb5_make_addrport (context, &enc_krb_cred_part.s_address, auth_context->local_address, auth_context->local_port); if (ret) goto out4; } if (auth_context->remote_address) { if (auth_context->remote_port) { krb5_boolean noaddr; krb5_const_realm srealm; srealm = krb5_principal_get_realm(context, out_creds->server); /* Is this correct, and should we use the paddrs == NULL trick here as well? Having an address-less ticket may indicate that we don't know our own global address, but it does not necessary mean that we don't know the server's. */ krb5_appdefault_boolean(context, NULL, srealm, "no-addresses", FALSE, &noaddr); if (!noaddr) { ret = krb5_make_addrport (context, &enc_krb_cred_part.r_address, auth_context->remote_address, auth_context->remote_port); if (ret) goto out4; } } else { ALLOC(enc_krb_cred_part.r_address, 1); if (enc_krb_cred_part.r_address == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto out4; } ret = krb5_copy_address (context, auth_context->remote_address, enc_krb_cred_part.r_address); if (ret) goto out4; } } /* fill ticket_info.val[0] */ enc_krb_cred_part.ticket_info.len = 1; krb_cred_info = enc_krb_cred_part.ticket_info.val; copy_EncryptionKey (&out_creds->session, &krb_cred_info->key); ALLOC(krb_cred_info->prealm, 1); copy_Realm (&out_creds->client->realm, krb_cred_info->prealm); ALLOC(krb_cred_info->pname, 1); copy_PrincipalName(&out_creds->client->name, krb_cred_info->pname); ALLOC(krb_cred_info->flags, 1); *krb_cred_info->flags = out_creds->flags.b; ALLOC(krb_cred_info->authtime, 1); *krb_cred_info->authtime = out_creds->times.authtime; ALLOC(krb_cred_info->starttime, 1); *krb_cred_info->starttime = out_creds->times.starttime; ALLOC(krb_cred_info->endtime, 1); *krb_cred_info->endtime = out_creds->times.endtime; ALLOC(krb_cred_info->renew_till, 1); *krb_cred_info->renew_till = out_creds->times.renew_till; ALLOC(krb_cred_info->srealm, 1); copy_Realm (&out_creds->server->realm, krb_cred_info->srealm); ALLOC(krb_cred_info->sname, 1); copy_PrincipalName (&out_creds->server->name, krb_cred_info->sname); ALLOC(krb_cred_info->caddr, 1); copy_HostAddresses (&out_creds->addresses, krb_cred_info->caddr); krb5_free_creds (context, out_creds); /* encode EncKrbCredPart */ ASN1_MALLOC_ENCODE(EncKrbCredPart, buf, buf_size, &enc_krb_cred_part, &len, ret); free_EncKrbCredPart (&enc_krb_cred_part); if (ret) { free_KRB_CRED(&cred); return ret; } if(buf_size != len) krb5_abortx(context, "internal error in ASN.1 encoder"); /** * Some older of the MIT gssapi library used clear-text tickets * (warped inside AP-REQ encryption), use the krb5_auth_context * flag KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED to support those * tickets. The session key is used otherwise to encrypt the * forwarded ticket. */ if (auth_context->flags & KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED) { cred.enc_part.etype = KRB5_ENCTYPE_NULL; cred.enc_part.kvno = NULL; cred.enc_part.cipher.data = buf; cred.enc_part.cipher.length = buf_size; } else { /* * Here older versions then 0.7.2 of Heimdal used the local or * remote subkey. That is wrong, the session key should be * used. Heimdal 0.7.2 and newer have code to try both in the * receiving end. */ ret = krb5_crypto_init(context, auth_context->keyblock, 0, &crypto); if (ret) { free(buf); free_KRB_CRED(&cred); return ret; } ret = krb5_encrypt_EncryptedData (context, crypto, KRB5_KU_KRB_CRED, buf, len, 0, &cred.enc_part); free(buf); krb5_crypto_destroy(context, crypto); if (ret) { free_KRB_CRED(&cred); return ret; } } ASN1_MALLOC_ENCODE(KRB_CRED, buf, buf_size, &cred, &len, ret); free_KRB_CRED (&cred); if (ret) return ret; if(buf_size != len) krb5_abortx(context, "internal error in ASN.1 encoder"); out_data->length = len; out_data->data = buf; return 0; out4: free_EncKrbCredPart(&enc_krb_cred_part); out3: free_KRB_CRED(&cred); out2: krb5_free_creds (context, out_creds); return ret; }
static int arange_parse_addr (krb5_context context, const char *address, krb5_address *addr) { char buf[1024], *p; krb5_address low0, high0; struct arange *a; krb5_error_code ret; if(strncasecmp(address, "RANGE:", 6) != 0) return -1; address += 6; p = strrchr(address, '/'); if (p) { krb5_addresses addrmask; char *q; long num; if (strlcpy(buf, address, sizeof(buf)) > sizeof(buf)) return -1; buf[p - address] = '\0'; ret = krb5_parse_address(context, buf, &addrmask); if (ret) return ret; if(addrmask.len != 1) { krb5_free_addresses(context, &addrmask); return -1; } address += p - address + 1; num = strtol(address, &q, 10); if (q == address || *q != '\0' || num < 0) { krb5_free_addresses(context, &addrmask); return -1; } ret = krb5_address_prefixlen_boundary(context, &addrmask.val[0], num, &low0, &high0); krb5_free_addresses(context, &addrmask); if (ret) return ret; } else { krb5_addresses low, high; strsep_copy(&address, "-", buf, sizeof(buf)); ret = krb5_parse_address(context, buf, &low); if(ret) return ret; if(low.len != 1) { krb5_free_addresses(context, &low); return -1; } strsep_copy(&address, "-", buf, sizeof(buf)); ret = krb5_parse_address(context, buf, &high); if(ret) { krb5_free_addresses(context, &low); return ret; } if(high.len != 1 && high.val[0].addr_type != low.val[0].addr_type) { krb5_free_addresses(context, &low); krb5_free_addresses(context, &high); return -1; } ret = krb5_copy_address(context, &high.val[0], &high0); if (ret == 0) { ret = krb5_copy_address(context, &low.val[0], &low0); if (ret) krb5_free_address(context, &high0); } krb5_free_addresses(context, &low); krb5_free_addresses(context, &high); if (ret) return ret; } krb5_data_alloc(&addr->address, sizeof(*a)); addr->addr_type = KRB5_ADDRESS_ARANGE; a = addr->address.data; if(krb5_address_order(context, &low0, &high0) < 0) { a->low = low0; a->high = high0; } else { a->low = high0; a->high = low0; } return 0; }