svn rev #24405: trunk/src/ plugins/preauth/ plugins/preauth/securid_sam2/

hartmans@MIT.EDU hartmans at MIT.EDU
Fri Oct 1 13:12:37 EDT 2010


http://src.mit.edu/fisheye/changelog/krb5/?cs=24405
Commit By: hartmans
Log Message:
Initial securid2 support.
builds but untested


Changed Files:
U   trunk/src/configure.in
A   trunk/src/plugins/preauth/securid_sam2/
A   trunk/src/plugins/preauth/securid_sam2/Makefile.in
A   trunk/src/plugins/preauth/securid_sam2/extern.h
A   trunk/src/plugins/preauth/securid_sam2/securid2.c
A   trunk/src/plugins/preauth/securid_sam2/securid_sam2.exports
A   trunk/src/plugins/preauth/securid_sam2/securid_sam2_main.c
Modified: trunk/src/configure.in
===================================================================
--- trunk/src/configure.in	2010-10-01 17:12:30 UTC (rev 24404)
+++ trunk/src/configure.in	2010-10-01 17:12:37 UTC (rev 24405)
@@ -1116,6 +1116,7 @@
 	plugins/kdb/db2/libdb2/test
 	plugins/kdb/hdb
 	plugins/preauth/cksum_body plugins/preauth/encrypted_challenge
+	plugins/preauth/securid_sam2
 	plugins/preauth/wpse
 	plugins/authdata/greet
 	plugins/authdata/greet_client

Copied: trunk/src/plugins/preauth/securid_sam2/Makefile.in (from rev 24404, trunk/src/plugins/preauth/encrypted_challenge/Makefile.in)
===================================================================
--- trunk/src/plugins/preauth/securid_sam2/Makefile.in	                        (rev 0)
+++ trunk/src/plugins/preauth/securid_sam2/Makefile.in	2010-10-01 17:12:37 UTC (rev 24405)
@@ -0,0 +1,38 @@
+mydir=plugins/preauth/securid_sam2
+BUILDTOP=$(REL)..$(S)..$(S)..
+KRB5_RUN_ENV = @KRB5_RUN_ENV@
+KRB5_CONFIG_SETUP = KRB5_CONFIG=$(top_srcdir)/config-files/krb5.conf ; export KRB5_CONFIG ;
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+MODULE_INSTALL_DIR = $(KRB5_PA_MODULE_DIR)
+DEFS=@DEFS@ -DARL_SECURID_PREAUTH
+
+LOCALINCLUDES = -I../../../include/krb5 -I.
+
+LIBBASE=securid_sam2
+LIBMAJOR=0
+LIBMINOR=0
+SO_EXT=.so
+RELDIR=../plugins/preauth/securid_sam2
+# Depends on libk5crypto and libkrb5
+SHLIB_EXPDEPS = \
+	$(TOPLIBD)/libk5crypto$(SHLIBEXT) \
+	$(TOPLIBD)/libkrb5$(SHLIBEXT)
+SHLIB_EXPLIBS= -lkrb5 -lcom_err -lk5crypto $(SUPPORT_LIB) $(LIBS)
+
+SHLIB_DIRS=-L$(TOPLIBD)
+SHLIB_RDIRS=$(KRB5_LIBDIR)
+STOBJLISTS=OBJS.ST
+STLIBOBJS=securid_sam2_main.o securid2.o
+
+SRCS= $(srcdir)/securid_sam2_main.c $(srcdir)/securid2.c 2
+
+all-unix:: all-liblinks
+install-unix:: install-libs
+clean-unix:: clean-libs clean-libobjs
+
+clean::
+	$(RM) lib$(LIBBASE)$(SO_EXT)
+
+ at libnover_frag@
+ at libobj_frag@

Added: trunk/src/plugins/preauth/securid_sam2/extern.h
===================================================================
--- trunk/src/plugins/preauth/securid_sam2/extern.h	                        (rev 0)
+++ trunk/src/plugins/preauth/securid_sam2/extern.h	2010-10-01 17:12:37 UTC (rev 24405)
@@ -0,0 +1,18 @@
+ krb5_error_code sam_get_db_entry(krb5_context , krb5_principal,
+                        int *, krb5_db_entry **);
+
+krb5_error_code
+securid_make_sam_challenge_2_and_cksum (krb5_context context,
+		krb5_sam_challenge_2 *sc2, krb5_sam_challenge_2_body *sc2b,
+					krb5_keyblock *cksum_key);
+krb5_error_code get_securid_edata_2(krb5_context context,
+				krb5_db_entry *client,
+				krb5_sam_challenge_2_body *sc2b,
+				    krb5_sam_challenge_2 *sc2);
+
+krb5_error_code verify_securid_data_2(krb5_context context,
+				      krb5_db_entry *client,
+				      krb5_sam_response_2 *sr2,
+				      krb5_enc_tkt_part *enc_tkt_reply,
+				      krb5_pa_data *pa,
+				      krb5_sam_challenge_2 **sc2_out);

