source: trunk/third/openssh/auth2-pam.c @ 18763

Revision 18763, 4.2 KB checked in by zacheiss, 22 years ago (diff)
Merge openssh 3.5p1.
Line 
1#include "includes.h"
2RCSID("$Id: auth2-pam.c,v 1.3 2003-02-06 03:45:45 zacheiss Exp $");
3
4#ifdef USE_PAM
5#include <security/pam_appl.h>
6
7#include "ssh.h"
8#include "ssh2.h"
9#include "auth.h"
10#include "auth-pam.h"
11#include "packet.h"
12#include "xmalloc.h"
13#include "dispatch.h"
14#include "log.h"
15
16static int do_pam_conversation_kbd_int(int num_msg,
17    const struct pam_message **msg, struct pam_response **resp,
18    void *appdata_ptr);
19void input_userauth_info_response_pam(int type, u_int32_t seqnr, void *ctxt);
20
21struct {
22        int finished, num_received, num_expected;
23        int *prompts;
24        struct pam_response *responses;
25} context_pam2 = {0, 0, 0, NULL};
26
27static struct pam_conv conv2 = {
28        do_pam_conversation_kbd_int,
29        NULL,
30};
31
32int
33auth2_pam(Authctxt *authctxt)
34{
35        int retval = -1;
36
37        if (authctxt->user == NULL)
38                fatal("auth2_pam: internal error: no user");
39
40        conv2.appdata_ptr = authctxt;
41        do_pam_set_conv(&conv2);
42
43        dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE,
44            &input_userauth_info_response_pam);
45        retval = (do_pam_authenticate(0) == PAM_SUCCESS);
46        dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
47
48        return retval;
49}
50
51static int
52do_pam_conversation_kbd_int(int num_msg, const struct pam_message **msg,
53    struct pam_response **resp, void *appdata_ptr)
54{
55        int i, j, done;
56        char *text;
57
58        context_pam2.finished = 0;
59        context_pam2.num_received = 0;
60        context_pam2.num_expected = 0;
61        context_pam2.prompts = xmalloc(sizeof(int) * num_msg);
62        context_pam2.responses = xmalloc(sizeof(struct pam_response) * num_msg);
63        memset(context_pam2.responses, 0, sizeof(struct pam_response) * num_msg);
64
65        text = NULL;
66        for (i = 0, context_pam2.num_expected = 0; i < num_msg; i++) {
67                int style = PAM_MSG_MEMBER(msg, i, msg_style);
68                switch (style) {
69                case PAM_PROMPT_ECHO_ON:
70                case PAM_PROMPT_ECHO_OFF:
71                        context_pam2.num_expected++;
72                        break;
73                case PAM_TEXT_INFO:
74                case PAM_ERROR_MSG:
75                default:
76                        /* Capture all these messages to be sent at once */
77                        message_cat(&text, PAM_MSG_MEMBER(msg, i, msg));
78                        break;
79                }
80        }
81
82        if (context_pam2.num_expected == 0)
83                return PAM_SUCCESS;
84
85        packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);
86        packet_put_cstring(""); /* Name */
87        packet_put_cstring(""); /* Instructions */
88        packet_put_cstring(""); /* Language */
89        packet_put_int(context_pam2.num_expected);
90       
91        for (i = 0, j = 0; i < num_msg; i++) {
92                int style = PAM_MSG_MEMBER(msg, i, msg_style);
93               
94                /* Skip messages which don't need a reply */
95                if (style != PAM_PROMPT_ECHO_ON && style != PAM_PROMPT_ECHO_OFF)
96                        continue;
97               
98                context_pam2.prompts[j++] = i;
99                if (text) {
100                        message_cat(&text, PAM_MSG_MEMBER(msg, i, msg));
101                        packet_put_cstring(text);
102                        text = NULL;
103                } else
104                        packet_put_cstring(PAM_MSG_MEMBER(msg, i, msg));
105                packet_put_char(style == PAM_PROMPT_ECHO_ON);
106        }
107        packet_send();
108        packet_write_wait();
109
110        /*
111         * Grabbing control of execution and spinning until we get what
112         * we want is probably rude, but it seems to work properly, and
113         * the client *should* be in lock-step with us, so the loop should
114         * only be traversed once.
115         */
116        while(context_pam2.finished == 0) {
117                done = 1;
118                dispatch_run(DISPATCH_BLOCK, &done, appdata_ptr);
119                if (context_pam2.finished == 0)
120                        debug("extra packet during conversation");
121        }
122
123        if (context_pam2.num_received == context_pam2.num_expected) {
124                *resp = context_pam2.responses;
125                return PAM_SUCCESS;
126        } else
127                return PAM_CONV_ERR;
128}
129
130void
131input_userauth_info_response_pam(int type, u_int32_t seqnr, void *ctxt)
132{
133        Authctxt *authctxt = ctxt;
134        unsigned int nresp = 0, rlen = 0, i = 0;
135        char *resp;
136
137        if (authctxt == NULL)
138                fatal("input_userauth_info_response_pam: no authentication context");
139
140        nresp = packet_get_int();       /* Number of responses. */
141        debug("got %d responses", nresp);
142
143        if (nresp != context_pam2.num_expected)
144                fatal("%s: Received incorrect number of responses "
145                    "(expected %d, received %u)", __func__,
146                    context_pam2.num_expected, nresp);
147
148        if (nresp > 100)
149                fatal("%s: too many replies", __func__);
150
151        for (i = 0; i < nresp; i++) {
152                int j = context_pam2.prompts[i];
153
154                resp = packet_get_string(&rlen);
155                context_pam2.responses[j].resp_retcode = PAM_SUCCESS;
156                context_pam2.responses[j].resp = xstrdup(resp);
157                xfree(resp);
158                context_pam2.num_received++;
159        }
160
161        context_pam2.finished = 1;
162
163        packet_check_eom();
164}
165#endif
Note: See TracBrowser for help on using the repository browser.