Exemple #1
0
krb5_error_code KRB5_LIB_FUNCTION
krb5_decode_ap_req(krb5_context context,
		   const krb5_data *inbuf,
		   krb5_ap_req *ap_req)
{
    krb5_error_code ret;
    size_t len;
    ret = decode_AP_REQ(inbuf->data, inbuf->length, ap_req, &len);
    if (ret)
	return ret;
    if (ap_req->pvno != 5){
	free_AP_REQ(ap_req);
	krb5_clear_error_string (context);
	return KRB5KRB_AP_ERR_BADVERSION;
    }
    if (ap_req->msg_type != krb_ap_req){
	free_AP_REQ(ap_req);
	krb5_clear_error_string (context);
	return KRB5KRB_AP_ERR_MSG_TYPE;
    }
    if (ap_req->ticket.tkt_vno != 5){
	free_AP_REQ(ap_req);
	krb5_clear_error_string (context);
	return KRB5KRB_AP_ERR_BADVERSION;
    }
    return 0;
}
Exemple #2
0
krb5_error_code KRB5_LIB_FUNCTION
krb5_kt_default_modify_name(krb5_context context, char *name, size_t namesize)
{
    const char *kt = NULL;
    if(context->default_keytab_modify == NULL) {
	if(strncasecmp(context->default_keytab, "ANY:", 4) != 0)
	    kt = context->default_keytab;
	else {
	    size_t len = strcspn(context->default_keytab + 4, ",");
	    if(len >= namesize) {
		krb5_clear_error_string(context);
		return KRB5_CONFIG_NOTENUFSPACE;
	    }
	    strlcpy(name, context->default_keytab + 4, namesize);
	    name[len] = '\0';
	    return 0;
	}    
    } else
	kt = context->default_keytab_modify;
    if (strlcpy (name, kt, namesize) >= namesize) {
	krb5_clear_error_string (context);
	return KRB5_CONFIG_NOTENUFSPACE;
    }
    return 0;
}
static krb5_error_code
mkt_remove_entry(krb5_context context,
		 krb5_keytab id,
		 krb5_keytab_entry *entry)
{
    struct mkt_data *d = id->data;
    krb5_keytab_entry *e, *end;
    int found = 0;
    
    if (d->num_entries == 0) {
	krb5_clear_error_string(context);
        return KRB5_KT_NOTFOUND;
    }

    /* do this backwards to minimize copying */
    for(end = d->entries + d->num_entries, e = end - 1; e >= d->entries; e--) {
	if(krb5_kt_compare(context, e, entry->principal, 
			   entry->vno, entry->keyblock.keytype)) {
	    krb5_kt_free_entry(context, e);
	    memmove(e, e + 1, (end - e - 1) * sizeof(*e));
	    memset(end - 1, 0, sizeof(*end));
	    d->num_entries--;
	    end--;
	    found = 1;
	}
    }
    if (!found) {
	krb5_clear_error_string (context);
	return KRB5_KT_NOTFOUND;
    }
    e = realloc(d->entries, d->num_entries * sizeof(*d->entries));
    if(e != NULL || d->num_entries == 0)
	d->entries = e;
    return 0;
}
static krb5_error_code
fkt_start_seq_get_int(krb5_context context, 
		      krb5_keytab id, 
		      int flags,
		      int exclusive,
		      krb5_kt_cursor *c)
{
    int8_t pvno, tag;
    krb5_error_code ret;
    struct fkt_data *d = id->data;
    
    c->fd = open (d->filename, flags);
    if (c->fd < 0) {
	ret = errno;
	krb5_set_error_string(context, "%s: %s", d->filename,
			      strerror(ret));
	return ret;
    }
    ret = _krb5_xlock(context, c->fd, exclusive, d->filename);
    if (ret) {
	close(c->fd);
	return ret;
    }
    c->sp = krb5_storage_from_fd(c->fd);
    if (c->sp == NULL) {
	_krb5_xunlock(context, c->fd);
	close(c->fd);
	krb5_set_error_string (context, "malloc: out of memory");
	return ENOMEM;
    }
    krb5_storage_set_eof_code(c->sp, KRB5_KT_END);
    ret = krb5_ret_int8(c->sp, &pvno);
    if(ret) {
	krb5_storage_free(c->sp);
	_krb5_xunlock(context, c->fd);
	close(c->fd);
	krb5_clear_error_string(context);
	return ret;
    }
    if(pvno != 5) {
	krb5_storage_free(c->sp);
	_krb5_xunlock(context, c->fd);
	close(c->fd);
	krb5_clear_error_string (context);
	return KRB5_KEYTAB_BADVNO;
    }
    ret = krb5_ret_int8(c->sp, &tag);
    if (ret) {
	krb5_storage_free(c->sp);
	_krb5_xunlock(context, c->fd);
	close(c->fd);
	krb5_clear_error_string(context);
	return ret;
    }
    id->version = tag;
    storage_set_flags(context, c->sp, id->version);
    return 0;
}
Exemple #5
0
krb5_error_code KRB5_LIB_FUNCTION
_krb5_s4u2self_to_checksumdata(krb5_context context, 
			       const PA_S4U2Self *self, 
			       krb5_data *data)
{
    krb5_error_code ret;
    krb5_ssize_t ssize;
    krb5_storage *sp;
    size_t size;
    int i;

    sp = krb5_storage_emem();
    if (sp == NULL) {
	krb5_clear_error_string(context);
	return ENOMEM;
    }
    krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
    ret = krb5_store_int32(sp, self->name.name_type);
    if (ret)
	goto out;
    for (i = 0; i < self->name.name_string.len; i++) {
	size = strlen(self->name.name_string.val[i]);
	ssize = krb5_storage_write(sp, self->name.name_string.val[i], size);
	if (ssize != size) {
	    ret = ENOMEM;
	    goto out;
	}
    }
    size = strlen(self->realm);
    ssize = krb5_storage_write(sp, self->realm, size);
    if (ssize != size) {
	ret = ENOMEM;
	goto out;
    }
    size = strlen(self->auth);
    ssize = krb5_storage_write(sp, self->auth, size);
    if (ssize != size) {
	ret = ENOMEM;
	goto out;
    }

    ret = krb5_storage_to_data(sp, data);
    krb5_storage_free(sp);
    return ret;

out:
    krb5_clear_error_string(context);
    return ret;
}
Exemple #6
0
krb5_error_code KRB5_LIB_FUNCTION
krb5_decrypt_ticket(krb5_context context,
		    Ticket *ticket,
		    krb5_keyblock *key,
		    EncTicketPart *out,
		    krb5_flags flags)
{
    EncTicketPart t;
    krb5_error_code ret;
    ret = decrypt_tkt_enc_part (context, key, &ticket->enc_part, &t);
    if (ret)
	return ret;
    
    {
	krb5_timestamp now;
	time_t start = t.authtime;

	krb5_timeofday (context, &now);
	if(t.starttime)
	    start = *t.starttime;
	if(start - now > context->max_skew
	   || (t.flags.invalid
	       && !(flags & KRB5_VERIFY_AP_REQ_IGNORE_INVALID))) {
	    free_EncTicketPart(&t);
	    krb5_clear_error_string (context);
	    return KRB5KRB_AP_ERR_TKT_NYV;
	}
	if(now - t.endtime > context->max_skew) {
	    free_EncTicketPart(&t);
	    krb5_clear_error_string (context);
	    return KRB5KRB_AP_ERR_TKT_EXPIRED;
	}
	
	if(!t.flags.transited_policy_checked) {
	    ret = check_transited(context, ticket, &t);
	    if(ret) {
		free_EncTicketPart(&t);
		return ret;
	    }
	}
    }
    
    if(out)
	*out = t;
    else
	free_EncTicketPart(&t);
    return 0;
}
static krb5_error_code
akf_start_seq_get(krb5_context context, 
		  krb5_keytab id, 
		  krb5_kt_cursor *c)
{
    int32_t ret;
    struct akf_data *d = id->data;

    c->fd = open (d->filename, O_RDONLY|O_BINARY, 0600);
    if (c->fd < 0) {
	ret = errno;
	krb5_set_error_string(context, "open(%s): %s", d->filename,
			      strerror(ret));
	return ret;
    }

    c->sp = krb5_storage_from_fd(c->fd);
    ret = krb5_ret_int32(c->sp, &d->num_entries);
    if(ret) {
	krb5_storage_free(c->sp);
	close(c->fd);
	krb5_clear_error_string (context);
	if(ret == KRB5_KT_END)
	    return KRB5_KT_NOTFOUND;
	return ret;
    }

    return 0;
}
Exemple #8
0
krb5_error_code KRB5_LIB_FUNCTION
krb5_get_init_creds_opt_get_error(krb5_context context,
				  krb5_get_init_creds_opt *opt,
				  KRB_ERROR **error)
{
    krb5_error_code ret;

    *error = NULL;

    ret = require_ext_opt(context, opt, "init_creds_opt_get_error");
    if (ret)
	return ret;

    if (opt->opt_private->error == NULL)
	return 0;

    *error = malloc(sizeof(**error));
    if (*error == NULL) {
	krb5_set_error_string(context, "malloc - out memory");
	return ENOMEM;
    }

    ret = copy_KRB_ERROR(*error, opt->opt_private->error);
    if (ret)
	krb5_clear_error_string(context);

    return 0;
}
Exemple #9
0
static krb5_error_code
any_next_entry (krb5_context context,
		krb5_keytab id,
		krb5_keytab_entry *entry,
		krb5_kt_cursor *cursor)
{
    krb5_error_code ret, ret2;
    struct any_cursor_extra_data *ed;

    ed = (struct any_cursor_extra_data *)cursor->data;
    do {
	ret = krb5_kt_next_entry(context, ed->a->kt, entry, &ed->cursor);
	if (ret == 0)
	    return 0;
	else if (ret != KRB5_KT_END)
	    return ret;

	ret2 = krb5_kt_end_seq_get (context, ed->a->kt, &ed->cursor);
	if (ret2)
	    return ret2;
	while ((ed->a = ed->a->next) != NULL) {
	    ret2 = krb5_kt_start_seq_get(context, ed->a->kt, &ed->cursor);
	    if (ret2 == 0)
		break;
	}
	if (ed->a == NULL) {
	    krb5_clear_error_string (context);
	    return KRB5_KT_END;
	}
    } while (1);
}
Exemple #10
0
static krb5_error_code
check_constrained_delegation(krb5_context context, 
			     krb5_kdc_configuration *config,
			     hdb_entry_ex *client,
			     krb5_const_principal server)
{
    const HDB_Ext_Constrained_delegation_acl *acl;
    krb5_error_code ret;
    int i;

    ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl);
    if (ret) {
	krb5_clear_error_string(context);
	return ret;
    }

    if (acl) {
	for (i = 0; i < acl->len; i++) {
	    if (krb5_principal_compare(context, server, &acl->val[i]) == TRUE)
		return 0;
	}
    }
    kdc_log(context, config, 0,
	    "Bad request for constrained delegation");
    return KRB5KDC_ERR_BADOPTION;
}
Exemple #11
0
static krb5_error_code
find_cred(krb5_context context,
	  krb5_ccache id,
	  krb5_principal server,
	  krb5_creds **tgts,
	  krb5_creds *out_creds)
{
    krb5_error_code ret;
    krb5_creds mcreds;

    krb5_cc_clear_mcred(&mcreds);
    mcreds.server = server;
    ret = krb5_cc_retrieve_cred(context, id, KRB5_TC_DONT_MATCH_REALM, 
				&mcreds, out_creds);
    if(ret == 0)
	return 0;
    while(tgts && *tgts){
	if(krb5_compare_creds(context, KRB5_TC_DONT_MATCH_REALM, 
			      &mcreds, *tgts)){
	    ret = krb5_copy_creds_contents(context, *tgts, out_creds);
	    return ret;
	}
	tgts++;
    }
    krb5_clear_error_string(context);
    return KRB5_CC_NOTFOUND;
}
Exemple #12
0
krb5_error_code KRB5_LIB_FUNCTION
krb5_kt_default_name(krb5_context context, char *name, size_t namesize)
{
    if (strlcpy (name, context->default_keytab, namesize) >= namesize) {
	krb5_clear_error_string (context);
	return KRB5_CONFIG_NOTENUFSPACE;
    }
    return 0;
}
Exemple #13
0
static krb5_error_code
find_etypelist(krb5_context context,
	       krb5_auth_context auth_context,
	       EtypeList *etypes)
{
    krb5_error_code ret;
    krb5_authdata *ad;
    krb5_authdata adIfRelevant;
    unsigned i;

    adIfRelevant.len = 0;

    etypes->len = 0;
    etypes->val = NULL;

    ad = auth_context->authenticator->authorization_data;
    if (ad == NULL)
	return 0;

    for (i = 0; i < ad->len; i++) {
	if (ad->val[i].ad_type == KRB5_AUTHDATA_IF_RELEVANT) {
	    ret = decode_AD_IF_RELEVANT(ad->val[i].ad_data.data,
					ad->val[i].ad_data.length,
					&adIfRelevant,
					NULL);
	    if (ret)
		return ret;

	    if (adIfRelevant.len == 1 &&
		adIfRelevant.val[0].ad_type ==
			KRB5_AUTHDATA_GSS_API_ETYPE_NEGOTIATION) {
		break;
	    }
	    free_AD_IF_RELEVANT(&adIfRelevant);
	    adIfRelevant.len = 0;
	}
    }

    if (adIfRelevant.len == 0)
	return 0;

    ret = decode_EtypeList(adIfRelevant.val[0].ad_data.data,
			   adIfRelevant.val[0].ad_data.length,
			   etypes,
			   NULL);
    if (ret)
	krb5_clear_error_string(context);

    free_AD_IF_RELEVANT(&adIfRelevant);

    return ret;
}
Exemple #14
0
static krb5_error_code
kcm_send_request(krb5_context context,
		 krb5_kcmcache *k,
		 krb5_storage *request,
		 krb5_data *response_data)
{
    krb5_error_code ret;
    krb5_data request_data;
    int i;

    response_data->data = NULL;
    response_data->length = 0;

    ret = krb5_storage_to_data(request, &request_data);
    if (ret) {
	krb5_clear_error_string(context);
	return KRB5_CC_NOMEM;
    }

    ret = KRB5_CC_IO;

    for (i = 0; i < context->max_retries; i++) {
	ret = try_door(context, k, &request_data, response_data);
	if (ret == 0 && response_data->length != 0)
	    break;
	ret = try_unix_socket(context, k, &request_data, response_data);
	if (ret == 0 && response_data->length != 0)
	    break;
    }

    krb5_data_free(&request_data);

    if (ret) {
	krb5_clear_error_string(context);
	ret = KRB5_CC_IO;
    }

    return ret;
}
Exemple #15
0
krb5_error_code KRB5_LIB_FUNCTION
_krb5_krb_tf_setup(krb5_context context, 
		   struct credentials *v4creds, 
		   const char *tkfile,
		   int append)
{
    krb5_error_code ret;
    krb5_storage *sp;

    sp = krb5_storage_emem();
    if (sp == NULL)
	return ENOMEM;

    krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_HOST);
    krb5_storage_set_eof_code(sp, KRB5_CC_IO);

    krb5_clear_error_string(context);

    if (!append) {
	RCHECK(ret, krb5_store_stringz(sp, v4creds->pname), error);
	RCHECK(ret, krb5_store_stringz(sp, v4creds->pinst), error);
    }

    /* cred */
    RCHECK(ret, krb5_store_stringz(sp, v4creds->service), error);
    RCHECK(ret, krb5_store_stringz(sp, v4creds->instance), error);
    RCHECK(ret, krb5_store_stringz(sp, v4creds->realm), error);
    ret = krb5_storage_write(sp, v4creds->session, 8);
    if (ret != 8) {
	ret = KRB5_CC_IO;
	goto error;
    }
    RCHECK(ret, krb5_store_int32(sp, v4creds->lifetime), error);
    RCHECK(ret, krb5_store_int32(sp, v4creds->kvno), error);
    RCHECK(ret, krb5_store_int32(sp, v4creds->ticket_st.length), error);

    ret = krb5_storage_write(sp, v4creds->ticket_st.dat, 
			     v4creds->ticket_st.length);
    if (ret != v4creds->ticket_st.length) {
	ret = KRB5_CC_IO;
	goto error;
    }
    RCHECK(ret, krb5_store_int32(sp, v4creds->issue_date), error);

    ret = write_v4_cc(context, tkfile, sp, append);

 error:
    krb5_storage_free(sp);

    return ret;
}
Exemple #16
0
static void
not_found(krb5_context context, krb5_const_principal p)
{
    krb5_error_code ret;
    char *str;

    ret = krb5_unparse_name(context, p, &str);
    if(ret) {
	krb5_clear_error_string(context);
	return;
    }
    krb5_set_error_string(context, "Matching credential (%s) not found", str);
    free(str);
}
Exemple #17
0
krb5_error_code KRB5_LIB_FUNCTION
krb5_rc_store(krb5_context context,
	      krb5_rcache id,
	      krb5_donot_replay *rep)
{
    struct rc_entry ent, tmp;
    time_t t;
    FILE *f;
    int ret;

    ent.stamp = time(NULL);
    checksum_authenticator(rep, ent.data);
    f = fopen(id->name, "r");
    if(f == NULL) {
	ret = errno;
	krb5_set_error_string (context, "open(%s): %s", id->name,
			       strerror(ret));
	return ret;
    }
    fread(&tmp, sizeof(ent), 1, f);
    t = ent.stamp - tmp.stamp;
    while(fread(&tmp, sizeof(ent), 1, f)){
	if(tmp.stamp < t)
	    continue;
	if(memcmp(tmp.data, ent.data, sizeof(ent.data)) == 0){
	    fclose(f);
	    krb5_clear_error_string (context);
	    return KRB5_RC_REPLAY;
	}
    }
    if(ferror(f)){
	ret = errno;
	fclose(f);
	krb5_set_error_string (context, "%s: %s", id->name, strerror(ret));
	return ret;
    }
    fclose(f);
    f = fopen(id->name, "a");
    if(f == NULL) {
	krb5_set_error_string (context, "open(%s): %s", id->name,
			       strerror(errno));
	return KRB5_RC_IO_UNKNOWN;
    }
    fwrite(&ent, 1, sizeof(ent), f);
    fclose(f);
    return 0;
}
Exemple #18
0
static krb5_error_code
add_addrs(krb5_context context,
	  krb5_addresses *addr,
	  struct addrinfo *ai)
{
    krb5_error_code ret;
    unsigned n, i;
    void *tmp;
    struct addrinfo *a;

