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

Revision 16801, 3.9 KB checked in by ghudson, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r16800, which included commits to RCS files with non-trunk default branches.
Line 
1#include "includes.h"
2RCSID("$Id: auth2-pam.c,v 1.1.1.1 2001-11-15 19:25:07 ghudson 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, int plen, 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, int plen, 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        for (i = 0; i < nresp; i++) {
144                int j = context_pam2.prompts[i];
145
146                resp = packet_get_string(&rlen);
147                context_pam2.responses[j].resp_retcode = PAM_SUCCESS;
148                context_pam2.responses[j].resp = xstrdup(resp);
149                xfree(resp);
150                context_pam2.num_received++;
151        }
152
153        context_pam2.finished = 1;
154
155        packet_done();
156}
157
158#endif
Note: See TracBrowser for help on using the repository browser.