head	1.5;
access;
symbols
	RELEASE_4_3_0:1.4
	RELEASE_4_2_0:1.3;
locks; strict;
comment	@# @;


1.5
date	2001.07.24.17.14.44;	author nectar;	state dead;
branches;
next	1.4;

1.4
date	2001.01.24.20.36.33;	author nectar;	state Exp;
branches;
next	1.3;

1.3
date	2000.11.06.20.00.02;	author nectar;	state Exp;
branches;
next	1.2;

1.2
date	2000.11.06.19.56.21;	author nectar;	state Exp;
branches;
next	1.1;

1.1
date	2000.11.06.19.01.43;	author nectar;	state Exp;
branches;
next	;


desc
@@


1.5
log
@Update pam_krb5 1.0 -> 1.0.1.
Change MASTER_SITES.

NB: This  versioning is  bogus.  Unfortunately,  there is  no official
release of  pam_krb5 yet,  but it has  substantially changed.   I made
this release based on what is in CVS.
@
text
@--- support.c.orig	Tue Jan  4 19:08:51 2000
+++ support.c	Wed Jan 24 13:37:28 2001
@@@@ -6,11 +6,15 @@@@
 
 static const char rcsid[] = "$Id: support.c,v 1.8 2000/01/04 09:50:03 fcusack Exp $";
 
+#include <errno.h>
 #include <stdio.h>	/* BUFSIZ */
+#include <stdlib.h>	/* malloc */
+#include <string.h>	/* strncpy */
 #include <syslog.h>	/* syslog */
 #include <security/pam_appl.h>
 #include <security/pam_modules.h>
 #include <krb5.h>
+#include <com_err.h>
 #include "pam_krb5.h"
 
 /*
@@@@ -22,11 +26,12 @@@@
 get_user_info(pam_handle_t *pamh, char *prompt, int type, char **response)
 {
     int pamret;
-    struct pam_message	msg, *pmsg;
+    struct pam_message	msg;
+    const struct pam_message *pmsg;
     struct pam_response	*resp = NULL;
     struct pam_conv	*conv;
 
-    if (pamret = pam_get_item(pamh, PAM_CONV, (void **) &conv))
+    if ((pamret = pam_get_item(pamh, PAM_CONV, (const void **) &conv)) != 0)
 	return pamret;
 
     /* set up conversation call */
@@@@ -34,7 +39,7 @@@@
     msg.msg_style = type;
     msg.msg = prompt;
 
-    if (pamret = conv->conv(1, &pmsg, &resp, conv->appdata_ptr))
+    if ((pamret = conv->conv(1, &pmsg, &resp, conv->appdata_ptr)) != 0)
 	return pamret;
 
     /* Caller should ignore errors for non-response conversations */
@@@@ -51,172 +56,71 @@@@
     return pamret;
 }
 