    n = 0;
    for (a = ai; a != NULL; a = a->ai_next)
	++n;

    tmp = realloc(addr->val, (addr->len + n) * sizeof(*addr->val));
    if (tmp == NULL) {
	krb5_set_error_string(context, "malloc: out of memory");
	ret = ENOMEM;
	goto fail;
    }
    addr->val = tmp;
    for (i = addr->len; i < (addr->len + n); ++i) {
	addr->val[i].addr_type = 0;
	krb5_data_zero(&addr->val[i].address);
    }
    i = addr->len;
    for (a = ai; a != NULL; a = a->ai_next) {
	krb5_address ad;

	ret = krb5_sockaddr2address (context, a->ai_addr, &ad);
	if (ret == 0) {
	    if (krb5_address_search(context, &ad, addr))
		krb5_free_address(context, &ad);
	    else
		addr->val[i++] = ad;
	}
	else if (ret == KRB5_PROG_ATYPE_NOSUPP)
	    krb5_clear_error_string (context);
	else
	    goto fail;
	addr->len = i;
    }
    return 0;
fail:
    krb5_free_addresses (context, addr);
    return ret;
}
Exemple #19
0
krb5_error_code KRB5_LIB_FUNCTION
krb5_rc_get_lifespan(krb5_context context,
		     krb5_rcache id,
		     krb5_deltat *auth_lifespan)
{
    FILE *f = fopen(id->name, "r");
    int r;
    struct rc_entry ent;
    r = fread(&ent, sizeof(ent), 1, f);
    fclose(f);
    if(r){
	*auth_lifespan = ent.stamp;
	return 0;
    }
    krb5_clear_error_string (context);
    return KRB5_RC_IO_UNKNOWN;
}
Exemple #20
0
static krb5_error_code
get_cred_kdc(krb5_context context, 
	     krb5_ccache id, 
	     krb5_kdc_flags flags,
	     krb5_addresses *addresses, 
	     krb5_creds *in_creds, 
	     krb5_creds *krbtgt,
	     krb5_creds *out_creds)
{
    krb5_error_code ret;

    ret = get_cred_kdc_usage(context, id, flags, addresses, in_creds,
			     krbtgt, out_creds, KRB5_KU_TGS_REQ_AUTH);
    if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
	krb5_clear_error_string (context);
	ret = get_cred_kdc_usage(context, id, flags, addresses, in_creds,
				 krbtgt, out_creds, KRB5_KU_AP_REQ_AUTH);
    }
    return ret;
}
Exemple #21
0
static krb5_error_code
fkt_remove_entry(krb5_context context,
		 krb5_keytab id,
		 krb5_keytab_entry *entry)
{
    krb5_keytab_entry e;
    krb5_kt_cursor cursor;
    off_t pos_start, pos_end;
    int found = 0;
    krb5_error_code ret;
    
    ret = fkt_start_seq_get_int(context, id, O_RDWR | O_BINARY, 1, &cursor);
    if(ret != 0) 
	goto out; /* return other error here? */
    while(fkt_next_entry_int(context, id, &e, &cursor, 
			     &pos_start, &pos_end) == 0) {
	if(krb5_kt_compare(context, &e, entry->principal, 
			   entry->vno, entry->keyblock.keytype)) {
	    int32_t len;
	    unsigned char buf[128];
	    found = 1;
	    krb5_storage_seek(cursor.sp, pos_start, SEEK_SET);
	    len = pos_end - pos_start - 4;
	    krb5_store_int32(cursor.sp, -len);
	    memset(buf, 0, sizeof(buf));
	    while(len > 0) {
		krb5_storage_write(cursor.sp, buf, min(len, sizeof(buf)));
		len -= min(len, sizeof(buf));
	    }
	}
	krb5_kt_free_entry(context, &e);
    }
    krb5_kt_end_seq_get(context, id, &cursor);
  out:
    if (!found) {
	krb5_clear_error_string (context);
	return KRB5_KT_NOTFOUND;
    }
    return 0;
}
Exemple #22
0
int
hdb_entry_get_password(krb5_context context, HDB *db, 
		       const hdb_entry *entry, char **p)
{
    HDB_extension *ext;
    char *str;
    int ret;

    ext = hdb_find_extension(entry, choice_HDB_extension_data_password);
    if (ext) {
	heim_utf8_string str;
	heim_octet_string pw;

	if (db->hdb_master_key_set && ext->data.u.password.mkvno) {
	    hdb_master_key key;

	    key = _hdb_find_master_key(ext->data.u.password.mkvno, 
				       db->hdb_master_key);

	    if (key == NULL) {
		krb5_set_error_string(context, "master key %d missing",
				      *ext->data.u.password.mkvno);
		return HDB_ERR_NO_MKEY;
	    }

	    ret = _hdb_mkey_decrypt(context, key, HDB_KU_MKEY,
				    ext->data.u.password.password.data,
				    ext->data.u.password.password.length,
				    &pw);
	} else {
	    ret = der_copy_octet_string(&ext->data.u.password.password, &pw);
	}
	if (ret) {
	    krb5_clear_error_string(context);
	    return ret;
	}

	str = pw.data;
	if (str[pw.length - 1] != '\0') {
	    krb5_set_error_string(context, "password malformated");
	    return EINVAL;
	}

	*p = strdup(str);

	der_free_octet_string(&pw);
	if (*p == NULL) {
	    krb5_set_error_string(context, "malloc: out of memory");
	    return ENOMEM;
	}
	return 0;
    }

    ret = krb5_unparse_name(context, entry->principal, &str);
    if (ret == 0) {
	krb5_set_error_string(context, "no password attributefor %s", str);
	free(str);
    } else 
	krb5_clear_error_string(context);

    return ENOENT;
}
Exemple #23
0
static krb5_error_code
tgs_build_reply(krb5_context context, 
		krb5_kdc_configuration *config,
		KDC_REQ *req, 
		KDC_REQ_BODY *b,
		hdb_entry_ex *krbtgt,
		krb5_enctype krbtgt_etype,
		krb5_ticket *ticket,
		krb5_data *reply,
		const char *from,
		const char **e_text,
		AuthorizationData *auth_data,
		const struct sockaddr *from_addr,
		int datagram_reply)
{
    krb5_error_code ret;
    krb5_principal cp = NULL, sp = NULL;
    krb5_principal client_principal = NULL;
    char *spn = NULL, *cpn = NULL;
    hdb_entry_ex *server = NULL, *client = NULL;
    EncTicketPart *tgt = &ticket->ticket;
    KRB5SignedPathPrincipals *spp = NULL;
    const EncryptionKey *ekey;
    krb5_keyblock sessionkey;
    krb5_kvno kvno;
    krb5_data rspac;
    int cross_realm = 0;

    PrincipalName *s;
    Realm r;
    int nloop = 0;
    EncTicketPart adtkt;
    char opt_str[128];
    int require_signedpath = 0;

    memset(&sessionkey, 0, sizeof(sessionkey));
    memset(&adtkt, 0, sizeof(adtkt));
    krb5_data_zero(&rspac);

    s = b->sname;
    r = b->realm;

    if(b->kdc_options.enc_tkt_in_skey){
	Ticket *t;
	hdb_entry_ex *uu;
	krb5_principal p;
	Key *uukey;
	    
	if(b->additional_tickets == NULL || 
	   b->additional_tickets->len == 0){
	    ret = KRB5KDC_ERR_BADOPTION; /* ? */
	    kdc_log(context, config, 0,
		    "No second ticket present in request");
	    goto out;
	}
	t = &b->additional_tickets->val[0];
	if(!get_krbtgt_realm(&t->sname)){
	    kdc_log(context, config, 0,
		    "Additional ticket is not a ticket-granting ticket");
	    ret = KRB5KDC_ERR_POLICY;
	    goto out;
	}
	_krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
	ret = _kdc_db_fetch(context, config, p, 
			    HDB_F_GET_CLIENT|HDB_F_GET_SERVER, 
			    NULL, &uu);
	krb5_free_principal(context, p);
	if(ret){
	    if (ret == HDB_ERR_NOENTRY)
		ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
	    goto out;
	}
	ret = hdb_enctype2key(context, &uu->entry, 
			      t->enc_part.etype, &uukey);
	if(ret){
	    _kdc_free_ent(context, uu);
	    ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
	    goto out;
	}
	ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
	_kdc_free_ent(context, uu);
	if(ret)
	    goto out;

	ret = verify_flags(context, config, &adtkt, spn);
	if (ret)
	    goto out;

	s = &adtkt.cname;
	r = adtkt.crealm;
    }

    _krb5_principalname2krb5_principal(context, &sp, *s, r);
    ret = krb5_unparse_name(context, sp, &spn);	
    if (ret)
	goto out;
    _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
    ret = krb5_unparse_name(context, cp, &cpn);
    if (ret)
	goto out;
    unparse_flags (KDCOptions2int(b->kdc_options),
		   asn1_KDCOptions_units(),
		   opt_str, sizeof(opt_str));
    if(*opt_str)
	kdc_log(context, config, 0,
		"TGS-REQ %s from %s for %s [%s]", 
		cpn, from, spn, opt_str);
    else
	kdc_log(context, config, 0,
		"TGS-REQ %s from %s for %s", cpn, from, spn);

    /*
     * Fetch server
     */

server_lookup:
    ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER, NULL, &server);

    if(ret){
	const char *new_rlm;
	Realm req_rlm;
	krb5_realm *realms;

	if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
	    if(nloop++ < 2) {
		new_rlm = find_rpath(context, tgt->crealm, req_rlm);
		if(new_rlm) {
		    kdc_log(context, config, 5, "krbtgt for realm %s "
			    "not found, trying %s", 
			    req_rlm, new_rlm);
		    krb5_free_principal(context, sp);
		    free(spn);
		    krb5_make_principal(context, &sp, r, 
					KRB5_TGS_NAME, new_rlm, NULL);
		    ret = krb5_unparse_name(context, sp, &spn);	
		    if (ret)
			goto out;
		    goto server_lookup;
		}
	    }
	} else if(need_referral(context, sp, &realms)) {
	    if (strcmp(realms[0], sp->realm) != 0) {
		kdc_log(context, config, 5,
			"Returning a referral to realm %s for "
			"server %s that was not found",
			realms[0], spn);
		krb5_free_principal(context, sp);
		free(spn);
		krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
				    realms[0], NULL);
		ret = krb5_unparse_name(context, sp, &spn);
		if (ret)
		    goto out;
		krb5_free_host_realm(context, realms);
		goto server_lookup;
	    }
	    krb5_free_host_realm(context, realms);
	}
	kdc_log(context, config, 0,
		"Server not found in database: %s: %s", spn,
		krb5_get_err_text(context, ret));
	if (ret == HDB_ERR_NOENTRY)
	    ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
	goto out;
    }

    ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT, NULL, &client);
    if(ret) {
	const char *krbtgt_realm; 

	/*
	 * If the client belongs to the same realm as our krbtgt, it
	 * should exist in the local database.
	 *
	 */

	krbtgt_realm = 
	    krb5_principal_get_comp_string(context, 
					   krbtgt->entry.principal, 1);

	if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
	    if (ret == HDB_ERR_NOENTRY)
		ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
	    kdc_log(context, config, 1, "Client no longer in database: %s",
		    cpn);
	    goto out;
	}
	
	kdc_log(context, config, 1, "Client not found in database: %s: %s",
		cpn, krb5_get_err_text(context, ret));

	cross_realm = 1;
    }
    
    /*
     * Check that service is in the same realm as the krbtgt. If its
     * not the same, its someone that is using a uni-directional trust
     * backward.
     */
    
    if (strcmp(krb5_principal_get_realm(context, sp),
	       krb5_principal_get_comp_string(context, 
					      krbtgt->entry.principal, 
					      1)) != 0) {
	char *tpn;
	ret = krb5_unparse_name(context, krbtgt->entry.principal, &tpn);
	kdc_log(context, config, 0,
		"Request with wrong krbtgt: %s",
		(ret == 0) ? tpn : "<unknown>");
	if(ret == 0)
	    free(tpn);
	ret = KRB5KRB_AP_ERR_NOT_US;
	goto out;
    }

    /*
     *
     */

    client_principal = cp;

    if (client) {
	const PA_DATA *sdata;
	int i = 0;

	sdata = _kdc_find_padata(req, &i, KRB5_PADATA_S4U2SELF);
	if (sdata) {
	    krb5_crypto crypto;
	    krb5_data datack;
	    PA_S4U2Self self;
	    char *selfcpn = NULL;
	    const char *str;

	    ret = decode_PA_S4U2Self(sdata->padata_value.data, 
				     sdata->padata_value.length,
				     &self, NULL);
	    if (ret) {
		kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
		goto out;
	    }

	    ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
	    if (ret)
		goto out;

	    ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
	    if (ret) {
		free_PA_S4U2Self(&self);
		krb5_data_free(&datack);
		kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
			krb5_get_err_text(context, ret));
		goto out;
	    }

	    ret = krb5_verify_checksum(context,
				       crypto,
				       KRB5_KU_OTHER_CKSUM,
				       datack.data, 
				       datack.length, 
				       &self.cksum);
	    krb5_data_free(&datack);
	    krb5_crypto_destroy(context, crypto);
	    if (ret) {
		free_PA_S4U2Self(&self);
		kdc_log(context, config, 0, 
			"krb5_verify_checksum failed for S4U2Self: %s",
			krb5_get_err_text(context, ret));
		goto out;
	    }

	    ret = _krb5_principalname2krb5_principal(context,
						     &client_principal,
						     self.name,
						     self.realm);
	    free_PA_S4U2Self(&self);
	    if (ret)
		goto out;

	    ret = krb5_unparse_name(context, client_principal, &selfcpn);	
	    if (ret)
		goto out;

	    /*
	     * Check that service doing the impersonating is
	     * requesting a ticket to it-self.
	     */
	    if (krb5_principal_compare(context, cp, sp) != TRUE) {
		kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
			"to impersonate some other user "
			"(tried for user %s to service %s)",
			cpn, selfcpn, spn);
		free(selfcpn);
		ret = KRB5KDC_ERR_BADOPTION; /* ? */
		goto out;
	    }

	    /*
	     * If the service isn't trusted for authentication to
	     * delegation, remove the forward flag.
	     */

	    if (client->entry.flags.trusted_for_delegation) {
		str = "[forwardable]";
	    } else {
		b->kdc_options.forwardable = 0;
		str = "";
	    }
	    kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
		    "service %s %s", cpn, selfcpn, spn, str);
	    free(selfcpn);
	}
    }

    /*
     * Constrained delegation
     */

    if (client != NULL
	&& b->additional_tickets != NULL
	&& b->additional_tickets->len != 0
	&& b->kdc_options.enc_tkt_in_skey == 0)
    {
	Key *clientkey;
	Ticket *t;
	char *str;

	t = &b->additional_tickets->val[0];

	ret = hdb_enctype2key(context, &client->entry, 
			      t->enc_part.etype, &clientkey);
	if(ret){
	    ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
	    goto out;
	}

	ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
	if (ret) {
	    kdc_log(context, config, 0,
		    "failed to decrypt ticket for "
		    "constrained delegation from %s to %s ", spn, cpn);
	    goto out;
	}

	/* check that ticket is valid */

	if (adtkt.flags.forwardable == 0) {
	    kdc_log(context, config, 0,
		    "Missing forwardable flag on ticket for "
		    "constrained delegation from %s to %s ", spn, cpn);
	    ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
	    goto out;
	}

	ret = check_constrained_delegation(context, config, client, sp);
	if (ret) {
	    kdc_log(context, config, 0,
		    "constrained delegation from %s to %s not allowed", 
		    spn, cpn);
	    goto out;
	}

	ret = _krb5_principalname2krb5_principal(context,
						 &client_principal,
						 adtkt.cname,
						 adtkt.crealm);
	if (ret)
	    goto out;

	ret = krb5_unparse_name(context, client_principal, &str);
	if (ret)
	    goto out;

	ret = verify_flags(context, config, &adtkt, str);
	if (ret) {
	    free(str);
	    goto out;
	}

	/*
	 * Check KRB5SignedPath in authorization data and add new entry to
	 * make sure servers can't fake a ticket to us.
	 */

	ret = check_KRB5SignedPath(context,
				   config,
				   krbtgt,
				   &adtkt,
				   &spp,
				   1);
	if (ret) {
	    kdc_log(context, config, 0,
		    "KRB5SignedPath check from service %s failed "
		    "for delegation to %s for client %s "
		    "from %s failed with %s",
		    spn, str, cpn, from, krb5_get_err_text(context, ret));
	    free(str);
	    goto out;
	}

	kdc_log(context, config, 0, "constrained delegation for %s "
		"from %s to %s", str, cpn, spn);
	free(str);

	/* 
	 * Also require that the KDC have issue the service's krbtgt
	 * used to do the request. 
	 */
	require_signedpath = 1;
    }

    /*
     * Check flags
     */

    ret = _kdc_check_flags(context, config, 
			   client, cpn,
			   server, spn,
			   FALSE);
    if(ret)
	goto out;

    if((b->kdc_options.validate || b->kdc_options.renew) && 
       !krb5_principal_compare(context, 
			       krbtgt->entry.principal,
			       server->entry.principal)){
	kdc_log(context, config, 0, "Inconsistent request.");
	ret = KRB5KDC_ERR_SERVER_NOMATCH;
	goto out;
    }

    /* check for valid set of addresses */
    if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
	ret = KRB5KRB_AP_ERR_BADADDR;
	kdc_log(context, config, 0, "Request from wrong address");
	goto out;
    }
	
    /*
     * Select enctype, return key and kvno.
     */

    {
	krb5_enctype etype;

	if(b->kdc_options.enc_tkt_in_skey) {
	    int i;
	    ekey = &adtkt.key;
	    for(i = 0; i < b->etype.len; i++)
		if (b->etype.val[i] == adtkt.key.keytype)
		    break;
	    if(i == b->etype.len) {
		krb5_clear_error_string(context);
		return KRB5KDC_ERR_ETYPE_NOSUPP;
	    }
	    etype = b->etype.val[i];
	    kvno = 0;
	} else {
	    Key *skey;
	    
	    ret = _kdc_find_etype(context, server, b->etype.val, b->etype.len,
				  &skey, &etype);
	    if(ret) {
		kdc_log(context, config, 0, 
			"Server (%s) has no support for etypes", spp);
		return ret;
	    }
	    ekey = &skey->key;
	    kvno = server->entry.kvno;
	}
	
	ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
	if (ret)
	    goto out;
    }

    /* check PAC if not cross realm and if there is one */
    if (!cross_realm) {
	Key *tkey;

	ret = hdb_enctype2key(context, &krbtgt->entry, 
			      krbtgt_etype, &tkey);
	if(ret) {
	    kdc_log(context, config, 0,
		    "Failed to find key for krbtgt PAC check");
	    goto out;
	}

	ret = check_PAC(context, config, client_principal, 
			client, server, ekey, &tkey->key,
			tgt, &rspac, &require_signedpath);
	if (ret) {
	    kdc_log(context, config, 0,
		    "Verify PAC failed for %s (%s) from %s with %s",
		    spn, cpn, from, krb5_get_err_text(context, ret));
	    goto out;
	}
    }

    /* also check the krbtgt for signature */
    ret = check_KRB5SignedPath(context,
			       config,
			       krbtgt,
			       tgt,
			       &spp,
			       require_signedpath);
    if (ret) {
	kdc_log(context, config, 0,
		"KRB5SignedPath check failed for %s (%s) from %s with %s",
		spn, cpn, from, krb5_get_err_text(context, ret));
	goto out;
    }

    /*
     *
     */

    ret = tgs_make_reply(context,
			 config, 
			 b, 
			 client_principal,
			 tgt, 
			 ekey,
			 &sessionkey,
			 kvno,
			 auth_data,
			 server, 
			 spn,
			 client, 
			 cp, 
			 krbtgt, 
			 krbtgt_etype,
			 spp,
			 &rspac,
			 e_text,
			 reply);
	
