d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen/*
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen Authors:
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen Sumit Bose <sbose@redhat.com>
2e533fb1283b5f06a4063b519e47f1861c910386Timo Sirainen
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen Copyright (C) 2011, 2012, 2013 Red Hat
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen This program is free software; you can redistribute it and/or modify
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen it under the terms of the GNU Lesser General Public License as published by
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen the Free Software Foundation; either version 3 of the License, or
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen (at your option) any later version.
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen
bf9fd727c3f23426ccdb23b18f4e34fcd1bdb8c7Timo Sirainen This program is distributed in the hope that it will be useful,
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen but WITHOUT ANY WARRANTY; without even the implied warranty of
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen GNU Lesser General Public License for more details.
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen You should have received a copy of the GNU Lesser General Public License
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen along with this program. If not, see <http://www.gnu.org/licenses/>.
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen*/
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen/* A short documentation about authdata plugins can be found in
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen * http://http://k5wiki.kerberos.org/wiki/Projects/VerifyAuthData */
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen#include <krb5/krb5.h>
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen#include <errno.h>
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen#include "krb5_authdata_int.h"
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen#include "sss_cli.h"
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainenstruct sssd_context {
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen krb5_data data;
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen};
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainenstatic krb5_error_code
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainensssdpac_init(krb5_context kcontext, void **plugin_context)
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen{
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen *plugin_context = NULL;
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen return 0;
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen}
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainen
d47a87c927ca77e780480f4eaf575511698d42c8Timo Sirainenstatic void
sssdpac_flags(krb5_context kcontext,
void *plugin_context,
krb5_authdatatype ad_type,
krb5_flags *flags)
{
*flags = AD_USAGE_KDC_ISSUED | AD_USAGE_TGS_REQ;
}
static void
sssdpac_fini(krb5_context kcontext, void *plugin_context)
{
return;
}
static krb5_error_code
sssdpac_request_init(krb5_context kcontext,
krb5_authdata_context context,
void *plugin_context,
void **request_context)
{
struct sssd_context *sssdctx;
sssdctx = (struct sssd_context *)calloc(1, sizeof(*sssdctx));
if (sssdctx == NULL) {
return ENOMEM;
}
*request_context = sssdctx;
return 0;
}
static krb5_error_code
sssdpac_import_authdata(krb5_context kcontext,
krb5_authdata_context context,
void *plugin_context,
void *request_context,
krb5_authdata **authdata,
krb5_boolean kdc_issued,
krb5_const_principal kdc_issuer)
{
char *data = NULL;
struct sssd_context *sssdctx = (struct sssd_context *)request_context;
if (authdata[0] == NULL) {
return EINVAL;
}
if (authdata[0]->length > 0) {
data = malloc(sizeof(char) * authdata[0]->length);
if (data == NULL) {
return ENOMEM;
}
memcpy(data, authdata[0]->contents, authdata[0]->length);
}
if (sssdctx->data.data != NULL) {
krb5_free_data_contents(kcontext, &sssdctx->data);
}
sssdctx->data.length = authdata[0]->length;
sssdctx->data.data = data;
return 0;
}
static void
sssdpac_request_fini(krb5_context kcontext,
krb5_authdata_context context,
void *plugin_context,
void *request_context)
{
struct sssd_context *sssdctx = (struct sssd_context *)request_context;
if (sssdctx != NULL) {
if (sssdctx->data.data != NULL) {
krb5_free_data_contents(kcontext, &sssdctx->data);
}
free(sssdctx);
}
}
static krb5_error_code sssdpac_verify(krb5_context kcontext,
krb5_authdata_context context,
void *plugin_context,
void *request_context,
const krb5_auth_context *auth_context,
const krb5_keyblock *key,
const krb5_ap_req *req)
{
krb5_error_code kerr;
int ret;
krb5_pac pac;
struct sssd_context *sssdctx = (struct sssd_context *)request_context;
struct sss_cli_req_data sss_data;
int errnop;
if (sssdctx == NULL || sssdctx->data.data == NULL) {
return EINVAL;
}
kerr = krb5_pac_parse(kcontext, sssdctx->data.data,
sssdctx->data.length, &pac);
if (kerr != 0) {
return EINVAL;
}
kerr = krb5_pac_verify(kcontext, pac,
req->ticket->enc_part2->times.authtime,
req->ticket->enc_part2->client, key, NULL);
/* deallocate pac */
krb5_pac_free(kcontext, pac);
pac = NULL;
if (kerr != 0) {
/* The krb5 documentation says:
* A checksum mismatch can occur if the PAC was copied from a
* cross-realm TGT by an ignorant KDC; also Apple Mac OS X Server
* Open Directory (as of 10.6) generates PACs with no server checksum
* at all. One should consider not failing the whole authentication
* because of this reason, but, instead, treating the ticket as
* if it did not contain a PAC or marking the PAC information as
* non-verified.
*/
return 0;
}
sss_data.len = sssdctx->data.length;
sss_data.data = sssdctx->data.data;
ret = sss_pac_make_request_with_lock(SSS_PAC_ADD_PAC_USER, &sss_data,
NULL, NULL, &errnop);
if (ret != 0) {
/* Ignore the error */
}
return 0;
}
static krb5_error_code
sssdpac_size(krb5_context kcontext,
krb5_authdata_context context,
void *plugin_context,
void *request_context,
size_t *sizep)
{
struct sssd_context *sssdctx = (struct sssd_context *)request_context;
*sizep += sizeof(krb5_int32);
*sizep += sssdctx->data.length;
*sizep += sizeof(krb5_int32);
return 0;
}
static krb5_error_code
sssdpac_externalize(krb5_context kcontext,
krb5_authdata_context context,
void *plugin_context,
void *request_context,
krb5_octet **buffer,
size_t *lenremain)
{
krb5_error_code code = 0;
struct sssd_context *sssdctx = (struct sssd_context *)request_context;
size_t required = 0;
krb5_octet *bp;
size_t remain;
bp = *buffer;
remain = *lenremain;
if (sssdctx->data.data != NULL) {
sssdpac_size(kcontext, context, plugin_context,
request_context, &required);
if (required <= remain) {
krb5_ser_pack_int32((krb5_int32)sssdctx->data.length,
&bp, &remain);
krb5_ser_pack_bytes((krb5_octet *)sssdctx->data.data,
(size_t)sssdctx->data.length,
&bp, &remain);
krb5_ser_pack_int32(0,
&bp, &remain);
} else {
code = ENOMEM;
}
} else {
krb5_ser_pack_int32(0, &bp, &remain); /* length */
krb5_ser_pack_int32(0, &bp, &remain); /* verified */
}
*buffer = bp;
*lenremain = remain;
return code;
}
static krb5_error_code
sssdpac_internalize(krb5_context kcontext,
krb5_authdata_context context,
void *plugin_context,
void *request_context,
krb5_octet **buffer,
size_t *lenremain)
{
struct sssd_context *sssdctx = (struct sssd_context *)request_context;
krb5_error_code code;
krb5_int32 ibuf;
krb5_octet *bp;
size_t remain;
krb5_data data;
bp = *buffer;
remain = *lenremain;
/* length */
code = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
if (code != 0) {
return code;
}
if (ibuf != 0) {
data.length = ibuf;
data.data = malloc(sizeof(char) * ibuf);
if (data.data == NULL) {
return ENOMEM;
}
memcpy(data.data, bp, ibuf);
bp += ibuf;
remain -= ibuf;
} else {
data.length = 0;
data.data = NULL;
}
/* verified */
code = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
if (code != 0) {
free(data.data);
return code;
}
if (sssdctx->data.data != NULL) {
krb5_free_data_contents(kcontext, &sssdctx->data);
}
sssdctx->data.length = data.length;
sssdctx->data.data = data.data;
*buffer = bp;
*lenremain = remain;
return 0;
}
static krb5_authdatatype sssdpac_ad_types[] = { KRB5_AUTHDATA_WIN2K_PAC, 0 };
krb5plugin_authdata_client_ftable_v0 authdata_client_0 = {
((void *)((uintptr_t)("sssd_sssdpac"))),
sssdpac_ad_types,
sssdpac_init,
sssdpac_fini,
sssdpac_flags,
sssdpac_request_init,
sssdpac_request_fini,
NULL,
NULL,
NULL,
NULL,
NULL,
sssdpac_import_authdata,
NULL,
NULL,
sssdpac_verify,
sssdpac_size,
sssdpac_externalize,
sssdpac_internalize,
NULL
};