Annotation of src/usr.bin/ssh/auth2-chall.c, Revision 1.4.2.2
1.1 markus 1: /*
1.3 deraadt 2: * Copyright (c) 2001 Markus Friedl. All rights reserved.
1.4.2.1 jason 3: * Copyright (c) 2001 Per Allansson. All rights reserved.
1.1 markus 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"
1.4.2.2 ! miod 26: RCSID("$OpenBSD: auth2-chall.c,v 1.4.2.1 2001/09/27 19:03:54 jason Exp $");
1.1 markus 27:
28: #include "ssh2.h"
29: #include "auth.h"
30: #include "packet.h"
31: #include "xmalloc.h"
32: #include "dispatch.h"
1.4.2.1 jason 33: #include "auth.h"
1.2 markus 34: #include "log.h"
1.1 markus 35:
1.4.2.1 jason 36: static int auth2_challenge_start(Authctxt *);
37: static int send_userauth_info_request(Authctxt *);
38: static void input_userauth_info_response(int, int, void *);
39:
40: #ifdef BSD_AUTH
41: extern KbdintDevice bsdauth_device;
42: #else
43: #ifdef SKEY
44: extern KbdintDevice skey_device;
45: #endif
46: #endif
47:
48: KbdintDevice *devices[] = {
49: #ifdef BSD_AUTH
50: &bsdauth_device,
51: #else
52: #ifdef SKEY
53: &skey_device,
54: #endif
55: #endif
56: NULL
57: };
58:
59: typedef struct KbdintAuthctxt KbdintAuthctxt;
60: struct KbdintAuthctxt
61: {
62: char *devices;
63: void *ctxt;
64: KbdintDevice *device;
65: };
66:
67: static KbdintAuthctxt *
68: kbdint_alloc(const char *devs)
69: {
70: KbdintAuthctxt *kbdintctxt;
71: int i;
72: char buf[1024];
73:
74: kbdintctxt = xmalloc(sizeof(KbdintAuthctxt));
75: if (strcmp(devs, "") == 0) {
76: buf[0] = '\0';
77: for (i = 0; devices[i]; i++) {
78: if (i != 0)
79: strlcat(buf, ",", sizeof(buf));
80: strlcat(buf, devices[i]->name, sizeof(buf));
81: }
82: debug("kbdint_alloc: devices '%s'", buf);
83: kbdintctxt->devices = xstrdup(buf);
84: } else {
85: kbdintctxt->devices = xstrdup(devs);
86: }
87: kbdintctxt->ctxt = NULL;
88: kbdintctxt->device = NULL;
89:
90: return kbdintctxt;
91: }
92: static void
93: kbdint_reset_device(KbdintAuthctxt *kbdintctxt)
94: {
95: if (kbdintctxt->ctxt) {
96: kbdintctxt->device->free_ctx(kbdintctxt->ctxt);
97: kbdintctxt->ctxt = NULL;
98: }
99: kbdintctxt->device = NULL;
100: }
101: static void
102: kbdint_free(KbdintAuthctxt *kbdintctxt)
103: {
104: if (kbdintctxt->device)
105: kbdint_reset_device(kbdintctxt);
106: if (kbdintctxt->devices) {
107: xfree(kbdintctxt->devices);
108: kbdintctxt->devices = NULL;
109: }
110: xfree(kbdintctxt);
111: }
112: /* get next device */
113: static int
114: kbdint_next_device(KbdintAuthctxt *kbdintctxt)
115: {
116: size_t len;
117: char *t;
118: int i;
119:
120: if (kbdintctxt->device)
121: kbdint_reset_device(kbdintctxt);
122: do {
123: len = kbdintctxt->devices ?
124: strcspn(kbdintctxt->devices, ",") : 0;
125:
126: if (len == 0)
127: break;
128: for (i = 0; devices[i]; i++)
129: if (strncmp(kbdintctxt->devices, devices[i]->name, len) == 0)
130: kbdintctxt->device = devices[i];
131: t = kbdintctxt->devices;
132: kbdintctxt->devices = t[len] ? xstrdup(t+len+1) : NULL;
133: xfree(t);
134: debug2("kbdint_next_device: devices %s", kbdintctxt->devices ?
135: kbdintctxt->devices : "<empty>");
136: } while (kbdintctxt->devices && !kbdintctxt->device);
137:
138: return kbdintctxt->device ? 1 : 0;
139: }
1.1 markus 140:
141: /*
1.4.2.2 ! miod 142: * try challenge-response, set authctxt->postponed if we have to
1.1 markus 143: * wait for the response.
144: */
145: int
146: auth2_challenge(Authctxt *authctxt, char *devs)
147: {
1.4.2.1 jason 148: debug("auth2_challenge: user=%s devs=%s",
149: authctxt->user ? authctxt->user : "<nouser>",
150: devs ? devs : "<no devs>");
1.1 markus 151:
1.4.2.1 jason 152: if (authctxt->user == NULL || !devs)
1.1 markus 153: return 0;
1.4.2.1 jason 154: if (authctxt->kbdintctxt == NULL)
155: authctxt->kbdintctxt = kbdint_alloc(devs);
156: return auth2_challenge_start(authctxt);
157: }
158:
159: /* side effect: sets authctxt->postponed if a reply was sent*/
160: static int
161: auth2_challenge_start(Authctxt *authctxt)
162: {
163: KbdintAuthctxt *kbdintctxt = authctxt->kbdintctxt;
164:
165: debug2("auth2_challenge_start: devices %s",
166: kbdintctxt->devices ? kbdintctxt->devices : "<empty>");
167:
168: if (kbdint_next_device(kbdintctxt) == 0) {
169: kbdint_free(kbdintctxt);
170: authctxt->kbdintctxt = NULL;
171: return 0;
172: }
173: debug("auth2_challenge_start: trying authentication method '%s'",
174: kbdintctxt->device->name);
175:
176: if ((kbdintctxt->ctxt = kbdintctxt->device->init_ctx(authctxt)) == NULL) {
177: kbdint_free(kbdintctxt);
178: authctxt->kbdintctxt = NULL;
179: return 0;
180: }
181: if (send_userauth_info_request(authctxt) == 0) {
182: kbdint_free(kbdintctxt);
183: authctxt->kbdintctxt = NULL;
1.1 markus 184: return 0;
1.4.2.1 jason 185: }
1.1 markus 186: dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE,
187: &input_userauth_info_response);
1.4.2.1 jason 188:
1.1 markus 189: authctxt->postponed = 1;
190: return 0;
191: }
192:
1.4.2.1 jason 193: static int
194: send_userauth_info_request(Authctxt *authctxt)
1.1 markus 195: {
1.4.2.1 jason 196: KbdintAuthctxt *kbdintctxt;
197: char *name, *instr, **prompts;
198: int i;
199: u_int numprompts, *echo_on;
200:
201: kbdintctxt = authctxt->kbdintctxt;
202: if (kbdintctxt->device->query(kbdintctxt->ctxt,
203: &name, &instr, &numprompts, &prompts, &echo_on))
204: return 0;
1.1 markus 205:
206: packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);
1.4.2.1 jason 207: packet_put_cstring(name);
208: packet_put_cstring(instr);
209: packet_put_cstring(""); /* language not used */
210: packet_put_int(numprompts);
211: for (i = 0; i < numprompts; i++) {
212: packet_put_cstring(prompts[i]);
213: packet_put_char(echo_on[i]);
214: }
1.1 markus 215: packet_send();
216: packet_write_wait();
1.4.2.1 jason 217:
218: for (i = 0; i < numprompts; i++)
219: xfree(prompts[i]);
220: xfree(prompts);
221: xfree(echo_on);
222: xfree(name);
223: xfree(instr);
224: return 1;
1.1 markus 225: }
226:
1.4.2.1 jason 227: static void
1.1 markus 228: input_userauth_info_response(int type, int plen, void *ctxt)
229: {
230: Authctxt *authctxt = ctxt;
1.4.2.1 jason 231: KbdintAuthctxt *kbdintctxt;
232: int i, authenticated = 0, res, len;
233: u_int nresp;
234: char **response = NULL, *method;
1.1 markus 235:
236: if (authctxt == NULL)
237: fatal("input_userauth_info_response: no authctxt");
1.4.2.1 jason 238: kbdintctxt = authctxt->kbdintctxt;
239: if (kbdintctxt == NULL || kbdintctxt->ctxt == NULL)
240: fatal("input_userauth_info_response: no kbdintctxt");
241: if (kbdintctxt->device == NULL)
242: fatal("input_userauth_info_response: no device");
1.1 markus 243:
244: authctxt->postponed = 0; /* reset */
245: nresp = packet_get_int();
1.4.2.1 jason 246: if (nresp > 0) {
247: response = xmalloc(nresp * sizeof(char*));
248: for (i = 0; i < nresp; i++)
249: response[i] = packet_get_string(NULL);
250: }
251: packet_done();
252:
253: if (authctxt->valid) {
254: res = kbdintctxt->device->respond(kbdintctxt->ctxt,
255: nresp, response);
256: } else {
257: res = -1;
258: }
259:
260: for (i = 0; i < nresp; i++) {
261: memset(response[i], 'r', strlen(response[i]));
262: xfree(response[i]);
263: }
264: if (response)
1.1 markus 265: xfree(response);
1.4.2.1 jason 266:
267: switch (res) {
268: case 0:
269: /* Success! */
270: authenticated = 1;
271: break;
272: case 1:
273: /* Authentication needs further interaction */
274: authctxt->postponed = 1;
275: if (send_userauth_info_request(authctxt) == 0) {
276: authctxt->postponed = 0;
277: }
278: break;
279: default:
280: /* Failure! */
281: break;
1.1 markus 282: }
1.4.2.1 jason 283:
284: len = strlen("keyboard-interactive") + 2 +
285: strlen(kbdintctxt->device->name);
286: method = xmalloc(len);
287: method[0] = '\0';
288: strlcat(method, "keyboard-interactive", len);
289: strlcat(method, "/", len);
290: strlcat(method, kbdintctxt->device->name, len);
291:
292: if (!authctxt->postponed) {
293: /* unregister callback */
1.1 markus 294: dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
1.4 markus 295:
1.4.2.1 jason 296: if (authenticated) {
297: kbdint_free(kbdintctxt);
298: authctxt->kbdintctxt = NULL;
299: } else {
300: /* start next device */
301: /* may set authctxt->postponed */
302: auth2_challenge_start(authctxt);
303: }
304: }
1.4 markus 305: userauth_finish(authctxt, authenticated, method);
1.4.2.1 jason 306: xfree(method);
1.1 markus 307: }