out:
    free(spn);
    free(cpn);
	    
    krb5_data_free(&rspac);
    krb5_free_keyblock_contents(context, &sessionkey);
    if(server)
	_kdc_free_ent(context, server);
    if(client)
	_kdc_free_ent(context, client);

    if (client_principal && client_principal != cp)
	krb5_free_principal(context, client_principal);
    if (cp)
	krb5_free_principal(context, cp);
    if (sp)
	krb5_free_principal(context, sp);

    free_EncTicketPart(&adtkt);

    return ret;
}
Exemple #24
0
krb5_error_code KRB5_LIB_FUNCTION
_krb5_krb_rd_req(krb5_context context,
		 krb5_data *authent,
		 const char *service,
		 const char *instance,
		 const char *local_realm,
		 int32_t from_addr,
		 const krb5_keyblock *key,
		 struct _krb5_krb_auth_data *ad)
{
    krb5_error_code ret;
    krb5_storage *sp;
    krb5_data ticket, eaut, aut;
    krb5_ssize_t size;
    int little_endian;
    int8_t pvno;
    int8_t type;
    int8_t s_kvno;
    uint8_t ticket_length;
    uint8_t eaut_length;
    uint8_t time_5ms;
    char *realm = NULL;
    char *sname = NULL;
    char *sinstance = NULL;
    char *r_realm = NULL;
    char *r_name = NULL;
    char *r_instance = NULL;

