~ubuntu-branches/ubuntu/edgy/openssh/edgy

« back to all changes in this revision

Viewing changes to auth2-chall.c

  • Committer: Bazaar Package Importer
  • Author(s): Noah Meyerhans
  • Date: 2006-10-31 17:53:38 UTC
  • Revision ID: james.westby@ubuntu.com-20061031175338-kh299ada2qc2kzlb
Tags: upstream-3.8.1p1
ImportĀ upstreamĀ versionĀ 3.8.1p1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2001 Markus Friedl.  All rights reserved.
 
3
 * Copyright (c) 2001 Per Allansson.  All rights reserved.
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions
 
7
 * are met:
 
8
 * 1. Redistributions of source code must retain the above copyright
 
9
 *    notice, this list of conditions and the following disclaimer.
 
10
 * 2. Redistributions in binary form must reproduce the above copyright
 
11
 *    notice, this list of conditions and the following disclaimer in the
 
12
 *    documentation and/or other materials provided with the distribution.
 
13
 *
 
14
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 
15
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 
16
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 
17
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 
18
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 
19
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
20
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
21
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
22
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 
23
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
24
 */
 
25
#include "includes.h"
 
26
RCSID("$OpenBSD: auth2-chall.c,v 1.20 2002/06/30 21:59:45 deraadt Exp $");
 
27
 
 
28
#include "ssh2.h"
 
29
#include "auth.h"
 
30
#include "buffer.h"
 
31
#include "packet.h"
 
32
#include "xmalloc.h"
 
33
#include "dispatch.h"
 
34
#include "auth.h"
 
35
#include "log.h"
 
36
 
 
37
static int auth2_challenge_start(Authctxt *);
 
38
static int send_userauth_info_request(Authctxt *);
 
39
static void input_userauth_info_response(int, u_int32_t, void *);
 
40
 
 
41
#ifdef BSD_AUTH
 
42
extern KbdintDevice bsdauth_device;
 
43
#else
 
44
#ifdef USE_PAM
 
45
extern KbdintDevice sshpam_device;
 
46
#endif
 
47
#ifdef SKEY
 
48
extern KbdintDevice skey_device;
 
49
#endif
 
50
#endif
 
51
 
 
52
KbdintDevice *devices[] = {
 
53
#ifdef BSD_AUTH
 
54
        &bsdauth_device,
 
55
#else
 
56
#ifdef USE_PAM
 
57
        &sshpam_device,
 
58
#endif
 
59
#ifdef SKEY
 
60
        &skey_device,
 
61
#endif
 
62
#endif
 
63
        NULL
 
64
};
 
65
 
 
66
typedef struct KbdintAuthctxt KbdintAuthctxt;
 
67
struct KbdintAuthctxt
 
68
{
 
69
        char *devices;
 
70
        void *ctxt;
 
71
        KbdintDevice *device;
 
72
        u_int nreq;
 
73
};
 
74
 
 
75
static KbdintAuthctxt *
 
76
kbdint_alloc(const char *devs)
 
77
{
 
78
        KbdintAuthctxt *kbdintctxt;
 
79
        Buffer b;
 
80
        int i;
 
81
 
 
82
        kbdintctxt = xmalloc(sizeof(KbdintAuthctxt));
 
83
        if (strcmp(devs, "") == 0) {
 
84
                buffer_init(&b);
 
85
                for (i = 0; devices[i]; i++) {
 
86
                        if (buffer_len(&b) > 0)
 
87
                                buffer_append(&b, ",", 1);
 
88
                        buffer_append(&b, devices[i]->name,
 
89
                            strlen(devices[i]->name));
 
90
                }
 
91
                buffer_append(&b, "\0", 1);
 
92
                kbdintctxt->devices = xstrdup(buffer_ptr(&b));
 
93
                buffer_free(&b);
 
94
        } else {
 
95
                kbdintctxt->devices = xstrdup(devs);
 
96
        }
 
97
        debug("kbdint_alloc: devices '%s'", kbdintctxt->devices);
 
98
        kbdintctxt->ctxt = NULL;
 
99
        kbdintctxt->device = NULL;
 
100
        kbdintctxt->nreq = 0;
 
101
 
 
102
        return kbdintctxt;
 
103
}
 
104
static void
 
105
kbdint_reset_device(KbdintAuthctxt *kbdintctxt)
 
106
{
 
107
        if (kbdintctxt->ctxt) {
 
108
                kbdintctxt->device->free_ctx(kbdintctxt->ctxt);
 
109
                kbdintctxt->ctxt = NULL;
 
110
        }
 
111
        kbdintctxt->device = NULL;
 
112
}
 
113
static void
 
114
kbdint_free(KbdintAuthctxt *kbdintctxt)
 
