Ejemplo n.º 1
0
krb5_error_code KRB5_CALLCONV
krb5_copy_creds(krb5_context context, const krb5_creds *incred, krb5_creds **outcred)
{
    krb5_creds *tempcred;
    krb5_error_code retval;
    krb5_data *scratch;

    if (!(tempcred = (krb5_creds *)malloc(sizeof(*tempcred))))
	return ENOMEM;

    *tempcred = *incred;
    retval = krb5_copy_principal(context, incred->client, &tempcred->client);
    if (retval)
	goto cleanlast;
    retval = krb5_copy_principal(context, incred->server, &tempcred->server);
    if (retval)
	goto cleanclient;
    retval = krb5_copy_keyblock_contents(context, &incred->keyblock,
					 &tempcred->keyblock);
    if (retval)
	goto cleanserver;
    retval = krb5_copy_addresses(context, incred->addresses, &tempcred->addresses);
    if (retval)
	goto cleanblock;
    retval = krb5_copy_data(context, &incred->ticket, &scratch);
    if (retval)
	goto cleanaddrs;
    tempcred->ticket = *scratch;
    krb5_xfree(scratch);
    retval = krb5_copy_data(context, &incred->second_ticket, &scratch);
    if (retval)
	goto cleanticket;

    tempcred->second_ticket = *scratch;
    krb5_xfree(scratch);

    retval = krb5_copy_authdata(context, incred->authdata,&tempcred->authdata);
    if (retval)
        goto clearticket;

    *outcred = tempcred;
    return 0;

 clearticket:    
    memset(tempcred->ticket.data,0,tempcred->ticket.length);
 cleanticket:
    free(tempcred->ticket.data);
 cleanaddrs:
    krb5_free_addresses(context, tempcred->addresses);
 cleanblock:
    krb5_xfree(tempcred->keyblock.contents);
 cleanserver:
    krb5_free_principal(context, tempcred->server);
 cleanclient:
    krb5_free_principal(context, tempcred->client);
 cleanlast:
    krb5_xfree(tempcred);
    return retval;
}
Ejemplo n.º 2
0
/*
 * Copy contents of input credentials structure to supplied
 * destination, allocating storage for indirect fields as needed.  On
 * success, the output is a deep copy of the input.  On error, the
 * output structure is garbage and its contents should be ignored.
 */
krb5_error_code
k5_copy_creds_contents(krb5_context context, const krb5_creds *incred,
                       krb5_creds *tempcred)
{
    krb5_error_code retval;
    krb5_data *scratch;

    *tempcred = *incred;
    retval = krb5_copy_principal(context, incred->client, &tempcred->client);
    if (retval)
        goto cleanlast;
    retval = krb5_copy_principal(context, incred->server, &tempcred->server);
    if (retval)
        goto cleanclient;
    retval = krb5_copy_keyblock_contents(context, &incred->keyblock,
                                         &tempcred->keyblock);
    if (retval)
        goto cleanserver;
    retval = krb5_copy_addresses(context, incred->addresses, &tempcred->addresses);
    if (retval)
        goto cleanblock;
    retval = krb5_copy_data(context, &incred->ticket, &scratch);
    if (retval)
        goto cleanaddrs;
    tempcred->ticket = *scratch;
    free(scratch);
    retval = krb5_copy_data(context, &incred->second_ticket, &scratch);
    if (retval)
        goto clearticket;

    tempcred->second_ticket = *scratch;
    free(scratch);

    retval = krb5_copy_authdata(context, incred->authdata,&tempcred->authdata);
    if (retval)
        goto clearsecondticket;

    return 0;

clearsecondticket:
    memset(tempcred->second_ticket.data,0,tempcred->second_ticket.length);
    free(tempcred->second_ticket.data);
clearticket:
    memset(tempcred->ticket.data,0,tempcred->ticket.length);
    free(tempcred->ticket.data);
cleanaddrs:
    krb5_free_addresses(context, tempcred->addresses);
cleanblock:
    free(tempcred->keyblock.contents);
cleanserver:
    krb5_free_principal(context, tempcred->server);
cleanclient:
    krb5_free_principal(context, tempcred->client);
cleanlast:
    /* Do not free tempcred - we did not allocate it - its contents are
       garbage - but we should not free it */
    return retval;
}
Ejemplo n.º 3
0
Archivo: chpw.c Proyecto: jmoldow/krb5
/* Decode error_packet as a KRB-ERROR message and retrieve its e-data into
 * *edata_out. */