    uint32_t r_time_sec;	/* Coarse time from authenticator */
    unsigned long delta_t;      /* Time in authenticator - local time */
    long tkt_age;		/* Age of ticket */

    struct timeval tv;

    krb5_data_zero(&ticket);
    krb5_data_zero(&eaut);
    krb5_data_zero(&aut);

    sp = krb5_storage_from_data(authent);
    if (sp == NULL) {
	krb5_set_error_string(context, "alloc: out of memory");
	return ENOMEM;
    }

    krb5_storage_set_eof_code(sp, EINVAL); /* XXX */

    ret = krb5_ret_int8(sp, &pvno);
    if (ret)
	goto error;

    if (pvno != KRB_PROT_VERSION) {
	ret = EINVAL; /* XXX */
	goto error;
    }

    ret = krb5_ret_int8(sp, &type);
    if (ret)
	goto error;

    little_endian = type & 1;
    type &= ~1;
    
    if(type != AUTH_MSG_APPL_REQUEST && type != AUTH_MSG_APPL_REQUEST_MUTUAL) {
	ret = EINVAL; /* RD_AP_MSG_TYPE */
	goto error;
    }

    RCHECK(ret, krb5_ret_int8(sp, &s_kvno), error);
    RCHECK(ret, get_v4_stringz(sp, &realm, REALM_SZ), error);
    RCHECK(ret, krb5_ret_uint8(sp, &ticket_length), error);
    RCHECK(ret, krb5_ret_uint8(sp, &eaut_length), error);
    RCHECK(ret, krb5_data_alloc(&ticket, ticket_length), error);