115
{
 
116
        if (kbdintctxt->device)
 
117
                kbdint_reset_device(kbdintctxt);
 
118
        if (kbdintctxt->devices) {
 
119
                xfree(kbdintctxt->devices);
 
120
                kbdintctxt->devices = NULL;
 
121
        }
 
122
        xfree(kbdintctxt);
 
123
}
 
124
/* get next device */
 
125
static int
 
126
kbdint_next_device(KbdintAuthctxt *kbdintctxt)
 
127
{
 
128
        size_t len;
 
129
        char *t;
 
130
        int i;
 
131
 
 
132
        if (kbdintctxt->device)
 
133
                kbdint_reset_device(kbdintctxt);
 
134
        do {
 
135
                len = kbdintctxt->devices ?
 
136
                    strcspn(kbdintctxt->devices, ",") : 0;
 
137
 
 
138
                if (len == 0)
 
139
                        break;
 
140
                for (i = 0; devices[i]; i++)
 
141
                        if (strncmp(kbdintctxt->devices, devices[i]->name, len) == 0)
 
142
                                kbdintctxt->device = devices[i];
 
143
                t = kbdintctxt->devices;
 
144
                kbdintctxt->devices = t[len] ? xstrdup(t+len+1) : NULL;
 
145
                xfree(t);
 
146
                debug2("kbdint_next_device: devices %s", kbdintctxt->devices ?
 
147
                   kbdintctxt->devices : "<empty>");
 
148
        } while (kbdintctxt->devices && !kbdintctxt->device);
 
149
 
 
150
        return kbdintctxt->device ? 1 : 0;
 
151
}
 
152
 
 
153
/*
 
154
 * try challenge-response, set authctxt->postponed if we have to
 
155
 * wait for the response.
 
156
 */
 
157
int
 
158
auth2_challenge(Authctxt *authctxt, char *devs)
 
159
{
 
160
        debug("auth2_challenge: user=%s devs=%s",
 
161
            authctxt->user ? authctxt->user : "<nouser>",
 
162
            devs ? devs : "<no devs>");
 
163
 
 
164
        if (authctxt->user == NULL || !devs)
 
165
                return 0;
 
166
        if (authctxt->kbdintctxt == NULL)
 
167
                authctxt->kbdintctxt = kbdint_alloc(devs);
 
168
        return auth2_challenge_start(authctxt);
 
169
}
 
170
 
 
171
/* unregister kbd-int callbacks and context */
 
172
void
 
173
auth2_challenge_stop(Authctxt *authctxt)
 
174
{
 
175
        /* unregister callback */
 
176
        dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
 
177
        if (authctxt->kbdintctxt != NULL)  {
 
178
                kbdint_free(authctxt->kbdintctxt);
 
179
                authctxt->kbdintctxt = NULL;
 
180
        }
 
181
}
 
182
 
 
183
/* side effect: sets authctxt->postponed if a reply was sent*/
 
184
static int
 
185
auth2_challenge_start(Authctxt *authctxt)
 
186
{
 
187
        KbdintAuthctxt *kbdintctxt = authctxt->kbdintctxt;
 
188
 
 
189
        debug2("auth2_challenge_start: devices %s",
 
190
            kbdintctxt->devices ?  kbdintctxt->devices : "<empty>");
 
191
 
 
192
        if (kbdint_next_device(kbdintctxt) == 0) {
 
193
                auth2_challenge_stop(authctxt);
 
194
                return 0;
 
195
        }
 
196
        debug("auth2_challenge_start: trying authentication method '%s'",
 
197
            kbdintctxt->device->name);
 
198
 
 
199
        if ((kbdintctxt->ctxt = kbdintctxt->device->init_ctx(authctxt)) == NULL) {
 
200
                auth2_challenge_stop(authctxt);
 
201
                return 0;
 
202
        }
 
203
        if (send_userauth_info_request(authctxt) == 0) {
 
204
                auth2_challenge_stop(authctxt);
 
205
                return 0;
 
206
        }
 
207
        dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE,
 
208
            &input_userauth_info_response);
 
209
 
 
210
        authctxt->postponed = 1;
 
211
        return 0;
 
212
}
 
213
 
 
214
static int
 
215
send_userauth_info_request(Authctxt *authctxt)
 
216
{
 
217
        KbdintAuthctxt *kbdintctxt;
 
218
        char *name, *instr, **prompts;
 
219
        int i;
 
220
        u_int *echo_on;
 
221
 
 
222
        kbdintctxt = authctxt->kbdintctxt;
 
223
        if (kbdintctxt->device->query(kbdintctxt->ctxt,
 
224
            &name, &instr, &kbdintctxt->nreq, &prompts, &echo_on))
 
225
                return 0;
 
226
 
 
227
        packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);
 
228
        packet_put_cstring(name);
 
229
        packet_put_cstring(instr);
 
230
        packet_put_cstring("");         /* language not used */
 
