If no server given, interate over keytab to find a key that can
decrypt the request. The resulting server principal is what in the keytab, the real service can be fetched from. git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@24257 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
@@ -524,6 +524,7 @@ struct krb5_rd_req_out_ctx_data {
|
||||
krb5_keyblock *keyblock;
|
||||
krb5_flags ap_req_options;
|
||||
krb5_ticket *ticket;
|
||||
krb5_principal server;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -561,7 +562,7 @@ krb5_rd_req_in_set_keytab(krb5_context context,
|
||||
*
|
||||
* @return Kerberos 5 error code, see krb5_get_error_message().
|
||||
*
|
||||
* @ingroup krb5
|
||||
* @ingroup krb5_auth
|
||||
*/
|
||||
|
||||
krb5_error_code KRB5_LIB_FUNCTION
|
||||
@@ -608,23 +609,40 @@ krb5_rd_req_out_get_keyblock(krb5_context context,
|
||||
return krb5_copy_keyblock(context, out->keyblock, keyblock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the principal that was used in the request from the
|
||||
* client. Might not match whats in the ticket if krb5_rd_req_ctx()
|
||||
* searched in the keytab for a matching key.
|
||||
*
|
||||
* @param context a Kerberos 5 context.
|
||||
* @param out a krb5_rd_req_out_ctx from krb5_rd_req_ctx().
|
||||
* @param principal return principal, free with krb5_free_principal().
|
||||
*
|
||||
* @ingroup krb5_auth
|
||||
*/
|
||||
|
||||
krb5_error_code KRB5_LIB_FUNCTION
|
||||
krb5_rd_req_out_get_server(krb5_context context,
|
||||
krb5_rd_req_out_ctx out,
|
||||
krb5_principal *principal)
|
||||
{
|
||||
return krb5_copy_principal(context, out->server, principal);
|
||||
}
|
||||
|
||||
void KRB5_LIB_FUNCTION
|
||||
krb5_rd_req_in_ctx_free(krb5_context context, krb5_rd_req_in_ctx ctx)
|
||||
{
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
krb5_error_code KRB5_LIB_FUNCTION
|
||||
_krb5_rd_req_out_ctx_alloc(krb5_context context, krb5_rd_req_out_ctx *ctx)
|
||||
{
|
||||
*ctx = calloc(1, sizeof(**ctx));
|
||||
if (*ctx == NULL) {
|
||||
krb5_set_error_message(context, ENOMEM,
|
||||
N_("malloc: out of memory", ""));
|
||||
return ENOMEM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* Free the krb5_rd_req_out_ctx.
|
||||
*
|
||||
* @param context Keberos 5 context.
|
||||
* @param ctx krb5_rd_req_out_ctx context to free.
|
||||
*
|
||||
* @ingroup krb5_auth
|
||||
*/
|
||||
|
||||
void KRB5_LIB_FUNCTION
|
||||
krb5_rd_req_out_ctx_free(krb5_context context, krb5_rd_req_out_ctx ctx)
|
||||
@@ -633,6 +651,8 @@ krb5_rd_req_out_ctx_free(krb5_context context, krb5_rd_req_out_ctx ctx)
|
||||
krb5_free_ticket(context, ctx->ticket);
|
||||
if (ctx->keyblock)
|
||||
krb5_free_keyblock(context, ctx->keyblock);
|
||||
if (ctx->server)
|
||||
krb5_free_principal(context, ctx->server);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
@@ -770,8 +790,24 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* The core server function that verify application authentication
|
||||
* requests from clients.
|
||||
*
|
||||
* @param context Keberos 5 context.
|
||||
* @param auth_context the authentication context, can be NULL, then
|
||||
* default values for the authentication context will used.
|
||||
* @param inbuf the (AP-REQ) authentication buffer
|
||||
* @param server the server with authenticate as, if NULL the function
|
||||
* will try to find any avaiable credentintial in the keytab
|
||||
* that will verify the reply.
|
||||
* @param inctx control the behavior of the function, if NULL, the
|
||||
* default behavior is used.
|
||||
* @param outctx the return outctx,can be NULL. If set and function
|
||||
* returns 0, free with krb5_rd_req_out_ctx_free()
|
||||
* @return Kerberos 5 error code, see krb5_get_error_message().
|
||||
*
|
||||
* @ingroup krb5_auth
|
||||
*/
|
||||
|
||||
krb5_error_code KRB5_LIB_FUNCTION
|
||||
@@ -784,12 +820,17 @@ krb5_rd_req_ctx(krb5_context context,
|
||||
{
|
||||
krb5_error_code ret;
|
||||
krb5_ap_req ap_req;
|
||||
krb5_principal service = NULL;
|
||||
krb5_rd_req_out_ctx o = NULL;
|
||||
krb5_keytab keytab = NULL;
|
||||
|
||||
ret = _krb5_rd_req_out_ctx_alloc(context, &o);
|
||||
if (ret)
|
||||
goto out;
|
||||
*outctx = NULL;
|
||||
|
||||
o = calloc(1, sizeof(*o));
|
||||
if (o == NULL) {
|
||||
krb5_set_error_message(context, ENOMEM,
|
||||
N_("malloc: out of memory", ""));
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
if (*auth_context == NULL) {
|
||||
ret = krb5_auth_con_init(context, auth_context);
|
||||
@@ -801,15 +842,6 @@ krb5_rd_req_ctx(krb5_context context,
|
||||
if(ret)
|
||||
goto out;
|
||||
|
||||
if(server == NULL){
|
||||
ret = _krb5_principalname2krb5_principal(context,
|
||||
&service,
|
||||
ap_req.ticket.sname,
|
||||
ap_req.ticket.realm);
|
||||
if (ret)
|
||||
goto out;
|
||||
server = service;
|
||||
}
|
||||
if (ap_req.ap_options.use_session_key &&
|
||||
(*auth_context)->keyblock == NULL) {
|
||||
ret = KRB5KRB_AP_ERR_NOKEY;
|
||||
@@ -831,35 +863,134 @@ krb5_rd_req_ctx(krb5_context context,
|
||||
&o->keyblock);
|
||||
if (ret)
|
||||
goto out;
|
||||
} else {
|
||||
krb5_keytab keytab = NULL;
|
||||
} else if (server) {
|
||||
krb5_keytab id = NULL;
|
||||
|
||||
if (inctx && inctx->keytab)
|
||||
keytab = inctx->keytab;
|
||||
id = inctx->keytab;
|
||||
|
||||
ret = get_key_from_keytab(context,
|
||||
auth_context,
|
||||
&ap_req,
|
||||
server,
|
||||
keytab,
|
||||
id,
|
||||
&o->keyblock);
|
||||
if(ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = krb5_verify_ap_req2(context,
|
||||
auth_context,
|
||||
&ap_req,
|
||||
server,
|
||||
o->keyblock,
|
||||
0,
|
||||
&o->ap_req_options,
|
||||
&o->ticket,
|
||||
KRB5_KU_AP_REQ_AUTH);
|
||||
/*
|
||||
* If we got an exact keymatch, use that.
|
||||
*/
|
||||
if (o->keyblock) {
|
||||
ret = krb5_verify_ap_req2(context,
|
||||
auth_context,
|
||||
&ap_req,
|
||||
server,
|
||||
o->keyblock,
|
||||
0,
|
||||
&o->ap_req_options,
|
||||
&o->ticket,
|
||||
KRB5_KU_AP_REQ_AUTH);
|
||||
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
} else {
|
||||
krb5_keytab id = NULL;
|
||||
krb5_kt_cursor cursor;
|
||||
krb5_keytab_entry entry;
|
||||
int done = 0, kvno = 0;
|
||||
|
||||
memset(&cursor, 0, sizeof(cursor));
|
||||
|
||||
if (ap_req.ticket.enc_part.kvno)
|
||||
kvno = *ap_req.ticket.enc_part.kvno;
|
||||
|
||||
if (inctx && inctx->keytab)
|
||||
id = inctx->keytab;
|
||||
|
||||
if(id == NULL) {
|
||||
krb5_kt_default(context, &keytab);
|
||||
id = keytab;
|
||||
}
|
||||
if (id == NULL)
|
||||
goto out;
|
||||
|
||||
ret = krb5_kt_start_seq_get(context, id, &cursor);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Interate over keytab to find a key that can decrypt the request.
|
||||
*/
|
||||
|
||||
done = 0;
|
||||
while (!done) {
|
||||
krb5_principal p;
|
||||
|
||||
ret = krb5_kt_next_entry(context, id, &entry, &cursor);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (entry.keyblock.keytype != ap_req.ticket.enc_part.etype ||
|
||||
(kvno && kvno != entry.vno)) {
|
||||
krb5_kt_free_entry (context, &entry);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = krb5_verify_ap_req2(context,
|
||||
auth_context,
|
||||
&ap_req,
|
||||
server,
|
||||
&entry.keyblock,
|
||||
0,
|
||||
&o->ap_req_options,
|
||||
&o->ticket,
|
||||
KRB5_KU_AP_REQ_AUTH);
|
||||
if (ret) {
|
||||
krb5_kt_free_entry (context, &entry);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Found a match, save the keyblock for PAC processing,
|
||||
* and update the service principal in the ticket to match
|
||||
* whatever is in the keytab.
|
||||
*/
|
||||
|
||||
ret = krb5_copy_keyblock(context,
|
||||
&entry.keyblock,
|
||||
&o->keyblock);
|
||||
if (ret) {
|
||||
krb5_kt_free_entry (context, &entry);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = krb5_copy_principal(context, entry.principal, &p);
|
||||
if (ret) {
|
||||
krb5_kt_free_entry (context, &entry);
|
||||
goto out;
|
||||
}
|
||||
krb5_free_principal(context, o->ticket->server);
|
||||
o->ticket->server = p;
|
||||
|
||||
krb5_kt_free_entry (context, &entry);
|
||||
|
||||
done = 1;
|
||||
}
|
||||
krb5_kt_end_seq_get (context, id, &cursor);
|
||||
}
|
||||
|
||||
/* Save that principal that was in the request */
|
||||
ret = _krb5_principalname2krb5_principal(context,
|
||||
&o->server,
|
||||
ap_req.ticket.sname,
|
||||
ap_req.ticket.realm);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
|
||||
/* If there is a PAC, verify its server signature */
|
||||
if (inctx->check_pac) {
|
||||
krb5_pac pac;
|
||||
@@ -894,7 +1025,9 @@ out:
|
||||
*outctx = o;
|
||||
|
||||
free_AP_REQ(&ap_req);
|
||||
if(service)
|
||||
krb5_free_principal(context, service);
|
||||
|
||||
if (keytab)
|
||||
krb5_kt_close(context, keytab);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
Reference in New Issue
Block a user