    size = krb5_storage_read(sp, ticket.data, ticket.length);
    if (size != ticket.length) {
	ret = EINVAL;
	goto error;
    }

    /* Decrypt and take apart ticket */
    ret = _krb5_krb_decomp_ticket(context, &ticket, key, local_realm, 
				  &sname, &sinstance, ad);
    if (ret)
	goto error;

    RCHECK(ret, krb5_data_alloc(&eaut, eaut_length), error);

    size = krb5_storage_read(sp, eaut.data, eaut.length);
    if (size != eaut.length) {
	ret = EINVAL;
	goto error;
    }

    krb5_storage_free(sp);
    sp = NULL;

    ret = decrypt_etext(context, &ad->session, &eaut, &aut);
    if (ret)
	goto error;

    sp = krb5_storage_from_data(&aut);
    if (sp == NULL) {
	krb5_set_error_string(context, "alloc: out of memory");
	ret = ENOMEM;
	goto error;
    }

    if (little_endian)
	krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE);
    else
	krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE);

    RCHECK(ret, get_v4_stringz(sp, &r_name, ANAME_SZ), error);
    RCHECK(ret, get_v4_stringz(sp, &r_instance, INST_SZ), error);
    RCHECK(ret, get_v4_stringz(sp, &r_realm, REALM_SZ), error);

    RCHECK(ret, krb5_ret_uint32(sp, &ad->checksum), error);
    RCHECK(ret, krb5_ret_uint8(sp, &time_5ms), error);
    RCHECK(ret, krb5_ret_uint32(sp, &r_time_sec), error);

    if (strcmp(ad->pname, r_name) != 0 ||
	strcmp(ad->pinst, r_instance) != 0 ||
	strcmp(ad->prealm, r_realm) != 0) {
	ret = EINVAL; /* RD_AP_INCON */
	goto error;
    }
    
    if (from_addr && from_addr != ad->address) {
	ret = EINVAL; /* RD_AP_BADD */
	goto error;
    }

    gettimeofday(&tv, NULL);
    delta_t = abs((int)(tv.tv_sec - r_time_sec));
    if (delta_t > CLOCK_SKEW) {
        ret = EINVAL; /* RD_AP_TIME */
	goto error;
    }

    /* Now check for expiration of ticket */

    tkt_age = tv.tv_sec - ad->time_sec;
    
    if ((tkt_age < 0) && (-tkt_age > CLOCK_SKEW)) {
        ret = EINVAL; /* RD_AP_NYV */
	goto error;
    }

    if (tv.tv_sec > _krb5_krb_life_to_time(ad->time_sec, ad->life)) {
	ret = EINVAL; /* RD_AP_EXP */
	goto error;
    }

    ret = 0;
 error:
    krb5_data_free(&ticket);
    krb5_data_free(&eaut);
    krb5_data_free(&aut);
    if (realm)
	free(realm);
    if (sname)
	free(sname);
    if (sinstance)
	free(sinstance);
    if (r_name)
	free(r_name);
    if (r_instance)
	free(r_instance);
    if (r_realm)
	free(r_realm);
    if (sp)
	krb5_storage_free(sp);

    if (ret)
	krb5_clear_error_string(context);

    return ret;
}
Exemple #25
0
krb5_error_code KRB5_LIB_FUNCTION
krb5_verify_ap_req2(krb5_context context,
		    krb5_auth_context *auth_context,
		    krb5_ap_req *ap_req,
		    krb5_const_principal server,
		    krb5_keyblock *keyblock,
		    krb5_flags flags,
		    krb5_flags *ap_req_options,
		    krb5_ticket **ticket,
		    krb5_key_usage usage)
{
    krb5_ticket *t;
    krb5_auth_context ac;
    krb5_error_code ret;
    EtypeList etypes;
    
    if (ticket)
	*ticket = NULL;

    if (auth_context && *auth_context) {
	ac = *auth_context;
    } else {
	ret = krb5_auth_con_init (context, &ac);
	if (ret)
	    return ret;
    }

    t = calloc(1, sizeof(*t));
    if (t == NULL) {
	ret = ENOMEM;
	krb5_clear_error_string (context);
	goto out;
    }

    if (ap_req->ap_options.use_session_key && ac->keyblock){
	ret = krb5_decrypt_ticket(context, &ap_req->ticket, 
				  ac->keyblock, 
				  &t->ticket,
				  flags);
	krb5_free_keyblock(context, ac->keyblock);
	ac->keyblock = NULL;
    }else
	ret = krb5_decrypt_ticket(context, &ap_req->ticket, 
				  keyblock, 
				  &t->ticket,
				  flags);
    
    if(ret)
	goto out;

    ret = _krb5_principalname2krb5_principal(context,
					     &t->server,
					     ap_req->ticket.sname, 
					     ap_req->ticket.realm);
    if (ret) goto out;
    ret = _krb5_principalname2krb5_principal(context,
					     &t->client,
					     t->ticket.cname, 
					     t->ticket.crealm);
    if (ret) goto out;

    /* save key */

    ret = krb5_copy_keyblock(context, &t->ticket.key, &ac->keyblock);
    if (ret) goto out;

    ret = decrypt_authenticator (context,
				 &t->ticket.key,
				 &ap_req->authenticator,
				 ac->authenticator,
				 usage);
    if (ret)
	goto out;

    {
	krb5_principal p1, p2;
	krb5_boolean res;
	
	_krb5_principalname2krb5_principal(context,
					   &p1,
					   ac->authenticator->cname,
					   ac->authenticator->crealm);
	_krb5_principalname2krb5_principal(context,
					   &p2, 
					   t->ticket.cname,
					   t->ticket.crealm);
	res = krb5_principal_compare (context, p1, p2);
	krb5_free_principal (context, p1);
	krb5_free_principal (context, p2);
	if (!res) {
	    ret = KRB5KRB_AP_ERR_BADMATCH;
	    krb5_clear_error_string (context);
	    goto out;
	}
    }

    /* check addresses */

    if (t->ticket.caddr
	&& ac->remote_address
	&& !krb5_address_search (context,
				 ac->remote_address,
				 t->ticket.caddr)) {
	ret = KRB5KRB_AP_ERR_BADADDR;
	krb5_clear_error_string (context);
	goto out;
    }

    /* check timestamp in authenticator */
    {
	krb5_timestamp now;

	krb5_timeofday (context, &now);

	if (abs(ac->authenticator->ctime - now) > context->max_skew) {
	    ret = KRB5KRB_AP_ERR_SKEW;
	    krb5_clear_error_string (context);
	    goto out;
	}
    }

    if (ac->authenticator->seq_number)
	krb5_auth_con_setremoteseqnumber(context, ac,
					 *ac->authenticator->seq_number);

    /* XXX - Xor sequence numbers */

    if (ac->authenticator->subkey) {
	ret = krb5_auth_con_setremotesubkey(context, ac,
					    ac->authenticator->subkey);
	if (ret)
	    goto out;
    }

    ret = find_etypelist(context, ac, &etypes);
    if (ret)
	goto out;

    ac->keytype = ETYPE_NULL;

    if (etypes.val) {
	int i;

	for (i = 0; i < etypes.len; i++) {
	    if (krb5_enctype_valid(context, etypes.val[i]) == 0) {
		ac->keytype = etypes.val[i];
		break;
	    }
	}
    }

    if (ap_req_options) {
	*ap_req_options = 0;
	if (ac->keytype != ETYPE_NULL)
	    *ap_req_options |= AP_OPTS_USE_SUBKEY;
	if (ap_req->ap_options.use_session_key)
	    *ap_req_options |= AP_OPTS_USE_SESSION_KEY;
	if (ap_req->ap_options.mutual_required)
	    *ap_req_options |= AP_OPTS_MUTUAL_REQUIRED;
    }

    if(ticket)
	*ticket = t;
    else
	krb5_free_ticket (context, t);
    if (auth_context) {
	if (*auth_context == NULL)
	    *auth_context = ac;
    } else
	krb5_auth_con_free (context, ac);
    free_EtypeList(&etypes);
    return 0;
 out:
    if (t)
	krb5_free_ticket (context, t);
    if (auth_context == NULL || *auth_context == NULL)
	krb5_auth_con_free (context, ac);
    return ret;
}
Exemple #26
0
static int
make_path(krb5_context context, struct tr_realm *r,
	  const char *from, const char *to)
{
    const char *p;
    struct tr_realm *path = r->next;
    struct tr_realm *tmp;

    if(strlen(from) < strlen(to)){
	const char *str;
	str = from;
	from = to;
	to = str;
    }
	
    if(strcmp(from + strlen(from) - strlen(to), to) == 0){
	p = from;
	while(1){
	    p = strchr(p, '.');
	    if(p == NULL) {
		krb5_clear_error_string (context);
		return KRB5KDC_ERR_POLICY;
	    }
	    p++;
	    if(strcmp(p, to) == 0)
		break;
	    tmp = calloc(1, sizeof(*tmp));
	    if(tmp == NULL){
		krb5_set_error_string (context, "malloc: out of memory");
		return ENOMEM;
	    }
	    tmp->next = path;
	    path = tmp;
	    path->realm = strdup(p);
	    if(path->realm == NULL){
		r->next = path; /* XXX */
		krb5_set_error_string (context, "malloc: out of memory");
		return ENOMEM;;
	    }
	}
    }else if(strncmp(from, to, strlen(to)) == 0){
	p = from + strlen(from);
	while(1){
	    while(p >= from && *p != '/') p--;
	    if(p == from) {
		r->next = path; /* XXX */
		return KRB5KDC_ERR_POLICY;
	    }
	    if(strncmp(to, from, p - from) == 0)
		break;
	    tmp = calloc(1, sizeof(*tmp));
	    if(tmp == NULL){
		krb5_set_error_string (context, "malloc: out of memory");
		return ENOMEM;
	    }
	    tmp->next = path;
	    path = tmp;
	    path->realm = malloc(p - from + 1);
	    if(path->realm == NULL){
		r->next = path; /* XXX */
		krb5_set_error_string (context, "malloc: out of memory");
		return ENOMEM;
	    }
	    memcpy(path->realm, from, p - from);
	    path->realm[p - from] = '\0';
	    p--;
	}
    } else {
	krb5_clear_error_string (context);
	return KRB5KDC_ERR_POLICY;
    }
    r->next = path;
    
    return 0;
}
Exemple #27
0
krb5_error_code KRB5_LIB_FUNCTION
krb5_sendauth(krb5_context context,
	      krb5_auth_context *auth_context,
	      krb5_pointer p_fd,
	      const char *appl_version,
	      krb5_principal client,
	      krb5_principal server,
	      krb5_flags ap_req_options,
	      krb5_data *in_data,
	      krb5_creds *in_creds,
	      krb5_ccache ccache,
	      krb5_error **ret_error,
	      krb5_ap_rep_enc_part **rep_result,
	      krb5_creds **out_creds)
{
    krb5_error_code ret;
    uint32_t len, net_len;
    const char *version = KRB5_SENDAUTH_VERSION;
    u_char repl;
    krb5_data ap_req, error_data;
    krb5_creds this_cred;
    krb5_principal this_client = NULL;
    krb5_creds *creds;
    ssize_t sret;
    krb5_boolean my_ccache = FALSE;

    len = strlen(version) + 1;
    net_len = htonl(len);
    if (krb5_net_write (context, p_fd, &net_len, 4) != 4
	|| krb5_net_write (context, p_fd, version, len) != len) {
	ret = errno;
	krb5_set_error_string (context, "write: %s", strerror(ret));
	return ret;
    }

    len = strlen(appl_version) + 1;
    net_len = htonl(len);
    if (krb5_net_write (context, p_fd, &net_len, 4) != 4
	|| krb5_net_write (context, p_fd, appl_version, len) != len) {
	ret = errno;
	krb5_set_error_string (context, "write: %s", strerror(ret));
	return ret;
    }

    sret = krb5_net_read (context, p_fd, &repl, sizeof(repl));
    if (sret < 0) {
	ret = errno;
	krb5_set_error_string (context, "read: %s", strerror(ret));
	return ret;
    } else if (sret != sizeof(repl)) {
	krb5_clear_error_string (context);
	return KRB5_SENDAUTH_BADRESPONSE;
    }

    if (repl != 0) {
	krb5_clear_error_string (context);
	return KRB5_SENDAUTH_REJECTED;
    }

    if (in_creds == NULL) {
	if (ccache == NULL) {
	    ret = krb5_cc_default (context, &ccache);
	    if (ret)
		return ret;
	    my_ccache = TRUE;
	}

	if (client == NULL) {
	    ret = krb5_cc_get_principal (context, ccache, &this_client);
	    if (ret) {
		if(my_ccache)
		    krb5_cc_close(context, ccache);
		return ret;
	    }
	    client = this_client;
	}
	memset(&this_cred, 0, sizeof(this_cred));
	this_cred.client = client;
	this_cred.server = server;
	this_cred.times.endtime = 0;
	this_cred.ticket.length = 0;
	in_creds = &this_cred;
    }
    if (in_creds->ticket.length == 0) {
	ret = krb5_get_credentials (context, 0, ccache, in_creds, &creds);
	if (ret) {
	    if(my_ccache)
		krb5_cc_close(context, ccache);
	    return ret;
	}
    } else {
	creds = in_creds;
    }
    if(my_ccache)
	krb5_cc_close(context, ccache);
    ret = krb5_mk_req_extended (context,
				auth_context,
				ap_req_options,
				in_data,
				creds,
				&ap_req);

    if (out_creds)
	*out_creds = creds;
    else
	krb5_free_creds(context, creds);
    if(this_client)
	krb5_free_principal(context, this_client);

    if (ret)
	return ret;

    ret = krb5_write_message (context,
			      p_fd,
			      &ap_req);
    if (ret)
	return ret;

    krb5_data_free (&ap_req);

    ret = krb5_read_message (context, p_fd, &error_data);
    if (ret)
	return ret;

    if (error_data.length != 0) {
	KRB_ERROR error;

	ret = krb5_rd_error (context, &error_data, &error);
	krb5_data_free (&error_data);
	if (ret == 0) {
	    ret = krb5_error_from_rd_error(context, &error, NULL);
	    if (ret_error != NULL) {
		*ret_error = malloc (sizeof(krb5_error));
		if (*ret_error == NULL) {
		    krb5_free_error_contents (context, &error);
		} else {
		    **ret_error = error;
		}
	    } else {
		krb5_free_error_contents (context, &error);
	    }
	    return ret;
	} else {
	    krb5_clear_error_string(context);
	    return ret;
	}
    }

    if (ap_req_options & AP_OPTS_MUTUAL_REQUIRED) {
	krb5_data ap_rep;
	krb5_ap_rep_enc_part *ignore;

	krb5_data_zero (&ap_rep);
	ret = krb5_read_message (context,
				 p_fd,
				 &ap_rep);
	if (ret)
	    return ret;

	ret = krb5_rd_rep (context, *auth_context, &ap_rep,
			   rep_result ? rep_result : &ignore);
	krb5_data_free (&ap_rep);
	if (ret)
	    return ret;
	if (rep_result == NULL)
	    krb5_free_ap_rep_enc_part (context, ignore);
    }
    return 0;
}
Exemple #28
0
krb5_error_code KRB5_LIB_FUNCTION
krb5_get_credentials_with_flags(krb5_context context,
				krb5_flags options,
				krb5_kdc_flags flags,
				krb5_ccache ccache,
				krb5_creds *in_creds,
				krb5_creds **out_creds)
{
    krb5_error_code ret;
    krb5_creds **tgts;
    krb5_creds *res_creds;
    int i;
    
    *out_creds = NULL;
    res_creds = calloc(1, sizeof(*res_creds));
    if (res_creds == NULL) {
	krb5_set_error_string(context, "malloc: out of memory");
	return ENOMEM;
    }

    if (in_creds->session.keytype)
	options |= KRB5_TC_MATCH_KEYTYPE;

    /* 
     * If we got a credential, check if credential is expired before
     * returning it.
     */
    ret = krb5_cc_retrieve_cred(context,
                                ccache,
                                in_creds->session.keytype ?
                                KRB5_TC_MATCH_KEYTYPE : 0,
                                in_creds, res_creds);
    /* 
     * If we got a credential, check if credential is expired before
     * returning it, but only if KRB5_GC_EXPIRED_OK is not set.
     */
    if (ret == 0) {
	krb5_timestamp timeret;

	/* If expired ok, don't bother checking */
        if(options & KRB5_GC_EXPIRED_OK) {
            *out_creds = res_creds;
            return 0;
        }
	    
	krb5_timeofday(context, &timeret);
	if(res_creds->times.endtime > timeret) {
	    *out_creds = res_creds;
	    return 0;
	}
	if(options & KRB5_GC_CACHED)
	    krb5_cc_remove_cred(context, ccache, 0, res_creds);

    } else if(ret != KRB5_CC_END) {
        free(res_creds);
        return ret;
    }
    free(res_creds);
    if(options & KRB5_GC_CACHED) {
        krb5_clear_error_string (context);        
        return KRB5_CC_NOTFOUND;
    }
    if(options & KRB5_GC_USER_USER)
	flags.b.enc_tkt_in_skey = 1;
    tgts = NULL;
    ret = get_cred_from_kdc_flags(context, flags, ccache, 
				  in_creds, out_creds, &tgts);
    for(i = 0; tgts && tgts[i]; i++) {
	krb5_cc_store_cred(context, ccache, tgts[i]);
	krb5_free_creds(context, tgts[i]);
    }
    free(tgts);
    if(ret == 0 && flags.b.enc_tkt_in_skey == 0)
	krb5_cc_store_cred(context, ccache, *out_creds);
    return ret;
}
Exemple #29
0
static krb5_error_code
get_cred_from_kdc_flags(krb5_context context,
			krb5_kdc_flags flags,
			krb5_ccache ccache,
			krb5_creds *in_creds,
			krb5_creds **out_creds,
			krb5_creds ***ret_tgts)
{
    krb5_error_code ret;
    krb5_creds *tgt, tmp_creds;
    krb5_const_realm client_realm, server_realm, try_realm;

    *out_creds = NULL;

    client_realm = krb5_principal_get_realm(context, in_creds->client);
    server_realm = krb5_principal_get_realm(context, in_creds->server);
    memset(&tmp_creds, 0, sizeof(tmp_creds));
    ret = krb5_copy_principal(context, in_creds->client, &tmp_creds.client);
    if(ret)
	return ret;

    try_realm = krb5_config_get_string(context, NULL, "capaths", 
				       client_realm, server_realm, NULL);
    
#if 1
    /* XXX remove in future release */
    if(try_realm == NULL)
	try_realm = krb5_config_get_string(context, NULL, "libdefaults", 
					   "capath", server_realm, NULL);
#endif

    if (try_realm == NULL)
	try_realm = client_realm;

    ret = krb5_make_principal(context,
			      &tmp_creds.server,
			      try_realm,
			      KRB5_TGS_NAME,
			      server_realm, 
			      NULL);
    if(ret){
	krb5_free_principal(context, tmp_creds.client);
	return ret;
    }
    {
	krb5_creds tgts;
	/* XXX try krb5_cc_retrieve_cred first? */
	ret = find_cred(context, ccache, tmp_creds.server, 
			*ret_tgts, &tgts);
	if(ret == 0){
	    *out_creds = calloc(1, sizeof(**out_creds));
	    if(*out_creds == NULL) {
		krb5_set_error_string(context, "malloc: out of memory");
		ret = ENOMEM;
	    } else {
		krb5_boolean noaddr;

		krb5_appdefault_boolean(context, NULL, tgts.server->realm,
					"no-addresses", FALSE, &noaddr);

		if (noaddr)
		    ret = get_cred_kdc(context, ccache, flags, NULL,
				       in_creds, &tgts, *out_creds);
		else
		    ret = get_cred_kdc_la(context, ccache, flags, 
					  in_creds, &tgts, *out_creds);
		if (ret) {
		    free (*out_creds);
		    *out_creds = NULL;
		}
	    }
	    krb5_free_cred_contents(context, &tgts);
	    krb5_free_principal(context, tmp_creds.server);
	    krb5_free_principal(context, tmp_creds.client);
	    return ret;
	}
    }
    if(krb5_realm_compare(context, in_creds->client, in_creds->server)) {
	krb5_clear_error_string (context);
	return KRB5_CC_NOTFOUND;
    }
    /* XXX this can loop forever */
    while(1){
	heim_general_string tgt_inst;

	ret = get_cred_from_kdc_flags(context, flags, ccache, &tmp_creds, 
				      &tgt, ret_tgts);
	if(ret) {
	    krb5_free_principal(context, tmp_creds.server);
	    krb5_free_principal(context, tmp_creds.client);
	    return ret;
	}
	ret = add_cred(context, ret_tgts, tgt);
	if(ret) {
	    krb5_free_principal(context, tmp_creds.server);
	    krb5_free_principal(context, tmp_creds.client);
	    return ret;
	}
	tgt_inst = tgt->server->name.name_string.val[1];
	if(strcmp(tgt_inst, server_realm) == 0)
	    break;
	krb5_free_principal(context, tmp_creds.server);
	ret = krb5_make_principal(context, &tmp_creds.server, 
				  tgt_inst, KRB5_TGS_NAME, server_realm, NULL);
	if(ret) {
	    krb5_free_principal(context, tmp_creds.server);
	    krb5_free_principal(context, tmp_creds.client);
	    return ret;
	}
	ret = krb5_free_creds(context, tgt);
	if(ret) {
	    krb5_free_principal(context, tmp_creds.server);
	    krb5_free_principal(context, tmp_creds.client);
	    return ret;
	}
    }
	
    krb5_free_principal(context, tmp_creds.server);
    krb5_free_principal(context, tmp_creds.client);
    *out_creds = calloc(1, sizeof(**out_creds));
    if(*out_creds == NULL) {
	krb5_set_error_string(context, "malloc: out of memory");
	ret = ENOMEM;
    } else {
	krb5_boolean noaddr;

	krb5_appdefault_boolean(context, NULL, tgt->server->realm,
				"no-addresses", FALSE, &noaddr);
	if (noaddr)
	    ret = get_cred_kdc (context, ccache, flags, NULL,
				in_creds, tgt, *out_creds);
	else
	    ret = get_cred_kdc_la(context, ccache, flags, 
				  in_creds, tgt, *out_creds);
	if (ret) {
	    free (*out_creds);
	    *out_creds = NULL;
	}
    }
    krb5_free_creds(context, tgt);
    return ret;
}
Exemple #30
0
static krb5_error_code
get_cred_kdc_usage(krb5_context context, 
		   krb5_ccache id, 
		   krb5_kdc_flags flags,
		   krb5_addresses *addresses, 
		   krb5_creds *in_creds, 
		   krb5_creds *krbtgt,
		   krb5_creds *out_creds,
		   krb5_key_usage usage)
{
    TGS_REQ req;
    krb5_data enc;
    krb5_data resp;
    krb5_kdc_rep rep;
    KRB_ERROR error;
    krb5_error_code ret;
    unsigned nonce;
    krb5_keyblock *subkey = NULL;
    size_t len;
    Ticket second_ticket;
    int send_to_kdc_flags = 0;
    
    krb5_data_zero(&resp);
    krb5_data_zero(&enc);

    krb5_generate_random_block(&nonce, sizeof(nonce));
    nonce &= 0xffffffff;
    
    if(flags.b.enc_tkt_in_skey){
	ret = decode_Ticket(in_creds->second_ticket.data, 
			    in_creds->second_ticket.length, 
			    &second_ticket, &len);
	if(ret)
	    return ret;
    }

    ret = init_tgs_req (context,
			id,
			addresses,
			flags,
			flags.b.enc_tkt_in_skey ? &second_ticket : NULL,
			in_creds,
			krbtgt,
			nonce,
			&subkey, 
			&req,
			usage);
    if(flags.b.enc_tkt_in_skey)
	free_Ticket(&second_ticket);
    if (ret)
	goto out;

    ASN1_MALLOC_ENCODE(TGS_REQ, enc.data, enc.length, &req, &len, ret);
    if (ret) 
	goto out;
    if(enc.length != len)
	krb5_abortx(context, "internal error in ASN.1 encoder");

    /* don't free addresses */
    req.req_body.addresses = NULL;
    free_TGS_REQ(&req);

    /*
     * Send and receive
     */
again:
    ret = krb5_sendto_kdc_flags (context, &enc, 
				 &krbtgt->server->name.name_string.val[1],
				 &resp,
				 send_to_kdc_flags);
    if(ret)
	goto out;

    memset(&rep, 0, sizeof(rep));
    if(decode_TGS_REP(resp.data, resp.length, &rep.kdc_rep, &len) == 0){
	ret = krb5_copy_principal(context, 
				  in_creds->client, 
				  &out_creds->client);
	if(ret)
	    goto out;
	ret = krb5_copy_principal(context, 
				  in_creds->server, 
				  &out_creds->server);
	if(ret)
	    goto out;
	/* this should go someplace else */
	out_creds->times.endtime = in_creds->times.endtime;

	ret = _krb5_extract_ticket(context,
				   &rep,
				   out_creds,
				   &krbtgt->session,
				   NULL,
				   KRB5_KU_TGS_REP_ENC_PART_SESSION,
				   &krbtgt->addresses,
				   nonce,
				   TRUE,
				   flags.b.request_anonymous,
				   decrypt_tkt_with_subkey,
				   subkey);
	krb5_free_kdc_rep(context, &rep);
    } else if(krb5_rd_error(context, &resp, &error) == 0) {
	ret = krb5_error_from_rd_error(context, &error, in_creds);
	krb5_free_error_contents(context, &error);

	if (ret == KRB5KRB_ERR_RESPONSE_TOO_BIG && !(send_to_kdc_flags & KRB5_KRBHST_FLAGS_LARGE_MSG)) {
	    send_to_kdc_flags |= KRB5_KRBHST_FLAGS_LARGE_MSG;
	    krb5_data_free(&resp);
	    goto again;
	}
    } else if(resp.data && ((char*)resp.data)[0] == 4) {
	ret = KRB5KRB_AP_ERR_V4_REPLY;
	krb5_clear_error_string(context);
    } else {
	ret = KRB5KRB_AP_ERR_MSG_TYPE;
	krb5_clear_error_string(context);
    }

out:
    krb5_data_free(&resp);
    krb5_data_free(&enc);
    if(subkey){
	krb5_free_keyblock_contents(context, subkey);
	free(subkey);
    }
    return ret;
    
}