diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/include/k5-int.h | 6 | ||||
-rw-r--r-- | src/include/krb5/krb5.hin | 5 | ||||
-rw-r--r-- | src/lib/krb5/krb/Makefile.in | 3 | ||||
-rw-r--r-- | src/lib/krb5/krb/deps | 11 | ||||
-rw-r--r-- | src/lib/krb5/krb/int-proto.h | 4 | ||||
-rw-r--r-- | src/lib/krb5/krb/preauth2.c | 2 | ||||
-rw-r--r-- | src/lib/krb5/krb/preauth_otp.c | 561 |
7 files changed, 592 insertions, 0 deletions
diff --git a/src/include/k5-int.h b/src/include/k5-int.h index 6a853ce798..d119d02be4 100644 --- a/src/include/k5-int.h +++ b/src/include/k5-int.h @@ -479,6 +479,12 @@ typedef struct _krb5_enc_sam_response_enc_2 { #define KRB5_OTP_FLAG_SEPARATE_PIN 0x02000000 #define KRB5_OTP_FLAG_CHECK_DIGIT 0x01000000 +#define KRB5_OTP_FORMAT_DECIMAL 0x00000000 +#define KRB5_OTP_FORMAT_HEXADECIMAL 0x00000001 +#define KRB5_OTP_FORMAT_ALPHANUMERIC 0x00000002 +#define KRB5_OTP_FORMAT_BINARY 0x00000003 +#define KRB5_OTP_FORMAT_BASE64 0x00000004 + typedef struct _krb5_otp_tokeninfo { krb5_flags flags; krb5_data vendor; diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin index fde0d8ff44..16da726663 100644 --- a/src/include/krb5/krb5.hin +++ b/src/include/krb5/krb5.hin @@ -970,6 +970,7 @@ krb5_c_keyed_checksum_types(krb5_context context, krb5_enctype enctype, #define KRB5_KEYUSAGE_AD_SIGNEDPATH -21 #define KRB5_KEYUSAGE_IAKERB_FINISHED 42 #define KRB5_KEYUSAGE_PA_PKINIT_KX 44 +#define KRB5_KEYUSAGE_PA_OTP_REQUEST 45 /* define in draft-ietf-krb-wg-preauth-framework*/ #define KRB5_KEYUSAGE_FAST_REQ_CHKSUM 50 #define KRB5_KEYUSAGE_FAST_ENC 51 @@ -1812,6 +1813,10 @@ krb5_verify_checksum(krb5_context context, krb5_cksumtype ctype, #define KRB5_PADATA_FX_FAST 136 #define KRB5_PADATA_FX_ERROR 137 #define KRB5_PADATA_ENCRYPTED_CHALLENGE 138 +#define KRB5_PADATA_OTP_CHALLENGE 141 +#define KRB5_PADATA_OTP_REQUEST 142 +#define KRB5_PADATA_OTP_CONFIRM 143 +#define KRB5_PADATA_OTP_PIN_CHANGE 144 #define KRB5_PADATA_PKINIT_KX 147 #define KRB5_ENCPADATA_REQ_ENC_PA_REP 149 diff --git a/src/lib/krb5/krb/Makefile.in b/src/lib/krb5/krb/Makefile.in index 3e48868a4c..8c3b5d1719 100644 --- a/src/lib/krb5/krb/Makefile.in +++ b/src/lib/krb5/krb/Makefile.in @@ -79,6 +79,7 @@ STLIBOBJS= \ preauth2.o \ preauth_ec.o \ preauth_encts.o \ + preauth_otp.o \ preauth_sam2.o \ gic_opt_set_pa.o \ princ_comp.o \ @@ -185,6 +186,7 @@ OBJS= $(OUTPRE)addr_comp.$(OBJEXT) \ $(OUTPRE)preauth2.$(OBJEXT) \ $(OUTPRE)preauth_ec.$(OBJEXT) \ $(OUTPRE)preauth_encts.$(OBJEXT) \ + $(OUTPRE)preauth_otp.$(OBJEXT) \ $(OUTPRE)preauth_sam2.$(OBJEXT) \ $(OUTPRE)gic_opt_set_pa.$(OBJEXT) \ $(OUTPRE)princ_comp.$(OBJEXT) \ @@ -291,6 +293,7 @@ SRCS= $(srcdir)/addr_comp.c \ $(srcdir)/preauth2.c \ $(srcdir)/preauth_ec.c \ $(srcdir)/preauth_encts.c \ + $(srcdir)/preauth_otp.c \ $(srcdir)/gic_opt_set_pa.c \ $(srcdir)/princ_comp.c \ $(srcdir)/privsafe.c \ diff --git a/src/lib/krb5/krb/deps b/src/lib/krb5/krb/deps index 8c4db775f2..5ca91e921a 100644 --- a/src/lib/krb5/krb/deps +++ b/src/lib/krb5/krb/deps @@ -755,6 +755,17 @@ preauth_encts.so preauth_encts.po $(OUTPRE)preauth_encts.$(OBJEXT): \ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \ $(top_srcdir)/include/krb5/preauth_plugin.h $(top_srcdir)/include/port-sockets.h \ $(top_srcdir)/include/socket-utils.h int-proto.h preauth_encts.c +preauth_otp.so preauth_otp.po $(OUTPRE)preauth_otp.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ + $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \ + $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \ + $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \ + $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \ + $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \ + $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \ + $(top_srcdir)/include/krb5/preauth_plugin.h $(top_srcdir)/include/port-sockets.h \ + $(top_srcdir)/include/socket-utils.h int-proto.h preauth_otp.c gic_opt_set_pa.so gic_opt_set_pa.po $(OUTPRE)gic_opt_set_pa.$(OBJEXT): \ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ diff --git a/src/lib/krb5/krb/int-proto.h b/src/lib/krb5/krb/int-proto.h index 8dc6867cdb..f794f143e6 100644 --- a/src/lib/krb5/krb/int-proto.h +++ b/src/lib/krb5/krb/int-proto.h @@ -68,6 +68,10 @@ clpreauth_sam2_initvt(krb5_context context, int maj_ver, int min_ver, krb5_plugin_vtable vtable); krb5_error_code +clpreauth_otp_initvt(krb5_context context, int maj_ver, int min_ver, + krb5_plugin_vtable vtable); + +krb5_error_code krb5int_construct_matching_creds(krb5_context context, krb5_flags options, krb5_creds *in_creds, krb5_creds *mcreds, krb5_flags *fields); diff --git a/src/lib/krb5/krb/preauth2.c b/src/lib/krb5/krb/preauth2.c index c47269e291..2ed53ab08c 100644 --- a/src/lib/krb5/krb/preauth2.c +++ b/src/lib/krb5/krb/preauth2.c @@ -127,6 +127,8 @@ krb5_init_preauth_context(krb5_context kcontext) clpreauth_encrypted_timestamp_initvt); k5_plugin_register(kcontext, PLUGIN_INTERFACE_CLPREAUTH, "sam2", clpreauth_sam2_initvt); + k5_plugin_register(kcontext, PLUGIN_INTERFACE_CLPREAUTH, "otp", + clpreauth_otp_initvt); /* Get all available clpreauth vtables. */ if (k5_plugin_load_all(kcontext, PLUGIN_INTERFACE_CLPREAUTH, &plugins)) diff --git a/src/lib/krb5/krb/preauth_otp.c b/src/lib/krb5/krb/preauth_otp.c new file mode 100644 index 0000000000..04eeb72ea1 --- /dev/null +++ b/src/lib/krb5/krb/preauth_otp.c @@ -0,0 +1,561 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* lib/krb5/krb/preauth_otp.c - OTP clpreauth module */ +/* + * Copyright 2011 NORDUnet A/S. All rights reserved. + * Copyright 2011 Red Hat, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "k5-int.h" +#include "int-proto.h" + +#include <krb5/preauth_plugin.h> + +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include <ctype.h> +#include <string.h> + +static krb5_preauthtype otp_client_supported_pa_types[] = + { KRB5_PADATA_OTP_CHALLENGE, 0 }; + +/* Tests krb5_data to see if it is printable. */ +static krb5_boolean +is_printable_string(const krb5_data *data) +{ + unsigned int i; + + if (data == NULL) + return FALSE; + + for (i = 0; i < data->length; i++) { + if (!isprint((unsigned char)data->data[i])) + return FALSE; + } + + return TRUE; +} + +/* Takes the nonce from the challenge and encrypts it into the request. */ +static krb5_error_code +encrypt_nonce(krb5_context ctx, krb5_keyblock *key, + const krb5_pa_otp_challenge *chl, krb5_pa_otp_req *req) +{ + krb5_error_code retval; + krb5_enc_data encdata; + krb5_data *er; + + /* Encode the nonce. */ + retval = encode_krb5_pa_otp_enc_req(&chl->nonce, &er); + if (retval != 0) + return retval; + + /* Do the encryption. */ + retval = krb5_encrypt_helper(ctx, key, KRB5_KEYUSAGE_PA_OTP_REQUEST, + er, &encdata); + krb5_free_data(ctx, er); + if (retval != 0) + return retval; + + free(req->enc_data.ciphertext.data); + req->enc_data = encdata; + + return 0; +} + +/* Checks to see if the user-supplied otp value matches the length and format + * of the supplied tokeninfo. */ +static int +otpvalue_matches_tokeninfo(const char *otpvalue, krb5_otp_tokeninfo *ti) +{ + int (*table[])(int c) = { isdigit, isxdigit, isalnum }; + + if (otpvalue == NULL || ti == NULL) + return 0; + + if (ti->length >= 0 && strlen(otpvalue) != (size_t)ti->length) + return 0; + + if (ti->format >= 0 && ti->format < 3) { + while (*otpvalue) { + if (!(*table[ti->format])((unsigned char)*otpvalue++)) + return 0; + } + } + + return 1; +} + +/* Removes the indexed tokeninfo from the array. */ +static void +remove_tokeninfo(krb5_context ctx, krb5_otp_tokeninfo **tis, unsigned int i) +{ + unsigned int j = 0; + + if (tis == NULL) + return; + + for (j = 0; tis[j]; j++) { + if (j == i) + k5_free_otp_tokeninfo(ctx, tis[j]); + if (j >= i) + tis[j] = tis[j+1]; + } +} + +/* Performs a prompt and saves the response in the out parameter. */ +static krb5_error_code +doprompt(krb5_context context, krb5_prompter_fct prompter, void *prompter_data, + const char *banner, const char *prompttxt, char *out, size_t len) +{ + krb5_prompt prompt; + krb5_data prompt_reply; + krb5_error_code retval; + + if (prompttxt == NULL || out == NULL) + return EINVAL; + + memset(out, 0, len); + + prompt_reply = make_data(out, len); + prompt.reply = &prompt_reply; + prompt.prompt = (char *)prompttxt; + prompt.hidden = 1; + + retval = (*prompter)(context, prompter_data, NULL, banner, 1, &prompt); + if (retval != 0) + return retval; + + return 0; +} + +/* Forces the user to choose a single tokeninfo via prompting. + * Removes all other tokeninfos from the array. */ +static krb5_error_code +choose_token(krb5_context context, krb5_prompter_fct prompter, + void *prompter_data, krb5_otp_tokeninfo **tis) +{ + char *banner = NULL, *tmp, response[1024]; + krb5_otp_tokeninfo *ti = NULL; + krb5_error_code retval = 0; + int i = 0, j = 0; + + for (i = 0; tis[i] != NULL; i++) { + if (asprintf(&tmp, "%s\t%d. %s %.*s\n", + banner ? banner : + _("Please choose from the following:\n"), + i + 1, tis[i]->vendor.length, + _("Vendor:"), + tis[i]->vendor.data) < 0) { + free(banner); + return ENOMEM; + } + + free(banner); + banner = tmp; + } + + do { + retval = doprompt(context, prompter, prompter_data, + banner, _("Enter #"), response, sizeof(response)); + if (retval != 0) { + free(banner); + return retval; + } + + errno = 0; + j = strtol(response, NULL, 0); + if (errno != 0) { + free(banner); + return errno; + } + if (j < 1 || j > i) + continue; + + ti = tis[--j]; + for (i = 0; tis[i] != NULL; i++) { + if (tis[i] != ti) + remove_tokeninfo(context, tis, i--); + } + } while (ti == NULL); + + free(banner); + return 0; +} + +/* Like asprintf() but saves output into a krb5_data structure. */ +static krb5_error_code +data_printf(krb5_data *data, const char *fmt, ...) +{ + va_list ap; + char *tmp = NULL; + + if (data == NULL) + return EINVAL; + + va_start(ap, fmt); + if (vasprintf(&tmp, fmt, ap) < 0) { + va_end(ap); + return errno; + } + va_end(ap); + + free(data->data); + data->data = tmp; + data->length = strlen(tmp); + + return 0; +} + +/* Takes the otp value in the request and base64 encodes it. */ +static krb5_error_code +base64_encode_request(krb5_pa_otp_req *req) +{ + return ENOTSUP; +} + +static int +is_tokeninfo_supported(krb5_otp_tokeninfo *ti) +{ + krb5_flags supported_flags = KRB5_OTP_FLAG_COLLECT_PIN | + KRB5_OTP_FLAG_NO_COLLECT_PIN | + KRB5_OTP_FLAG_SEPARATE_PIN; + + /* Flags we don't support... */ + if (ti->flags & ~supported_flags) + return 0; + + /* We don't currently support hashing. */ + if (ti->supported_hash_alg != NULL || ti->iteration_count >= 0) + return 0; + + /* Remove tokeninfos with invalid vendor strings. */ + if (!is_printable_string(&ti->vendor)) + return 0; + + /* We don't currently support base64. */ + if (ti->format == KRB5_OTP_FORMAT_BASE64) + return 0; + + return 1; +} + +/* Builds a challenge string from the given tokeninfo. */ +static krb5_error_code +make_challenge(const krb5_otp_tokeninfo *ti, char **challenge) +{ + if (challenge == NULL) + return EINVAL; + + *challenge = NULL; + + if (ti == NULL || ti->challenge.data == NULL) + return 0; + + /* + * If the challenge isn't printable, then we have some kind of binary + * challenge which we cannot properly handle. So error out. Ideally there + * would be some mechanism to handle binary challenges to hardware tokens. + */ + if (!is_printable_string(&ti->challenge)) + return KRB5_PREAUTH_FAILED; + + if (asprintf(challenge, "%s %.*s\n", + _("OTP Challenge:"), + ti->challenge.length, + ti->challenge.data) < 0) + return ENOMEM; + + return 0; +} + +/* Sets the otp value into the request. Similarly, collects and sets + * the pin if necessary. */ +static krb5_error_code +set_value_and_collect_pin(krb5_context context, krb5_prompter_fct prompter, + void *prompter_data, const krb5_otp_tokeninfo *ti, + const char *otpvalue, krb5_pa_otp_req *req) +{ + krb5_error_code retval; + char otppin[1024]; + krb5_flags pin; + + pin = ti->flags & (KRB5_OTP_FLAG_COLLECT_PIN | KRB5_OTP_FLAG_SEPARATE_PIN); + + /* If no PIN will be collected, just set the otp value. */ + if (pin == 0) { + retval = data_printf(&req->otp_value, "%s", otpvalue); + if (retval != 0) + return retval; + + req->pin = empty_data(); + return 0; + } + + /* Collect the PIN. */ + retval = doprompt(context, prompter, prompter_data, NULL, + _("OTP Token PIN"), otppin, sizeof(otppin)); + if (retval != 0) + return retval; + + /* Set the separate PIN and Value fields. */ + if (pin & KRB5_OTP_FLAG_SEPARATE_PIN) { + retval = data_printf(&req->otp_value, "%s", otpvalue); + if (retval != 0) + return retval; + + retval = data_printf(&req->pin, "%s", otppin); + if (retval != 0) + return retval; + + /* Prepend PIN to the Value field. */ + } else { + retval = data_printf(&req->otp_value, "%s%s", otppin, otpvalue); + if (retval != 0) + return retval; + + req->pin = empty_data(); + } + + return 0; +} + +/* Builds a request object to send to the KDC, prompting the user if + * necessary. */ +static krb5_error_code +make_request(krb5_context context, krb5_prompter_fct prompter, + void *prompter_data, krb5_otp_tokeninfo **tis, + krb5_pa_otp_req **request) +{ + krb5_error_code retval; + int i, challengers = 0; + char *challenge = NULL; + char otpvalue[1024]; + krb5_pa_otp_req *req; + + memset(otpvalue, 0, sizeof(otpvalue)); + + if (request == NULL || tis == NULL || tis[0] == NULL) + return EINVAL; + + /* Filter out any tokeninfos we don't support. */ + for (i = 0; tis[i] != NULL; i++) { + if (!is_tokeninfo_supported(tis[i])) { + remove_tokeninfo(context, tis, i--); + continue; + } + + if (tis[i]->challenge.data != NULL) + challengers++; /* Count how many challenges we have. */ + } + if (tis[0] == NULL) { + krb5_set_error_message(context, KRB5_PREAUTH_FAILED, + _("No supported tokens")); + return KRB5_PREAUTH_FAILED; /* We have no supported tokeninfos. */ + } + + /* Setup our challenge, if present. */ + if (challengers > 0) { + /* If we have multiple tokeninfos still, choose now. */ + if (tis[1] != NULL) { + retval = choose_token(context, prompter, prompter_data, tis); + if (retval != 0) + return retval; + } + + /* Create the challenge prompt. */ + retval = make_challenge(tis[0], &challenge); + if (retval != 0) + return retval; + } + + /* Prompt for token value. */ + retval = doprompt(context, prompter, prompter_data, challenge, + _("Enter OTP Token Value"), otpvalue, sizeof(otpvalue)); + free(challenge); + if (retval != 0) + return retval; + + /* Filter out tokeninfos that don't match our token value. */ + for (i = 0; tis[i] != NULL; i++) { + if (!otpvalue_matches_tokeninfo(otpvalue, tis[i])) + remove_tokeninfo(context, tis, i--); + } + + /* If we still have multiple tokeninfos, choose now. */ + if (tis[0] != NULL && tis[1] != NULL) { + retval = choose_token(context, prompter, prompter_data, tis); + if (retval != 0) + return retval; + } + if (tis == NULL || tis[0] == NULL) { + krb5_set_error_message(context, KRB5_PREAUTH_FAILED, + _("OTP value doesn't match any token formats")); + return KRB5_PREAUTH_FAILED; /* We have no supported tokeninfos. */ + } + + /* Create the request. */ + req = calloc(1, sizeof(krb5_pa_otp_req)); + if (req == NULL) + return ENOMEM; + + /* Collect the PIN, if necessary. */ + retval = set_value_and_collect_pin(context, prompter, prompter_data, + tis[0], otpvalue, req); + if (retval != 0) { + k5_free_pa_otp_req(context, req); + return retval; + } + + /* Do Base64 encoding, if necessary. */ + if (tis[0]->format == KRB5_OTP_FORMAT_BASE64) { + retval = base64_encode_request(req); + if (retval != 0) { + k5_free_pa_otp_req(context, req); + return retval; + } + } + + /* Steal values from the tokeninfo. */ + req->flags = tis[0]->flags; + req->alg_id = tis[0]->alg_id; + req->format = tis[0]->format; + req->token_id = tis[0]->token_id; + req->vendor = tis[0]->vendor; + tis[0]->alg_id = empty_data(); + tis[0]->token_id = empty_data(); + tis[0]->vendor = empty_data(); + + *request = req; + return 0; +} + +static int +otp_client_get_flags(krb5_context context, krb5_preauthtype pa_type) +{ + return PA_REAL; +} + +static krb5_error_code +otp_client_process(krb5_context context, krb5_clpreauth_moddata moddata, + krb5_clpreauth_modreq modreq, krb5_get_init_creds_opt *opt, + krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock, + krb5_kdc_req *request, krb5_data *encoded_request_body, + krb5_data *encoded_previous_request, krb5_pa_data *pa_data, + krb5_prompter_fct prompter, void *prompter_data, + krb5_pa_data ***pa_data_out) +{ + krb5_pa_otp_challenge *chl = NULL; + krb5_pa_data **out_data = NULL; + krb5_keyblock *as_key = NULL; + krb5_pa_otp_req *req = NULL; + krb5_error_code retval = 0; + krb5_data tmp, *tmpp; + + *pa_data_out = NULL; + + /* Get FAST armor key. */ + as_key = cb->fast_armor(context, rock); + if (as_key == NULL) + return ENOENT; + + /* Use FAST armor key as response key. */ + retval = cb->set_as_key(context, rock, as_key); + if (retval != 0) + return retval; + + /* Decode the challenge. */ + tmp = make_data(pa_data->contents, pa_data->length); + retval = decode_krb5_pa_otp_challenge(&tmp, &chl); + if (retval != 0) + return retval; + + /* Fill in the request info from the TokenInfo structs .*/ + retval = make_request(context, prompter, prompter_data, + chl->tokeninfo, &req); + if (retval != 0) { + k5_free_pa_otp_challenge(context, chl); + return retval; + } + + /* Encrypt the challenge's nonce and set it in the request. */ + retval = encrypt_nonce(context, as_key, chl, req); + k5_free_pa_otp_challenge(context, chl); + if (retval != 0) { + k5_free_pa_otp_req(context, req); + return retval; + } + + /* Allocate the preauth data array and one item. */ + out_data = calloc(2, sizeof(krb5_pa_data *)); + if (out_data == NULL) { + k5_free_pa_otp_req(context, req); + return ENOMEM; + } + out_data[0] = calloc(1, sizeof(krb5_pa_data)); + out_data[1] = NULL; + if (out_data[0] == NULL) { + free(out_data); + k5_free_pa_otp_req(context, req); + return ENOMEM; + } + + /* Encode our request into the preauth data item. */ + memset(out_data[0], 0, sizeof(krb5_pa_data)); + out_data[0]->pa_type = KRB5_PADATA_OTP_REQUEST; + retval = encode_krb5_pa_otp_req(req, &tmpp); + k5_free_pa_otp_req(context, req); + if (retval != 0) { + free(out_data[0]); + free(out_data); + return ENOMEM; + } + out_data[0]->contents = (krb5_octet*)tmpp->data; + out_data[0]->length = tmpp->length; + + *pa_data_out = out_data; + return 0; +} + +krb5_error_code +clpreauth_otp_initvt(krb5_context context, int maj_ver, int min_ver, + krb5_plugin_vtable vtable) +{ + krb5_clpreauth_vtable vt; + + if (maj_ver != 1) + return KRB5_PLUGIN_VER_NOTSUPP; + + vt = (krb5_clpreauth_vtable)vtable; + vt->name = "otp"; + vt->pa_type_list = otp_client_supported_pa_types; + vt->flags = otp_client_get_flags; + vt->process = otp_client_process; + vt->gic_opts = NULL; + + return 0; +} |