-
-krb5_error_code
-pam_prompter(krb5_context context, void *data, const char *name,
-	     const char *banner, int num_prompts, krb5_prompt prompts[])
-{
-    int		pam_prompts = num_prompts;
-    int		pamret, i;
-
-    struct pam_message	*msg;
-    struct pam_response	*resp = NULL;
-    struct pam_conv	*conv;
-    pam_handle_t	*pamh = (pam_handle_t *) data;
-
-    if (pamret = pam_get_item(pamh, PAM_CONV, (void **) &conv))
-	return KRB5KRB_ERR_GENERIC;
-
-    if (name)
-	pam_prompts++;
-
-    if (banner)
-	pam_prompts++;
-
-    msg = calloc(sizeof(struct pam_message) * pam_prompts, 1);
-    if (!msg)
-	return ENOMEM;
-
-    /* Now use pam_prompts as an index */
-    pam_prompts = 0;
-
-    /* Sigh. malloc all the prompts. */
-    if (name) {
-	msg[pam_prompts].msg = malloc(strlen(name) + 1);
-	if (!msg[pam_prompts].msg)
-	    goto cleanup;
-	strcpy(msg[pam_prompts].msg, name);
-	msg[pam_prompts].msg_style = PAM_TEXT_INFO;
-	pam_prompts++;
-    }
-
-    if (banner) {
-	msg[pam_prompts].msg = malloc(strlen(banner) + 1);
-	if (!msg[pam_prompts].msg)
-	    goto cleanup;
-	strcpy(msg[pam_prompts].msg, banner);
-	msg[pam_prompts].msg_style = PAM_TEXT_INFO;
-	pam_prompts++;
-    }
-
-    for (i = 0; i < num_prompts; i++) {
-	msg[pam_prompts].msg = malloc(strlen(prompts[i].prompt) + 3);
-	if (!msg[pam_prompts].msg)
-	    goto cleanup;
-	sprintf(msg[pam_prompts].msg, "%s: ", prompts[i].prompt);
-	msg[pam_prompts].msg_style = prompts[i].hidden ? PAM_PROMPT_ECHO_OFF
-						       : PAM_PROMPT_ECHO_ON;
-	pam_prompts++;
-    }
-
-    if (pamret = conv->conv(pam_prompts, &msg, &resp, conv->appdata_ptr))
-	goto cleanup;
-
-    if (!resp)
-	goto cleanup;
-
-    /* Reuse pam_prompts as a starting index */
-    pam_prompts = 0;
-    if (name)
-	pam_prompts++;
-    if (banner)
-	pam_prompts++;
-
-    for (i = 0; i < num_prompts; i++, pam_prompts++) {
-	register int len;
-	if (!resp[pam_prompts].resp) {
-	    pamret = PAM_AUTH_ERR;
-	    goto cleanup;
-	}
-	len = strlen(resp[pam_prompts].resp); /* Help out the compiler */
-	if (len > prompts[i].reply->length) {
-	    pamret = PAM_AUTH_ERR;
-	    goto cleanup;
-	}
-	memcpy(prompts[i].reply->data, resp[pam_prompts].resp, len);
-	prompts[i].reply->length = len;
-    }
-
-cleanup:
-    /* pam_prompts is correct at this point */
-
-    for (i = 0; i < pam_prompts; i++) {
-	if (msg[i].msg)
-	    free(msg[i].msg);
-    }
-    free(msg);
-
-    if (resp) {
-	for (i = 0; i < pam_prompts; i++) {
-	    /*
-	     * Note that PAM is underspecified wrt free()'ing resp[i].resp.
-	     * It's not clear if I should free it, or if the application
-	     * has to. Therefore most (all?) apps won't free() it, and I
-	     * can't either, as I am not sure it was malloc()'d. All PAM
-	     * implementations I've seen leak memory here. Not so bad, IFF
-	     * you fork/exec for each PAM authentication (as is typical).
-	     */
-#if 0
-	    if (resp[i].resp)
-		free(resp[i].resp);
-#endif /* 0 */
-	}
-	/* This does not lose resp[i].resp if the application saved a copy. */
-	free(resp);
-    }
-
-    return (pamret ? KRB5KRB_ERR_GENERIC : 0);
-}
-
-
 /*
  * This routine with some modification is from the MIT V5B6 appl/bsd/login.c
+ * Modified by Sam Hartman <hartmans@@mit.edu> to support PAM services
+ * for Debian.
  *
  * Verify the Kerberos ticket-granting ticket just retrieved for the
  * user.  If the Kerberos server doesn't respond, assume the user is
  * trying to fake us out (since we DID just get a TGT from what is
  * supposedly our KDC).  If the host/<host> service is unknown (i.e.,
- * the local keytab doesn't have it), let her in.
+ * the local keytab doesn't have it), and we cannot find another
+ * service we do have, let her in.
  *
  * Returns 1 for confirmation, -1 for failure, 0 for uncertainty.
  */
 int
