preauth.c: add SAM support
authorMark Eichin <eichin@mit.edu>
Tue, 9 Apr 1996 22:57:14 +0000 (22:57 +0000)
committerMark Eichin <eichin@mit.edu>
Tue, 9 Apr 1996 22:57:14 +0000 (22:57 +0000)
str_conv.c: add AFS3 support
init_ctx.c: add processing for default_tkt_enctypes, matching
default_tgs_enctypes but client-side (so as not to hard code it,
since hard coded values are usually wrong :-)

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@7773 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/krb5/krb/init_ctx.c
src/lib/krb5/krb/preauth.c
src/lib/krb5/krb/str_conv.c

index 14ca0a653d99aecbf39f80f2169b99b67b623a47..96c406535725d246c350fab4ac1cfe4a0aa6b461 100644 (file)
@@ -136,16 +136,8 @@ krb5_set_default_in_tkt_ktypes(context, ktypes)
            return ENOMEM;
 
     } else {
-       i = 3;
-
-       /* Should reset the list to the runtime defaults */
-       if ((new_ktypes = (krb5_enctype *)malloc(sizeof(krb5_enctype) * i))) {
-           new_ktypes[0] = ENCTYPE_DES3_CBC_MD5;
-           new_ktypes[1] = ENCTYPE_DES_CBC_MD5;
-           new_ktypes[2] = ENCTYPE_DES_CBC_CRC;
-       } else {
-           return ENOMEM;
-       }
+       i = 0;
+       new_ktypes = 0;
     }
 
     if (context->in_tkt_ktypes) 
