Exemplo n.º 1
0
krb5_error_code
_kdc_tkt_add_if_relevant_ad(krb5_context context,
			    EncTicketPart *tkt,
			    int type,
			    const krb5_data *data)
{
    krb5_error_code ret;
    size_t size = 0;

    if (tkt->authorization_data == NULL) {
	tkt->authorization_data = calloc(1, sizeof(*tkt->authorization_data));
	if (tkt->authorization_data == NULL) {
	    krb5_set_error_message(context, ENOMEM, "out of memory");
	    return ENOMEM;
	}
    }

    /* add the entry to the last element */
    {
	AuthorizationData ad = { 0, NULL };
	AuthorizationDataElement ade;

	ade.ad_type = type;
	ade.ad_data = *data;

	ret = add_AuthorizationData(&ad, &ade);
	if (ret) {
	    krb5_set_error_message(context, ret, "add AuthorizationData failed");
	    return ret;
	}

	ade.ad_type = KRB5_AUTHDATA_IF_RELEVANT;

	ASN1_MALLOC_ENCODE(AuthorizationData,
			   ade.ad_data.data, ade.ad_data.length,
			   &ad, &size, ret);
	free_AuthorizationData(&ad);
	if (ret) {
	    krb5_set_error_message(context, ret, "ASN.1 encode of "
				   "AuthorizationData failed");
	    return ret;
	}
	if (ade.ad_data.length != size)
	    krb5_abortx(context, "internal asn.1 encoder error");

	ret = add_AuthorizationData(tkt->authorization_data, &ade);
	der_free_octet_string(&ade.ad_data);
	if (ret) {
	    krb5_set_error_message(context, ret, "add AuthorizationData failed");
	    return ret;
	}
    }

    return 0;
}
Exemplo n.º 2
0
static krb5_error_code
find_KRB5SignedPath(krb5_context context,
		    const AuthorizationData *ad,
		    krb5_data *data)
{
    AuthorizationData child;
    krb5_error_code ret;
    int pos;
	
    if (ad == NULL || ad->len == 0)
	return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;

    pos = ad->len - 1;

    if (ad->val[pos].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
	return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;

    ret = decode_AuthorizationData(ad->val[pos].ad_data.data,
				   ad->val[pos].ad_data.length,
				   &child,
				   NULL);
    if (ret) {
	krb5_set_error_string(context, "Failed to decode "
			      "IF_RELEVANT with %d", ret);
	return ret;
    }

    if (child.len != 1) {
	free_AuthorizationData(&child);
	return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
    }

    if (child.val[0].ad_type != KRB5_AUTHDATA_SIGNTICKET) {
	free_AuthorizationData(&child);
	return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
    }

    if (data)
	ret = der_copy_octet_string(&child.val[0].ad_data, data);
    free_AuthorizationData(&child);
    return ret;
}
Exemplo n.º 3
0
krb5_error_code KRB5_LIB_FUNCTION
krb5_free_cred_contents (krb5_context context, krb5_creds *c)
{
    krb5_free_principal (context, c->client);
    c->client = NULL;
    krb5_free_principal (context, c->server);
    c->server = NULL;
    krb5_free_keyblock_contents (context, &c->session);
    krb5_data_free (&c->ticket);
    krb5_data_free (&c->second_ticket);
    free_AuthorizationData (&c->authdata);
    krb5_free_addresses (context, &c->addresses);
    memset(c, 0, sizeof(*c));
    return 0;
}
Exemplo n.º 4
0
static krb5_error_code
tgs_make_reply(krb5_context context, 
	       krb5_kdc_configuration *config,
	       KDC_REQ_BODY *b, 
	       krb5_const_principal tgt_name,
	       const EncTicketPart *tgt, 
	       const EncryptionKey *serverkey,
	       const krb5_keyblock *sessionkey,
	       krb5_kvno kvno,
	       AuthorizationData *auth_data,
	       hdb_entry_ex *server, 
	       const char *server_name, 
	       hdb_entry_ex *client, 
	       krb5_principal client_principal, 
	       hdb_entry_ex *krbtgt,
	       krb5_enctype krbtgt_etype,
	       KRB5SignedPathPrincipals *spp,
	       const krb5_data *rspac,
	       const char **e_text,
	       krb5_data *reply)
{
    KDC_REP rep;
    EncKDCRepPart ek;
    EncTicketPart et;
    KDCOptions f = b->kdc_options;
    krb5_error_code ret;
    
    memset(&rep, 0, sizeof(rep));
    memset(&et, 0, sizeof(et));
    memset(&ek, 0, sizeof(ek));
    
    rep.pvno = 5;
    rep.msg_type = krb_tgs_rep;

    et.authtime = tgt->authtime;
    _kdc_fix_time(&b->till);
    et.endtime = min(tgt->endtime, *b->till);
    ALLOC(et.starttime);
    *et.starttime = kdc_time;
    
    ret = check_tgs_flags(context, config, b, tgt, &et);
    if(ret)
	goto out;

    /* We should check the transited encoding if:
       1) the request doesn't ask not to be checked
       2) globally enforcing a check
       3) principal requires checking
       4) we allow non-check per-principal, but principal isn't marked as allowing this
       5) we don't globally allow this
    */

#define GLOBAL_FORCE_TRANSITED_CHECK		\
    (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
#define GLOBAL_ALLOW_PER_PRINCIPAL			\
    (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
#define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK			\
    (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)

/* these will consult the database in future release */
#define PRINCIPAL_FORCE_TRANSITED_CHECK(P)		0
#define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P)	0

    ret = fix_transited_encoding(context, config, 
				 !f.disable_transited_check ||
				 GLOBAL_FORCE_TRANSITED_CHECK ||
				 PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
				 !((GLOBAL_ALLOW_PER_PRINCIPAL && 
				    PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
				   GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
				 &tgt->transited, &et,
				 *krb5_princ_realm(context, client_principal),
				 *krb5_princ_realm(context, server->entry.principal),
				 *krb5_princ_realm(context, krbtgt->entry.principal));
    if(ret)
	goto out;

    copy_Realm(krb5_princ_realm(context, server->entry.principal), 
	       &rep.ticket.realm);
    _krb5_principal2principalname(&rep.ticket.sname, server->entry.principal);
    copy_Realm(&tgt_name->realm, &rep.crealm);
/*
    if (f.request_anonymous)
	_kdc_make_anonymous_principalname (&rep.cname);
    else */

    copy_PrincipalName(&tgt_name->name, &rep.cname);
    rep.ticket.tkt_vno = 5;

    ek.caddr = et.caddr;
    if(et.caddr == NULL)
	et.caddr = tgt->caddr;

    {
	time_t life;
	life = et.endtime - *et.starttime;
	if(client && client->entry.max_life)
	    life = min(life, *client->entry.max_life);
	if(server->entry.max_life)
	    life = min(life, *server->entry.max_life);
	et.endtime = *et.starttime + life;
    }
    if(f.renewable_ok && tgt->flags.renewable && 
       et.renew_till == NULL && et.endtime < *b->till){
	et.flags.renewable = 1;
	ALLOC(et.renew_till);
	*et.renew_till = *b->till;
    }
    if(et.renew_till){
	time_t renew;
	renew = *et.renew_till - et.authtime;
	if(client && client->entry.max_renew)
	    renew = min(renew, *client->entry.max_renew);
	if(server->entry.max_renew)
	    renew = min(renew, *server->entry.max_renew);
	*et.renew_till = et.authtime + renew;
    }
	    
    if(et.renew_till){
	*et.renew_till = min(*et.renew_till, *tgt->renew_till);
	*et.starttime = min(*et.starttime, *et.renew_till);
	et.endtime = min(et.endtime, *et.renew_till);
    }
    
    *et.starttime = min(*et.starttime, et.endtime);

    if(*et.starttime == et.endtime){
	ret = KRB5KDC_ERR_NEVER_VALID;
	goto out;
    }
    if(et.renew_till && et.endtime == *et.renew_till){
	free(et.renew_till);
	et.renew_till = NULL;
	et.flags.renewable = 0;
    }
    
    et.flags.pre_authent = tgt->flags.pre_authent;
    et.flags.hw_authent  = tgt->flags.hw_authent;
    et.flags.anonymous   = tgt->flags.anonymous;
    et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
	    
    if (auth_data) {
	/* XXX Check enc-authorization-data */
	et.authorization_data = calloc(1, sizeof(*et.authorization_data));
	if (et.authorization_data == NULL) {
	    ret = ENOMEM;
	    goto out;
	}
	ret = copy_AuthorizationData(auth_data, et.authorization_data);
	if (ret)
	    goto out;

	/* Filter out type KRB5SignedPath */
	ret = find_KRB5SignedPath(context, et.authorization_data, NULL);
	if (ret == 0) {
	    if (et.authorization_data->len == 1) {
		free_AuthorizationData(et.authorization_data);
		free(et.authorization_data);
		et.authorization_data = NULL;
	    } else {
		AuthorizationData *ad = et.authorization_data;
		free_AuthorizationDataElement(&ad->val[ad->len - 1]);
		ad->len--;
	    }
	}
    }

    if(rspac->length) {
	/*
	 * No not need to filter out the any PAC from the
	 * auth_data since its signed by the KDC.
	 */
	ret = _kdc_tkt_add_if_relevant_ad(context, &et,
					  KRB5_AUTHDATA_WIN2K_PAC,
					  rspac);
	if (ret)
	    goto out;
    }

    ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
    if (ret)
	goto out;
    et.crealm = tgt->crealm;
    et.cname = tgt_name->name;
	    
    ek.key = et.key;
    /* MIT must have at least one last_req */
    ek.last_req.len = 1;
    ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
    if (ek.last_req.val == NULL) {
	ret = ENOMEM;
	goto out;
    }
    ek.nonce = b->nonce;
    ek.flags = et.flags;
    ek.authtime = et.authtime;
    ek.starttime = et.starttime;
    ek.endtime = et.endtime;
    ek.renew_till = et.renew_till;
    ek.srealm = rep.ticket.realm;
    ek.sname = rep.ticket.sname;
    
    _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime, 
		       et.endtime, et.renew_till);

    /* Don't sign cross realm tickets, they can't be checked anyway */
    {
	char *r = get_krbtgt_realm(&ek.sname);

	if (r == NULL || strcmp(r, ek.srealm) == 0) {
	    ret = _kdc_add_KRB5SignedPath(context,
					  config,
					  krbtgt,
					  krbtgt_etype,
					  NULL,
					  spp,
					  &et);
	    if (ret)
		goto out;
	}
    }

    /* It is somewhat unclear where the etype in the following
       encryption should come from. What we have is a session
       key in the passed tgt, and a list of preferred etypes
       *for the new ticket*. Should we pick the best possible
       etype, given the keytype in the tgt, or should we look
       at the etype list here as well?  What if the tgt
       session key is DES3 and we want a ticket with a (say)
       CAST session key. Should the DES3 etype be added to the
       etype list, even if we don't want a session key with
       DES3? */
    ret = _kdc_encode_reply(context, config, 
			    &rep, &et, &ek, et.key.keytype,
			    kvno, 
			    serverkey, 0, &tgt->key, e_text, reply);
out:
    free_TGS_REP(&rep);
    free_TransitedEncoding(&et.transited);
    if(et.starttime)
	free(et.starttime);
    if(et.renew_till)
	free(et.renew_till);
    if(et.authorization_data) {
	free_AuthorizationData(et.authorization_data);
	free(et.authorization_data);
    }
    free_LastReq(&ek.last_req);
    memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
    free_EncryptionKey(&et.key);
    return ret;
}
Exemplo n.º 5
0
static krb5_error_code
check_PAC(krb5_context context,
	  krb5_kdc_configuration *config,
	  const krb5_principal client_principal,
	  hdb_entry_ex *client,
	  hdb_entry_ex *server,
	  const EncryptionKey *server_key,
	  const EncryptionKey *krbtgt_key,
	  EncTicketPart *tkt,
	  krb5_data *rspac,
	  int *require_signedpath)
{
    AuthorizationData *ad = tkt->authorization_data;
    unsigned i, j;
    krb5_error_code ret;

    if (ad == NULL || ad->len == 0)
	return 0;

    for (i = 0; i < ad->len; i++) {
	AuthorizationData child;

	if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
	    continue;

	ret = decode_AuthorizationData(ad->val[i].ad_data.data,
				       ad->val[i].ad_data.length,
				       &child,
				       NULL);
	if (ret) {
	    krb5_set_error_string(context, "Failed to decode "
				  "IF_RELEVANT with %d", ret);
	    return ret;
	}
	for (j = 0; j < child.len; j++) {

	    if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) {
		krb5_pac pac;

		/* Found PAC */
		ret = krb5_pac_parse(context,
				     child.val[j].ad_data.data,
				     child.val[j].ad_data.length,
				     &pac);
		free_AuthorizationData(&child);
		if (ret)
		    return ret;

		ret = krb5_pac_verify(context, pac, tkt->authtime, 
				      client_principal,
				      krbtgt_key, NULL);
		if (ret) {
		    krb5_pac_free(context, pac);
		    return ret;
		}

		ret = _kdc_pac_verify(context, client_principal, 
				      client, server, &pac);
		if (ret) {
		    krb5_pac_free(context, pac);
		    return ret;
		}
		*require_signedpath = 0;

		ret = _krb5_pac_sign(context, pac, tkt->authtime,
				     client_principal,
				     server_key, krbtgt_key, rspac);

		krb5_pac_free(context, pac);

		return ret;
	    }
	}
	free_AuthorizationData(&child);
    }
    return 0;
}
Exemplo n.º 6
0
krb5_error_code
_kdc_tgs_rep(krb5_context context, 
	     krb5_kdc_configuration *config,
	     KDC_REQ *req, 
	     krb5_data *data,
	     const char *from,
	     struct sockaddr *from_addr,
	     int datagram_reply)
{
    AuthorizationData *auth_data = NULL;
    krb5_error_code ret;
    int i = 0;
    const PA_DATA *tgs_req;

    hdb_entry_ex *krbtgt = NULL;
    krb5_ticket *ticket = NULL;
    const char *e_text = NULL;
    krb5_enctype krbtgt_etype = ETYPE_NULL;

    time_t *csec = NULL;
    int *cusec = NULL;

    if(req->padata == NULL){
	ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
	kdc_log(context, config, 0,
		"TGS-REQ from %s without PA-DATA", from);
	goto out;
    }
    
    tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);

    if(tgs_req == NULL){
	ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
	
	kdc_log(context, config, 0, 
		"TGS-REQ from %s without PA-TGS-REQ", from);
	goto out;
    }
    ret = tgs_parse_request(context, config, 
			    &req->req_body, tgs_req,
			    &krbtgt,
			    &krbtgt_etype,
			    &ticket,
			    &e_text,
			    from, from_addr,
			    &csec, &cusec,
			    &auth_data);
    if (ret) {
	kdc_log(context, config, 0, 
		"Failed parsing TGS-REQ from %s", from);
	goto out;
    }

    ret = tgs_build_reply(context,
			  config,
			  req,
			  &req->req_body,
			  krbtgt,
			  krbtgt_etype,
			  ticket,
			  data,
			  from,
			  &e_text,
			  auth_data,
			  from_addr,
			  datagram_reply);
    if (ret) {
	kdc_log(context, config, 0, 
		"Failed building TGS-REP to %s", from);
	goto out;
    }

    /* */
    if (datagram_reply && data->length > config->max_datagram_reply_length) {
	krb5_data_free(data);
	ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
	e_text = "Reply packet too large";
    }

out:
    if(ret && data->data == NULL){
	krb5_mk_error(context,
		      ret,
		      NULL,
		      NULL,
		      NULL,
		      NULL,
		      csec,
		      cusec,
		      data);
    }
    free(csec);
    free(cusec);
    if (ticket)
	krb5_free_ticket(context, ticket);
    if(krbtgt)
	_kdc_free_ent(context, krbtgt);

    if (auth_data) {
	free_AuthorizationData(auth_data);
	free(auth_data);
    }

    return 0;
}
Exemplo n.º 7
0
static krb5_error_code
make_etypelist(krb5_context context,
	       krb5_authdata **auth_data)
{
    EtypeList etypes;
    krb5_error_code ret;
    krb5_authdata ad;
    u_char *buf;
    size_t len = 0;
    size_t buf_size;

    ret = _krb5_init_etype(context, KRB5_PDU_NONE,
			   &etypes.len, &etypes.val,
			   NULL);
    if (ret)
	return ret;

    ASN1_MALLOC_ENCODE(EtypeList, buf, buf_size, &etypes, &len, ret);
    if (ret) {
	free_EtypeList(&etypes);
	return ret;
    }
    if(buf_size != len)
	krb5_abortx(context, "internal error in ASN.1 encoder");
    free_EtypeList(&etypes);

    ALLOC_SEQ(&ad, 1);
    if (ad.val == NULL) {
	free(buf);
	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
	return ENOMEM;
    }

    ad.val[0].ad_type = KRB5_AUTHDATA_GSS_API_ETYPE_NEGOTIATION;
    ad.val[0].ad_data.length = len;
    ad.val[0].ad_data.data = buf;

    ASN1_MALLOC_ENCODE(AD_IF_RELEVANT, buf, buf_size, &ad, &len, ret);
    if (ret) {
	free_AuthorizationData(&ad);
	return ret;
    }
    if(buf_size != len)
	krb5_abortx(context, "internal error in ASN.1 encoder");
    free_AuthorizationData(&ad);

    ALLOC(*auth_data, 1);
    if (*auth_data == NULL) {
        free(buf);
	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
	return ENOMEM;
    }

    ALLOC_SEQ(*auth_data, 1);
    if ((*auth_data)->val == NULL) {
        free(*auth_data);
	free(buf);
	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
	return ENOMEM;
    }

    (*auth_data)->val[0].ad_type = KRB5_AUTHDATA_IF_RELEVANT;
    (*auth_data)->val[0].ad_data.length = len;
    (*auth_data)->val[0].ad_data.data = buf;

    return 0;
}
Exemplo n.º 8
0
static int
find_type_in_ad(krb5_context context,
		int type,
		krb5_data *data,
		krb5_boolean *found,
		krb5_boolean failp,
		krb5_keyblock *sessionkey,
		const AuthorizationData *ad,
		int level)
{
    krb5_error_code ret = 0;
    size_t i;

    if (level > 9) {
	ret = ENOENT; /* XXX */
	krb5_set_error_message(context, ret,
			       N_("Authorization data nested deeper "
				  "then %d levels, stop searching", ""),
			       level);
	goto out;
    }

    /*
     * Only copy out the element the first time we get to it, we need
     * to run over the whole authorization data fields to check if
     * there are any container clases we need to care about.
     */
    for (i = 0; i < ad->len; i++) {
	if (!*found && ad->val[i].ad_type == type) {
	    ret = der_copy_octet_string(&ad->val[i].ad_data, data);
	    if (ret) {
		krb5_set_error_message(context, ret,
				       N_("malloc: out of memory", ""));
		goto out;
	    }
	    *found = TRUE;
	    continue;
	}
	switch (ad->val[i].ad_type) {
	case KRB5_AUTHDATA_IF_RELEVANT: {
	    AuthorizationData child;
	    ret = decode_AuthorizationData(ad->val[i].ad_data.data,
					   ad->val[i].ad_data.length,
					   &child,
					   NULL);
	    if (ret) {
		krb5_set_error_message(context, ret,
				       N_("Failed to decode "
					  "IF_RELEVANT with %d", ""),
				       (int)ret);
		goto out;
	    }
	    ret = find_type_in_ad(context, type, data, found, FALSE,
				  sessionkey, &child, level + 1);
	    free_AuthorizationData(&child);
	    if (ret)
		goto out;
	    break;
	}
#if 0 /* XXX test */
	case KRB5_AUTHDATA_KDC_ISSUED: {
	    AD_KDCIssued child;

	    ret = decode_AD_KDCIssued(ad->val[i].ad_data.data,
				      ad->val[i].ad_data.length,
				      &child,
				      NULL);
	    if (ret) {
		krb5_set_error_message(context, ret,
				       N_("Failed to decode "
					  "AD_KDCIssued with %d", ""),
				       ret);
		goto out;
	    }
	    if (failp) {
		krb5_boolean valid;
		krb5_data buf;
		size_t len;

		ASN1_MALLOC_ENCODE(AuthorizationData, buf.data, buf.length,
				   &child.elements, &len, ret);
		if (ret) {
		    free_AD_KDCIssued(&child);
		    krb5_clear_error_message(context);
		    goto out;
		}
		if(buf.length != len)
		    krb5_abortx(context, "internal error in ASN.1 encoder");

		ret = krb5_c_verify_checksum(context, sessionkey, 19, &buf,
					     &child.ad_checksum, &valid);
		krb5_data_free(&buf);
		if (ret) {
		    free_AD_KDCIssued(&child);
		    goto out;
		}
		if (!valid) {
		    krb5_clear_error_message(context);
		    ret = ENOENT;
		    free_AD_KDCIssued(&child);
		    goto out;
		}
	    }
	    ret = find_type_in_ad(context, type, data, found, failp, sessionkey,
				  &child.elements, level + 1);
	    free_AD_KDCIssued(&child);
	    if (ret)
		goto out;
	    break;
	}
#endif
	case KRB5_AUTHDATA_AND_OR:
	    if (!failp)
		break;
	    ret = ENOENT; /* XXX */
	    krb5_set_error_message(context, ret,
				   N_("Authorization data contains "
				      "AND-OR element that is unknown to the "
				      "application", ""));
	    goto out;
	default:
	    if (!failp)
		break;
	    ret = ENOENT; /* XXX */
	    krb5_set_error_message(context, ret,
				   N_("Authorization data contains "
				      "unknown type (%d) ", ""),
				   ad->val[i].ad_type);
	    goto out;
	}
    }
out:
    if (ret) {
	if (*found) {
	    krb5_data_free(data);
	    *found = 0;
	}
    }
    return ret;
}
void
free_AD_MANDATORY_FOR_KDC(AD_MANDATORY_FOR_KDC *data)
{
free_AuthorizationData(data);
}