-verify_krb_v5_tgt(krb5_context context, krb5_ccache ccache, int debug)
+verify_krb_v5_tgt(krb5_context context, krb5_ccache ccache,
+		  char * pam_service, int debug)
 {
     char		phost[BUFSIZ];
-    krb5_error_code	retval;
+    char *services [3];
+    char **service;
+    krb5_error_code	retval = -1;
     krb5_principal	princ;
     krb5_keyblock *	keyblock = 0;
     krb5_data		packet;
     krb5_auth_context	auth_context = NULL;
-    krb5_keytab		keytab = NULL;
-    char *		kt_name = NULL;
 
     packet.data = 0;
 
     /*
-     * Get the server principal for the local host.
-     * (Use defaults of "host" and canonicalized local name.)
-     */
-    if (retval = krb5_sname_to_principal(context, NULL, NULL,
-					 KRB5_NT_SRV_HST, &princ)) {
+    * If possible we want to try and verify the ticket we have
+    * received against a keytab.  We will try multiple service
+    * principals, including at least the host principal and the PAM
+    * service principal.  The host principal is preferred because access
+    * to that key is generally sufficient to compromise root, while the
+    *     service key for this PAM service may be less carefully guarded.
+    * It is important to check the keytab first before the KDC so we do
+    * not get spoofed by a fake  KDC.*/
+    services [0] = "host";
+    services [1] = pam_service;
+    services [2] = NULL;
+    for ( service = &services[0]; *service != NULL; service++ ) {
+      if ((retval = krb5_sname_to_principal(context, NULL, *service, KRB5_NT_SRV_HST,
+					    &princ)) != 0) {
 	if (debug)
-	    syslog(LOG_DEBUG, "pam_krb5: verify_krb_v5_tgt(): %s: %s",
-		   "krb5_sname_to_principal()", error_message(retval));
+	  syslog(LOG_DEBUG, "pam_krb5: verify_krb_v5_tgt(): %s: %s",
+		 "krb5_sname_to_principal()", error_message(retval));
 	return -1;
-    }
+      }
 
-    /* Extract the name directly. */
-    strncpy(phost, krb5_princ_component(c, princ, 1)->data, BUFSIZ);
-    phost[BUFSIZ - 1] = '\0';
-
-    /*
-     * Do we have host/<host> keys?
-     * (use default/configured keytab, kvno IGNORE_VNO to get the
-     * first match, and enctype is currently ignored anyhow.)
-     */
-    if (retval = krb5_kt_read_service_key(context, NULL, princ, 0,
-					  ENCTYPE_DES_CBC_MD5, &keyblock)) {
+      /* Extract the name directly. */
+      strncpy(phost, compat_princ_component(context, princ, 1), BUFSIZ);
+      phost[BUFSIZ - 1] = '\0';
+
+      /*
+       * Do we have service/<host> keys?
+       * (use default/configured keytab, kvno IGNORE_VNO to get the
+       * first match, and ignore enctype.)
+       */
+      if ((retval = krb5_kt_read_service_key(context, NULL, princ, 0,
+					     0, &keyblock)) != 0)
+	continue;
+      break;
+    }
+    if (retval != 0 ) {		/* failed to find key */
 	/* Keytab or service key does not exist */
 	if (debug)
 	    syslog(LOG_DEBUG, "pam_krb5: verify_krb_v5_tgt(): %s: %s",
@@@@ -228,7 +132,7 @@@@
 	krb5_free_keyblock(context, keyblock);
 
     /* Talk to the kdc and construct the ticket. */
-    retval = krb5_mk_req(context, &auth_context, 0, "host", phost,
+    retval = krb5_mk_req(context, &auth_context, 0, *service, phost,
 			 NULL, ccache, &packet);
     if (auth_context) {
 	krb5_auth_con_free(context, auth_context);
@@@@ -256,7 +160,7 @@@@
 
 cleanup:
     if (packet.data)
-	krb5_free_data_contents(context, &packet);
+	compat_free_data_contents(context, &packet);
     krb5_free_principal(context, princ);
     return retval;
 
@


1.4
log
@Bug fixes and paranoia:

compat_heimdal.c:
   = Stop shooting at feet when freeing a particular chunk of memory.
     Found by complaints from free(), and pinpointed with MALLOC_OPTIONS=A.
pam_krb5_auth.c:
   = In addition to dropping and restoring uid when delving in /tmp,
     drop and restore gid.
   = Explicitly set permissions on the credentials cache for good measure.

The following was
Obtained from:	Sam Hartman <hartmans@@mit.edu> via bugs.debian.org

support.c:
   = verify_krb_v5_tgt: Do a little more to prevent KDC spoofing.
     Allow for a key separate from the host key to use only for PAM.
@
text
@@


1.3
log
@(forced commit)

Double oops.  I initially added a version of this port that was a bit
dated.  The last commit brings it up to date: in particular, MIT Kerberos
support was broken in theory (though not in practice).
@
text
@d2 1
a2 1
+++ support.c	Mon Nov  6 13:36:39 2000
d43 1
a43 1
@@@@ -51,124 +56,6 @@@@
d167 2
d170 21
a190 1
@@@@ -189,8 +76,6 @@@@
d199 4
a202 4
@@@@ -198,8 +83,8 @@@@
      * Get the server principal for the local host.
      * (Use defaults of "host" and canonicalized local name.)
      */
d205 14
a218 2
+    if ((retval = krb5_sname_to_principal(context, NULL, NULL, KRB5_NT_SRV_HST,
+      &princ)) != 0) {
d220 7
a226 4
 	    syslog(LOG_DEBUG, "pam_krb5: verify_krb_v5_tgt(): %s: %s",
 		   "krb5_sname_to_principal()", error_message(retval));
@@@@ -207,7 +92,7 @@@@
     }
d228 1
a228 1
     /* Extract the name directly. */
d230 7
a236 8
+    strncpy(phost, compat_princ_component(context, princ, 1), BUFSIZ);
     phost[BUFSIZ - 1] = '\0';
 
     /*
@@@@ -215,8 +100,8 @@@@
      * (use default/configured keytab, kvno IGNORE_VNO to get the
      * first match, and enctype is currently ignored anyhow.)
      */
d239 15
a253 2
+    if ((retval = krb5_kt_read_service_key(context, NULL, princ, 0,
+      ENCTYPE_DES_CBC_MD5, &keyblock)) != 0) {
d257 10
a266 1
@@@@ -256,7 +141,7 @@@@
@


1.2
log
@Oops,
@
text
@@


1.1
log
@A Pluggable Authentication Module for Kerberos 5.
@
text
@d2 2
a3 2
+++ support.c	Mon Nov  6 11:55:47 2000
@@@@ -6,12 +6,17 @@@@
a16 1
+#include "krb5compat.h"
d19 1
a19 2
  * Get info from the user. Disallow null responses (regardless of flags).
@@@@ -22,11 +27,12 @@@@
d34 1
a34 1
@@@@ -34,7 +40,7 @@@@
d43 3
a45 1
@@@@ -53,8 +59,8 @@@@
d47 2
a48 2
 
 krb5_error_code
d51 9
a59 9
+pam_prompter(krb5_context context, void *data, const char *banner, int 
+  num_prompts, krb5_prompt prompts[])
 {
     int		pam_prompts = num_prompts;
     int		pamret, i;
@@@@ -64,12 +70,9 @@@@
     struct pam_conv	*conv;
     pam_handle_t	*pamh = (pam_handle_t *) data;
 
d61 2
a62 3
+    if ((pamret = pam_get_item(pamh, PAM_CONV, (const void **) &conv)) != 0)
 	return KRB5KRB_ERR_GENERIC;
 
d66 10
a75 7
     if (banner)
 	pam_prompts++;
 
@@@@ -80,21 +83,11 @@@@
     /* Now use pam_prompts as an index */
     pam_prompts = 0;
 
d86 4
a89 4
     if (banner) {
 	msg[pam_prompts].msg = malloc(strlen(banner) + 1);
 	if (!msg[pam_prompts].msg)
 	    goto cleanup;
d91 8
a98 8
+	strcpy((char *) msg[pam_prompts].msg, banner);
 	msg[pam_prompts].msg_style = PAM_TEXT_INFO;
 	pam_prompts++;
     }
@@@@ -103,13 +96,14 @@@@
 	msg[pam_prompts].msg = malloc(strlen(prompts[i].prompt) + 3);
 	if (!msg[pam_prompts].msg)
 	    goto cleanup;
d100 5
a104 6
+	sprintf((char *) msg[pam_prompts].msg, "%s: ", prompts[i].prompt);
 	msg[pam_prompts].msg_style = prompts[i].hidden ? PAM_PROMPT_ECHO_OFF
 						       : PAM_PROMPT_ECHO_ON;
 	pam_prompts++;
     }
 
d106 7
a112 9
+    if ((pamret = conv->conv(pam_prompts, (const struct pam_message **) &msg, 
+      &resp, conv->appdata_ptr)) != 0) 
 	goto cleanup;
 
     if (!resp)
@@@@ -117,8 +111,6 @@@@
 
     /* Reuse pam_prompts as a starting index */
     pam_prompts = 0;
d115 23
a137 7
     if (banner)
 	pam_prompts++;
 
@@@@ -142,7 +134,7 @@@@
 
     for (i = 0; i < pam_prompts; i++) {
 	if (msg[i].msg)
d139 30
a168 5
+	    free((char *) msg[i].msg);
     }
     free(msg);
 
@@@@ -189,8 +181,6 @@@@
d177 1
a177 1
@@@@ -198,8 +188,8 @@@@
d188 1
a188 1
@@@@ -207,7 +197,7 @@@@
d197 1
a197 1
@@@@ -215,8 +205,8 @@@@
d208 1
a208 1
@@@@ -256,7 +246,7 @@@@
@