231
        packet_put_int(kbdintctxt->nreq);
 
232
        for (i = 0; i < kbdintctxt->nreq; i++) {
 
233
                packet_put_cstring(prompts[i]);
 
234
                packet_put_char(echo_on[i]);
 
235
        }
 
236
        packet_send();
 
237
        packet_write_wait();
 
238
 
 
239
        for (i = 0; i < kbdintctxt->nreq; i++)
 
240
                xfree(prompts[i]);
 
241
        xfree(prompts);
 
242
        xfree(echo_on);
 
243
        xfree(name);
 
244
        xfree(instr);
 
245
        return 1;
 
246
}
 
247
 
 
248
static void
 
249
input_userauth_info_response(int type, u_int32_t seq, void *ctxt)
 
250
{
 
251
        Authctxt *authctxt = ctxt;
 
252
        KbdintAuthctxt *kbdintctxt;
 
253
        int i, authenticated = 0, res, len;
 
254
        u_int nresp;
 
255
        char **response = NULL, *method;
 
256
 
 
257
        if (authctxt == NULL)
 
258
                fatal("input_userauth_info_response: no authctxt");
 
259
        kbdintctxt = authctxt->kbdintctxt;
 
260
        if (kbdintctxt == NULL || kbdintctxt->ctxt == NULL)
 
261
                fatal("input_userauth_info_response: no kbdintctxt");
 
262
        if (kbdintctxt->device == NULL)
 
263
                fatal("input_userauth_info_response: no device");
 
264
 
 
265
        authctxt->postponed = 0;        /* reset */
 
266
        nresp = packet_get_int();
 
267
        if (nresp != kbdintctxt->nreq)
 
268
                fatal("input_userauth_info_response: wrong number of replies");
 
269
        if (nresp > 100)
 
270
                fatal("input_userauth_info_response: too many replies");
 
271
        if (nresp > 0) {
 
272
                response = xmalloc(nresp * sizeof(char *));
 
273
                for (i = 0; i < nresp; i++)
 
274
                        response[i] = packet_get_string(NULL);
 
275
        }
 
276
        packet_check_eom();
 
277
 
 
278
        if (authctxt->valid) {
 
279
                res = kbdintctxt->device->respond(kbdintctxt->ctxt,
 
280
                    nresp, response);
 
281
        } else {
 
282
                res = -1;
 
283
        }
 
284
 
 
285
        for (i = 0; i < nresp; i++) {
 
286
                memset(response[i], 'r', strlen(response[i]));
 
287
                xfree(response[i]);
 
288
        }
 
289
        if (response)
 
290
                xfree(response);
 
291
 
 
292
        switch (res) {
 
293
        case 0:
 
294
                /* Success! */
 
295
                authenticated = 1;
 
296
                break;
 
297
        case 1:
 
298
                /* Authentication needs further interaction */
 
299
                if (send_userauth_info_request(authctxt) == 1)
 
300
                        authctxt->postponed = 1;
 
301
                break;
 
302
        default:
 
303
                /* Failure! */
 
304
                break;
 
305
        }
 
306
 
 
307
        len = strlen("keyboard-interactive") + 2 +
 
308
                strlen(kbdintctxt->device->name);
 
309
        method = xmalloc(len);
 
310
        snprintf(method, len, "keyboard-interactive/%s",
 
311
            kbdintctxt->device->name);
 
312
 
 
313
        if (!authctxt->postponed) {
 
314
                if (authenticated) {
 
315
                        auth2_challenge_stop(authctxt);
 
316
                } else {
 
317
                        /* start next device */
 
318
                        /* may set authctxt->postponed */
 
319
                        auth2_challenge_start(authctxt);
 
320
                }
 
321
        }
 
322
        userauth_finish(authctxt, authenticated, method);
 
323
        xfree(method);
 
324
}
 
325
 
 
326
void
 
327
privsep_challenge_enable(void)
 
328
{
 
329
#if defined(BSD_AUTH) || defined(USE_PAM) || defined(SKEY)
 
330
        int n = 0;
 
331
#endif
 
332
#ifdef BSD_AUTH
 
333
        extern KbdintDevice mm_bsdauth_device;
 
334
#endif
 
335
#ifdef USE_PAM
 
336
        extern KbdintDevice mm_sshpam_device;
 
337
#endif
 
338
#ifdef SKEY
 
339
        extern KbdintDevice mm_skey_device;
 
340
#endif
 
341
 
 
342
#ifdef BSD_AUTH
 
343
        devices[n++] = &mm_bsdauth_device;
 
344
#else
 
345
#ifdef USE_PAM
 
346
        devices[n++] = &mm_sshpam_device;
 
347
#endif
 
348
#ifdef SKEY
 
349
        devices[n++] = &mm_skey_device;
 
350
#endif
 
351
#endif
 
352
}