[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RFC3244 set password protocol in kpasswdd [was: LDAP backendsupport for OpenLDAP 2.1.x]



On Wed, 2003-06-04 at 19:48, Luke Howard wrote:
> 
> BTW, I implemented RFC 3244 support in kpasswdd some time ago :-)
> 
> -- Luke
> 
> --
> Luke Howard | PADL Software Pty Ltd | www.padl.com

Hi Luke.

This is my "experimental" patch for those who have been asked support
for the RFC3244. (for example myself). Right now there is a new RFC
draft so I thinks is not going to be very useful, but I am sending this
patch anyway. Maybe you could add something.

Please consider this:
1- Doesn't have support for the TCP protocol.
2- Doesn't have a "smart" authorization mechanism.
3- You need to modify the kadmin/changepw principal. You must disable
the disallow-tgt-based attribute (from the kadmin console) so the KDC
doesn't complain about KDC policy rejection. (a TGS is not valid for a
ticket that have the initial flag set).
4- Doesn't implement the initial flag check.
5- Doesn't implement the client program to set the password ( I am using
a modified program client provided by Microsoft with the SASL-GSSAPI
that you wrote for Microsoft ;-) )



diff -Naur heimdal-0.6/kpasswd/kpasswdd.c heimdal-0.6-setpasswd/kpasswd/kpasswdd.c
--- heimdal-0.6/kpasswd/kpasswdd.c	2002-12-02 08:31:52.000000000 -0600
+++ heimdal-0.6-setpasswd/kpasswd/kpasswdd.c	2003-06-09 20:53:09.000000000 -0500
@@ -41,11 +41,36 @@
 #include <hdb.h>
 #include <kadm5/private.h>
 
+#define USER_WITH_ADMIN_RIGHTS	"administrator@MYREALM"
+
 static krb5_context context;
 static krb5_log_facility *log_facility;
 
 static sig_atomic_t exit_flag = 0;
 
+
+/* 
+ This function must be replaced with a real authorization check!
+ This sample just check for a hardcoded principal name. 
+ 
+*/
+static int
+is_authorized2setpw(krb5_context context,krb5_principal principal)
+{
+char *adminUser;
+int  rc;
+
+    krb5_unparse_name(context,principal,&adminUser);
+
+    if ( !strcmp(adminUser,USER_WITH_ADMIN_RIGHTS) )
+    	rc = 1;
+    else
+    	rc = 0;
+	
+    free(adminUser);
+    return rc;
+}
+
 static void
 send_reply (int s,
 	    struct sockaddr *sa,
@@ -211,7 +236,7 @@
     kadm5_config_params conf;
     void *kadm5_handle;
     char *tmp;
-
+   
     memset (&conf, 0, sizeof(conf));
     
     krb5_unparse_name (context, principal, &client);
@@ -240,7 +265,7 @@
 	kadm5_destroy (kadm5_handle);
 	return;
     }
-
+    
     tmp = malloc (pwd_data->length + 1);
     if (tmp == NULL) {
 	krb5_warnx (context, "malloc: out of memory");
@@ -250,7 +275,7 @@
     }
     memcpy (tmp, pwd_data->data, pwd_data->length);
     tmp[pwd_data->length] = '\0';
-
+    
     ret = kadm5_s_chpass_principal_cond (kadm5_handle, principal, tmp);
     memset (tmp, 0, pwd_data->length);
     free (tmp);
@@ -268,6 +293,7 @@
 static int
 verify (krb5_auth_context *auth_context,
 	krb5_principal server,
+	krb5_principal *targetPrincipal,
 	krb5_keytab keytab,
 	krb5_ticket **ticket,
 	krb5_data *out_data,
@@ -281,6 +307,9 @@
     u_int16_t pkt_len, pkt_ver, ap_req_len;
     krb5_data ap_req_data;
     krb5_data krb_priv_data;
+    /* ASN Sequence for set password protocol */
+    ChangePasswdData sChangePasswdData;
+    size_t len2;
 
     pkt_len = (msg[0] << 8) | (msg[1]);
     pkt_ver = (msg[2] << 8) | (msg[3]);
@@ -291,7 +320,7 @@
 	reply_error (server, s, sa, sa_size, 0, 1, "Bad request");
 	return 1;
     }