Added: trunk/src/plugins/preauth/securid_sam2/securid2.c
===================================================================
--- trunk/src/plugins/preauth/securid_sam2/securid2.c	                        (rev 0)
+++ trunk/src/plugins/preauth/securid_sam2/securid2.c	2010-10-01 17:12:37 UTC (rev 24405)
@@ -0,0 +1,674 @@
+
+#include "k5-int.h"
+#include <kdb.h>
+#include <stdio.h>
+#include <adm_proto.h>
+
+
+#include <syslog.h>
+#include <acexport.h>
+#include <sdi_defs.h>
+#include <sdi_athd.h>
+#include "extern.h"
+
+#define KRB5_SAM_SECURID_NEXT_CHALLENGE_MAGIC		0x5ec1d000
+struct securid_track_data {
+	SDI_HANDLE handle;
+	char state;
+	char passcode[LENPRNST+1];
+        long hostid;
+};
+
+#define SECURID_STATE_NEW_PIN           1       /* Ask for a new pin */
+#define SECURID_STATE_NEW_PIN_AGAIN     2       /* Ask for new pin again */
+#define SECURID_STATE_NEXT_CODE         3       /* Ask for the next pin code */
+#define SECURID_STATE_INITIAL           4
+
+
+static char *PASSCODE_message = 	"SecurID Passcode";
+static char *NEXT_PASSCODE_message = 	"Next Passcode";
+static char *NEW_PIN_AGAIN_message = 	"New PIN Again";
+static char PIN_message[64];		/* Max length should be 50 chars */
+
+/*	krb5_error_code get_securid_key():
+ *		inputs:  context:  from KDC process
+ *			 client:   database entry of client executing
+ *				   SecurID SAM preauthentication
+ *		outputs: client_securid_key: pointer to krb5_keyblock
+ *				   which is key for the client's SecurID
+ *				   database entry.
+ *		returns: 0 on success
+ *			 KRB5 error codes otherwise
+ *
+ *		builds pricipal name with final instance of "SECURID" and
+ *		finds the database entry, decrypts the key out of the database
+ *		and passes the key back to the calling process
+ */
+
+static krb5_error_code get_securid_key(krb5_context context,
+				       krb5_db_entry *client,
+				       krb5_keyblock *client_securid_key)
+{
+  krb5_db_entry *sam_securid_entry = NULL;
+    krb5_key_data *client_securid_key_data = NULL;
+    int sam_type = PA_SAM_TYPE_SECURID;
+    krb5_error_code retval = 0;
+
+    if (!client_securid_key) return(KRB5_PREAUTH_NO_KEY);
+
+    retval = sam_get_db_entry(context, client->princ,
+			      &sam_type, &sam_securid_entry);
+
+    if (retval)
+      return(KRB5_PREAUTH_NO_KEY);
+
+
+    /* Find key with key_type = salt_type = kvno = -1.  This finds the	*/
+    /* latest kvno in the list.  					*/
+
+    retval = krb5_dbe_find_enctype(context, sam_securid_entry,
+		-1, -1, -1, &client_securid_key_data);
+    if (retval) {
+	krb5_set_error_message(context, retval,
+		"while getting key from client's SAM SecurID entry");
+	goto cleanup;
+    }
+    retval = krb5_dbe_decrypt_key_data(context, NULL,
+		client_securid_key_data, client_securid_key, NULL);
+    if (retval) {
+	krb5_set_error_message(context, retval,
+		"while decrypting key from client's SAM SecurID entry ");
+	goto cleanup;
+    }
+ cleanup:
+    if (sam_securid_entry)
+      krb5_db_free_principal(context, sam_securid_entry);
+    return retval;
+}
+
+krb5_error_code
+securid_make_sam_challenge_2_and_cksum (krb5_context context,
+		krb5_sam_challenge_2 *sc2, krb5_sam_challenge_2_body *sc2b,
+		krb5_keyblock *cksum_key)
+{
+  krb5_error_code retval;
+  krb5_checksum **cksum_array = NULL;
+  krb5_checksum *cksum = NULL;
+  krb5_cksumtype cksumtype;
+  krb5_data *encoded_challenge_body = NULL;
+
+  if (!cksum_key) return(KRB5_PREAUTH_NO_KEY);
+  if (!sc2 || !sc2b) return(KRB5KDC_ERR_PREAUTH_FAILED);
+
+  retval = encode_krb5_sam_challenge_2_body(sc2b, &encoded_challenge_body);
+  if (retval || !encoded_challenge_body) {
+	encoded_challenge_body = NULL;
+	goto cksum_cleanup;
+  }
+
+  cksum_array = calloc(2, sizeof(krb5_checksum *));
+  if (!cksum_array) {
+     retval = ENOMEM;
+     goto cksum_cleanup;
+  }
+
+  cksum = (krb5_checksum *)k5alloc(sizeof(krb5_checksum), &retval);
+  if (retval)
+    goto cksum_cleanup;
+  cksum_array[0] = cksum;
+  cksum_array[1] = NULL;
+
+  retval = krb5int_c_mandatory_cksumtype(context, cksum_key->enctype, &cksumtype);
+  if (retval) goto cksum_cleanup;
+
+  retval = krb5_c_make_checksum(context, cksumtype,
+		cksum_key, KRB5_KEYUSAGE_PA_SAM_CHALLENGE_CKSUM,
+		encoded_challenge_body, cksum);
+  if (retval) goto cksum_cleanup;
+
+  sc2->sam_cksum = cksum_array;
+  sc2->sam_challenge_2_body = *encoded_challenge_body;
+  return(0);
+
+cksum_cleanup:
+  if (encoded_challenge_body) krb5_free_data(context, encoded_challenge_body);
+  if (cksum_array) krb5_xfree(cksum_array);
+  if (cksum) krb5_xfree(cksum);
+  return (retval);
+}
+
+
+static krb5_error_code
+securid_decrypt_track_data_2(krb5_context context, krb5_db_entry *client,
+                        krb5_data *enc_track_data, krb5_data *output) {
+    krb5_error_code retval;
+    krb5_keyblock sam_key;
+    krb5_enc_data tmp_enc_data;
+    sam_key.contents = NULL;
+
+    if ((retval = get_securid_key(context, client,
+				  &sam_key) ) != 0)
+	return(retval);
+
+    tmp_enc_data.ciphertext = *enc_track_data;
+    tmp_enc_data.enctype = ENCTYPE_UNKNOWN;
+    tmp_enc_data.kvno = 0;
+
+    output->length = tmp_enc_data.ciphertext.length;
+    if (output->data)
+	free(output->data);
+    output->data = k5alloc(output->length, &retval);
+    if (retval) goto cleanup;
+    retval = krb5_c_decrypt(context, &sam_key,
+	KRB5_KEYUSAGE_PA_SAM_CHALLENGE_TRACKID, 0, &tmp_enc_data, output);
+ cleanup:
+    krb5_free_keyblock_contents(context, &sam_key);
+
+    if (retval) {
+	output->length = 0;
+	if (output->data)
+	  free(output->data);
+	output->data = NULL;
+	return(retval);
+    }
+
+    return(0);
+}
+
+static krb5_error_code
+securid_encrypt_track_data_2(krb5_context context, krb5_db_entry *client,
+                        krb5_data *track_data, krb5_data *output) {
+    krb5_error_code retval;
+    size_t olen;
+    krb5_keyblock sam_key;
+    krb5_enc_data tmp_enc_data;
+    output->data = NULL;
+
+    if ((retval = get_securid_key(context,client,
+				  &sam_key)) != 0)
+	return(retval);
+
+    if ((retval = krb5_c_encrypt_length(context, sam_key.enctype,
+					track_data->length, &olen)) != 0)
+      goto cleanup;
+    assert (olen <= 65536);
+    output->length = olen;
+    output->data = k5alloc(output->length, &retval);
+    if (retval)
+      goto cleanup;
+    tmp_enc_data.ciphertext = *output;
+    tmp_enc_data.enctype = sam_key.enctype;
+    tmp_enc_data.kvno = 0;
+
+    retval = krb5_c_encrypt(context, &sam_key,
+	KRB5_KEYUSAGE_PA_SAM_CHALLENGE_TRACKID, 0, track_data, &tmp_enc_data);
+ cleanup:
+    krb5_free_keyblock_contents(context, &sam_key);
+
+    if (retval) {
+	output->length = 0;
+	if (output->data)
+	  krb5_xfree(output->data);
+	output->data = NULL;
+	return(retval);
+    }
+    return(0);
+}
+
+
+krb5_error_code get_securid_edata_2(krb5_context context,
+				krb5_db_entry *client,
+				krb5_sam_challenge_2_body *sc2b,
+				krb5_sam_challenge_2 *sc2)
+{
+	krb5_error_code retval;
+	krb5_data scratch;
+	krb5_keyblock client_key;
+	char *user = NULL;
+	char *def_user = "<unknown user>";
+	struct securid_track_data sid_track_data;
+	krb5_data tmp_data;
+	client_key.contents = NULL;
+	scratch.data = NULL;
+	sc2b->sam_track_id.data = NULL;
+
+	retval =  krb5_unparse_name(context, client->princ, &user);
+	if (retval)
+	  goto cleanup;
+
+
+	   sc2b->sam_flags = KRB5_SAM_SEND_ENCRYPTED_SAD;
+	   sc2b->sam_type_name.length = 0;
+	   sc2b->sam_challenge_label.length = 0;
+	   sc2b->sam_challenge.length = 0;
+	   sc2b->sam_response_prompt.data = PASSCODE_message;
+	   sc2b->sam_response_prompt.length =
+			strlen(sc2b->sam_response_prompt.data);
+	   sc2b->sam_pk_for_sad.length = 0;
+
+	   sid_track_data.state = SECURID_STATE_INITIAL;
+	   sid_track_data.hostid = gethostid();
+	   tmp_data.data = (char *) &sid_track_data;
+	   tmp_data.length = sizeof(sid_track_data);
+	   if((retval = securid_encrypt_track_data_2(context, client,
+						    &tmp_data,
+						     &sc2b->sam_track_id)) != 0) {
+	     krb5_set_error_message(context, retval, "While encrypting nonce track data");
+	     goto cleanup;
+	   }
+
+
+	   scratch.data = (char *)&sc2b->sam_nonce;
+	   scratch.length = sizeof(sc2b->sam_nonce);
+	   retval = krb5_c_random_make_octets(context, &scratch);
+	   if (retval) {
+	     krb5_set_error_message(context, retval,
+		"while generating nonce data in get_securid_edata_2 (%s)",
+		user ? user : def_user);
+	     goto cleanup;
+	   }
+
+	   /* Get the client's key */
+	   if ((retval = get_securid_key(context, client, &client_key)) != 0) {
+	     krb5_set_error_message(context, retval,
+		"while getting SecurID SAM key in get_securid_edata_2 (%s)",
+		user ? user : def_user);
+	     goto cleanup;
+	   }
+	   sc2b->sam_etype = client_key.enctype;
+
+	   retval = securid_make_sam_challenge_2_and_cksum(context,
+			sc2, sc2b, &client_key);
+	   if (retval) {
+	      krb5_set_error_message(context, retval,
+		"while making SAM_CHALLENGE_2 checksum (%s)",
+		user ? user : def_user);
+	   }
+
+ cleanup:
+	   krb5_free_keyblock_contents(context, &client_key);
+	if (user) krb5_xfree(user);
+	if (retval) {
+	  krb5_free_data_contents(context, &sc2b->sam_track_id);
+	  sc2b->sam_track_id.data = NULL;
+	}
+	return(retval);
+}
+
+krb5_error_code verify_securid_data_2(krb5_context context,
+				      krb5_db_entry *client,
+				      krb5_sam_response_2 *sr2,
+				      krb5_enc_tkt_part *enc_tkt_reply,
+				      krb5_pa_data *pa,
+				      krb5_sam_challenge_2 **sc2_out)
+{
+    krb5_error_code retval;
+    int new_pin = 0;
+    krb5_key_data *client_key_data = NULL;
+    krb5_keyblock client_key;
+    krb5_data scratch;
+    krb5_enc_sam_response_enc_2 *esre2 = NULL;
+    struct securid_track_data sid_track_data, *trackp = NULL;
+    krb5_data tmp_data;
+    SDI_HANDLE sd_handle = SDI_HANDLE_NONE;
+    krb5_sam_challenge_2 *sc2p = NULL;
+    char *cp, *user = NULL;
+    char *securid_user = NULL;
+    char passcode[LENPRNST+1];
+    char max_pin_len, min_pin_len, alpha_pin;
+
+    memset(&client_key, 0, sizeof(client_key));
+    memset(&scratch, 0, sizeof(scratch));
+    *sc2_out = NULL;
+
+    if ((retval = krb5_unparse_name(context, client->princ, &user)) !=0 ) {
+	krb5_set_error_message(context, retval,
+		"while unparsing client name in verify_securid_data_2");
+	return(retval);
+    }
+
+    if ((sr2->sam_enc_nonce_or_sad.ciphertext.data == NULL) ||
+	(sr2->sam_enc_nonce_or_sad.ciphertext.length <= 0)) {
+	  retval = KRB5KDC_ERR_PREAUTH_FAILED;
+	  krb5_set_error_message(context, retval,
+		"No preauth data supplied in verify_securid_data_2 (%s)", user);
+	  goto cleanup;
+    }
+
+    retval = krb5_dbe_find_enctype(context, client,
+		sr2->sam_enc_nonce_or_sad.enctype, KRB5_KDB_SALTTYPE_NORMAL,
+		sr2->sam_enc_nonce_or_sad.kvno , &client_key_data);
+    if (retval) {
+	krb5_set_error_message(context, retval,
+		"while getting client key in verify_securid_data_2 (%s)", user);
+	goto cleanup;
+    }
+
+    if ((retval = krb5_dbe_decrypt_key_data(context, NULL,
+					      client_key_data, &client_key, NULL)) != 0) {
+	krb5_set_error_message(context, retval,
+		"while decrypting client key in verify_securid_data_2 (%s)",
+		user);
+	goto cleanup;
+    }
+
+    scratch.length = sr2->sam_enc_nonce_or_sad.ciphertext.length;
+    scratch.data = k5alloc(scratch.length, &retval);
+    if (retval)
+      goto cleanup;
+    retval = krb5_c_decrypt(context, &client_key,
+		KRB5_KEYUSAGE_PA_SAM_RESPONSE, 0,
+		&sr2->sam_enc_nonce_or_sad, &scratch);
+    if (retval) {
+	krb5_set_error_message(context, retval,
+		"while decrypting SAD in verify_securid_data_2 (%s)", user);
+	goto cleanup;
+    }
+
+    retval = decode_krb5_enc_sam_response_enc_2(&scratch, &esre2);
+    if (retval) {
+	krb5_set_error_message(context, retval,
+		"while decoding SAD in verify_securid_data_2 (%s)", user);
+	esre2 = NULL;
+	goto cleanup;
+    }
+
+    if (sr2->sam_nonce != esre2->sam_nonce) {
+	krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
+		"while checking nonce in verify_securid_data_2 (%s)", user);
+	retval = KRB5KDC_ERR_PREAUTH_FAILED;
+	goto cleanup;
+    }
+
+    if ((esre2->sam_sad.length == 0) || (esre2->sam_sad.data == NULL)) {
+	krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
+		"No SecurID passcode in verify_securid_data_2 (%s)", user);
+	retval = KRB5KDC_ERR_PREAUTH_FAILED;
+	goto cleanup;
+    }
+
+    /* Copy out SAD to null-terminated buffer */
+    memset(passcode, 0, sizeof(passcode));
+    if (esre2->sam_sad.length > (sizeof(passcode) - 1)) {
+	retval = KRB5KDC_ERR_PREAUTH_FAILED;
+	krb5_set_error_message(context, retval,
+		"SecurID passcode/PIN too long (%d bytes) in verify_securid_data_2 (%s)",
+		esre2->sam_sad.length, user);
+	goto cleanup;
+    }
+    memcpy(passcode, esre2->sam_sad.data, esre2->sam_sad.length);
+
+    securid_user = strdup(user);
+    if (!securid_user) {
+      retval = ENOMEM;
+	krb5_set_error_message(context, ENOMEM,
+		"while copying user name in verify_securid_data_2 (%s)", user);
+	goto cleanup;
+    }
+    if ((cp = strchr(securid_user, '@')))
+	*cp = (char)0;
+
+    /* Check for any track_id data that may have state from a previous	*/
+    /* attempt at SecurID authentication 				*/
+
+    if (sr2->sam_track_id.data && (sr2->sam_track_id.length > 0)) {
+	krb5_data track_id_data;
+	memset(&track_id_data, 0, sizeof(track_id_data));
+	retval = securid_decrypt_track_data_2(context, client,
+			&sr2->sam_track_id, &track_id_data);
+	if (retval) {
+	   krb5_set_error_message(context, retval,
+	      "while decrypting SecurID trackID in verify_securid_data_2 (%s)",
+			user);
+	   goto cleanup;
+	}
+	if (track_id_data.length <= sizeof (struct securid_track_data)) {
+	  retval = KRB5KDC_ERR_PREAUTH_FAILED;
+	  krb5_set_error_message(context, retval, "Length of track data incorrect");
+	  goto cleanup;
+	}
+	trackp = (struct securid_track_data *)track_id_data.data;
+
+	if(trackp->hostid != gethostid()) {
+	  krb5_klog_syslog(LOG_INFO, "Unexpected challenge response");
+	  retval = KRB5KDC_ERR_DISCARD;
+	  goto cleanup;
+	}
+
+	switch(trackp->state) {
+	  case SECURID_STATE_INITIAL:
+	    goto initial;
+	    break;
+	  case SECURID_STATE_NEW_PIN_AGAIN:
+		{
+		  int pin1_len, pin2_len;
+
+		  trackp->handle = ntohl(trackp->handle);
+		  pin2_len = strlen(passcode);
+		  pin1_len = strlen(trackp->passcode);
+
+		  if ((pin1_len != pin2_len) ||
+			(memcmp(passcode, trackp->passcode, pin1_len) != 0)) {
+		     retval = KRB5KDC_ERR_PREAUTH_FAILED;
+		     krb5_klog_syslog(LOG_INFO,
+			"New SecurID PIN Failed for user %s: PIN mis-match",
+			user);
+		     break;
+		  }
+		  retval = SD_Pin(trackp->handle, passcode);
+		  SD_Close(trackp->handle);
+		  if (retval == ACM_NEW_PIN_ACCEPTED) {
+		    enc_tkt_reply->flags|=  TKT_FLG_HW_AUTH;
+		    enc_tkt_reply->flags|=  TKT_FLG_PRE_AUTH;
+		     krb5_klog_syslog(LOG_INFO,
+			"SecurID PIN Accepted for %s in verify_securid_data_2",
+			securid_user);
+		     retval = 0;
+		  } else {
+		     retval = KRB5KDC_ERR_PREAUTH_FAILED;
+		     krb5_klog_syslog(LOG_INFO,
+			"SecurID PIN Failed for user %s (AceServer returns %d) in verify_securid_data_2",
+                        user, retval);
+		  }
+		  break;
+		}
+	  case SECURID_STATE_NEW_PIN: {
+	    krb5_sam_challenge_2_body sc2b;
+	    sc2p = k5alloc(sizeof *sc2p, &retval);
+	    if (retval)
+	      goto cleanup;
+	    memset(sc2p, 0, sizeof(*sc2p));
+		memset(&sc2b, 0, sizeof(sc2b));
+		sc2b.sam_type = PA_SAM_TYPE_SECURID;
+		sc2b.sam_response_prompt.data = NEW_PIN_AGAIN_message;
+		sc2b.sam_response_prompt.length =
+				strlen(sc2b.sam_response_prompt.data);
+		sc2b.sam_flags = KRB5_SAM_SEND_ENCRYPTED_SAD;
+		sc2b.sam_etype = client_key.enctype;
+
+		tmp_data.data = (char *)&sc2b.sam_nonce;
+		tmp_data.length = sizeof(sc2b.sam_nonce);
+		if ((retval = krb5_c_random_make_octets(context, &tmp_data))) {
+		  krb5_set_error_message(context, retval,
+			"while making nonce for SecurID new PIN2 SAM_CHALLENGE_2 (%s)", user);
+		  goto cleanup;
+		}
+		sid_track_data.state = SECURID_STATE_NEW_PIN_AGAIN;
+		sid_track_data.handle = trackp->handle;
+		sid_track_data.hostid = gethostid();
+		/* Should we complain if sizes don't work ??  */
+		memcpy(sid_track_data.passcode, passcode,
+			sizeof(sid_track_data.passcode));
+		tmp_data.data = (char *)&sid_track_data;
+		tmp_data.length = sizeof(sid_track_data);
+		if ((retval = securid_encrypt_track_data_2(context, client,
+							   &tmp_data, &sc2b.sam_track_id))) {
+		   krb5_set_error_message(context, retval,
+			"while encrypting NEW PIN2 SecurID track data for SAM_CHALLENGE_2 (%s)",
+			securid_user);
+		   goto cleanup;
+		}
+		retval = securid_make_sam_challenge_2_and_cksum(context, sc2p,
+			&sc2b, &client_key);
+		if (retval) {
+		   krb5_set_error_message(context, retval,
+		      "while making cksum for SAM_CHALLENGE_2 (new PIN2) (%s)",
+		      securid_user);
+		   goto cleanup;
+		}
+		krb5_klog_syslog(LOG_INFO,
+		   "Requesting verification of new PIN for user %s",
+		   securid_user);
+		*sc2_out = sc2p;
+		sc2p = NULL;
+		/*sc2_out may be set even on error path*/
+		retval = KRB5KDC_ERR_PREAUTH_REQUIRED;
+		goto cleanup;
+	  }
+	  case SECURID_STATE_NEXT_CODE:
+		trackp->handle = ntohl(trackp->handle);
+		retval = SD_Next(trackp->handle, passcode);
+		SD_Close(trackp->handle);
+		if (retval == ACM_OK) {
+		  enc_tkt_reply->flags |=  TKT_FLG_HW_AUTH
+		    | TKT_FLG_PRE_AUTH;
+
+		   krb5_klog_syslog(LOG_INFO,
+			"Next SecurID Code Accepted for user %s", securid_user);
+		   retval = 0;
+		} else {
+		   krb5_klog_syslog(LOG_INFO,
+			"Next SecurID Code Failed for user %s (AceServer returns %d) in verify_securid_data_2",
+			user, retval);
+		   retval = KRB5KDC_ERR_PREAUTH_FAILED;
+		}
+		break;
+	}
+    } else {		/* No track data, this is first of N attempts */
+initial:
+      if ((retval = SD_Init(&sd_handle))) {
+	   krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
+		"SD_Init() returns error %d in verify_securid_data_2 (%s)",
+			retval, securid_user);
+	   retval = KRB5KDC_ERR_PREAUTH_FAILED;
+	   goto cleanup;
+	}
+
+	if((retval = SD_Lock(sd_handle, securid_user)) != ACM_OK) {
+	  SD_Close(sd_handle);
+	  retval = KRB5KDC_ERR_PREAUTH_FAILED;
+	  krb5_klog_syslog(LOG_INFO,
+		"SD_Lock() failed (AceServer returns %d) for %s",
+		retval, securid_user);
+	  goto cleanup;
+	}
+
+	retval = SD_Check(sd_handle, passcode, securid_user);
+	switch (retval) {
+	   case ACM_OK:
+		SD_Close(sd_handle);
+		    enc_tkt_reply->flags|=  TKT_FLG_HW_AUTH;
+		    enc_tkt_reply->flags|=  TKT_FLG_PRE_AUTH;
+		    krb5_klog_syslog(LOG_INFO,
+		   "SecurID passcode accepted for user %s", user);
+		retval = 0;
+		break;
+	   case ACM_ACCESS_DENIED:
+		SD_Close(sd_handle);
+		retval = KRB5KDC_ERR_PREAUTH_FAILED;
+		krb5_klog_syslog(LOG_INFO,
+		   "AceServer returns Access Denied for user %s (SAM2)",user);
+		goto cleanup;
+	   case ACM_NEW_PIN_REQUIRED:
+	     new_pin = 1;
+	     /*fall through*/
+	   case ACM_NEXT_CODE_REQUIRED: {
+		krb5_sam_challenge_2_body sc2b;
+		sc2p = k5alloc(sizeof *sc2p, &retval);
+		if (retval)
+		  goto cleanup;
+
+		memset(sc2p, 0, sizeof(*sc2p));
+		memset(&sc2b, 0, sizeof(sc2b));
+
+		sc2b.sam_type = PA_SAM_TYPE_SECURID;
+		sc2b.sam_response_prompt.data = NEXT_PASSCODE_message;
+		sc2b.sam_response_prompt.length =
+				strlen(sc2b.sam_response_prompt.data);
+		sc2b.sam_flags = KRB5_SAM_SEND_ENCRYPTED_SAD;
+		sc2b.sam_etype = client_key.enctype;
+		if (new_pin) {
+		  if ((AceGetMaxPinLen(sd_handle, &max_pin_len) == ACE_SUCCESS)
+		      && (AceGetMinPinLen(sd_handle, &min_pin_len) == ACE_SUCCESS)
+		      && (AceGetAlphanumeric(sd_handle, &alpha_pin) == ACE_SUCCESS))
+		    {
+		      sprintf(PIN_message,
+			      "New PIN must contain %d to %d %sdigits",
+			      min_pin_len, max_pin_len,
+			      (alpha_pin == 0) ? "" : "alphanumeric ");
+		      sc2b.sam_challenge_label.data = PIN_message;
+		      sc2b.sam_challenge_label.length =
+			strlen(sc2b.sam_challenge_label.data);
+		    } else {
+		    sc2b.sam_challenge_label.length = 0;
+		  }
+		}
+
+		tmp_data.data = (char *)&sc2b.sam_nonce;
+		tmp_data.length = sizeof(sc2b.sam_nonce);
+		if ((retval = krb5_c_random_make_octets(context, &tmp_data))) {
+		   krb5_set_error_message(context, retval,
+			"while making nonce for SecurID  SAM_CHALLENGE_2 (%s)", user);
+		   goto cleanup;
+		}
+		if (new_pin)
+				sid_track_data.state = SECURID_STATE_NEW_PIN;
+		else 		sid_track_data.state = SECURID_STATE_NEXT_CODE;
+		sid_track_data.handle = htonl(sd_handle);
+		sid_track_data.hostid = gethostid();
+		tmp_data.data = (char *)&sid_track_data;
+		tmp_data.length = sizeof(sid_track_data);
+		if ((retval = securid_encrypt_track_data_2(context, client,
+							   &tmp_data, &sc2b.sam_track_id))) {
+		   krb5_set_error_message(context, retval,
+			"while encrypting SecurID track data for SAM_CHALLENGE_2 (%s)",
+			securid_user);
+		   goto cleanup;
+		}
+		retval = securid_make_sam_challenge_2_and_cksum(context, sc2p,
+			&sc2b, &client_key);
+		if (retval) {
+		   krb5_set_error_message(context, retval,
+		      "while making cksum for SAM_CHALLENGE_2 (%s)",
+		      securid_user);
+		}
+		if (new_pin)
+				krb5_klog_syslog(LOG_INFO,
+		   "New SecurID PIN required for user %s", securid_user);
+		else 		krb5_klog_syslog(LOG_INFO,
+		   "Next SecurID passcode required for user %s", securid_user);
+		*sc2_out = sc2p;
+		sc2p = NULL;
+		retval = KRB5KDC_ERR_PREAUTH_FAILED;
+		/*sc2_out is permitted as an output on error path*/
+		goto cleanup;
+	   }
+	   default:
+		krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
+			"AceServer returns unknown error code %d in verify_securid_data_2\n", retval);
+		retval = KRB5KDC_ERR_PREAUTH_FAILED;
+		goto cleanup;
+	}
+    }	/* no track_id data */
+
+cleanup:
+    if (client_key.contents) krb5_free_keyblock_contents(context, &client_key);
+    if (scratch.data) krb5_xfree(scratch.data);
+    if (esre2) krb5_free_enc_sam_response_enc_2(context, esre2);
+    if (user) krb5_xfree(user);
+    if (securid_user) krb5_xfree(securid_user);
+    if (trackp) krb5_xfree(trackp);
+    if (sc2p)
+      krb5_free_sam_challenge_2(context, sc2p);
+    return(retval);
+}

