Esempio n. 1
0
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;
}
Esempio n. 2
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;
}
Esempio n. 3
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;
}
Esempio n. 4
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;
}
Esempio n. 5
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;
}
Esempio n. 6
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;
}
Esempio n. 7
0
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;
}
Esempio n. 8
0
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;
}