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

Re: redhat kerberos PAM



>>>>> "Brian" == Brian May <bam@snoopy.apana.org.au> writes:

    Joel> I've managed to make Franck Cusack's PAM module work with
    Joel> heimdal with only a small patch. You can find the module on
    Joel> http://www.fcusack.com/ and my patch on
    Joel> http://ns1.logidee.com/~joko/heimdal/

I was playing around with this, but haven't been able to get it to work -
the real killer was this:

Nov  9 12:17:00 snoopy sshd[32542]: PAM unable to dlopen(/lib/security/pam_krb5.so)
Nov  9 12:17:00 snoopy sshd[32542]: PAM [dlerror: /usr/lib/libroken.so.9: undefined symbol: res_search]
Nov  9 12:17:00 snoopy sshd[32542]: PAM adding faulty module: /lib/security/pam_krb5.so

So, now I am attempting to solve all the warnings. One seems a real
problem:

[902] [snoopy:bam] ~/source/notmine/pam-krb5-1.0/build >make pam_krb5_pass.o
gcc -c -O2 -fPIC -Wall -I/opt/local/include pam_krb5_pass.c
pam_krb5_pass.c: In function `pam_sm_chauthtok':
pam_krb5_pass.c:72: warning: implicit declaration of function `error_message'
pam_krb5_pass.c:131: warning: passing arg 5 of `krb5_get_init_creds_password' from incompatible pointer type

This is because it defined pam_prompter as:

krb5_error_code
pam_prompter(krb5_context context, void *data, const char *name,
             const char *banner, int num_prompts, krb5_prompt prompts[])

but Heimdal expects:

typedef int (*krb5_prompter_fct)(krb5_context context,
                                 void *data,
                                 const char *banner,
                                 int num_prompts,
                                 krb5_prompt prompts[]);

ie. no name parameter.


Not sure where error_message is defined, no can I see any reference to
res_search (this probably means I am missing a library).

I have also found a number of instances where krbret is used but not
defined.

Attached are my current changes and the compiler output (includes
warnings I haven't yet been able to fix). Some of these warnings I
don't understand (eg. "discards qualifiers"). Apply my patch *AFTER* the
patch mentioned above.

diff -c build.old/Makefile build/Makefile
*** build.old/Makefile	Thu Nov  9 15:18:08 2000
--- build/Makefile	Thu Nov  9 15:42:15 2000
***************
*** 3,10 ****
  #
  
  CC = gcc
! CFLAGS = -O2 -fPIC
! LDFLAGS = -shared -Xlinker -x
  #LDFLAGS = -G
  
  DESTDIR = /usr/lib/security
--- 3,10 ----
  #
  
  CC = gcc
! CFLAGS = -O2 -fPIC -Wall
! LDFLAGS = -shared -Xlinker -x -Wall
  #LDFLAGS = -G
  
  DESTDIR = /usr/lib/security
diff -c build.old/pam_krb5_acct.c build/pam_krb5_acct.c
*** build.old/pam_krb5_acct.c	Thu Nov  9 15:17:16 2000
--- build/pam_krb5_acct.c	Thu Nov  9 15:49:45 2000
***************
*** 38,49 ****
      }
  
      /* Get username */
!     if (pam_get_item(pamh, PAM_USER, (void **) &name)) {
  	return PAM_PERM_DENIED;;
      }
  
      /* Get service name */
!     (void) pam_get_item(pamh, PAM_SERVICE, (void **) &service);
      if (!service)
  	service = "unknown";
  
--- 38,49 ----
      }
  
      /* Get username */
!     if (pam_get_item(pamh, PAM_USER, (const void **) &name)) {
  	return PAM_PERM_DENIED;;
      }
  
      /* Get service name */
!     (void) pam_get_item(pamh, PAM_SERVICE, (const void **) &service);
      if (!service)
  	service = "unknown";
  
***************
*** 55,66 ****
  	return PAM_SUCCESS;
      }
  
!     if (krb5_init_context(&pam_context)) {
  	DLOG("krb5_init_context()", error_message(krbret));
  	return PAM_PERM_DENIED;;
      }
  
!     if (krbret = krb5_cc_get_principal(pam_context, ccache, &princ)) {
  	DLOG("krb5_cc_get_principal()", error_message(krbret));
  	pamret = PAM_PERM_DENIED;;
  	goto cleanup;
--- 55,66 ----
  	return PAM_SUCCESS;
      }
  
!     if ((krbret = krb5_init_context(&pam_context))) {
  	DLOG("krb5_init_context()", error_message(krbret));
  	return PAM_PERM_DENIED;;
      }
  
!     if ((krbret = krb5_cc_get_principal(pam_context, ccache, &princ))) {
  	DLOG("krb5_cc_get_principal()", error_message(krbret));
  	pamret = PAM_PERM_DENIED;;
  	goto cleanup;
diff -c build.old/pam_krb5_auth.c build/pam_krb5_auth.c
*** build.old/pam_krb5_auth.c	Thu Nov  9 15:18:08 2000
--- build/pam_krb5_auth.c	Thu Nov  9 16:06:42 2000
***************
*** 20,25 ****
--- 20,27 ----
  #include <security/pam_modules.h>
  
  #include <krb5.h>
+ #include <malloc.h>
+ #include <string.h>
  #include "pam_krb5.h"
  
  extern krb5_cc_ops krb5_mcc_ops;
***************
*** 43,49 ****
      krb5_get_init_creds_opt opts;
  
      int			pamret, i;
!     char		*name, *name2;
      char		*princ_name = NULL;
      char		*pass = NULL, *service = NULL;
      char		*prompt = NULL;
--- 45,51 ----
      krb5_get_init_creds_opt opts;
  
      int			pamret, i;
!     char		*name;
      char		*princ_name = NULL;
      char		*pass = NULL, *service = NULL;
      char		*prompt = NULL;
***************
*** 75,87 ****
      }
  
      /* Get service name */
!     (void) pam_get_item(pamh, PAM_SERVICE, (void **) &service);
      if (!service)
  	service = "unknown";
  
      DLOG("entry", "");
  
!     if (krb5_init_context(&pam_context)) {
  	DLOG("krb5_init_context()", error_message(krbret));
  	return PAM_SERVICE_ERR;
      }
--- 77,89 ----
      }
  
      /* Get service name */
!     (void) pam_get_item(pamh, PAM_SERVICE, (const void **) &service);
      if (!service)
  	service = "unknown";
  
      DLOG("entry", "");
  
!     if ((krbret = krb5_init_context(&pam_context))) {
  	DLOG("krb5_init_context()", error_message(krbret));
  	return PAM_SERVICE_ERR;
      }
***************
*** 94,100 ****
  	krb5_get_init_creds_opt_set_forwardable(&opts, 1);
  
      /* For CNS */
!     if (krbret = krb5_cc_register(pam_context, &krb5_mcc_ops, FALSE)) {
  	/* Solaris dtlogin doesn't call pam_end() on failure */
  	if (krbret != KRB5_CC_TYPE_EXISTS) {
  	    DLOG("krb5_cc_register()", error_message(krbret));
--- 96,102 ----
  	krb5_get_init_creds_opt_set_forwardable(&opts, 1);
  
      /* For CNS */
!     if ((krbret = krb5_cc_register(pam_context, &krb5_mcc_ops, FALSE))) {
  	/* Solaris dtlogin doesn't call pam_end() on failure */
  	if (krbret != KRB5_CC_TYPE_EXISTS) {
  	    DLOG("krb5_cc_register()", error_message(krbret));
***************
*** 104,117 ****
      }
  
      /* Get principal name */
!     if (krbret = krb5_parse_name(pam_context, name, &princ)) {
  	DLOG("krb5_parse_name()", error_message(krbret));
  	pamret = PAM_SERVICE_ERR;
  	goto cleanup3;
      }
  
      /* Now convert the principal name into something human readable */
!     if (krbret = krb5_unparse_name(pam_context, princ, &princ_name)) {
  	DLOG("krb5_unparse_name()", error_message(krbret));
  	pamret = PAM_SERVICE_ERR;
  	goto cleanup2;
--- 106,119 ----
      }
  
      /* Get principal name */
!     if ((krbret = krb5_parse_name(pam_context, name, &princ))) {
  	DLOG("krb5_parse_name()", error_message(krbret));
  	pamret = PAM_SERVICE_ERR;
  	goto cleanup3;
      }
  
      /* Now convert the principal name into something human readable */
!     if ((krbret = krb5_unparse_name(pam_context, princ, &princ_name))) {
  	DLOG("krb5_unparse_name()", error_message(krbret));
  	pamret = PAM_SERVICE_ERR;
  	goto cleanup2;
***************
*** 127,144 ****
      (void) sprintf(prompt, "Password for %s: ", princ_name);
  
      if (try_first_pass || use_first_pass)
! 	(void) pam_get_item(pamh, PAM_AUTHTOK, (void **) &pass);
  
  get_pass:
      if (!pass) {
  	try_first_pass = 0;
! 	if (pamret = get_user_info(pamh, prompt, PAM_PROMPT_ECHO_OFF, &pass)) {
  	    DLOG("get_user_info()", pam_strerror(pamh, pamret));
  	    pamret = PAM_SERVICE_ERR;
  	    goto cleanup2;
  	}
  	/* We have to free pass. */
! 	if (pamret = pam_set_item(pamh, PAM_AUTHTOK, pass)) {
  	    DLOG("pam_set_item()", pam_strerror(pamh, pamret));
  	    free(pass);
  	    pamret = PAM_SERVICE_ERR;
--- 129,146 ----
      (void) sprintf(prompt, "Password for %s: ", princ_name);
  
      if (try_first_pass || use_first_pass)
! 	(void) pam_get_item(pamh, PAM_AUTHTOK, (const void **) &pass);
  
  get_pass:
      if (!pass) {
  	try_first_pass = 0;
! 	if ((pamret = get_user_info(pamh, prompt, PAM_PROMPT_ECHO_OFF, &pass))) {
  	    DLOG("get_user_info()", pam_strerror(pamh, pamret));
  	    pamret = PAM_SERVICE_ERR;
  	    goto cleanup2;
  	}
  	/* We have to free pass. */
! 	if ((pamret = pam_set_item(pamh, PAM_AUTHTOK, pass))) {
  	    DLOG("pam_set_item()", pam_strerror(pamh, pamret));
  	    free(pass);
  	    pamret = PAM_SERVICE_ERR;
***************
*** 146,170 ****
  	}
  	free(pass);
  	/* Now we get it back from the library. */
! 	(void) pam_get_item(pamh, PAM_AUTHTOK, (void **) &pass);
      }
  
      /* Verify the local user exists (AFTER getting the password) */
      if (strchr(name, '@')) {
  	/* get a local account name for this principal */
! 	if (krbret = krb5_aname_to_localname(pam_context, princ,
! 					     sizeof(lname), lname)) {
  	    DLOG("krb5_aname_to_localname()", error_message(krbret));
  	    pamret = PAM_USER_UNKNOWN;
  	    goto cleanup2;
  	}
  	DLOG("changing PAM_USER to", lname);
! 	if (pamret = pam_set_item(pamh, PAM_USER, lname)) {
  	    DLOG("pam_set_item()", pam_strerror(pamh, pamret));
  	    pamret = PAM_SERVICE_ERR;
  	    goto cleanup2;
  	}
! 	if (pamret = pam_get_item(pamh, PAM_USER, (void **) &name)) {
  	    DLOG("pam_get_item()", pam_strerror(pamh, pamret));
  	    pamret = PAM_SERVICE_ERR;
  	    goto cleanup2;
--- 148,172 ----
  	}
  	free(pass);
  	/* Now we get it back from the library. */
! 	(void) pam_get_item(pamh, PAM_AUTHTOK, (const void **) &pass);
      }
  
      /* Verify the local user exists (AFTER getting the password) */
      if (strchr(name, '@')) {
  	/* get a local account name for this principal */
! 	if ((krbret = krb5_aname_to_localname(pam_context, princ,
! 					     sizeof(lname), lname))) {
  	    DLOG("krb5_aname_to_localname()", error_message(krbret));
  	    pamret = PAM_USER_UNKNOWN;
  	    goto cleanup2;
  	}
  	DLOG("changing PAM_USER to", lname);
! 	if ((pamret = pam_set_item(pamh, PAM_USER, lname))) {
  	    DLOG("pam_set_item()", pam_strerror(pamh, pamret));
  	    pamret = PAM_SERVICE_ERR;
  	    goto cleanup2;
  	}
! 	if ((pamret = pam_get_item(pamh, PAM_USER, (const void **) &name))) {
  	    DLOG("pam_get_item()", pam_strerror(pamh, pamret));
  	    pamret = PAM_SERVICE_ERR;
  	    goto cleanup2;
***************
*** 178,186 ****
      }
  
      /* Get a TGT */
!     if (krbret = krb5_get_init_creds_password(pam_context, &creds, princ,
  					      pass, pam_prompter, pamh,
! 					      0, NULL, &opts)) {
  	DLOG("krb5_get_init_creds_password()", error_message(krbret));
  	if (try_first_pass && krbret == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
  	    pass = NULL;
--- 180,188 ----
      }
  
      /* Get a TGT */
!     if ((krbret = krb5_get_init_creds_password(pam_context, &creds, princ,
  					      pass, pam_prompter, pamh,
! 					      0, NULL, &opts))) {
  	DLOG("krb5_get_init_creds_password()", error_message(krbret));
  	if (try_first_pass && krbret == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
  	    pass = NULL;
***************
*** 194,210 ****
      strcpy(cache_name, "MEMORY:");
      (void) tmpnam(&cache_name[7]);
  
!     if (krbret = krb5_cc_resolve(pam_context, cache_name, &ccache)) {
  	DLOG("krb5_cc_resolve()", error_message(krbret));
  	pamret = PAM_SERVICE_ERR;
  	goto cleanup;
      }
!     if (krbret = krb5_cc_initialize(pam_context, ccache, princ)) {
  	DLOG("krb5_cc_initialize()", error_message(krbret));
  	pamret = PAM_SERVICE_ERR;
   	goto cleanup;
      }
!     if (krbret = krb5_cc_store_cred(pam_context, ccache, &creds)) {
  	DLOG("krb5_cc_store_cred()", error_message(krbret));
  	(void) krb5_cc_destroy(pam_context, ccache);
  	pamret = PAM_SERVICE_ERR;
--- 196,212 ----
      strcpy(cache_name, "MEMORY:");
      (void) tmpnam(&cache_name[7]);
  
!     if ((krbret = krb5_cc_resolve(pam_context, cache_name, &ccache))) {
  	DLOG("krb5_cc_resolve()", error_message(krbret));
  	pamret = PAM_SERVICE_ERR;
  	goto cleanup;
      }
!     if ((krbret = krb5_cc_initialize(pam_context, ccache, princ))) {
  	DLOG("krb5_cc_initialize()", error_message(krbret));
  	pamret = PAM_SERVICE_ERR;
   	goto cleanup;
      }
!     if ((krbret = krb5_cc_store_cred(pam_context, ccache, &creds))) {
  	DLOG("krb5_cc_store_cred()", error_message(krbret));
  	(void) krb5_cc_destroy(pam_context, ccache);
  	pamret = PAM_SERVICE_ERR;
***************
*** 212,218 ****
      }
  
      /* Verify it */
!     if (verify_krb_v5_tgt(pam_context, ccache, debug) == -1) {
  	(void) krb5_cc_destroy(pam_context, ccache);
  	pamret = PAM_AUTH_ERR;
  	goto cleanup;
--- 214,220 ----
      }
  
      /* Verify it */
!     if ((verify_krb_v5_tgt(pam_context, ccache, debug) == -1)) {
  	(void) krb5_cc_destroy(pam_context, ccache);
  	pamret = PAM_AUTH_ERR;
  	goto cleanup;
***************
*** 225,231 ****
  	pamret = PAM_AUTH_ERR;
  	goto cleanup;
      }
!     if (pamret = pam_set_data(pamh, "ccache", ccache, cleanup_cache)) {
  	DLOG("pam_set_data()", pam_strerror(pamh, pamret));
  	(void) krb5_cc_destroy(pam_context, ccache);
  	pamret = PAM_SERVICE_ERR;
--- 227,233 ----
  	pamret = PAM_AUTH_ERR;
  	goto cleanup;
      }
!     if ((pamret = pam_set_data(pamh, "ccache", ccache, cleanup_cache))) {
  	DLOG("pam_set_data()", pam_strerror(pamh, pamret));
  	(void) krb5_cc_destroy(pam_context, ccache);
  	pamret = PAM_SERVICE_ERR;
***************
*** 293,310 ****
      }
  
      /* Get username */
!     if (pam_get_item(pamh, PAM_USER, (void **) &name)) {
  	return PAM_SERVICE_ERR;
      }
  
      /* Get service name */
!     (void) pam_get_item(pamh, PAM_SERVICE, (void **) &service);
      if (!service)
  	service = "unknown";
  
      DLOG("entry", "");
  
!     if (krb5_init_context(&pam_context)) {
  	DLOG("krb5_init_context()", error_message(krbret));
  	return PAM_SERVICE_ERR;
      }
--- 295,312 ----
      }
  
      /* Get username */
!     if (pam_get_item(pamh, PAM_USER, (const void **) &name)) {
  	return PAM_SERVICE_ERR;
      }
  
      /* Get service name */
!     (void) pam_get_item(pamh, PAM_SERVICE, (const void **) &service);
      if (!service)
  	service = "unknown";
  
      DLOG("entry", "");
  
!     if ((krbret = krb5_init_context(&pam_context))) {
  	DLOG("krb5_init_context()", error_message(krbret));
  	return PAM_SERVICE_ERR;
      }
***************
*** 312,318 ****
      euid = geteuid(); /* Usually 0 */
  
      /* Retrieve the cache name */
!     if (pamret = pam_get_data(pamh, "ccache", (const void **) &ccache_temp)) {
  	DLOG("pam_get_data()", pam_strerror(pamh, pamret));
  	pamret = PAM_CRED_UNAVAIL;
  	goto cleanup3;
--- 314,320 ----
      euid = geteuid(); /* Usually 0 */
  
      /* Retrieve the cache name */
!     if ((pamret = pam_get_data(pamh, "ccache", (const void **) &ccache_temp))) {
  	DLOG("pam_get_data()", pam_strerror(pamh, pamret));
  	pamret = PAM_CRED_UNAVAIL;
  	goto cleanup3;
***************
*** 341,347 ****
  	    pamret = PAM_BUF_ERR;
  	    goto cleanup3;
  	}
! 	sprintf(cache_name, "FILE:/tmp/krb5cc_%ld", pw->pw_uid);
      } else {
  	/* cache_name was supplied */
  	char *p = calloc(PATH_MAX + 10, 1); /* should be plenty */
--- 343,349 ----
  	    pamret = PAM_BUF_ERR;
  	    goto cleanup3;
  	}
! 	sprintf(cache_name, "FILE:/tmp/krb5cc_%d", pw->pw_uid);
      } else {
  	/* cache_name was supplied */
  	char *p = calloc(PATH_MAX + 10, 1); /* should be plenty */
***************
*** 358,367 ****
  	    if (*q == '%') {
  		q++;
  		if (*q == 'u') {
! 		    sprintf(p, "%ld", pw->pw_uid);
  		    p += strlen(p);
  		} else if (*q == 'p') {
! 		    sprintf(p, "%ld", getpid());
  		    p += strlen(p);
  		} else {
  		    /* Not a special token */
--- 360,369 ----
  	    if (*q == '%') {
  		q++;
  		if (*q == 'u') {
! 		    sprintf(p, "%d", pw->pw_uid);
  		    p += strlen(p);
  		} else if (*q == 'p') {
! 		    sprintf(p, "%d", getpid());
  		    p += strlen(p);
  		} else {
  		    /* Not a special token */
***************
*** 376,399 ****
      }
  
      /* Initialize the new ccache */
!     if (krbret = krb5_cc_get_principal(pam_context, ccache_temp, &princ)) {
  	DLOG("krb5_cc_get_principal()", error_message(krbret));
  	pamret = PAM_SERVICE_ERR;
  	goto cleanup3;
      }
!     if (krbret = krb5_cc_resolve(pam_context, cache_name, &ccache_perm)) {
  	DLOG("krb5_cc_resolve()", error_message(krbret));
  	pamret = PAM_SERVICE_ERR;
  	goto cleanup2;
      }
!     if (krbret = krb5_cc_initialize(pam_context, ccache_perm, princ)) {
  	DLOG("krb5_cc_initialize()", error_message(krbret));
  	pamret = PAM_SERVICE_ERR;
   	goto cleanup2;
      }
  
      /* Prepare for iteration over creds */
!     if (krbret = krb5_cc_start_seq_get(pam_context, ccache_temp, &cursor)) {
  	DLOG("krb5_cc_start_seq_get()", error_message(krbret));
  	(void) krb5_cc_destroy(pam_context, ccache_perm);
  	pamret = PAM_SERVICE_ERR;
--- 378,401 ----
      }
  
      /* Initialize the new ccache */
!     if ((krbret = krb5_cc_get_principal(pam_context, ccache_temp, &princ))) {
  	DLOG("krb5_cc_get_principal()", error_message(krbret));
  	pamret = PAM_SERVICE_ERR;
  	goto cleanup3;
      }
!     if ((krbret = krb5_cc_resolve(pam_context, cache_name, &ccache_perm))) {
  	DLOG("krb5_cc_resolve()", error_message(krbret));
  	pamret = PAM_SERVICE_ERR;
  	goto cleanup2;
      }
!     if ((krbret = krb5_cc_initialize(pam_context, ccache_perm, princ))) {
  	DLOG("krb5_cc_initialize()", error_message(krbret));
  	pamret = PAM_SERVICE_ERR;
   	goto cleanup2;
      }
  
      /* Prepare for iteration over creds */
!     if ((krbret = krb5_cc_start_seq_get(pam_context, ccache_temp, &cursor))) {
  	DLOG("krb5_cc_start_seq_get()", error_message(krbret));
  	(void) krb5_cc_destroy(pam_context, ccache_perm);
  	pamret = PAM_SERVICE_ERR;
***************
*** 403,409 ****
      /* Copy the creds (should be two of them) */
      while ((krbret = krb5_cc_next_cred(pam_context, ccache_temp,
  				       &creds, &cursor) == 0)) {
! 	if (krbret = krb5_cc_store_cred(pam_context, ccache_perm, &creds)) {
  	    DLOG("krb5_cc_store_cred()", error_message(krbret));
  	    (void) krb5_cc_destroy(pam_context, ccache_perm);
  	    krb5_free_cred_contents(pam_context, &creds);
--- 405,411 ----
      /* Copy the creds (should be two of them) */
      while ((krbret = krb5_cc_next_cred(pam_context, ccache_temp,
  				       &creds, &cursor) == 0)) {
! 	if ((krbret = krb5_cc_store_cred(pam_context, ccache_perm, &creds))) {
  	    DLOG("krb5_cc_store_cred()", error_message(krbret));
  	    (void) krb5_cc_destroy(pam_context, ccache_perm);
  	    krb5_free_cred_contents(pam_context, &creds);
***************
*** 443,449 ****
      }
  
      sprintf(cache_env_name, "KRB5CCNAME=%s", cache_name);
!     if (pamret = pam_putenv(pamh, cache_env_name)) {
  	DLOG("pam_putenv()", pam_strerror(pamh, pamret));
  	(void) krb5_cc_destroy(pam_context, ccache_perm);
  	pamret = PAM_SERVICE_ERR;
--- 445,451 ----
      }
  
      sprintf(cache_env_name, "KRB5CCNAME=%s", cache_name);
!     if ((pamret = pam_putenv(pamh, cache_env_name))) {
  	DLOG("pam_putenv()", pam_strerror(pamh, pamret));
  	(void) krb5_cc_destroy(pam_context, ccache_perm);
  	pamret = PAM_SERVICE_ERR;
diff -c build.old/pam_krb5_pass.c build/pam_krb5_pass.c
*** build.old/pam_krb5_pass.c	Thu Nov  9 15:18:08 2000
--- build/pam_krb5_pass.c	Thu Nov  9 15:48:38 2000
***************
*** 11,16 ****
--- 11,18 ----
  #include <security/pam_appl.h>
  #include <security/pam_modules.h>
  #include <krb5.h>
+ #include <stdio.h>
+ #include <malloc.h>
  #include "pam_krb5.h"
  
  /* A useful logging macro */
***************
*** 27,33 ****
      krb5_context	pam_context;
      krb5_creds		creds;
      krb5_principal	princ;
-     krb5_ccache		ccache;
      krb5_get_init_creds_opt opts;
  
      int		result_code;
--- 29,34 ----
***************
*** 56,78 ****
      }
  
      /* Get username */
!     if (pam_get_item(pamh, PAM_USER, (void **) &name)) {
  	return PAM_SERVICE_ERR;
      }
  
      /* Get service name */
!     (void) pam_get_item(pamh, PAM_SERVICE, (void **) &service);
      if (!service)
  	service = "unknown";
  
      DLOG("entry", "");
  
!     if (krb5_init_context(&pam_context)) {
  	DLOG("krb5_init_context()", error_message(krbret));
  	return PAM_SERVICE_ERR;
      }
  
!     if (krb5_init_context(&pam_context)) {
  	DLOG("krb5_init_context()", error_message(krbret));
  	return PAM_SERVICE_ERR;
      }
--- 57,79 ----
      }
  
      /* Get username */
!     if (pam_get_item(pamh, PAM_USER, (const void **) &name)) {
  	return PAM_SERVICE_ERR;
      }
  
      /* Get service name */
!     (void) pam_get_item(pamh, PAM_SERVICE, (const void **) &service);
      if (!service)
  	service = "unknown";
  
      DLOG("entry", "");
  
!     if ((krbret = krb5_init_context(&pam_context))) {
  	DLOG("krb5_init_context()", error_message(krbret));
  	return PAM_SERVICE_ERR;
      }
  
!     if ((krbret = krb5_init_context(&pam_context))) {
  	DLOG("krb5_init_context()", error_message(krbret));
  	return PAM_SERVICE_ERR;
      }
***************
*** 80,93 ****
      memset(&creds, 0, sizeof(krb5_creds));
  
      /* Get principal name */
!     if (krbret = krb5_parse_name(pam_context, name, &princ)) {
  	DLOG("krb5_parse_name()", error_message(krbret));
  	pamret = PAM_USER_UNKNOWN;
  	goto cleanup3;
      }
  
      /* Now convert the principal name into something human readable */
!     if (krbret = krb5_unparse_name(pam_context, princ, &princ_name)) {
  	DLOG("krb5_unparse_name()", error_message(krbret));
  	pamret = PAM_SERVICE_ERR;
  	goto cleanup2;
--- 81,94 ----
      memset(&creds, 0, sizeof(krb5_creds));
  
      /* Get principal name */
!     if ((krbret = krb5_parse_name(pam_context, name, &princ))) {
  	DLOG("krb5_parse_name()", error_message(krbret));
  	pamret = PAM_USER_UNKNOWN;
  	goto cleanup3;
      }
  
      /* Now convert the principal name into something human readable */
!     if ((krbret = krb5_unparse_name(pam_context, princ, &princ_name))) {
  	DLOG("krb5_unparse_name()", error_message(krbret));
  	pamret = PAM_SERVICE_ERR;
  	goto cleanup2;
***************
*** 103,120 ****
      (void) sprintf(prompt, "Password for %s: ", princ_name);
  
      if (try_first_pass || use_first_pass)
! 	(void) pam_get_item(pamh, PAM_AUTHTOK, (void **) &pass);
  
  get_pass:
      if (!pass) {
  	try_first_pass = 0;
! 	if (pamret = get_user_info(pamh, prompt, PAM_PROMPT_ECHO_OFF, &pass)) {
  	    DLOG("get_user_info()", pam_strerror(pamh, pamret));
  	    pamret = PAM_SERVICE_ERR;
  	    goto cleanup2;
  	}
  	/* We have to free pass. */
! 	if (pamret = pam_set_item(pamh, PAM_AUTHTOK, pass)) {
  	    DLOG("pam_set_item()", pam_strerror(pamh, pamret));
  	    free(pass);
  	    pamret = PAM_SERVICE_ERR;
--- 104,121 ----
      (void) sprintf(prompt, "Password for %s: ", princ_name);
  
      if (try_first_pass || use_first_pass)
! 	(void) pam_get_item(pamh, PAM_AUTHTOK, (const void **) &pass);
  
  get_pass:
      if (!pass) {
  	try_first_pass = 0;
! 	if ((pamret = get_user_info(pamh, prompt, PAM_PROMPT_ECHO_OFF, &pass))) {
  	    DLOG("get_user_info()", pam_strerror(pamh, pamret));
  	    pamret = PAM_SERVICE_ERR;
  	    goto cleanup2;
  	}
  	/* We have to free pass. */
! 	if ((pamret = pam_set_item(pamh, PAM_AUTHTOK, pass))) {
  	    DLOG("pam_set_item()", pam_strerror(pamh, pamret));
  	    free(pass);
  	    pamret = PAM_SERVICE_ERR;
***************
*** 122,133 ****
  	}
  	free(pass);
  	/* Now we get it back from the library. */
! 	(void) pam_get_item(pamh, PAM_AUTHTOK, (void **) &pass);
      }
  
!     if (krbret = krb5_get_init_creds_password(pam_context, &creds, princ,
  					      pass, pam_prompter, pamh,
! 					      0, "kadmin/changepw", &opts)) {
  	DLOG("krb5_get_init_creds_password()", error_message(krbret));
  	if (try_first_pass && krbret == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
  	    pass = NULL;
--- 123,134 ----
  	}
  	free(pass);
  	/* Now we get it back from the library. */
! 	(void) pam_get_item(pamh, PAM_AUTHTOK, (const void **) &pass);
      }
  
!     if ((krbret = krb5_get_init_creds_password(pam_context, &creds, princ,
  					      pass, pam_prompter, pamh,
! 					      0, "kadmin/changepw", &opts))) {
  	DLOG("krb5_get_init_creds_password()", error_message(krbret));
  	if (try_first_pass && krbret == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
  	    pass = NULL;
***************
*** 140,153 ****
      /* Now get the new password */
      free(prompt);
      prompt = "Enter new password: ";
!     if (pamret = get_user_info(pamh, prompt, PAM_PROMPT_ECHO_OFF, &pass)) {
  	DLOG("get_user_info()", pam_strerror(pamh, pamret));
  	prompt = NULL;
  	pamret = PAM_SERVICE_ERR;
  	goto cleanup;
      }
      prompt = "Enter it again: ";
!     if (pamret = get_user_info(pamh, prompt, PAM_PROMPT_ECHO_OFF, &pass2)) {
  	DLOG("get_user_info()", pam_strerror(pamh, pamret));
  	prompt = NULL;
  	pamret = PAM_SERVICE_ERR;
--- 141,154 ----
      /* Now get the new password */
      free(prompt);
      prompt = "Enter new password: ";
!     if ((pamret = get_user_info(pamh, prompt, PAM_PROMPT_ECHO_OFF, &pass))) {
  	DLOG("get_user_info()", pam_strerror(pamh, pamret));
  	prompt = NULL;
  	pamret = PAM_SERVICE_ERR;
  	goto cleanup;
      }
      prompt = "Enter it again: ";
!     if ((pamret = get_user_info(pamh, prompt, PAM_PROMPT_ECHO_OFF, &pass2))) {
  	DLOG("get_user_info()", pam_strerror(pamh, pamret));
  	prompt = NULL;
  	pamret = PAM_SERVICE_ERR;
***************
*** 162,170 ****
      }
  
      /* Change it */
!     if (krbret = krb5_change_password(pam_context, &creds, pass,
  				      &result_code, &result_code_string,
! 				      &result_string)) {
  	DLOG("krb5_change_password()", error_message(krbret));
  	pamret = PAM_AUTHTOK_ERR;
  	goto cleanup;
--- 163,171 ----
      }
  
      /* Change it */
!     if ((krbret = krb5_change_password(pam_context, &creds, pass,
  				      &result_code, &result_code_string,
! 				      &result_string))) {
  	DLOG("krb5_change_password()", error_message(krbret));
  	pamret = PAM_AUTHTOK_ERR;
  	goto cleanup;
diff -c build.old/support.c build/support.c
*** build.old/support.c	Thu Nov  9 15:18:08 2000
--- build/support.c	Thu Nov  9 16:00:23 2000
***************
*** 12,17 ****
--- 12,19 ----
  #include <security/pam_appl.h>
  #include <security/pam_modules.h>
  #include <krb5.h>
+ #include <malloc.h>
+ #include <string.h>
  #include "pam_krb5.h"
  
  /*
***************
*** 23,33 ****
  get_user_info(pam_handle_t *pamh, char *prompt, int type, char **response)
  {
      int pamret;
!     struct pam_message	msg, *pmsg;
      struct pam_response	*resp = NULL;
      struct pam_conv	*conv;
  
!     if (pamret = pam_get_item(pamh, PAM_CONV, (void **) &conv))
  	return pamret;
  
      /* set up conversation call */
--- 25,36 ----
  get_user_info(pam_handle_t *pamh, char *prompt, int type, char **response)
  {
      int pamret;
!     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, (const void **) &conv)))
  	return pamret;
  
      /* set up conversation call */
***************
*** 35,41 ****
      msg.msg_style = type;
      msg.msg = prompt;
  
!     if (pamret = conv->conv(1, &pmsg, &resp, conv->appdata_ptr))
  	return pamret;
  
      /* Caller should ignore errors for non-response conversations */
--- 38,44 ----
      msg.msg_style = type;
      msg.msg = prompt;
  
!     if ((pamret = conv->conv(1, &pmsg, &resp, conv->appdata_ptr)))
  	return pamret;
  
      /* Caller should ignore errors for non-response conversations */
***************
*** 65,71 ****
      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)
--- 68,74 ----
      struct pam_conv	*conv;
      pam_handle_t	*pamh = (pam_handle_t *) data;
  
!     if ((pamret = pam_get_item(pamh, PAM_CONV, (const void **) &conv)))
  	return KRB5KRB_ERR_GENERIC;
  
      if (name)
***************
*** 110,116 ****
  	pam_prompts++;
      }
  
!     if (pamret = conv->conv(pam_prompts, &msg, &resp, conv->appdata_ptr))
  	goto cleanup;
  
      if (!resp)
--- 113,119 ----
  	pam_prompts++;
      }
  
!     if ((pamret = conv->conv(pam_prompts, &msg, &resp, conv->appdata_ptr)))
  	goto cleanup;
  
      if (!resp)
***************
*** 190,200 ****
      krb5_keyblock *	keyblock = 0;
      krb5_data		packet;
      krb5_auth_context	auth_context = NULL;
-     krb5_keytab		keytab = NULL;
-     char *		kt_name = NULL;
      char *		princname;
      char *		pn_host;
!     size_t *		pn_host_sz;
  
  
      packet.data = 0;
--- 193,201 ----
      krb5_keyblock *	keyblock = 0;
      krb5_data		packet;
      krb5_auth_context	auth_context = NULL;
      char *		princname;
      char *		pn_host;
!     size_t 		pn_host_sz;
  
  
      packet.data = 0;
***************
*** 203,210 ****
       * 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 (debug)
  	    syslog(LOG_DEBUG, "pam_krb5: verify_krb_v5_tgt(): %s: %s",
  		   "krb5_sname_to_principal()", error_message(retval));
--- 204,211 ----
       * 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 (debug)
  	    syslog(LOG_DEBUG, "pam_krb5: verify_krb_v5_tgt(): %s: %s",
  		   "krb5_sname_to_principal()", error_message(retval));
***************
*** 216,222 ****
      strncpy(phost, krb5_princ_component(context, princ, 1)->data, BUFSIZ);
  #endif
      
!     if (retval = krb5_unparse_name(context,princ,&princname)) {
          if (debug)
              syslog(LOG_DEBUG, "pam_krb5: verify_krb5_v5_tgt(): %s: %s",
                     "krb5_unparse_name()", error_message(retval));
--- 217,223 ----
      strncpy(phost, krb5_princ_component(context, princ, 1)->data, BUFSIZ);
  #endif
      
!     if ((retval = krb5_unparse_name(context,princ,&princname))) {
          if (debug)
              syslog(LOG_DEBUG, "pam_krb5: verify_krb5_v5_tgt(): %s: %s",
                     "krb5_unparse_name()", error_message(retval));
***************
*** 241,248 ****
       * (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)) {
  	/* Keytab or service key does not exist */
  	if (debug)
  	    syslog(LOG_DEBUG, "pam_krb5: verify_krb_v5_tgt(): %s: %s",
--- 242,249 ----
       * (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))) {
  	/* Keytab or service key does not exist */
  	if (debug)
  	    syslog(LOG_DEBUG, "pam_krb5: verify_krb_v5_tgt(): %s: %s",
gcc -c -O2 -fPIC -Wall -I/opt/local/include pam_krb5_auth.c
pam_krb5_auth.c: In function `pam_sm_authenticate':
pam_krb5_auth.c:75: warning: passing arg 2 of `pam_get_user' from incompatible pointer type
pam_krb5_auth.c:87: warning: implicit declaration of function `error_message'
pam_krb5_auth.c:185: warning: passing arg 5 of `krb5_get_init_creds_password' from incompatible pointer type
pam_krb5_auth.c: In function `pam_sm_setcred':
pam_krb5_auth.c:294: warning: assignment discards qualifiers from pointer target type
gcc -c -O2 -fPIC -Wall -I/opt/local/include pam_krb5_pass.c
pam_krb5_pass.c: In function `pam_sm_chauthtok':
pam_krb5_pass.c:72: warning: implicit declaration of function `error_message'
pam_krb5_pass.c:131: warning: passing arg 5 of `krb5_get_init_creds_password' from incompatible pointer type
gcc -c -O2 -fPIC -Wall -I/opt/local/include pam_krb5_acct.c
pam_krb5_acct.c: In function `pam_sm_acct_mgmt':
pam_krb5_acct.c:59: warning: implicit declaration of function `error_message'
gcc -c -O2 -fPIC -Wall -I/opt/local/include pam_krb5_sess.c
gcc -c -O2 -fPIC -Wall -I/opt/local/include support.c
support.c: In function `pam_prompter':
support.c:92: warning: passing arg 1 of `__strcpy_small' discards qualifiers from pointer target type
support.c:92: warning: passing arg 1 of `memcpy' discards qualifiers from pointer target type
support.c:92: warning: passing arg 1 of `strcpy' discards qualifiers from pointer target type
support.c:101: warning: passing arg 1 of `__strcpy_small' discards qualifiers from pointer target type
support.c:101: warning: passing arg 1 of `memcpy' discards qualifiers from pointer target type
support.c:101: warning: passing arg 1 of `strcpy' discards qualifiers from pointer target type
support.c:110: warning: passing arg 1 of `sprintf' discards qualifiers from pointer target type
support.c:116: warning: passing arg 2 of pointer to function from incompatible pointer type
support.c:149: warning: passing arg 1 of `free' discards qualifiers from pointer target type
support.c: In function `verify_krb_v5_tgt':
support.c:211: warning: implicit declaration of function `error_message'
gcc -o pam_krb5.so -shared -Xlinker -x -Wall pam_krb5_auth.o pam_krb5_pass.o pam_krb5_acct.o pam_krb5_sess.o support.o -lpam  -L/opt/local/lib -lkrb5 -lcom_err -lasn1 -lgssapi -ldes -lroken -ldb
-- 
Brian May <bam@snoopy.apana.org.au>