Ejemplo n.º 1
0
krb5_error_code krb5_obtain_padata(krb5_context context, krb5_pa_data **preauth_to_use, git_key_proc key_proc, krb5_const_pointer key_seed, krb5_creds *creds, krb5_kdc_req *request)
{
    krb5_error_code		retval;
    krb5_etype_info	    	etype_info = 0;
    krb5_pa_data **		pa;
    krb5_pa_data **		send_pa_list;
    krb5_pa_data **		send_pa;
    const krb5_preauth_ops	*ops;
    krb5_keyblock *		def_enc_key = 0;
    krb5_enctype 		enctype;
    krb5_data 			salt;
    krb5_data			scratch;
    int				size;
    int				f_salt = 0;

    if (preauth_to_use == NULL)
	return 0;

    for (pa = preauth_to_use, size=0; *pa; pa++, size++) {
	if ((*pa)->pa_type == KRB5_PADATA_ETYPE_INFO) {
	    /* XXX use the first one.  Is there another way to disambiguate? */
	    if (etype_info)
		continue;

	    scratch.length = (*pa)->length;
	    scratch.data = (char *) (*pa)->contents;
	    retval = decode_krb5_etype_info(&scratch, &etype_info);
	    if (retval)
		return retval;
	    if (etype_info[0] == NULL) {
		krb5_free_etype_info(context, etype_info);
		etype_info = NULL;
	    }
	}
    }

    if ((send_pa_list = malloc((size+1) * sizeof(krb5_pa_data *))) == NULL)
	return ENOMEM;

    send_pa = send_pa_list;
    *send_pa = 0;

    enctype = request->ktype[0];
    salt.data = 0;
    salt.length = SALT_TYPE_NO_LENGTH;
    if (etype_info) {
	enctype = etype_info[0]->etype;
	salt.data = (char *) etype_info[0]->salt;
	if(etype_info[0]->length == KRB5_ETYPE_NO_SALT) 
	  salt.length = SALT_TYPE_NO_LENGTH; /* XXX */
	else 
	  salt.length = etype_info[0]->length;
    }
    if (salt.length == SALT_TYPE_NO_LENGTH) {
        /*
	 * This will set the salt length 
	 */
	if ((retval = krb5_principal2salt(context, request->client, &salt)))
	    return(retval);
	f_salt = 1;
    }
    
    if ((retval = (*key_proc)(context, enctype, &salt, key_seed,
			      &def_enc_key)))
	goto cleanup;
    

    for (pa = preauth_to_use; *pa; pa++) {
	if (find_pa_system((*pa)->pa_type, &ops))
	    continue;

	if (ops->obtain == 0)
	    continue;
	
	retval = ((ops)->obtain)(context, *pa, etype_info, def_enc_key,
				 key_proc, key_seed, creds,
				 request, send_pa);
	if (retval)
	    goto cleanup;

	if (*send_pa)
	    send_pa++;
	*send_pa = 0;
    }

    retval = 0;

    if (send_pa_list[0]) {
	request->padata = send_pa_list;
	send_pa_list = 0;
    }

cleanup:
    if (etype_info)
	krb5_free_etype_info(context, etype_info);
    if (f_salt)
	free(salt.data);
    if (send_pa_list)
	krb5_free_pa_data(context, send_pa_list);
    if (def_enc_key)
	krb5_free_keyblock(context, def_enc_key);
    return retval;
    
}
Ejemplo n.º 2
0
/* Set etype info parameters in rock based on padata. */
static krb5_error_code
get_etype_info(krb5_context context, krb5_pa_data **padata,
               krb5_kdc_req *request, krb5_clpreauth_rock rock)
{
    krb5_error_code ret = 0;
    krb5_pa_data *pa;
    krb5_data d;
    krb5_etype_info etype_info = NULL, e;
    krb5_etype_info_entry *entry;
    krb5_boolean valid_found;
    int i;

    /* Find an etype-info2 or etype-info element in padata. */
    pa = krb5int_find_pa_data(context, padata, KRB5_PADATA_ETYPE_INFO2);
    if (pa != NULL) {
        d = padata2data(*pa);
        (void)decode_krb5_etype_info2(&d, &etype_info);
    } else {
        pa = krb5int_find_pa_data(context, padata, KRB5_PADATA_ETYPE_INFO);
        if (pa != NULL) {
            d = padata2data(*pa);
            (void)decode_krb5_etype_info(&d, &etype_info);
        }
    }

    /* Fall back to pw-salt/afs3-salt if no etype-info element is present. */
    if (etype_info == NULL)
        return get_salt(context, padata, request, rock);

    /* Search entries in order of the request's enctype preference. */
    entry = NULL;
    valid_found = FALSE;
    for (i = 0; i < request->nktypes && entry == NULL; i++) {
        for (e = etype_info; *e != NULL && entry == NULL; e++) {
            if ((*e)->etype == request->ktype[i])
                entry = *e;
            if (krb5_c_valid_enctype((*e)->etype))
                valid_found = TRUE;
        }
    }
    if (entry == NULL) {
        ret = (valid_found) ? KRB5_CONFIG_ETYPE_NOSUPP :
            KRB5_PROG_ETYPE_NOSUPP;
        goto cleanup;
    }

    /* Set rock fields based on the entry we selected. */
    *rock->etype = entry->etype;
    krb5_free_data_contents(context, rock->salt);
    if (entry->length != KRB5_ETYPE_NO_SALT) {
        *rock->salt = make_data(entry->salt, entry->length);
        entry->salt = NULL;
        *rock->default_salt = FALSE;
    } else {
        *rock->salt = empty_data();
        *rock->default_salt = TRUE;
    }
    krb5_free_data_contents(context, rock->s2kparams);
    *rock->s2kparams = entry->s2kparams;
    entry->s2kparams = empty_data();
    TRACE_PREAUTH_ETYPE_INFO(context, *rock->etype, rock->salt,
                             rock->s2kparams);

cleanup:
    krb5_free_etype_info(context, etype_info);
    return ret;
}
Ejemplo n.º 3
0
krb5_error_code
krb5_do_preauth(krb5_context context,
		krb5_kdc_req *request,
		krb5_pa_data **in_padata, krb5_pa_data ***out_padata,
		krb5_data *salt, krb5_data *s2kparams,
		krb5_enctype *etype,
		krb5_keyblock *as_key,
		krb5_prompter_fct prompter, void *prompter_data,
		krb5_gic_get_as_key_fct gak_fct, void *gak_data)
{
    int h, i, j, out_pa_list_size;
    int seen_etype_info2 = 0;
    krb5_pa_data *out_pa = NULL, **out_pa_list = NULL;
    krb5_data scratch;
    krb5_etype_info etype_info = NULL;
    krb5_error_code ret;
    static const int paorder[] = { PA_INFO, PA_REAL };
    int realdone;

    KRB5_LOG0(KRB5_INFO, "krb5_do_preauth() start");

    if (in_padata == NULL) {
	*out_padata = NULL;
	return(0);
    }

#ifdef DEBUG
    if (salt && salt->data && salt->length > 0) {
    	fprintf (stderr, "salt len=%d", salt->length);
	    if (salt->length > 0)
		fprintf (stderr, " '%*s'", salt->length, salt->data);
	    fprintf (stderr, "; preauth data types:");
	    for (i = 0; in_padata[i]; i++) {
		fprintf (stderr, " %d", in_padata[i]->pa_type);
    	}
    	fprintf (stderr, "\n");
    }
#endif

    out_pa_list = NULL;
    out_pa_list_size = 0;

    /* first do all the informational preauths, then the first real one */

    for (h=0; h<(sizeof(paorder)/sizeof(paorder[0])); h++) {
	realdone = 0;
	for (i=0; in_padata[i] && !realdone; i++) {
	    int k, l, etype_found, valid_etype_found;
	    /*
	     * This is really gross, but is necessary to prevent
	     * lossge when talking to a 1.0.x KDC, which returns an
	     * erroneous PA-PW-SALT when it returns a KRB-ERROR
	     * requiring additional preauth.
	     */
	    switch (in_padata[i]->pa_type) {
	    case KRB5_PADATA_ETYPE_INFO:
	    case KRB5_PADATA_ETYPE_INFO2:
	    {
		krb5_preauthtype pa_type = in_padata[i]->pa_type;
		if (etype_info) {
		    if (seen_etype_info2 || pa_type != KRB5_PADATA_ETYPE_INFO2)
			continue;
		    if (pa_type == KRB5_PADATA_ETYPE_INFO2) {
                        krb5_free_etype_info( context, etype_info);
			etype_info = NULL;
                    }
		}

		scratch.length = in_padata[i]->length;
		scratch.data = (char *) in_padata[i]->contents;
		if (pa_type == KRB5_PADATA_ETYPE_INFO2) {
                    seen_etype_info2++;
                    ret = decode_krb5_etype_info2(&scratch, &etype_info);
		}
		else ret = decode_krb5_etype_info(&scratch, &etype_info);
		if (ret) {
                    ret = 0; /*Ignore error and etype_info element*/
                    krb5_free_etype_info( context, etype_info);
                    etype_info = NULL;
                    continue;
		}
		if (etype_info[0] == NULL) {
		    krb5_free_etype_info(context, etype_info);
		    etype_info = NULL;
		    break;
		}
		/*
		 * Select first etype in our request which is also in
		 * etype-info (preferring client request ktype order).
		 */
		for (etype_found = 0, valid_etype_found = 0, k = 0;
		       	!etype_found && k < request->nktypes; k++) {
		    for (l = 0; etype_info[l]; l++) {
			if (etype_info[l]->etype == request->ktype[k]) {
			    etype_found++;
			    break;
			}
			/* check if program has support for this etype for more
			 * precise error reporting.
			 */
			if (valid_enctype(etype_info[l]->etype))
			    valid_etype_found++;
		    }
		}
		if (!etype_found) {
		    KRB5_LOG(KRB5_ERR, "error !etype_found, "
				"valid_etype_found = %d",
				valid_etype_found); 
		    if (valid_etype_found) {
			/* supported enctype but not requested */
			ret = KRB5_CONFIG_ETYPE_NOSUPP;
			goto cleanup;
		    }
		    else {
			/* unsupported enctype */
			ret = KRB5_PROG_ETYPE_NOSUPP;
			goto cleanup;
		    }

		}
		scratch.data = (char *) etype_info[l]->salt;
		scratch.length = etype_info[l]->length;
		krb5_free_data_contents(context, salt);
		if (scratch.length == KRB5_ETYPE_NO_SALT)
		  salt->data = NULL;
		else
                    if ((ret = krb5int_copy_data_contents( context,
				&scratch, salt)) != 0)
			goto cleanup;
		*etype = etype_info[l]->etype;
		krb5_free_data_contents(context, s2kparams);
		if ((ret = krb5int_copy_data_contents(context,
				&etype_info[l]->s2kparams,
				s2kparams)) != 0)
		  goto cleanup;
		break;
	    }
	    case KRB5_PADATA_PW_SALT:
	    case KRB5_PADATA_AFS3_SALT:
		if (etype_info)
		    continue;
		break;
	    default:
		;
	    }
	    for (j=0; pa_types[j].type >= 0; j++) {
		if ((in_padata[i]->pa_type == pa_types[j].type) &&
		    (pa_types[j].flags & paorder[h])) {
		    out_pa = NULL;

		    if ((ret = ((*pa_types[j].fct)(context, request,
					in_padata[i], &out_pa,
					salt, s2kparams, etype, as_key,
					prompter, prompter_data,
					gak_fct, gak_data)))) {
			goto cleanup;
		    }

		    if (out_pa) {
			if (out_pa_list == NULL) {
			    if ((out_pa_list =
				 (krb5_pa_data **)
				 malloc(2*sizeof(krb5_pa_data *)))
				== NULL) {
				ret = ENOMEM;
				goto cleanup;
			     }
			} else {
			    if ((out_pa_list =
				 (krb5_pa_data **)
				 realloc(out_pa_list,
					 (out_pa_list_size+2)*
					 sizeof(krb5_pa_data *)))
				== NULL) {
				/* XXX this will leak the pointers which
				   have already been allocated.  oh well. */
				ret = ENOMEM;
				goto cleanup;
			    }
			}
			
			out_pa_list[out_pa_list_size++] = out_pa;
		    }
		    if (paorder[h] == PA_REAL)
			realdone = 1;
		}
	    }
	}
    }

    if (out_pa_list)
	out_pa_list[out_pa_list_size++] = NULL;

    *out_padata = out_pa_list;
    if (etype_info)
	krb5_free_etype_info(context, etype_info);
   
    KRB5_LOG0(KRB5_INFO, "krb5_do_preauth() end");
    return(0);
cleanup:
    if (out_pa_list) {
	out_pa_list[out_pa_list_size++] = NULL;
	krb5_free_pa_data(context, out_pa_list);
    }
    if (etype_info)
	krb5_free_etype_info(context, etype_info);

    KRB5_LOG0(KRB5_INFO, "krb5_do_preauth() end");
    return (ret);

}