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 $
7 * $DragonFly: src/lib/libpam/modules/pam_krb5/Attic/support.c,v 1.2 2003/06/17 04:26:50 dillon Exp $
10 static const char rcsid[] = "$Id: support.c,v 1.8 2000/01/04 09:50:03 fcusack Exp $";
13 #include <stdio.h> /* BUFSIZ */
14 #include <stdlib.h> /* malloc */
15 #include <string.h> /* strncpy */
16 #include <syslog.h> /* syslog */
17 #include <security/pam_appl.h>
18 #include <security/pam_modules.h>
24 * Get info from the user. Disallow null responses (regardless of flags).
25 * response gets allocated and filled in on successful return. Caller
26 * is responsible for freeing it.
29 get_user_info(pam_handle_t *pamh, char *prompt, int type, char **response)
32 struct pam_message msg;
33 const struct pam_message *pmsg;
34 struct pam_response *resp = NULL;
35 struct pam_conv *conv;
37 if ((pamret = pam_get_item(pamh, PAM_CONV, (const void **) &conv)) != 0)
40 /* set up conversation call */
45 if ((pamret = conv->conv(1, &pmsg, &resp, conv->appdata_ptr)) != 0)
48 /* Caller should ignore errors for non-response conversations */
52 if (!(resp->resp && resp->resp[0])) {
57 *response = resp->resp;
63 * This routine with some modification is from the MIT V5B6 appl/bsd/login.c
64 * Modified by Sam Hartman <hartmans@mit.edu> to support PAM services
67 * Verify the Kerberos ticket-granting ticket just retrieved for the
68 * user. If the Kerberos server doesn't respond, assume the user is
69 * trying to fake us out (since we DID just get a TGT from what is
70 * supposedly our KDC). If the host/<host> service is unknown (i.e.,
71 * the local keytab doesn't have it), and we cannot find another
72 * service we do have, let her in.
74 * Returns 1 for confirmation, -1 for failure, 0 for uncertainty.
77 verify_krb_v5_tgt(krb5_context context, krb5_ccache ccache,
78 char * pam_service, int debug)
83 krb5_error_code retval = -1;
85 krb5_keyblock * keyblock = 0;
87 krb5_auth_context auth_context = NULL;
92 * If possible we want to try and verify the ticket we have
93 * received against a keytab. We will try multiple service
94 * principals, including at least the host principal and the PAM
95 * service principal. The host principal is preferred because access
96 * to that key is generally sufficient to compromise root, while the
97 * service key for this PAM service may be less carefully guarded.
98 * It is important to check the keytab first before the KDC so we do
99 * not get spoofed by a fake KDC.*/
100 services [0] = "host";
101 services [1] = pam_service;
103 for ( service = &services[0]; *service != NULL; service++ ) {
104 if ((retval = krb5_sname_to_principal(context, NULL, *service, KRB5_NT_SRV_HST,
107 syslog(LOG_DEBUG, "pam_krb5: verify_krb_v5_tgt(): %s: %s",
108 "krb5_sname_to_principal()", error_message(retval));
112 /* Extract the name directly. */
113 strncpy(phost, compat_princ_component(context, princ, 1), BUFSIZ);
114 phost[BUFSIZ - 1] = '\0';
117 * Do we have service/<host> keys?
118 * (use default/configured keytab, kvno IGNORE_VNO to get the
119 * first match, and ignore enctype.)
121 if ((retval = krb5_kt_read_service_key(context, NULL, princ, 0,
126 if (retval != 0 ) { /* failed to find key */
127 /* Keytab or service key does not exist */
129 syslog(LOG_DEBUG, "pam_krb5: verify_krb_v5_tgt(): %s: %s",
130 "krb5_kt_read_service_key()", error_message(retval));
135 krb5_free_keyblock(context, keyblock);
137 /* Talk to the kdc and construct the ticket. */
138 retval = krb5_mk_req(context, &auth_context, 0, *service, phost,
139 NULL, ccache, &packet);
141 krb5_auth_con_free(context, auth_context);
142 auth_context = NULL; /* setup for rd_req */
146 syslog(LOG_DEBUG, "pam_krb5: verify_krb_v5_tgt(): %s: %s",
147 "krb5_mk_req()", error_message(retval));
152 /* Try to use the ticket. */
153 retval = krb5_rd_req(context, &auth_context, &packet, princ,
157 syslog(LOG_DEBUG, "pam_krb5: verify_krb_v5_tgt(): %s: %s",
158 "krb5_rd_req()", error_message(retval));
166 compat_free_data_contents(context, &packet);
167 krb5_free_principal(context, princ);
173 /* Free the memory for cache_name. Called by pam_end() */
175 cleanup_cache(pam_handle_t *pamh, void *data, int pam_end_status)
177 krb5_context pam_context;
180 if (krb5_init_context(&pam_context))
183 ccache = (krb5_ccache) data;
184 (void) krb5_cc_destroy(pam_context, ccache);
185 krb5_free_context(pam_context);