krb5 commit: Add indicator support to OTP

Greg Hudson ghudson at mit.edu
Wed Jul 22 13:29:43 EDT 2015


https://github.com/krb5/krb5/commit/e6e6e54e89bc9644144436c3f267796ed790f70c
commit e6e6e54e89bc9644144436c3f267796ed790f70c
Author: Greg Hudson <ghudson at mit.edu>
Date:   Thu Jan 8 15:56:37 2015 -0500

    Add indicator support to OTP
    
    Read an "indicator" profile variable for OTP token types and assert
    its values as indicators when that token type is used to authenticate.
    Add a test case in t_otp.py for this feature.
    
    ticket: 8157

 src/plugins/preauth/otp/main.c      |   13 ++++++++++++-
 src/plugins/preauth/otp/otp_state.c |   29 ++++++++++++++++++++++++-----
 src/plugins/preauth/otp/otp_state.h |    3 ++-
 src/tests/t_otp.py                  |    7 ++++++-
 4 files changed, 44 insertions(+), 8 deletions(-)

diff --git a/src/plugins/preauth/otp/main.c b/src/plugins/preauth/otp/main.c
index 7941b4a..2649e9a 100644
--- a/src/plugins/preauth/otp/main.c
+++ b/src/plugins/preauth/otp/main.c
@@ -40,9 +40,12 @@ static krb5_preauthtype otp_pa_type_list[] =
   { KRB5_PADATA_OTP_REQUEST, 0 };
 
 struct request_state {
+    krb5_context context;
     krb5_kdcpreauth_verify_respond_fn respond;
     void *arg;
     krb5_enc_tkt_part *enc_tkt_reply;
+    krb5_kdcpreauth_callbacks preauth_cb;
+    krb5_kdcpreauth_rock rock;
 };
 
 static krb5_error_code
@@ -151,9 +154,11 @@ nonce_generate(krb5_context ctx, unsigned int length, krb5_data *nonce_out)
 }
 
 static void
-on_response(void *data, krb5_error_code retval, otp_response response)
+on_response(void *data, krb5_error_code retval, otp_response response,
+            char *const *indicators)
 {
     struct request_state rs = *(struct request_state *)data;
+    char *const *ind;
 
     free(data);
 
@@ -163,6 +168,9 @@ on_response(void *data, krb5_error_code retval, otp_response response)
     if (retval == 0)
         rs.enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
 
+    for (ind = indicators; ind != NULL && *ind != NULL && retval == 0; ind++)
+        retval = rs.preauth_cb->add_auth_indicator(rs.context, rs.rock, *ind);
+
     rs.respond(rs.arg, retval, NULL, NULL, NULL);
 }
 
