summaryrefslogtreecommitdiffstats
path: root/lib/libpam/modules/pam_krb5/compat_heimdal.c
blob: fb4e1025e6ef063a9e983744a7a644186bfa824b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
 * compat_heimdal.c
 *
 * Heimdal compatability layer.
 *
 * $FreeBSD$
 */

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <krb5.h>
#include <security/pam_appl.h>
#include <security/pam_modules.h>
#include "pam_krb5.h"

const char *
compat_princ_component(krb5_context context, krb5_principal princ, int n)
{
	return princ->name.name_string.val[n];
}

void
compat_free_data_contents(krb5_context context, krb5_data *data)
{
	krb5_xfree(data->data);
}

krb5_error_code
compat_cc_next_cred(krb5_context context, const krb5_ccache id, 
    krb5_cc_cursor *cursor, krb5_creds *creds)
{
	return krb5_cc_next_cred(context, id, creds, cursor);
}


static krb5_error_code
heimdal_pam_prompter(krb5_context context, void *data, const char *banner, int 
  num_prompts, krb5_prompt prompts[])
{
    int		pam_prompts = num_prompts;
    int		pamret, i;

    struct pam_message	*msg;
    struct pam_response	*resp = NULL;
    struct pam_conv	*conv;
    pam_handle_t	*pamh = (pam_handle_t *) data;

    if ((pamret = pam_get_item(pamh, PAM_CONV, (const void **) &conv)) != 0)
	return KRB5KRB_ERR_GENERIC;

    if (banner)
	pam_prompts++;

    msg = calloc(sizeof(struct pam_message) * pam_prompts, 1);
    if (!msg)
	return ENOMEM;

    /* Now use pam_prompts as an index */
    pam_prompts = 0;

    if (banner) {
	msg[pam_prompts].msg = malloc(strlen(banner) + 1);
	if (!msg[pam_prompts].msg)
	    goto cleanup;
	strcpy((char *) msg[pam_prompts].msg, banner);
	msg[pam_prompts].msg_style = PAM_TEXT_INFO;
	pam_prompts++;
    }

    for (i = 0; i < num_prompts; i++) {
	msg[pam_prompts].msg = malloc(strlen(prompts[i].prompt) + 3);
	if (!msg[pam_prompts].msg)
	    goto cleanup;
	sprintf((char *) msg[pam_prompts].msg, "%s: ", prompts[i].prompt);
	msg[pam_prompts].msg_style = prompts[i].hidden ? PAM_PROMPT_ECHO_OFF
						       : PAM_PROMPT_ECHO_ON;
	pam_prompts++;
    }

    if ((pamret = conv->conv(pam_prompts, (const struct pam_message **) &msg, 
      &resp, conv->appdata_ptr)) != 0) 
	goto cleanup;

    if (!resp)
	goto cleanup;

    /* Reuse pam_prompts as a starting index */
    pam_prompts = 0;
    if (banner)
	pam_prompts++;

    for (i = 0; i < num_prompts; i++, pam_prompts++) {
	register int len;
	if (!resp[pam_prompts].resp) {
	    pamret = PAM_AUTH_ERR;
	    goto cleanup;
	}
	len = strlen(resp[pam_prompts].resp); /* Help out the compiler */
	if (len > prompts[i].reply->length) {
	    pamret = PAM_AUTH_ERR;
	    goto cleanup;
	}
	memcpy(prompts[i].reply->data, resp[pam_prompts].resp, len);
	prompts[i].reply->length = len;
    }

cleanup:
    /* pam_prompts is correct at this point */

    for (i = 0; i < pam_prompts; i++) {
	if (msg[i].msg)
	    free((char *) msg[i].msg);
    }
    free(msg);

    if (resp) {
	for (i = 0; i < pam_prompts; i++) {
	    /*
	     * Note that PAM is underspecified wrt free()'ing resp[i].resp.
	     * It's not clear if I should free it, or if the application
	     * has to. Therefore most (all?) apps won't free() it, and I
	     * can't either, as I am not sure it was malloc()'d. All PAM
	     * implementations I've seen leak memory here. Not so bad, IFF
	     * you fork/exec for each PAM authentication (as is typical).
	     */
#if 0
	    if (resp[i].resp)
		free(resp[i].resp);
#endif /* 0 */
	}
	/* This does not lose resp[i].resp if the application saved a copy. */
	free(resp);
    }

    return (pamret ? KRB5KRB_ERR_GENERIC : 0);
}

krb5_prompter_fct pam_prompter = heimdal_pam_prompter;
OpenPOWER on IntegriCloud