4 * Support functions for pam_krb5
6 * $FreeBSD: src/lib/libpam/modules/pam_krb5/support.c,v 1.1.2.1 2001/06/07 09:37:07 markm Exp $
9 static const char rcsid[] = "$Id: support.c,v 1.8 2000/01/04 09:50:03 fcusack Exp $";
12 #include <stdio.h> /* BUFSIZ */
13 #include <stdlib.h> /* malloc */
14 #include <string.h> /* strncpy */
15 #include <syslog.h> /* syslog */
16 #include <security/pam_appl.h>
17 #include <security/pam_modules.h>
23 * Get info from the user. Disallow null responses (regardless of flags).
24 * response gets allocated and filled in on successful return. Caller
25 * is responsible for freeing it.
28 get_user_info(pam_handle_t *pamh, char *prompt, int type, char **response)
31 struct pam_message msg;
32 const struct pam_message *pmsg;
33 struct pam_response *resp = NULL;
34 struct pam_conv *conv;
36 if ((pamret = pam_get_item(pamh, PAM_CONV, (const void **) &conv)) != 0)
39 /* set up conversation call */
44 if ((pamret = conv->conv(1, &pmsg, &resp, conv->appdata_ptr)) != 0)
47 /* Caller should ignore errors for non-response conversations */
51 if (!(resp->resp && resp->resp[0])) {
56 *response = resp->resp;
62 * This routine with some modification is from the MIT V5B6 appl/bsd/login.c
63 * Modified by Sam Hartman <hartmans@mit.edu> to support PAM services
66 * Verify the Kerberos ticket-granting ticket just retrieved for the
67 * user. If the Kerberos server doesn't respond, assume the user is
68 * trying to fake us out (since we DID just get a TGT from what is
69 * supposedly our KDC). If the host/<host> service is unknown (i.e.,
70 * the local keytab doesn't have it), and we cannot find another
71 * service we do have, let her in.
73 * Returns 1 for confirmation, -1 for failure, 0 for uncertainty.
76 verify_krb_v5_tgt(krb5_context context, krb5_ccache ccache,
77 char * pam_service, int debug)
82 krb5_error_code retval = -1;
84 krb5_keyblock * keyblock = 0;
86 krb5_auth_context auth_context = NULL;
91 * If possible we want to try and verify the ticket we have
92 * received against a keytab. We will try multiple service
93 * principals, including at least the host principal and the PAM
94 * service principal. The host principal is preferred because access
95 * to that key is generally sufficient to compromise root, while the
96 * service key for this PAM service may be less carefully guarded.
97 * It is important to check the keytab first before the KDC so we do
98 * not get spoofed by a fake KDC.*/
99 services [0] = "host";
100 services [1] = pam_service;
102 for ( service = &services[0]; *service != NULL; service++ ) {
103 if ((retval = krb5_sname_to_principal(context, NULL, *service, KRB5_NT_SRV_HST,
106 syslog(LOG_DEBUG, "pam_krb5: verify_krb_v5_tgt(): %s: %s",
107 "krb5_sname_to_principal()", error_message(retval));
111 /* Extract the name directly. */
112 strncpy(phost, compat_princ_component(context, princ, 1), BUFSIZ);
113 phost[BUFSIZ - 1] = '\0';
116 * Do we have service/<host> keys?
117 * (use default/configured keytab, kvno IGNORE_VNO to get the
118 * first match, and ignore enctype.)
120 if ((retval = krb5_kt_read_service_key(context, NULL, princ, 0,
125 if (retval != 0 ) { /* failed to find key */
126 /* Keytab or service key does not exist */
128 syslog(LOG_DEBUG, "pam_krb5: verify_krb_v5_tgt(): %s: %s",
129 "krb5_kt_read_service_key()", error_message(retval));
134 krb5_free_keyblock(context, keyblock);
136 /* Talk to the kdc and construct the ticket. */
137 retval = krb5_mk_req(context, &auth_context, 0, *service, phost,
138 NULL, ccache, &packet);
140 krb5_auth_con_free(context, auth_context);
141 auth_context = NULL; /* setup for rd_req */
145 syslog(LOG_DEBUG, "pam_krb5: verify_krb_v5_tgt(): %s: %s",
146 "krb5_mk_req()", error_message(retval));
151 /* Try to use the ticket. */
152 retval = krb5_rd_req(context, &auth_context, &packet, princ,
156 syslog(LOG_DEBUG, "pam_krb5: verify_krb_v5_tgt(): %s: %s",
157 "krb5_rd_req()", error_message(retval));
165 compat_free_data_contents(context, &packet);
166 krb5_free_principal(context, princ);
172 /* Free the memory for cache_name. Called by pam_end() */
174 cleanup_cache(pam_handle_t *pamh, void *data, int pam_end_status)
176 krb5_context pam_context;
179 if (krb5_init_context(&pam_context))
182 ccache = (krb5_ccache) data;
183 (void) krb5_cc_destroy(pam_context, ccache);
184 krb5_free_context(pam_context);