@@ -162,13 +154,75 @@ krb5_get_default_in_tkt_ktypes(context, ktypes)
 {
     krb5_enctype * old_ktypes;
 
-    if ((old_ktypes = (krb5_enctype *)malloc(sizeof(krb5_enctype) *
-                                            (context->in_tkt_ktype_count + 1)))) {
+    if (context->in_tkt_ktype_count) {
+      /* application-set defaults */
+      if ((old_ktypes = 
+          (krb5_enctype *)malloc(sizeof(krb5_enctype) *
+                                 (context->in_tkt_ktype_count + 1)))) {
        memcpy(old_ktypes, context->in_tkt_ktypes, sizeof(krb5_enctype) * 
-                               context->in_tkt_ktype_count);
+              context->in_tkt_ktype_count);
        old_ktypes[context->in_tkt_ktype_count] = 0;
-    } else {
+      } else {
        return ENOMEM;
+      }
+    } else {
+       /* taken directly from krb5_get_tgs_ktypes... */
+        /*
+          XXX - For now, we only support libdefaults
+          Perhaps this should be extended to allow for per-host / per-realm
+          session key types.
+        */
+
+       char *retval;
+       char *sp, *ep;
+       int i, j, count;
+       krb5_error_code code;
+
+       code = profile_get_string(context->profile,
+                                 "libdefaults", "default_tkt_enctypes", NULL,
+                                 "des3-cbc-md5 des-cbc-md5 des-cbc-crc",
+                                 &retval);
+       if (code)
+           return code;
+
+       count = 0;
+       sp = retval;
+       while (sp) {
+           for (ep = sp; *ep && (*ep != ',') && !isspace(*ep); ep++)
+               ;
+           if (*ep) {
+               *ep++ = '\0';
+               while (isspace(*ep))
+                   ep++;
+           } else
+               ep = (char *) NULL;
+
+           count++;
+           sp = ep;
+       }
+       
+       if ((old_ktypes =
+            (krb5_enctype *)malloc(sizeof(krb5_enctype) * (count + 1))) ==
+           (krb5_enctype *) NULL)
+           return ENOMEM;
+       
+       sp = retval;
+       j = 0;
+       i = 1;
+       while (1) {
+           if (! krb5_string_to_enctype(sp, &old_ktypes[j]))
+               j++;
+
+           if (i++ >= count)
+               break;
+
+           /* skip to next token */
+           while (*sp) sp++;
+           while (! *sp) sp++;
+       }
+
+       old_ktypes[j] = (krb5_enctype) 0;
+       free(retval);
     }
 
     *ktypes = old_ktypes;
index e062f0606cad07bab0022a54530c03ce9dd459af..a266d9bc9883ea6cc7c8b2b8702eec1f0a4b9a38 100644 (file)
@@ -26,7 +26,6 @@
  * kerberos kdc request, with various hardware/software verification devices.
  */
 
-
 #include "k5-int.h"
 #include <stdio.h>
 #include <time.h>
@@ -71,6 +70,21 @@ KRB5_NPROTOTYPE((krb5_context,
                 krb5_int32 *,
                 krb5_int32 *));
 
+static krb5_error_code obtain_sam_padata
+KRB5_NPROTOTYPE((krb5_context,
+                krb5_pa_data *,
+                krb5_etype_info,
+                krb5_keyblock *, 
+                krb5_error_code ( * )(krb5_context,
+                                      krb5_const krb5_enctype,
+                                      krb5_data *,
+                                      krb5_const_pointer,
+                                      krb5_keyblock **),
+                krb5_const_pointer,
+                krb5_creds *,
+                krb5_kdc_req *,
+                krb5_pa_data **));
+
 static krb5_preauth_ops preauth_systems[] = {
     {
        KV5M_PREAUTH_OPS,
@@ -86,6 +100,20 @@ static krb5_preauth_ops preauth_systems[] = {
         0,
         process_pw_salt,
     },
+    {
+       KV5M_PREAUTH_OPS,
+       KRB5_PADATA_AFS3_SALT,
+        0,
+        0,
+        process_pw_salt,
+    },
+    {
+       KV5M_PREAUTH_OPS,
+       KRB5_PADATA_SAM_CHALLENGE,
+        0,
+        obtain_sam_padata,
+        0,
+    },
     { KV5M_PREAUTH_OPS, -1 }
 };
 
@@ -335,7 +363,8 @@ process_pw_salt(context, padata, request, as_reply,
        return 0;
 
     salt.data = (char *) padata->contents;
-    salt.length = padata->length;
+    salt.length = 
+      (padata->pa_type == KRB5_PADATA_AFS3_SALT)?(-1):(padata->length);
     
     if ((retval = (*key_proc)(context, as_reply->enc_part.enctype,
                              &salt, keyseed, decrypt_key))) {
@@ -361,3 +390,222 @@ find_pa_system(type, preauth)
     return 0;
 } 
 
+
+extern char *krb5_default_pwd_prompt1;
+
+static krb5_error_code
+sam_get_pass_from_user(context, etype_info, key_proc, key_seed, request,
+                      new_enc_key, prompt)
+    krb5_context               context;
+    krb5_etype_info            etype_info;
+    git_key_proc               key_proc;
+    krb5_const_pointer         key_seed;
+    krb5_kdc_req *             request;
+    krb5_keyblock **           new_enc_key;
+    const char *               prompt;
+{
+    krb5_enctype               enctype;
+    krb5_error_code            retval;
+    char *oldprompt;
+
+    /* enctype = request->ktype[0]; */
+    enctype = ENCTYPE_DES_CBC_MD5;
+/* hack with this first! */
+    oldprompt = krb5_default_pwd_prompt1;
+    krb5_default_pwd_prompt1 = prompt;
+    {
+      krb5_data newpw;
+      newpw.data = 0; newpw.length = 0;
+      /* we don't keep the new password, just the key... */
+      retval = (*key_proc)(context, enctype, 0, 
+                          (krb5_const_pointer)&newpw, new_enc_key);
+      krb5_xfree(newpw.data);
+    }
+    krb5_default_pwd_prompt1 = oldprompt;
+    return retval;
+}
+static 
+char *handle_sam_labels(sc)
+     krb5_sam_challenge *sc;
+{
+    char *label = sc->sam_challenge_label.data;
+    int label_len = sc->sam_challenge_label.length;
+    char *prompt = sc->sam_response_prompt.data;
+    int prompt_len = sc->sam_response_prompt.length;
+    char *challenge = sc->sam_challenge.data;
+    int challenge_len = sc->sam_challenge.length;
+    char *prompt1, *p;
+    char *sep1 = ": [";
+    char *sep2 = "]\n";
+    char *sep3 = ": ";
+
+    if (sc->sam_cksum.length == 0) {
+      /* or invalid -- but lets just handle presence now XXX */
+      switch (sc->sam_type) {
+      case PA_SAM_TYPE_ENIGMA: /* Enigma Logic */
+       label = "Challenge for Enigma Logic mechanism";
+       break;
+      case PA_SAM_TYPE_DIGI_PATH: /*  Digital Pathways */
+       label = "Challenge for Digital Pathways mechanism";
+       break;
+      case PA_SAM_TYPE_SKEY_K0:        /*  S/key where  KDC has key 0 */
+       label = "Challenge for Enhanced S/Key mechanism";
+       break;
+      case PA_SAM_TYPE_SKEY:   /*  Traditional S/Key */
+       label = "Challenge for Traditional S/Key mechanism";
+       break;
+      case PA_SAM_TYPE_SECURID:        /*  Security Dynamics */
+       label = "Challenge for Security Dynamics mechanism";
+       break;
+      }
+      prompt = "Passcode";
+      label_len = strlen(label);
+      prompt_len = strlen(prompt);
+    }
+
+    /* example:
+       Challenge for Digital Pathways mechanism: [134591]
+       Passcode: 
+     */
+    p = prompt1 = malloc(label_len + strlen(sep1) +
+                        challenge_len + strlen(sep2) +
+                        prompt_len+ strlen(sep3) + 1);
+    strncpy(p, label, label_len); p += label_len;
+    strcpy(p, sep1); p += strlen(sep1);
+    strncpy(p, challenge, challenge_len); p += challenge_len;
+    strcpy(p, sep2); p += strlen(sep2);
+    strncpy(p, prompt, prompt_len); p += prompt_len;
+    strcpy(p, sep3); /* p += strlen(sep3); */
+    return prompt1;
+}
+
+/*
+ * This routine is the "obtain" function for the SAM_CHALLENGE
+ * preauthentication type.  It presents the challenge...
+ */
+static krb5_error_code
+obtain_sam_padata(context, in_padata, etype_info, def_enc_key,
+                 key_proc, key_seed, creds, request, out_padata)
+    krb5_context               context;
+    krb5_pa_data *             in_padata;
+    krb5_etype_info            etype_info;
+    krb5_keyblock *            def_enc_key;
+    git_key_proc               key_proc;
+    krb5_const_pointer         key_seed;
+    krb5_creds *               creds;
+    krb5_kdc_req *             request;
+    krb5_pa_data **            out_padata;
+{
+    krb5_pa_enc_ts             pa_enc;
+    krb5_error_code            retval;
+    krb5_data *                        scratch;
+    krb5_data                  tmpsam;
+    krb5_pa_data *             pa;
+    krb5_sam_challenge         *sam_challenge = 0;
+    krb5_sam_response          sam_response;
+    /* these two get encrypted and stuffed in to sam_response */
+    krb5_enc_sam_response_enc  enc_sam_response_enc;
+    krb5_keyblock *            sam_use_key = 0;
+    char * prompt;
+
+    tmpsam.length = in_padata->length;
+    tmpsam.data = in_padata->contents;
+    retval = decode_krb5_sam_challenge(&tmpsam, &sam_challenge);
+    if (retval)
+      return retval;
+
+    if (sam_challenge->sam_flags & KRB5_SAM_MUST_PK_ENCRYPT_SAD) {
+      return KRB5_SAM_UNSUPPORTED;
+    }
+
+    enc_sam_response_enc.sam_nonce = sam_challenge->sam_nonce;
+    if (sam_challenge->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD) {
+      /* encrypt passcode in key by stuffing it here */
+      int pcsize = 256;
+      char *passcode = malloc(pcsize+1);
+      prompt = handle_sam_labels(sam_challenge);
+      retval = krb5_read_password(context, prompt, 0, passcode, &pcsize);
+      free(prompt);
+
+      if (retval) {
+       free(passcode);
+       return retval;
+      }
+      enc_sam_response_enc.sam_passcode.data = passcode;
+      enc_sam_response_enc.sam_passcode.length = pcsize;
+    } else if (sam_challenge->sam_flags & KRB5_SAM_USE_SAD_AS_KEY) {
+      if (sam_challenge->sam_nonce) {
+       /* use nonce in the next AS request? */
+      } else {
+       retval = krb5_us_timeofday(context, 
+                                  &enc_sam_response_enc.sam_timestamp,
+                                  &enc_sam_response_enc.sam_usec);
+       sam_response.sam_patimestamp = enc_sam_response_enc.sam_timestamp;
+      }
+      if (retval)
+       return retval;      
+      prompt = handle_sam_labels(sam_challenge);
+      retval = sam_get_pass_from_user(context, etype_info, key_proc, 
+                                     key_seed, request, &sam_use_key,
+                                     prompt);
+      free(prompt);
+      if (retval)
+       return retval;      
+      enc_sam_response_enc.sam_passcode.length = 0;
+    } else {
+      /* what *was* it? */
+      return KRB5_SAM_UNSUPPORTED;
+    }
+
+    /* so at this point, either sam_use_key is generated from the passcode
+     * or enc_sam_response_enc.sam_passcode is set to it, and we use 
+     * def_enc_key instead. */
+    /* encode the encoded part of the response */
+    if ((retval = encode_krb5_enc_sam_response_enc(&enc_sam_response_enc,
+                                                  &scratch)) != 0)
+      return retval;
+
+    if ((retval = krb5_encrypt_data(context, 
+                                   sam_use_key?sam_use_key:def_enc_key, 
+                                   0, scratch,
+                                   &sam_response.sam_enc_nonce_or_ts)))
+      goto cleanup;
+
+    krb5_free_data(context, scratch);
+    scratch = 0;
+
+    /* sam_enc_key is reserved for future use */
+    sam_response.sam_enc_key.ciphertext.length = 0;
+
+    /* copy things from the challenge */
+    sam_response.sam_nonce = sam_challenge->sam_nonce;
+    sam_response.sam_flags = sam_challenge->sam_flags;
+    sam_response.sam_track_id = sam_challenge->sam_track_id;
+    sam_response.sam_type = sam_challenge->sam_type;
+    sam_response.magic = KV5M_SAM_RESPONSE;
+
+    if ((retval = encode_krb5_sam_response(&sam_response, &scratch)) != 0)
+       return retval;
+    
+    if ((pa = malloc(sizeof(krb5_pa_data))) == NULL) {
+       retval = ENOMEM;
+       goto cleanup;
+    }
+
+    pa->magic = KV5M_PA_DATA;
+    pa->pa_type = KRB5_PADATA_SAM_RESPONSE;
+    pa->length = scratch->length;
+    pa->contents = scratch->data;
+    scratch = 0;               /* so we don't free it! */
+
+    *out_padata = pa;
+
+    retval = 0;
+    
+cleanup:
+    if (scratch)
+       krb5_free_data(context, scratch);
+    if (sam_challenge)
+        krb5_xfree(sam_challenge);
+    return retval;
+}
index fea6d6b2f73b9f447d761cce5a1198c03eae1ba4..854ac9189b525e29c2a4665d8b85e081588faa5f 100644 (file)
@@ -104,11 +104,13 @@ static const char stype_v4_in[]           = "v4";
 static const char stype_norealm_in[]   = "norealm";
 static const char stype_olrealm_in[]   = "onlyrealm";
 static const char stype_special_in[]   = "special";
+static const char stype_afs3_in[]      = "afs3";
 static const char stype_v5_out[]       = "Version 5";
 static const char stype_v4_out[]       = "Version 4";
 static const char stype_norealm_out[]  = "Version 5 - No Realm";
 static const char stype_olrealm_out[]  = "Version 5 - Realm Only";
 static const char stype_special_out[]  = "Special";
+static const char stype_afs3_out[]     = "AFS version 3";
 
 /* Checksum type strings */
 static const char cstype_crc32_in[]    = "crc32";
@@ -195,7 +197,8 @@ static const struct salttype_lookup_entry salttype_table[] = {
 { KRB5_KDB_SALTTYPE_V4,                stype_v4_in,            stype_v4_out      },
 { KRB5_KDB_SALTTYPE_NOREALM,   stype_norealm_in,       stype_norealm_out },
 { KRB5_KDB_SALTTYPE_ONLYREALM, stype_olrealm_in,       stype_olrealm_out },
-{ KRB5_KDB_SALTTYPE_SPECIAL,   stype_special_in,       stype_special_out }
+{ KRB5_KDB_SALTTYPE_SPECIAL,   stype_special_in,       stype_special_out },
+{ KRB5_KDB_SALTTYPE_AFS3,      stype_afs3_in,          stype_afs3_out    }
 };
 static const int salttype_table_nents = sizeof(salttype_table)/
                                        sizeof(salttype_table[0]);