@@ -305,9 +313,12 @@ otp_verify(krb5_context context, krb5_data *req_pkt, krb5_kdc_req *request,
     rs = k5alloc(sizeof(struct request_state), &retval);
     if (rs == NULL)
         goto error;
+    rs->context = context;
     rs->arg = arg;
     rs->respond = respond;
     rs->enc_tkt_reply = enc_tkt_reply;
+    rs->preauth_cb = cb;
+    rs->rock = rock;
 
     /* Get the principal's OTP configuration string. */
     retval = cb->get_string(context, rock, "otp", &config);
diff --git a/src/plugins/preauth/otp/otp_state.c b/src/plugins/preauth/otp/otp_state.c
index 7deb462..79fbc4d 100644
--- a/src/plugins/preauth/otp/otp_state.c
+++ b/src/plugins/preauth/otp/otp_state.c
@@ -52,6 +52,7 @@ typedef struct token_type_st {
     int timeout;
     size_t retries;
     krb5_boolean strip_realm;
+    char **indicators;
 } token_type;
 
 typedef struct token_st {
@@ -133,6 +134,7 @@ token_type_free(token_type *type)
     free(type->name);
     free(type->server);
     free(type->secret);
+    profile_free_list(type->indicators);
 }
 
 /* Construct the internal default token type. */
@@ -172,6 +174,8 @@ static krb5_error_code
 token_type_decode(profile_t profile, const char *name, token_type *out)
 {
     char *server = NULL, *name_copy = NULL, *secret = NULL, *pstr = NULL;
+    char **indicators = NULL;
+    const char *keys[4];
     int strip_realm, timeout, retries;
     krb5_error_code retval;
 
@@ -241,18 +245,32 @@ token_type_decode(profile_t profile, const char *name, token_type *out)
     if (retval != 0)
         goto cleanup;
 
+    /* Get the authentication indicators to assert if this token is used. */
+    keys[0] = "otp";
+    keys[1] = name;
+    keys[2] = "indicator";
+    keys[3] = NULL;
+    retval = profile_get_values(profile, keys, &indicators);
+    if (retval == PROF_NO_RELATION)
+        retval = 0;
+    if (retval != 0)
+        goto cleanup;
+
     out->name = name_copy;
     out->server = server;
     out->secret = secret;
     out->timeout = timeout;
     out->retries = retries;
     out->strip_realm = strip_realm;
+    out->indicators = indicators;
     name_copy = server = secret = NULL;
+    indicators = NULL;
 
 cleanup:
     free(name_copy);
     free(server);
     free(secret);
+    profile_free_list(indicators);
     return retval;
 }
 
@@ -545,6 +563,7 @@ callback(krb5_error_code retval, const krad_packet *rqst,
          const krad_packet *resp, void *data)
 {
     request *req = data;
+    char *const *indicators = req->tokens[req->index].type->indicators;
 
     req->index++;
 
@@ -554,7 +573,7 @@ callback(krb5_error_code retval, const krad_packet *rqst,
     /* If we received an accept packet, success! */
     if (krad_packet_get_code(resp) ==
         krad_code_name2num("Access-Accept")) {
-        req->cb(req->data, retval, otp_response_success);
+        req->cb(req->data, retval, otp_response_success, indicators);
         request_free(req);
         return;
     }
@@ -567,7 +586,7 @@ callback(krb5_error_code retval, const krad_packet *rqst,
     request_send(req);
 
 error:
-    req->cb(req->data, retval, otp_response_fail);
+    req->cb(req->data, retval, otp_response_fail, NULL);
     request_free(req);
 }
 
@@ -594,7 +613,7 @@ request_send(request *req)
     return;
 
 error:
-    req->cb(req->data, retval, otp_response_fail);
+    req->cb(req->data, retval, otp_response_fail, NULL);
     request_free(req);
 }
 
@@ -615,7 +634,7 @@ otp_state_verify(otp_state *state, verto_ctx *ctx, krb5_const_principal princ,
 
     rqst = calloc(1, sizeof(request));
     if (rqst == NULL) {
-        (*cb)(data, ENOMEM, otp_response_fail);
+        (*cb)(data, ENOMEM, otp_response_fail, NULL);
         return;
     }
     rqst->state = state;
@@ -646,6 +665,6 @@ otp_state_verify(otp_state *state, verto_ctx *ctx, krb5_const_principal princ,
     return;
 
 error:
-    (*cb)(data, retval, otp_response_fail);
+    (*cb)(data, retval, otp_response_fail, NULL);
     request_free(rqst);
 }
diff --git a/src/plugins/preauth/otp/otp_state.h b/src/plugins/preauth/otp/otp_state.h
index 4247d0b..da57ad9 100644
--- a/src/plugins/preauth/otp/otp_state.h
+++ b/src/plugins/preauth/otp/otp_state.h
@@ -43,7 +43,8 @@ typedef enum otp_response {
 
 typedef struct otp_state_st otp_state;
 typedef void
-(*otp_cb)(void *data, krb5_error_code retval, otp_response response);
+(*otp_cb)(void *data, krb5_error_code retval, otp_response response,
+          char *const *indicators);
 
 krb5_error_code
 otp_state_new(krb5_context ctx, otp_state **self);
diff --git a/src/tests/t_otp.py b/src/tests/t_otp.py
index 1a90a70..bfc1eef 100755
--- a/src/tests/t_otp.py
+++ b/src/tests/t_otp.py
@@ -167,7 +167,8 @@ atexit.register(lambda: os.remove(secret_file))
 conf = {'plugins': {'kdcpreauth': {'enable_only': 'otp'}},
         'otp': {'udp': {'server': '127.0.0.1:$port9',
                         'secret': secret_file,
-                        'strip_realm': 'true'},
+                        'strip_realm': 'true',
+                        'indicator': ['indotp1', 'indotp2']},
                 'unix': {'server': socket_file,
                          'strip_realm': 'false'}}}
 
@@ -194,6 +195,10 @@ queue.get()
 realm.run([kadminl, 'setstr', realm.user_princ, 'otp', otpconfig('udp')])
 realm.kinit(realm.user_princ, 'accept', flags=flags)
 verify(daemon, queue, True, realm.user_princ.split('@')[0], 'accept')
+realm.extract_keytab(realm.krbtgt_princ, realm.keytab)
+out = realm.run(['./adata', realm.krbtgt_princ])
+if '+97: [indotp1, indotp2]' not in out:
+    fail('auth indicators not seen in OTP ticket')
 
 # Detect upstream pyrad bug
 #   https://github.com/wichert/pyrad/pull/18


More information about the cvs-krb5 mailing list