6d21d398cbab50b7fa5eb1093f5401556a255a22
[dragonfly.git] / lib / libpam / modules / pam_krb5 / compat_heimdal.c
1 /*
2  * compat_heimdal.c
3  *
4  * Heimdal compatibility layer.
5  *
6  * $FreeBSD: src/lib/libpam/modules/pam_krb5/compat_heimdal.c,v 1.1.2.2 2001/07/29 18:57:30 markm Exp $
7  * $DragonFly: src/lib/libpam/modules/pam_krb5/Attic/compat_heimdal.c,v 1.4 2004/10/25 19:38:45 drhodus Exp $
8  */
9
10 #include <errno.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14
15 #include <krb5.h>
16 #include <security/pam_appl.h>
17 #include <security/pam_modules.h>
18 #include "pam_krb5.h"
19
20 const char *
21 compat_princ_component(krb5_context context, krb5_principal princ, int n)
22 {
23         return princ->name.name_string.val[n];
24 }
25
26 void
27 compat_free_data_contents(krb5_context context, krb5_data *data)
28 {
29         krb5_xfree(data->data);
30 }
31
32 static krb5_error_code
33 heimdal_pam_prompter(krb5_context context, void *data, const char *name,
34     const char *banner, int num_prompts, krb5_prompt prompts[])
35 {
36     int         pam_prompts = num_prompts;
37     int         pamret, i;
38
39     struct pam_message  *msg;
40     struct pam_response *resp = NULL;
41     struct pam_conv     *conv;
42     pam_handle_t        *pamh = (pam_handle_t *) data;
43
44     if ((pamret = pam_get_item(pamh, PAM_CONV, (const void **) &conv)) != 0)
45         return KRB5KRB_ERR_GENERIC;
46
47     if (banner)
48         pam_prompts++;
49
50     msg = calloc(sizeof(struct pam_message) * pam_prompts, 1);
51     if (!msg)
52         return ENOMEM;
53
54     /* Now use pam_prompts as an index */
55     pam_prompts = 0;
56
57     if (banner) {
58         msg[pam_prompts].msg = malloc(strlen(banner) + 1);
59         if (!msg[pam_prompts].msg)
60             goto cleanup;
61         strcpy((char *) msg[pam_prompts].msg, banner);
62         msg[pam_prompts].msg_style = PAM_TEXT_INFO;
63         pam_prompts++;
64     }
65
66     for (i = 0; i < num_prompts; i++) {
67         msg[pam_prompts].msg = malloc(strlen(prompts[i].prompt) + 3);
68         if (!msg[pam_prompts].msg)
69             goto cleanup;
70         sprintf((char *) msg[pam_prompts].msg, "%s: ", prompts[i].prompt);
71         msg[pam_prompts].msg_style = prompts[i].hidden ? PAM_PROMPT_ECHO_OFF
72                                                        : PAM_PROMPT_ECHO_ON;
73         pam_prompts++;
74     }
75
76     if ((pamret = conv->conv(pam_prompts, (const struct pam_message **) &msg, 
77       &resp, conv->appdata_ptr)) != 0) 
78         goto cleanup;
79
80     if (!resp)
81         goto cleanup;
82
83     /* Reuse pam_prompts as a starting index */
84     pam_prompts = 0;
85     if (banner)
86         pam_prompts++;
87
88     for (i = 0; i < num_prompts; i++, pam_prompts++) {
89         int len;
90         if (!resp[pam_prompts].resp) {
91             pamret = PAM_AUTH_ERR;
92             goto cleanup;
93         }
94         len = strlen(resp[pam_prompts].resp); /* Help out the compiler */
95         if (len > prompts[i].reply->length) {
96             pamret = PAM_AUTH_ERR;
97             goto cleanup;
98         }
99         memcpy(prompts[i].reply->data, resp[pam_prompts].resp, len);
100         prompts[i].reply->length = len;
101     }
102
103 cleanup:
104     /* pam_prompts is correct at this point */
105
106     for (i = 0; i < pam_prompts; i++) {
107         if (msg[i].msg)
108             free((char *) msg[i].msg);
109     }
110     free(msg);
111
112     if (resp) {
113         for (i = 0; i < pam_prompts; i++) {
114             /*
115              * Note that PAM is underspecified wrt free()'ing resp[i].resp.
116              * It's not clear if I should free it, or if the application
117              * has to. Therefore most (all?) apps won't free() it, and I
118              * can't either, as I am not sure it was malloc()'d. All PAM
119              * implementations I've seen leak memory here. Not so bad, IFF
120              * you fork/exec for each PAM authentication (as is typical).
121              */
122 #if 0
123             if (resp[i].resp)
124                 free(resp[i].resp);
125 #endif /* 0 */
126         }
127         /* This does not lose resp[i].resp if the application saved a copy. */
128         free(resp);
129     }
130
131     return (pamret ? KRB5KRB_ERR_GENERIC : 0);
132 }
133
134 krb5_prompter_fct pam_prompter = heimdal_pam_prompter;