Added: trunk/src/plugins/preauth/securid_sam2/securid_sam2.exports
===================================================================
--- trunk/src/plugins/preauth/securid_sam2/securid_sam2.exports	                        (rev 0)
+++ trunk/src/plugins/preauth/securid_sam2/securid_sam2.exports	2010-10-01 17:12:37 UTC (rev 24405)
@@ -0,0 +1 @@
+preauthentication_server_1

Added: trunk/src/plugins/preauth/securid_sam2/securid_sam2_main.c
===================================================================
--- trunk/src/plugins/preauth/securid_sam2/securid_sam2_main.c	                        (rev 0)
+++ trunk/src/plugins/preauth/securid_sam2/securid_sam2_main.c	2010-10-01 17:12:37 UTC (rev 24405)
@@ -0,0 +1,274 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * plugins/preauth/encrypted_challenge/encrypted_challenge.c
+ *
+ * Copyright (C) 2009, 2010 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * Copyright (c) 2002 Naval Research Laboratory (NRL/CCS)
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the software,
+ * derivative works or modified versions, and any portions thereof.
+ *
+ * NRL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION AND
+ * DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ */
+
+#include <k5-int.h>
+#include <krb5/preauth_plugin.h>
+#include <kdb.h>
+#include "extern.h"
+
+
+static struct {
+  char* name;
+  int   sam_type;
+} *sam_ptr, sam_inst_map[] = {
+  { "SECURID", PA_SAM_TYPE_SECURID, },
+  { "GRAIL", PA_SAM_TYPE_GRAIL, },
+  { 0, 0 },
+};
+
+ krb5_error_code sam_get_db_entry(
+    krb5_context context,
+			krb5_principal client,
+			int *sam_type,
+			struct _krb5_db_entry_new **db_entry)
+{
+    struct _krb5_db_entry_new *assoc = NULL;
+   krb5_principal newp = NULL;
+   int probeslot;
+   void *ptr = NULL;
+   krb5_error_code retval;
+   if (db_entry)
+       *db_entry = NULL;
+   retval = krb5_copy_principal(context, client, &newp);
+   if (retval) {
+	krb5_set_error_message(context, retval, "copying client name for preauth probe");
+	return retval;
+   }
+
+   probeslot = krb5_princ_size(context, newp)++;
+   ptr =
+	realloc(krb5_princ_name(context, newp),
+		krb5_princ_size(context, newp) * sizeof(krb5_data));
+   if (ptr == NULL) {
+       retval = ENOMEM;
+       goto cleanup;
+   } else krb5_princ_name(context, newp) = ptr;
+
+   for(sam_ptr = sam_inst_map; sam_ptr->name; sam_ptr++) {
+	if (*sam_type && (*sam_type != sam_ptr->sam_type)) continue;
+
+	krb5_princ_component(context,newp,probeslot)->data = sam_ptr->name;
+	krb5_princ_component(context,newp,probeslot)->length =
+	strlen(sam_ptr->name);
+	retval = krb5_db_get_principal(context, newp, 0, &assoc);
+	if(!retval )
+	   break;
+	}
+cleanup:
+   if (ptr) {
+       krb5_princ_component(context,newp,probeslot)->data = 0;
+       krb5_princ_component(context,newp,probeslot)->length = 0;
+       krb5_free_principal(context, newp);
+   }
+   if (probeslot)
+       krb5_princ_size(context, newp)--;
+   if (retval)
+       return retval;
+   if (sam_ptr->sam_type)  {
+	/* Found entry of type sam_ptr->sam_type */
+	if (sam_type) *sam_type = sam_ptr->sam_type;
+	if (db_entry) *db_entry = assoc;
+        else krb5_db_free_principal( context, assoc);
+	return(0);
+   } else {
+	return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
+   }
+}
+
+static krb5_error_code
+kdc_include_padata(krb5_context context, krb5_kdc_req *request,
+                   struct _krb5_db_entry_new *client,
+                   struct _krb5_db_entry_new *server,
+                   preauth_get_entry_data_proc get_entry_proc,
+                   void *pa_module_context, krb5_pa_data *pa_data)
+{
+  krb5_error_code retval;
+  krb5_sam_challenge_2 sc2;
+  krb5_sam_challenge_2_body sc2b;
+  int sam_type = 0;		/* unknown */
+  krb5_db_entry *sam_db_entry = NULL;
+  krb5_data *encoded_challenge = NULL;
+  memset(&sc2, 0, sizeof(sc2));
+  memset(&sc2b, 0, sizeof(sc2b));
+  sc2b.magic = KV5M_SAM_CHALLENGE_2;
+  sc2b.sam_type = sam_type;
+
+  retval = sam_get_db_entry(context, client->princ, &sam_type,
+			&sam_db_entry);
+  if (retval) return (retval);
+
+  if (sam_type == 0) {
+     retval = KRB5_PREAUTH_BAD_TYPE;
+     goto cleanup;
+  }
+
+  /* Defer getting the key for the SAM principal associated with the	*/
+  /* client until the mechanism-specific code.  The mechanism may want	*/
+  /* to get a specific keytype						*/
+
+
+  switch (sam_type) {
+#ifdef ARL_SECURID_PREAUTH
+     case PA_SAM_TYPE_SECURID:
+         if ((retval = get_securid_edata_2(context, client, &sc2b, &sc2)))
+	   goto cleanup;
+
+	retval = encode_krb5_sam_challenge_2(&sc2, &encoded_challenge);
+	if (retval) {
+	   krb5_set_error_message(context, retval,"while encoding SECURID SAM_CHALLENGE_2");
+           goto cleanup;
+	}
+
+	pa_data->magic = KV5M_PA_DATA;
+	pa_data->pa_type = KRB5_PADATA_SAM_CHALLENGE_2;
+	pa_data->contents = (krb5_octet *) encoded_challenge->data;
+	pa_data->length = encoded_challenge->length;
+        encoded_challenge->data = NULL;
+
+	retval = 0;
+	break;
+#endif  /* ARL_SECURID_PREAUTH */
+     default:
+	retval = KRB5_PREAUTH_BAD_TYPE;
+	goto cleanup;
+  }
+
+cleanup:
+      krb5_free_data( context, encoded_challenge);
+  if (sam_db_entry)
+	krb5_db_free_principal(context, sam_db_entry);
+  return (retval);
+}
+
+static krb5_error_code
+kdc_verify_preauth(krb5_context context, struct _krb5_db_entry_new *client,
+                   krb5_data *req_pkt, krb5_kdc_req *request,
+                   krb5_enc_tkt_part *enc_tkt_reply, krb5_pa_data *pa_data,
+                   preauth_get_entry_data_proc get_entry_proc,
+                   void *pa_module_context, void **opaque,
+                   krb5_data **e_data, krb5_authdata ***authz_data)
+{
+    krb5_error_code retval;
+  krb5_sam_response_2 *sr2 = NULL;
+  krb5_data scratch, *scratch2;
+    char *client_name = NULL;
+    krb5_sam_challenge_2 *out_sc2 = NULL;
+
+  scratch.data = (char *) pa_data->contents;
+  scratch.length = pa_data->length;
+
+  retval = krb5_unparse_name(context, client->princ, &client_name);
+  if (retval)
+     goto cleanup;
+
+  retval = decode_krb5_sam_response_2(&scratch, &sr2);
+  if (retval) {
+      krb5_set_error_message(context,  retval,
+		"while decoding SAM_RESPONSE_2 in verify_sam_response_2");
+     sr2 = NULL;
+     goto cleanup;
+  }
+
+  switch (sr2->sam_type) {
+#ifdef ARL_SECURID_PREAUTH
+	case PA_SAM_TYPE_SECURID:
+	  retval = verify_securid_data_2(context, client, sr2,
+                                         enc_tkt_reply, pa_data, &out_sc2);
+	  if (retval) goto cleanup;
+	  break;
+#endif  /* ARL_SECURID_PREAUTH */
+	default:
+	  retval = KRB5_PREAUTH_BAD_TYPE;
+	  krb5_set_error_message(context , retval, "while verifying SAM 2 data");
+	  break;
+  }
+
+  /* It is up to the method-specific verify routine to set the ticket flags */
+  /* to indicate TKT_FLG_HW_AUTH and/or TKT_FLG_PRE_AUTH.  Some methods     */
+  /* may require more than one round of dialog with the client and must     */
+  /* return successfully from their verify routine.  If does not set the    */
+  /* TGT flags, the required_preauth conditions will not be met and it will */
+  /* try again to get enough preauth data from the client.  Do not set TGT  */
+  /* flags here.                                                            */
+cleanup:
+  /*Note that e_data is an output even in error conditions.*/
+  if (out_sc2) {
+      krb5_pa_data pa_out;
+      krb5_pa_data *pa_array[2];
+      pa_array[0] = &pa_out;
+      pa_array[1] = NULL;
+      pa_out.pa_type = KRB5_PADATA_SAM_CHALLENGE_2;
+      retval = encode_krb5_sam_challenge_2(out_sc2, &scratch2);
+      krb5_free_sam_challenge_2(context, out_sc2);
+      if (retval)
+          goto encode_error;
+      pa_out.contents = (krb5_octet *) scratch2->data;
+      pa_out.length = scratch2->length;
+      retval = encode_krb5_padata_sequence(pa_array, e_data);
+      krb5_free_data(context, scratch2);
+        }
+encode_error: if (sr2)
+     krb5_free_sam_response_2(context, sr2);
+  if (client_name)
+free(client_name);
+
+  return(retval);
+}
+
+
+static int
+kdc_preauth_flags(krb5_context context, krb5_preauthtype patype)
+{
+    return 0;
+}
+
+krb5_preauthtype supported_pa_types[] = {
+    KRB5_PADATA_SAM_RESPONSE_2, 0};
+
+struct krb5plugin_preauth_server_ftable_v1 preauthentication_server_1 = {
+    "SAM2",
+    &supported_pa_types[0],
+    NULL,
+    NULL,
+    kdc_preauth_flags,
+    kdc_include_padata,
+    kdc_verify_preauth,
+    NULL,
+    NULL
+};




More information about the cvs-krb5 mailing list