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