static krb5_error_code
get_error_edata(krb5_context context, const krb5_data *error_packet,
                krb5_data **edata_out)
{
    krb5_error_code ret;
    krb5_error *krberror = NULL;

    *edata_out = NULL;

    ret = krb5_rd_error(context, error_packet, &krberror);
    if (ret)
        return ret;

    if (krberror->e_data.data == NULL) {
        /* Return a krb5 error code based on the error number. */
        ret = ERROR_TABLE_BASE_krb5 + (krb5_error_code)krberror->error;
        goto cleanup;
    }

    ret = krb5_copy_data(context, &krberror->e_data, edata_out);

cleanup:
    krb5_free_error(context, krberror);
    return ret;
}
Ejemplo n.º 4
0
static krb5_error_code
set_paid(struct pa_info_data *paid, krb5_context context,
	 krb5_enctype etype,
	 krb5_salttype salttype, void *salt_string, size_t salt_len,
	 krb5_data *s2kparams)
{
    paid->etype = etype;
    paid->salt.salttype = salttype;
    paid->salt.saltvalue.data = malloc(salt_len + 1);
    if (paid->salt.saltvalue.data == NULL) {
	krb5_clear_error_message(context);
	return ENOMEM;
    }
    memcpy(paid->salt.saltvalue.data, salt_string, salt_len);
    ((char *)paid->salt.saltvalue.data)[salt_len] = '\0';
    paid->salt.saltvalue.length = salt_len;
    if (s2kparams) {
	krb5_error_code ret;

	ret = krb5_copy_data(context, s2kparams, &paid->s2kparams);
	if (ret) {
	    krb5_clear_error_message(context);
	    krb5_free_salt(context, paid->salt);
	    return ret;
	}
    } else
	paid->s2kparams = NULL;

    return 0;
}
Ejemplo n.º 5
0
static krb5_error_code greet_hello(krb5_context context, krb5_data **ret)
{
    krb5_data tmp;

    tmp.data = "Hello, KDC issued acceptor world!";
    tmp.length = strlen(tmp.data);

    return krb5_copy_data(context, &tmp, ret);
}
Ejemplo n.º 6
0
void
kdc_insert_lookaside(krb5_data *inpkt, krb5_data *outpkt)
{
    register krb5_kdc_replay_ent *eptr;    
    krb5_int32 timenow;
    time_t db_age;

    if (krb5_timeofday(kdc_context, &timenow) || 
	krb5_db_get_age(kdc_context, 0, &db_age))
	return;

    /* this is a new entry */
    eptr = (krb5_kdc_replay_ent *)calloc(1, sizeof(*eptr));
    if (!eptr)
	return;
    eptr->timein = timenow;
    eptr->db_age = db_age;
    /*
     * This is going to hurt a lot malloc()-wise due to the need to
     * allocate memory for the krb5_data and krb5_address elements.
     * ARGH!
     */
    if (krb5_copy_data(kdc_context, inpkt, &eptr->req_packet)) {
	free(eptr);
	return;
    }
    if (krb5_copy_data(kdc_context, outpkt, &eptr->reply_packet)) {
	krb5_free_data(kdc_context, eptr->req_packet);
	free(eptr);
	return;
    }
    eptr->next = root_ptr.next;
    root_ptr.next = eptr;
    num_entries++;
    return;
}
Ejemplo n.º 7
0
krb5_boolean
kdc_check_lookaside(krb5_data *inpkt, krb5_data **outpkt)
{
    krb5_int32 timenow;
    register krb5_kdc_replay_ent *eptr, *last, *hold;
    time_t db_age;

    if (krb5_timeofday(kdc_context, &timenow) || 
	krb5_db_get_age(kdc_context, 0, &db_age))
	return FALSE;

    calls++;

    /* search for a replay entry in the queue, possibly removing
       stale entries while we're here */

    if (root_ptr.next) {
	for (last = &root_ptr, eptr = root_ptr.next;
	     eptr;
	     eptr = eptr->next) {
	    if (MATCH(eptr)) {
		eptr->num_hits++;
		hits++;

		if (krb5_copy_data(kdc_context, eptr->reply_packet, outpkt))
		    return FALSE;
		else
		    return TRUE;
		/* return here, don't bother flushing even if it is stale.
		   if we just matched, we may get another retransmit... */
	    }
	    if (STALE(eptr)) {
		/* flush it and collect stats */
		max_hits_per_entry = max(max_hits_per_entry, eptr->num_hits);
		krb5_free_data(kdc_context, eptr->req_packet);
		krb5_free_data(kdc_context, eptr->reply_packet);
		hold = eptr;
		last->next = eptr->next;
		eptr = last;
		free(hold);
	    } else {
		/* this isn't it, just move along */
		last = eptr;
	    }
	}
    }
    return FALSE;
}
Ejemplo n.º 8
0
static krb5_error_code
make_etype_info_entry(krb5_context context, ETYPE_INFO_ENTRY *ent, Key *key)
{
    ent->etype = key->key.keytype;
    if(key->salt){
#if 0
	ALLOC(ent->salttype);

	if(key->salt->type == hdb_pw_salt)
	    *ent->salttype = 0; /* or 1? or NULL? */
	else if(key->salt->type == hdb_afs3_salt)
	    *ent->salttype = 2;
	else {
	    kdc_log(context, config, 0, "unknown salt-type: %d",
		    key->salt->type);
	    return KRB5KRB_ERR_GENERIC;
	}
	/* according to `the specs', we can't send a salt if
	   we have AFS3 salted key, but that requires that you
	   *know* what cell you are using (e.g by assuming
	   that the cell is the same as the realm in lower
	   case) */
#elif 0
	ALLOC(ent->salttype);
	*ent->salttype = key->salt->type;
#else
	/*
	 * We shouldn't sent salttype since it is incompatible with the
	 * specification and it breaks windows clients.  The afs
	 * salting problem is solved by using KRB5-PADATA-AFS3-SALT
	 * implemented in Heimdal 0.7 and later.
	 */
	ent->salttype = NULL;
#endif
	krb5_copy_data(context, &key->salt->salt,
		       &ent->salt);
    } else {
	/* we return no salt type at all, as that should indicate
	 * the default salt type and make everybody happy.  some
	 * systems (like w2k) dislike being told the salt type
	 * here. */

	ent->salttype = NULL;
	ent->salt = NULL;
    }
    return 0;
}
Ejemplo n.º 9
0
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_pac_verify(krb5_context context,
		const krb5_pac pac,
		time_t authtime,
		krb5_const_principal principal,
		const krb5_keyblock *server,
		const krb5_keyblock *privsvr)
{
    krb5_error_code ret;

    if (pac->server_checksum == NULL) {
	krb5_set_error_message(context, EINVAL, "PAC missing server checksum");
	return EINVAL;
    }
    if (pac->privsvr_checksum == NULL) {
	krb5_set_error_message(context, EINVAL, "PAC missing kdc checksum");
	return EINVAL;
    }
    if (pac->logon_name == NULL) {
	krb5_set_error_message(context, EINVAL, "PAC missing logon name");
	return EINVAL;
    }

    ret = verify_logonname(context,
			   pac->logon_name,
			   &pac->data,
			   authtime,
			   principal);
    if (ret)
	return ret;

    /*
     * in the service case, clean out data option of the privsvr and
     * server checksum before checking the checksum.
     */
    {
	krb5_data *copy;

	ret = krb5_copy_data(context, &pac->data, &copy);
	if (ret)
	    return ret;

	if (pac->server_checksum->buffersize < 4)
	    return EINVAL;
	if (pac->privsvr_checksum->buffersize < 4)
	    return EINVAL;

	memset((char *)copy->data + pac->server_checksum->offset_lo + 4,
	       0,
	       pac->server_checksum->buffersize - 4);

	memset((char *)copy->data + pac->privsvr_checksum->offset_lo + 4,
	       0,
	       pac->privsvr_checksum->buffersize - 4);

	ret = verify_checksum(context,
			      pac->server_checksum,
			      &pac->data,
			      copy->data,
			      copy->length,
			      server);
	krb5_free_data(context, copy);
	if (ret)
	    return ret;
    }
    if (privsvr) {
	/* The priv checksum covers the server checksum */
	ret = verify_checksum(context,
			      pac->privsvr_checksum,
			      &pac->data,
			      (char *)pac->data.data
			      + pac->server_checksum->offset_lo + 4,
			      pac->server_checksum->buffersize - 4,
			      privsvr);
	if (ret)
	    return ret;
    }

    return 0;
}
Ejemplo n.º 10
0
int create_keys(krb5_context krbctx,
                krb5_principal princ,
                char *password,
                const char *enctypes_string,
                struct keys_container *keys,
                char **err_msg)
{
    struct krb_key_salt *ksdata;
    krb5_error_code krberr;
    krb5_data key_password;
    krb5_data *realm = NULL;
    int i, nkeys;
    int ret;

    *err_msg = NULL;

    ret = prep_ksdata(krbctx, enctypes_string, keys, err_msg);
    if (ret == 0) return 0;

    ksdata = keys->ksdata;
    nkeys = keys->nkeys;

    if (password) {
        key_password.data = password;
        key_password.length = strlen(password);

        realm = krb5_princ_realm(krbctx, princ);
    }

    for (i = 0; i < nkeys; i++) {
        krb5_data *salt;

        if (!password) {
            /* cool, random keys */
            krberr = krb5_c_make_random_key(krbctx,
                                            ksdata[i].enctype,
                                            &ksdata[i].key);
            if (krberr) {
                *err_msg = _("Failed to create random key!\n");
                return 0;
            }
            /* set the salt to NO_SALT as the key was random */
            ksdata[i].salttype = NO_SALT;
            continue;
        }

        /* Make keys using password and required salt */
        switch (ksdata[i].salttype) {
        case KRB5_KDB_SALTTYPE_ONLYREALM:
            krberr = krb5_copy_data(krbctx, realm, &salt);
            if (krberr) {
                *err_msg = _("Failed to create key!\n");
                return 0;
            }

            ksdata[i].salt.length = salt->length;
            ksdata[i].salt.data = malloc(salt->length);
            if (!ksdata[i].salt.data) {
                *err_msg = _("Out of memory!\n");
                return 0;
            }
            memcpy(ksdata[i].salt.data, salt->data, salt->length);
            krb5_free_data(krbctx, salt);
            break;

        case KRB5_KDB_SALTTYPE_NOREALM:
            krberr = ipa_krb5_principal2salt_norealm(krbctx, princ,
                                                     &ksdata[i].salt);
            if (krberr) {
                *err_msg = _("Failed to create key!\n");
                return 0;
            }
            break;

        case KRB5_KDB_SALTTYPE_NORMAL:
            krberr = krb5_principal2salt(krbctx, princ, &ksdata[i].salt);
            if (krberr) {
                *err_msg = _("Failed to create key!\n");
                return 0;
            }
            break;

        /* no KRB5_KDB_SALTTYPE_V4, we do not support krb v4 */

        case KRB5_KDB_SALTTYPE_AFS3:
            /* Comment from MIT sources:
             * * Why do we do this? Well, the afs_mit_string_to_key
             * * needs to use strlen, and the realm is not NULL
             * * terminated....
             */
            ksdata[i].salt.data = (char *)malloc(realm->length + 1);
            if (NULL == ksdata[i].salt.data) {
                *err_msg = _("Out of memory!\n");
                return 0;
            }
            memcpy((char *)ksdata[i].salt.data,
                   (char *)realm->data, realm->length);
            ksdata[i].salt.data[realm->length] = '\0';
            /* AFS uses a special length (UGLY) */
            ksdata[i].salt.length = SALT_TYPE_AFS_LENGTH;
            break;

        default:
            *err_msg = _("Bad or unsupported salt type.\n");
/* FIXME:
            fprintf(stderr, _("Bad or unsupported salt type (%d)!\n"),
                ksdata[i].salttype);
*/
            return 0;
        }

        krberr = krb5_c_string_to_key(krbctx,
                                      ksdata[i].enctype,
                                      &key_password,
                                      &ksdata[i].salt,
                                      &ksdata[i].key);
        if (krberr) {
            *err_msg = _("Failed to create key!\n");
            return 0;
        }

        /* set back salt length to real value if AFS3 */
        if (ksdata[i].salttype == KRB5_KDB_SALTTYPE_AFS3) {
            ksdata[i].salt.length = realm->length;
        }
    }

    return nkeys;
}
Ejemplo n.º 11
0
/*ARGSUSED*/
void
process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
               const krb5_fulladdr *from, kdc_realm_t *kdc_active_realm,
               verto_ctx *vctx, loop_respond_fn respond, void *arg)
{
    krb5_error_code errcode;
    krb5_timestamp rtime;
    unsigned int s_flags = 0;
    krb5_data encoded_req_body;
    krb5_enctype useenctype;
    struct as_req_state *state;

    state = k5alloc(sizeof(*state), &errcode);
    if (state == NULL) {
        (*respond)(arg, errcode, NULL);
        return;
    }
    state->respond = respond;
    state->arg = arg;
    state->request = request;
    state->req_pkt = req_pkt;
    state->from = from;
    state->active_realm = kdc_active_realm;

    errcode = kdc_make_rstate(kdc_active_realm, &state->rstate);
    if (errcode != 0) {
        (*respond)(arg, errcode, NULL);
        return;
    }
    if (state->request->msg_type != KRB5_AS_REQ) {
        state->status = "msg_type mismatch";
        errcode = KRB5_BADMSGTYPE;
        goto errout;
    }
    if (fetch_asn1_field((unsigned char *) req_pkt->data,
                         1, 4, &encoded_req_body) != 0) {
        errcode = ASN1_BAD_ID;
        state->status = "Finding req_body";
        goto errout;
    }
    errcode = kdc_find_fast(&state->request, &encoded_req_body, NULL, NULL,
                            state->rstate, &state->inner_body);
    if (errcode) {
        state->status = "error decoding FAST";
        goto errout;
    }
    if (state->inner_body == NULL) {
        /* Not a FAST request; copy the encoded request body. */
        errcode = krb5_copy_data(kdc_context, &encoded_req_body,
                                 &state->inner_body);
        if (errcode) {
            state->status = "storing req body";
            goto errout;
        }
    }
    state->rock.request = state->request;
    state->rock.inner_body = state->inner_body;
    state->rock.rstate = state->rstate;
    state->rock.vctx = vctx;
    if (!state->request->client) {
        state->status = "NULL_CLIENT";
        errcode = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
        goto errout;
    }
    if ((errcode = krb5_unparse_name(kdc_context,
                                     state->request->client,
                                     &state->cname))) {
        state->status = "UNPARSING_CLIENT";
        goto errout;
    }
    limit_string(state->cname);
    if (!state->request->server) {
        state->status = "NULL_SERVER";
        errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
        goto errout;
    }
    if ((errcode = krb5_unparse_name(kdc_context,
                                     state->request->server,
                                     &state->sname))) {
        state->status = "UNPARSING_SERVER";
        goto errout;
    }
    limit_string(state->sname);

    /*
     * We set KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY as a hint
     * to the backend to return naming information in lieu
     * of cross realm TGS entries.
     */
    setflag(state->c_flags, KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY);
    /*
     * Note that according to the referrals draft we should
     * always canonicalize enterprise principal names.
     */
    if (isflagset(state->request->kdc_options, KDC_OPT_CANONICALIZE) ||
        state->request->client->type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
        setflag(state->c_flags, KRB5_KDB_FLAG_CANONICALIZE);
        setflag(state->c_flags, KRB5_KDB_FLAG_ALIAS_OK);
    }
    if (include_pac_p(kdc_context, state->request)) {
        setflag(state->c_flags, KRB5_KDB_FLAG_INCLUDE_PAC);
    }
    errcode = krb5_db_get_principal(kdc_context, state->request->client,
                                    state->c_flags, &state->client);
    if (errcode == KRB5_KDB_CANTLOCK_DB)
        errcode = KRB5KDC_ERR_SVC_UNAVAILABLE;
    if (errcode == KRB5_KDB_NOENTRY) {
        state->status = "CLIENT_NOT_FOUND";
        if (vague_errors)
            errcode = KRB5KRB_ERR_GENERIC;
        else
            errcode = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
        goto errout;
    } else if (errcode) {
        state->status = "LOOKING_UP_CLIENT";
        goto errout;
    }
    state->rock.client = state->client;

    /*
     * If the backend returned a principal that is not in the local
     * realm, then we need to refer the client to that realm.
     */
    if (!is_local_principal(kdc_active_realm, state->client->princ)) {
        /* Entry is a referral to another realm */
        state->status = "REFERRAL";
        errcode = KRB5KDC_ERR_WRONG_REALM;
        goto errout;
    }

    s_flags = 0;
    setflag(s_flags, KRB5_KDB_FLAG_ALIAS_OK);
    if (isflagset(state->request->kdc_options, KDC_OPT_CANONICALIZE)) {
        setflag(s_flags, KRB5_KDB_FLAG_CANONICALIZE);
    }
    errcode = krb5_db_get_principal(kdc_context, state->request->server,
                                    s_flags, &state->server);
    if (errcode == KRB5_KDB_CANTLOCK_DB)
        errcode = KRB5KDC_ERR_SVC_UNAVAILABLE;
    if (errcode == KRB5_KDB_NOENTRY) {
        state->status = "SERVER_NOT_FOUND";
        errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
        goto errout;
    } else if (errcode) {
        state->status = "LOOKING_UP_SERVER";
        goto errout;
    }

    if ((errcode = krb5_timeofday(kdc_context, &state->kdc_time))) {
        state->status = "TIMEOFDAY";
        goto errout;
    }
    state->authtime = state->kdc_time; /* for audit_as_request() */

    if ((errcode = validate_as_request(kdc_active_realm,
                                       state->request, *state->client,
                                       *state->server, state->kdc_time,
                                       &state->status, &state->e_data))) {
        if (!state->status)
            state->status = "UNKNOWN_REASON";
        errcode += ERROR_TABLE_BASE_krb5;
        goto errout;
    }

    /*
     * Select the keytype for the ticket session key.
     */
    if ((useenctype = select_session_keytype(kdc_active_realm, state->server,
                                             state->request->nktypes,
                                             state->request->ktype)) == 0) {
        /* unsupported ktype */
        state->status = "BAD_ENCRYPTION_TYPE";
        errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
        goto errout;
    }

    if ((errcode = krb5_c_make_random_key(kdc_context, useenctype,
                                          &state->session_key))) {
        state->status = "RANDOM_KEY_FAILED";
        goto errout;
    }

    /*
     * Canonicalization is only effective if we are issuing a TGT
     * (the intention is to allow support for Windows "short" realm
     * aliases, nothing more).
     */
    if (isflagset(s_flags, KRB5_KDB_FLAG_CANONICALIZE) &&
        krb5_is_tgs_principal(state->request->server) &&
        krb5_is_tgs_principal(state->server->princ)) {
        state->ticket_reply.server = state->server->princ;
    } else {
        state->ticket_reply.server = state->request->server;
    }

    state->enc_tkt_reply.flags = 0;
    state->enc_tkt_reply.times.authtime = state->authtime;

    setflag(state->enc_tkt_reply.flags, TKT_FLG_INITIAL);
    setflag(state->enc_tkt_reply.flags, TKT_FLG_ENC_PA_REP);

    /*
     * It should be noted that local policy may affect the
     * processing of any of these flags.  For example, some
     * realms may refuse to issue renewable tickets
     */

    if (isflagset(state->request->kdc_options, KDC_OPT_FORWARDABLE))
        setflag(state->enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);

    if (isflagset(state->request->kdc_options, KDC_OPT_PROXIABLE))
        setflag(state->enc_tkt_reply.flags, TKT_FLG_PROXIABLE);

    if (isflagset(state->request->kdc_options, KDC_OPT_ALLOW_POSTDATE))
        setflag(state->enc_tkt_reply.flags, TKT_FLG_MAY_POSTDATE);

    state->enc_tkt_reply.session = &state->session_key;
    if (isflagset(state->c_flags, KRB5_KDB_FLAG_CANONICALIZE)) {
        state->client_princ = *(state->client->princ);
    } else {
        state->client_princ = *(state->request->client);
        /* The realm is always canonicalized */
        state->client_princ.realm = state->client->princ->realm;
    }
    state->enc_tkt_reply.client = &state->client_princ;
    state->enc_tkt_reply.transited.tr_type = KRB5_DOMAIN_X500_COMPRESS;
    state->enc_tkt_reply.transited.tr_contents = empty_string;

    if (isflagset(state->request->kdc_options, KDC_OPT_POSTDATED)) {
        setflag(state->enc_tkt_reply.flags, TKT_FLG_POSTDATED);
        setflag(state->enc_tkt_reply.flags, TKT_FLG_INVALID);
        state->enc_tkt_reply.times.starttime = state->request->from;
    } else
        state->enc_tkt_reply.times.starttime = state->kdc_time;

    kdc_get_ticket_endtime(kdc_active_realm,
                           state->enc_tkt_reply.times.starttime,
                           kdc_infinity, state->request->till, state->client,
                           state->server, &state->enc_tkt_reply.times.endtime);

    if (isflagset(state->request->kdc_options, KDC_OPT_RENEWABLE_OK) &&
        !isflagset(state->client->attributes, KRB5_KDB_DISALLOW_RENEWABLE) &&
        (state->enc_tkt_reply.times.endtime < state->request->till)) {

        /* we set the RENEWABLE option for later processing */

        setflag(state->request->kdc_options, KDC_OPT_RENEWABLE);
        state->request->rtime = state->request->till;
    }
    rtime = (state->request->rtime == 0) ? kdc_infinity :
        state->request->rtime;

    if (isflagset(state->request->kdc_options, KDC_OPT_RENEWABLE)) {
        /*
         * XXX Should we squelch the output renew_till to be no
         * earlier than the endtime of the ticket?
         */
        setflag(state->enc_tkt_reply.flags, TKT_FLG_RENEWABLE);
        state->enc_tkt_reply.times.renew_till =
            min(rtime, state->enc_tkt_reply.times.starttime +
                min(state->client->max_renewable_life,
                    min(state->server->max_renewable_life,
                        max_renewable_life_for_realm)));
    } else
        state->enc_tkt_reply.times.renew_till = 0; /* XXX */

    /*
     * starttime is optional, and treated as authtime if not present.
     * so we can nuke it if it matches
     */
    if (state->enc_tkt_reply.times.starttime ==
        state->enc_tkt_reply.times.authtime)
        state->enc_tkt_reply.times.starttime = 0;

    state->enc_tkt_reply.caddrs = state->request->addresses;
    state->enc_tkt_reply.authorization_data = 0;

    /* If anonymous requests are being used, adjust the realm of the client
     * principal. */
    if (isflagset(state->request->kdc_options, KDC_OPT_REQUEST_ANONYMOUS)) {
        if (!krb5_principal_compare_any_realm(kdc_context,
                                              state->request->client,
                                              krb5_anonymous_principal())) {
            errcode = KRB5KDC_ERR_BADOPTION;
            state->status = "Anonymous requested but anonymous "
                "principal not used.";
            goto errout;
        }
        setflag(state->enc_tkt_reply.flags, TKT_FLG_ANONYMOUS);
        krb5_free_principal(kdc_context, state->request->client);
        state->request->client = NULL;
        errcode = krb5_copy_principal(kdc_context, krb5_anonymous_principal(),
                                      &state->request->client);
        if (errcode) {
            state->status = "Copying anonymous principal";
            goto errout;
        }
        state->enc_tkt_reply.client = state->request->client;
        setflag(state->client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH);
    }

    /*
     * Check the preauthentication if it is there.
     */
    if (state->request->padata) {
        check_padata(kdc_context, &state->rock, state->req_pkt,
                     state->request, &state->enc_tkt_reply, &state->pa_context,
                     &state->e_data, &state->typed_e_data, finish_preauth,
                     state);
    } else
        finish_preauth(state, 0);
    return;

errout:
    finish_process_as_req(state, errcode);
}
Ejemplo n.º 12
0
krb5_error_code
kdc_find_fast(krb5_kdc_req **requestptr,
              krb5_data *checksummed_data,
              krb5_keyblock *tgs_subkey,
              krb5_keyblock *tgs_session,
              struct kdc_request_state *state,
              krb5_data **inner_body_out)
{
    krb5_error_code retval = 0;
    krb5_pa_data *fast_padata, *cookie_padata = NULL;
    krb5_data scratch, *inner_body = NULL;
    krb5_fast_req * fast_req = NULL;
    krb5_kdc_req *request = *requestptr;
    krb5_fast_armored_req *fast_armored_req = NULL;
    krb5_checksum *cksum;
    krb5_boolean cksum_valid;
    krb5_keyblock empty_keyblock;
    kdc_realm_t *kdc_active_realm = state->realm_data;

    if (inner_body_out != NULL)
        *inner_body_out = NULL;
    scratch.data = NULL;
    krb5_clear_error_message(kdc_context);
    memset(&empty_keyblock, 0, sizeof(krb5_keyblock));
    fast_padata = krb5int_find_pa_data(kdc_context,
                                       request->padata, KRB5_PADATA_FX_FAST);
    if (fast_padata !=  NULL){
        scratch.length = fast_padata->length;
        scratch.data = (char *) fast_padata->contents;
        retval = decode_krb5_pa_fx_fast_request(&scratch, &fast_armored_req);
        if (retval == 0 &&fast_armored_req->armor) {
            switch (fast_armored_req->armor->armor_type) {
            case KRB5_FAST_ARMOR_AP_REQUEST:
                if (tgs_subkey) {
                    retval = KRB5KDC_ERR_PREAUTH_FAILED;
                    krb5_set_error_message(kdc_context, retval,
                                           _("Ap-request armor not permitted "
                                             "with TGS"));
                    break;
                }
                retval = armor_ap_request(state, fast_armored_req->armor);
                break;
            default:
                krb5_set_error_message(kdc_context, KRB5KDC_ERR_PREAUTH_FAILED,
                                       _("Unknown FAST armor type %d"),
                                       fast_armored_req->armor->armor_type);
                retval = KRB5KDC_ERR_PREAUTH_FAILED;
            }
        }
        if (retval == 0 && !state->armor_key) {
            if (tgs_subkey)
                retval = krb5_c_fx_cf2_simple(kdc_context,
                                              tgs_subkey, "subkeyarmor",
                                              tgs_session, "ticketarmor",
                                              &state->armor_key);
            else {
                retval = KRB5KDC_ERR_PREAUTH_FAILED;
                krb5_set_error_message(kdc_context, retval,
                                       _("No armor key but FAST armored "
                                         "request present"));
            }
        }
        if (retval == 0) {
            krb5_data plaintext;
            plaintext.length = fast_armored_req->enc_part.ciphertext.length;
            plaintext.data = malloc(plaintext.length);
            if (plaintext.data == NULL)
                retval = ENOMEM;
            retval = krb5_c_decrypt(kdc_context,
                                    state->armor_key,
                                    KRB5_KEYUSAGE_FAST_ENC, NULL,
                                    &fast_armored_req->enc_part,
                                    &plaintext);
            if (retval == 0)
                retval = decode_krb5_fast_req(&plaintext, &fast_req);
            if (retval == 0 && inner_body_out != NULL) {
                retval = fetch_asn1_field((unsigned char *)plaintext.data,
                                          1, 2, &scratch);
                if (retval == 0) {
                    retval = krb5_copy_data(kdc_context, &scratch,
                                            &inner_body);
                }
            }
            if (plaintext.data)
                free(plaintext.data);
        }
        cksum = &fast_armored_req->req_checksum;
        if (retval == 0)
            retval = krb5_c_verify_checksum(kdc_context, state->armor_key,
                                            KRB5_KEYUSAGE_FAST_REQ_CHKSUM,
                                            checksummed_data, cksum,
                                            &cksum_valid);
        if (retval == 0 && !cksum_valid) {
            retval = KRB5KRB_AP_ERR_MODIFIED;
            krb5_set_error_message(kdc_context, retval,
                                   _("FAST req_checksum invalid; request "
                                     "modified"));
        }
        if (retval == 0) {
            if (!krb5_c_is_keyed_cksum(cksum->checksum_type)) {
                retval = KRB5KDC_ERR_POLICY;
                krb5_set_error_message(kdc_context, retval,
                                       _("Unkeyed checksum used in fast_req"));
            }
        }
        if (retval == 0) {
            if ((fast_req->fast_options & UNSUPPORTED_CRITICAL_FAST_OPTIONS) != 0)
                retval = KRB5KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTION;
        }
        if (retval == 0)
            cookie_padata = krb5int_find_pa_data(kdc_context,
                                                 fast_req->req_body->padata,
                                                 KRB5_PADATA_FX_COOKIE);
        if (retval == 0) {
            state->fast_options = fast_req->fast_options;
            krb5_free_kdc_req( kdc_context, request);
            *requestptr = fast_req->req_body;
            fast_req->req_body = NULL;
        }
    }
    else {
        cookie_padata = krb5int_find_pa_data(kdc_context,
                                             request->padata,
                                             KRB5_PADATA_FX_COOKIE);
    }
    if (retval == 0 && cookie_padata != NULL) {
        krb5_pa_data *new_padata = malloc(sizeof (krb5_pa_data));
        if (new_padata == NULL) {
            retval = ENOMEM;
        } else {
            new_padata->pa_type = KRB5_PADATA_FX_COOKIE;
            new_padata->length = cookie_padata->length;
            new_padata->contents = malloc(new_padata->length);
            if (new_padata->contents == NULL) {
                retval = ENOMEM;
                free(new_padata);
            } else {
                memcpy(new_padata->contents, cookie_padata->contents,
                       new_padata->length);
                state->cookie = new_padata;
            }
        }
    }
    if (retval == 0 && inner_body_out != NULL) {
        *inner_body_out = inner_body;
        inner_body = NULL;
    }
    krb5_free_data(kdc_context, inner_body);
    if (fast_req)
        krb5_free_fast_req( kdc_context, fast_req);
    if (fast_armored_req)
        krb5_free_fast_armored_req(kdc_context, fast_armored_req);
    return retval;
}
Ejemplo n.º 13
0
static void
change (krb5_auth_context auth_context,
        krb5_principal admin_principal,
        uint16_t version,
        int s,
        struct sockaddr *sa,
        int sa_size,
        krb5_data *in_data)
{
    krb5_error_code ret;
    char *client = NULL, *admin = NULL;
    const char *pwd_reason;
    kadm5_config_params conf;
    void *kadm5_handle = NULL;
    krb5_principal principal = NULL;
    krb5_data *pwd_data = NULL;
    char *tmp;
    ChangePasswdDataMS chpw;

    memset (&conf, 0, sizeof(conf));
    memset(&chpw, 0, sizeof(chpw));

    if (version == KRB5_KPASSWD_VERS_CHANGEPW) {
        ret = krb5_copy_data(context, in_data, &pwd_data);
        if (ret) {
            krb5_warn (context, ret, "krb5_copy_data");
            reply_priv (auth_context, s, sa, sa_size, KRB5_KPASSWD_MALFORMED,
                        "out out memory copying password");
            return;
        }
        principal = admin_principal;
    } else if (version == KRB5_KPASSWD_VERS_SETPW) {
        size_t len;

        ret = decode_ChangePasswdDataMS(in_data->data, in_data->length,
                                        &chpw, &len);
        if (ret) {
            krb5_warn (context, ret, "decode_ChangePasswdDataMS");
            reply_priv (auth_context, s, sa, sa_size, KRB5_KPASSWD_MALFORMED,
                        "malformed ChangePasswdData");
            return;
        }


        ret = krb5_copy_data(context, &chpw.newpasswd, &pwd_data);
        if (ret) {
            krb5_warn (context, ret, "krb5_copy_data");
            reply_priv (auth_context, s, sa, sa_size, KRB5_KPASSWD_MALFORMED,
                        "out out memory copying password");
            goto out;
        }

        if (chpw.targname == NULL && chpw.targrealm != NULL) {
            krb5_warn (context, ret, "kadm5_init_with_password_ctx");
            reply_priv (auth_context, s, sa, sa_size,
                        KRB5_KPASSWD_MALFORMED,
                        "targrealm but not targname");
            goto out;
        }

        if (chpw.targname) {
            krb5_principal_data princ;

            princ.name = *chpw.targname;
            princ.realm = *chpw.targrealm;
            if (princ.realm == NULL) {
                ret = krb5_get_default_realm(context, &princ.realm);

                if (ret) {
                    krb5_warnx (context,
                                "kadm5_init_with_password_ctx: "
                                "failed to allocate realm");
                    reply_priv (auth_context, s, sa, sa_size,
                                KRB5_KPASSWD_SOFTERROR,
                                "failed to allocate realm");
                    goto out;
                }
            }
            ret = krb5_copy_principal(context, &princ, &principal);
            if (*chpw.targrealm == NULL)
                free(princ.realm);
            if (ret) {
                krb5_warn(context, ret, "krb5_copy_principal");
                reply_priv(auth_context, s, sa, sa_size,
                           KRB5_KPASSWD_HARDERROR,
                           "failed to allocate principal");
                goto out;
            }
        } else
            principal = admin_principal;
    } else {
        krb5_warnx (context, "kadm5_init_with_password_ctx: unknown proto");
        reply_priv (auth_context, s, sa, sa_size,
                    KRB5_KPASSWD_HARDERROR,
                    "Unknown protocol used");
        return;
    }

    ret = krb5_unparse_name (context, admin_principal, &admin);
    if (ret) {
        krb5_warn (context, ret, "unparse_name failed");
        reply_priv (auth_context, s, sa, sa_size,
                    KRB5_KPASSWD_HARDERROR, "out of memory error");
        goto out;
    }

    conf.realm = principal->realm;
    conf.mask |= KADM5_CONFIG_REALM;

    ret = kadm5_init_with_password_ctx(context,
                                       admin,
                                       NULL,
                                       KADM5_ADMIN_SERVICE,
                                       &conf, 0, 0,
                                       &kadm5_handle);
    if (ret) {
        krb5_warn (context, ret, "kadm5_init_with_password_ctx");
        reply_priv (auth_context, s, sa, sa_size, 2,
                    "Internal error");
        goto out;
    }

    ret = krb5_unparse_name(context, principal, &client);
    if (ret) {
        krb5_warn (context, ret, "unparse_name failed");
        reply_priv (auth_context, s, sa, sa_size,
                    KRB5_KPASSWD_HARDERROR, "out of memory error");
        goto out;
    }

    /*
     * Check password quality if not changing as administrator
     */

    if (krb5_principal_compare(context, admin_principal, principal) == TRUE) {

        pwd_reason = kadm5_check_password_quality (context, principal,
                     pwd_data);
        if (pwd_reason != NULL ) {
            krb5_warnx (context,
                        "%s didn't pass password quality check with error: %s",
                        client, pwd_reason);
            reply_priv (auth_context, s, sa, sa_size,
                        KRB5_KPASSWD_SOFTERROR, pwd_reason);
            goto out;
        }
        krb5_warnx (context, "Changing password for %s", client);
    } else {
        ret = _kadm5_acl_check_permission(kadm5_handle, KADM5_PRIV_CPW,
                                          principal);
        if (ret) {
            krb5_warn (context, ret,
                       "Check ACL failed for %s for changing %s password",
                       admin, client);
            reply_priv (auth_context, s, sa, sa_size,
                        KRB5_KPASSWD_HARDERROR, "permission denied");
            goto out;
        }
        krb5_warnx (context, "%s is changing password for %s", admin, client);
    }

    ret = krb5_data_realloc(pwd_data, pwd_data->length + 1);
    if (ret) {
        krb5_warn (context, ret, "malloc: out of memory");
        reply_priv (auth_context, s, sa, sa_size, KRB5_KPASSWD_HARDERROR,
                    "Internal error");
        goto out;
    }
    tmp = pwd_data->data;
    tmp[pwd_data->length - 1] = '\0';

    ret = kadm5_s_chpass_principal_cond (kadm5_handle, principal, tmp);
    krb5_free_data (context, pwd_data);
    pwd_data = NULL;
    if (ret) {
        const char *str = krb5_get_error_message(context, ret);
        krb5_warnx(context, "kadm5_s_chpass_principal_cond: %s", str);
        reply_priv (auth_context, s, sa, sa_size, KRB5_KPASSWD_SOFTERROR,
                    str ? str : "Internal error");
        krb5_free_error_message(context, str);
        goto out;
    }
    reply_priv (auth_context, s, sa, sa_size, KRB5_KPASSWD_SUCCESS,
                "Password changed");
out:
    free_ChangePasswdDataMS(&chpw);
    if (principal != admin_principal)
        krb5_free_principal(context, principal);
    if (admin)
        free(admin);
    if (client)
        free(client);
    if (pwd_data)
        krb5_free_data(context, pwd_data);
    if (kadm5_handle)
        kadm5_destroy (kadm5_handle);
}
Ejemplo n.º 14
0
static krb5_error_code
kdcrep2creds(krb5_context context, krb5_kdc_rep *pkdcrep, krb5_address *const *address,
             krb5_data *psectkt, krb5_creds **ppcreds)
{
    krb5_error_code retval;
    krb5_data *pdata;

    if ((*ppcreds = (krb5_creds *)calloc(1,sizeof(krb5_creds))) == NULL) {
        return ENOMEM;
    }

    if ((retval = krb5_copy_principal(context, pkdcrep->client,
                                      &(*ppcreds)->client)))
        goto cleanup;

    if ((retval = krb5_copy_principal(context, pkdcrep->enc_part2->server,
                                      &(*ppcreds)->server)))
        goto cleanup;

    if ((retval = krb5_copy_keyblock_contents(context,
                                              pkdcrep->enc_part2->session,
                                              &(*ppcreds)->keyblock)))
        goto cleanup;
    TRACE_TGS_REPLY(context, (*ppcreds)->client, (*ppcreds)->server,
                    &(*ppcreds)->keyblock);

    if ((retval = krb5_copy_data(context, psectkt, &pdata)))
        goto cleanup_keyblock;
    (*ppcreds)->second_ticket = *pdata;
    free(pdata);

    (*ppcreds)->ticket_flags = pkdcrep->enc_part2->flags;
    (*ppcreds)->times = pkdcrep->enc_part2->times;
    (*ppcreds)->magic = KV5M_CREDS;

    (*ppcreds)->authdata = NULL;                        /* not used */
    (*ppcreds)->is_skey = psectkt->length != 0;

    if (pkdcrep->enc_part2->caddrs) {
        if ((retval = krb5_copy_addresses(context, pkdcrep->enc_part2->caddrs,
                                          &(*ppcreds)->addresses)))
            goto cleanup_keyblock;
    } else {
        /* no addresses in the list means we got what we had */
        if ((retval = krb5_copy_addresses(context, address,
                                          &(*ppcreds)->addresses)))
            goto cleanup_keyblock;
    }

    if ((retval = encode_krb5_ticket(pkdcrep->ticket, &pdata)))
        goto cleanup_keyblock;

    (*ppcreds)->ticket = *pdata;
    free(pdata);
    return 0;

cleanup_keyblock:
    krb5_free_keyblock_contents(context, &(*ppcreds)->keyblock);

cleanup:
    free (*ppcreds);
    *ppcreds = NULL;
    return retval;
}
Ejemplo n.º 15
0
Archivo: chpw.c Proyecto: jmoldow/krb5
/* Decode a reply to produce the clear-text output. */
static krb5_error_code
get_clear_result(krb5_context context, krb5_auth_context auth_context,
                 const krb5_data *packet, krb5_data **clear_out,
                 krb5_boolean *is_error_out)
{
    krb5_error_code ret;
    char *ptr, *end = packet->data + packet->length;
    unsigned int plen, vno, aplen;
    krb5_data ap_rep, cipher, error;
    krb5_ap_rep_enc_part *ap_rep_enc;
    krb5_replay_data replay;
    krb5_key send_subkey = NULL;
    krb5_data clear = empty_data();

    *clear_out = NULL;
    *is_error_out = FALSE;

    /* Check for an unframed KRB-ERROR (expected for RFC 3244 requests; also
     * received from MS AD for version 1 requests). */
    if (krb5_is_krb_error(packet)) {
        *is_error_out = TRUE;
        return get_error_edata(context, packet, clear_out);
    }

    if (packet->length < 6)
        return KRB5KRB_AP_ERR_MODIFIED;

    /* Decode and verify the length. */
    ptr = packet->data;
    plen = (*ptr++ & 0xff);
    plen = (plen << 8) | (*ptr++ & 0xff);
    if (plen != packet->length)
        return KRB5KRB_AP_ERR_MODIFIED;

    /* Decode and verify the version number. */
    vno = (*ptr++ & 0xff);
    vno = (vno << 8) | (*ptr++ & 0xff);
    if (vno != 1 && vno != 0xff80)
        return KRB5KDC_ERR_BAD_PVNO;

    /* Decode and check the AP-REP length. */
    aplen = (*ptr++ & 0xff);
    aplen = (aplen << 8) | (*ptr++ & 0xff);
    if (aplen > end - ptr)
        return KRB5KRB_AP_ERR_MODIFIED;

    /* A zero-length AP-REQ indicates a framed KRB-ERROR response.  (Expected
     * for protocol version 1; specified but unusual for RFC 3244 requests.) */
    if (aplen == 0) {
        *is_error_out = TRUE;
        error = make_data(ptr, end - ptr);
        return get_error_edata(context, &error, clear_out);
    }

    /* We have an AP-REP.  Save send_subkey to later smash recv_subkey. */
    ret = krb5_auth_con_getsendsubkey_k(context, auth_context, &send_subkey);
    if (ret)
        return ret;

    /* Verify the AP-REP. */
    ap_rep = make_data(ptr, aplen);
    ptr += ap_rep.length;
    ret = krb5_rd_rep(context, auth_context, &ap_rep, &ap_rep_enc);
    if (ret)
        goto cleanup;
    krb5_free_ap_rep_enc_part(context, ap_rep_enc);

    /* Smash recv_subkey to be send_subkey, per spec. */
    ret = krb5_auth_con_setrecvsubkey_k(context, auth_context, send_subkey);
    if (ret)
        goto cleanup;

    /* Extract and decrypt the result. */
    cipher = make_data(ptr, end - ptr);
    ret = krb5_rd_priv(context, auth_context, &cipher, &clear, &replay);
    if (ret)
        goto cleanup;

    ret = krb5_copy_data(context, &clear, clear_out);
    if (ret)
        goto cleanup;
    *is_error_out = FALSE;

cleanup:
    krb5_k_free_key(context, send_subkey);
    krb5_free_data_contents(context, &clear);
    return ret;
}