-    if (pkt_ver != 0x0001) {
+    if (pkt_ver != 0x0001 && pkt_ver != 0xff80) {
 	krb5_warnx (context, "Bad version (%d)", pkt_ver);
 	reply_error (server, s, sa, sa_size, 0, 1, "Wrong program version");
 	return 1;
@@ -319,13 +348,35 @@
 	reply_error (server, s, sa, sa_size, ret, 3, "Authentication failed");
 	return 1;
     }
-
-    if (!(*ticket)->ticket.flags.initial) {
-	krb5_warnx (context, "initial flag not set");
-	reply_error (server, s, sa, sa_size, ret, 1,
-		     "Bad request");
-	goto out;
+    if (pkt_ver == 0x0001) {
+        if (!(*ticket)->ticket.flags.initial) {
+	    krb5_warnx (context, "initial flag not set");
+	    reply_error (server, s, sa, sa_size, ret, 1,
+	        	     "Bad request");
+	    goto out;
+        }
+    }
+    else {
+    /* Should verify if the Initial flag must be set */
+    /* If should be and is not set then return 0x0007 */ 
+    /* Not implemented !!! */
+    	int initial_flag_is_required = FALSE;
+    	if ( initial_flag_is_required )
+            if (!(*ticket)->ticket.flags.initial) {
+	    	krb5_warnx (context, "initial flag not set");
+	    	reply_error (server, s, sa, sa_size, ret, 0x0007,
+	        	     "Bad request");
+	    	goto out;
+            }
+    /* Then check authorization. If doesnt met criteria */
+    /* then return 0x0005. Obviously in result code. */
+    	if ( !is_authorized2setpw(context, (*ticket)->client ) ) {
+	    krb5_warn (context, ret, "is_authorized");
+	    reply_error (server, s, sa, sa_size, ret, 0x0005, "Authorization Failed.");
+	    goto out;
+        }
     }
+
     krb_priv_data.data   = msg + 6 + ap_req_len;
     krb_priv_data.length = len - 6 - ap_req_len;
 
@@ -340,7 +391,46 @@
 	reply_error (server, s, sa, sa_size, ret, 3, "Bad request");
 	goto out;
     }
+    /* If the request is set password		*/
+    /* then I need to decode the setpw structure */
+    if (pkt_ver == 0xff80) {
+        memset(&sChangePasswdData, 0, sizeof(sChangePasswdData));
+
+        ret = decode_ChangePasswdData(out_data->data,out_data->length,&sChangePasswdData,&len2);
+    	if (ret) {
+	    krb5_warn (context, ret, "decode_ChangePasswdData");
+	    reply_error (server, s, sa, sa_size, ret, 3, "Bad Request RFC3244");
+	    goto out;
+        }
+	krb5_data_free(out_data); 
+
+	/* Now put back password to out_data */
+	ret = krb5_data_copy (out_data,
+			sChangePasswdData.newpasswd.data,
+			sChangePasswdData.newpasswd.length);
+    	if (ret) {
+	    krb5_warn (context, ret, "krb5_data_copy");
+	    reply_error (server, s, sa, sa_size, ret, 3, "Bad Request RFC3244");
+	    goto out1;
+        }
+	
+	/* targetPrincipal is not the ticket owner, is the targname in the */
+	/* KRB_PRIV message */
+	principalname2krb5_principal(targetPrincipal,
+				     *sChangePasswdData.targname,
+				     *sChangePasswdData.targrealm);
+
+	free_ChangePasswdData (&sChangePasswdData);
+    }
+    else{
+    	/* This is the owner of the ticket*/
+        *targetPrincipal=(*ticket)->client;
+    }
     return 0;
+
+out1: 
+    krb5_data_free(out_data);
+
 out:
     krb5_free_ticket (context, *ticket);
     return 1;
@@ -361,7 +451,8 @@
     krb5_data out_data;
     krb5_ticket *ticket;
     krb5_address other_addr;
-
+    krb5_principal targetPrincipal;
+    
     krb5_data_zero (&out_data);
 
     ret = krb5_auth_con_init (context, &auth_context);
@@ -389,13 +480,14 @@
 	goto out;
     }
 
-    if (verify (&auth_context, server, keytab, &ticket, &out_data,
+    /* We need to know who is the target prioncipal to set the password */
+    /* So add a new parameter to verify */
+    /* this is targetPrincipal */
+    if (verify (&auth_context, server, &targetPrincipal, keytab, &ticket, &out_data,
 		s, sa, sa_size, msg, len) == 0) {
-	change (auth_context,
-		ticket->client,
-		s,
-		sa, sa_size,
-		&out_data);
+		
+	change (auth_context, targetPrincipal, s, sa, sa_size, &out_data);
+
 	memset (out_data.data, 0, out_data.length);
 	krb5_free_ticket (context, ticket);
 	free (ticket);
@@ -610,3 +702,4 @@
 
     return doit (keytab, port);
 }
+
diff -Naur heimdal-0.6/lib/asn1/k5.asn1 heimdal-0.6-setpasswd/lib/asn1/k5.asn1
--- heimdal-0.6/lib/asn1/k5.asn1	2003-01-14 21:13:47.000000000 -0600
+++ heimdal-0.6-setpasswd/lib/asn1/k5.asn1	2003-06-09 18:45:48.000000000 -0500
@@ -440,6 +440,12 @@
 	e-data[12]		OCTET STRING OPTIONAL
 }
 
+ChangePasswdData  ::= SEQUENCE {
+                                newpasswd[0]    OCTET STRING,
+                                targname[1]     PrincipalName OPTIONAL,
+                                targrealm[2]    Realm OPTIONAL
+                                }
+
 pvno INTEGER ::= 5 -- current Kerberos protocol version number
 
 -- transited encodings
diff -Naur heimdal-0.6/lib/asn1/Makefile.am heimdal-0.6-setpasswd/lib/asn1/Makefile.am
--- heimdal-0.6/lib/asn1/Makefile.am	2003-05-12 10:20:44.000000000 -0500
+++ heimdal-0.6-setpasswd/lib/asn1/Makefile.am	2003-06-09 18:46:40.000000000 -0500
@@ -23,6 +23,7 @@
 	asn1_Authenticator.x			\
 	asn1_AuthorizationData.x		\
 	asn1_CKSUMTYPE.x			\
+	asn1_ChangePasswdData.x			\
 	asn1_Checksum.x				\
 	asn1_ENCTYPE.x				\
 	asn1_ETYPE_INFO.x			\