diff options
author | Ben Lindstrom <mouring@eviladmin.org> | 2001-06-05 18:56:16 +0000 |
---|---|---|
committer | Ben Lindstrom <mouring@eviladmin.org> | 2001-06-05 18:56:16 +0000 |
commit | 551ea37576333968c760f3f080a8dfe51ca9b06a (patch) | |
tree | 824a61c317213749b57ba877a700ff7102ea4dd7 /auth2-chall.c | |
parent | c4bcb7d9e3a381a4dd5048ee23e4bd2cd6023de7 (diff) |
- markus@cvs.openbsd.org 2001/05/18 14:13:29
[auth-chall.c auth.h auth1.c auth2-chall.c auth2.c readconf.c
readconf.h servconf.c servconf.h sshconnect1.c sshconnect2.c sshd.c]
improved kbd-interactive support. work by per@appgate.com and me
Diffstat (limited to 'auth2-chall.c')
-rw-r--r-- | auth2-chall.c | 279 |
1 files changed, 237 insertions, 42 deletions
diff --git a/auth2-chall.c b/auth2-chall.c index 5af60e42f..ad4f7ac42 100644 --- a/auth2-chall.c +++ b/auth2-chall.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2001 Markus Friedl. All rights reserved. | 2 | * Copyright (c) 2001 Markus Friedl. All rights reserved. |
3 | * Copyright (c) 2001 Per Allansson. All rights reserved. | ||
3 | * | 4 | * |
4 | * Redistribution and use in source and binary forms, with or without | 5 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions | 6 | * modification, are permitted provided that the following conditions |
@@ -22,91 +23,285 @@ | |||
22 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 23 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
23 | */ | 24 | */ |
24 | #include "includes.h" | 25 | #include "includes.h" |
25 | RCSID("$OpenBSD: auth2-chall.c,v 1.4 2001/03/28 22:43:31 markus Exp $"); | 26 | RCSID("$OpenBSD: auth2-chall.c,v 1.5 2001/05/18 14:13:28 markus Exp $"); |
26 | 27 | ||
27 | #include "ssh2.h" | 28 | #include "ssh2.h" |
28 | #include "auth.h" | 29 | #include "auth.h" |
29 | #include "packet.h" | 30 | #include "packet.h" |
30 | #include "xmalloc.h" | 31 | #include "xmalloc.h" |
31 | #include "dispatch.h" | 32 | #include "dispatch.h" |
33 | #include "auth.h" | ||
32 | #include "log.h" | 34 | #include "log.h" |
33 | 35 | ||
34 | void send_userauth_into_request(Authctxt *authctxt, char *challenge, int echo); | 36 | static int auth2_challenge_start(Authctxt *authctxt); |
35 | void input_userauth_info_response(int type, int plen, void *ctxt); | 37 | static int send_userauth_info_request(Authctxt *authctxt); |
38 | static void input_userauth_info_response(int type, int plen, void *ctxt); | ||
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 | 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 | 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 | 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 | 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 | } | ||
36 | 140 | ||
37 | /* | 141 | /* |
38 | * try challenge-reponse, return -1 (= postponed) if we have to | 142 | * try challenge-reponse, set authctxt->postponed if we have to |
39 | * wait for the response. | 143 | * wait for the response. |
40 | */ | 144 | */ |
41 | int | 145 | int |
42 | auth2_challenge(Authctxt *authctxt, char *devs) | 146 | auth2_challenge(Authctxt *authctxt, char *devs) |
43 | { | 147 | { |
44 | char *challenge; | 148 | debug("auth2_challenge: user=%s devs=%s", |
149 | authctxt->user ? authctxt->user : "<nouser>", | ||
150 | devs ? devs : "<no devs>"); | ||
151 | |||
152 | if (!authctxt->valid || authctxt->user == NULL || !devs) | ||
153 | return 0; | ||
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); | ||
45 | 175 | ||
46 | if (!authctxt->valid || authctxt->user == NULL) | 176 | if ((kbdintctxt->ctxt = kbdintctxt->device->init_ctx(authctxt)) == NULL) { |
177 | kbdint_free(kbdintctxt); | ||
178 | authctxt->kbdintctxt = NULL; | ||
47 | return 0; | 179 | return 0; |
48 | if ((challenge = get_challenge(authctxt, devs)) == NULL) | 180 | } |
181 | if (send_userauth_info_request(authctxt) == 0) { | ||
182 | kbdint_free(kbdintctxt); | ||
183 | authctxt->kbdintctxt = NULL; | ||
49 | return 0; | 184 | return 0; |
50 | send_userauth_into_request(authctxt, challenge, 0); | 185 | } |
51 | dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, | 186 | dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, |
52 | &input_userauth_info_response); | 187 | &input_userauth_info_response); |
188 | |||
53 | authctxt->postponed = 1; | 189 | authctxt->postponed = 1; |
54 | return 0; | 190 | return 0; |
55 | } | 191 | } |
56 | 192 | ||
57 | void | 193 | static int |
58 | send_userauth_into_request(Authctxt *authctxt, char *challenge, int echo) | 194 | send_userauth_info_request(Authctxt *authctxt) |
59 | { | 195 | { |
60 | int nprompts = 1; | 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; | ||
61 | 205 | ||
62 | packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST); | 206 | packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST); |
63 | /* name, instruction and language are unused */ | 207 | packet_put_cstring(name); |
64 | packet_put_cstring(""); | 208 | packet_put_cstring(instr); |
65 | packet_put_cstring(""); | 209 | packet_put_cstring(""); /* language not used */ |
66 | packet_put_cstring(""); | 210 | packet_put_int(numprompts); |
67 | packet_put_int(nprompts); | 211 | for (i = 0; i < numprompts; i++) { |
68 | packet_put_cstring(challenge); | 212 | packet_put_cstring(prompts[i]); |
69 | packet_put_char(echo); | 213 | packet_put_char(echo_on[i]); |
214 | } | ||
70 | packet_send(); | 215 | packet_send(); |
71 | packet_write_wait(); | 216 | packet_write_wait(); |
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; | ||
72 | } | 225 | } |
73 | 226 | ||
74 | void | 227 | static void |
75 | input_userauth_info_response(int type, int plen, void *ctxt) | 228 | input_userauth_info_response(int type, int plen, void *ctxt) |
76 | { | 229 | { |
77 | Authctxt *authctxt = ctxt; | 230 | Authctxt *authctxt = ctxt; |
78 | int authenticated = 0; | 231 | KbdintAuthctxt *kbdintctxt; |
79 | u_int nresp, rlen; | 232 | int i, authenticated = 0, res, len; |
80 | char *response, *method = "challenge-reponse"; | 233 | u_int nresp; |
234 | char **response = NULL, *method; | ||
81 | 235 | ||
82 | if (authctxt == NULL) | 236 | if (authctxt == NULL) |
83 | fatal("input_userauth_info_response: no authctxt"); | 237 | fatal("input_userauth_info_response: no authctxt"); |
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"); | ||
84 | 243 | ||
85 | authctxt->postponed = 0; /* reset */ | 244 | authctxt->postponed = 0; /* reset */ |
86 | nresp = packet_get_int(); | 245 | nresp = packet_get_int(); |
87 | if (nresp == 1) { | 246 | if (nresp > 0) { |
88 | response = packet_get_string(&rlen); | 247 | response = xmalloc(nresp * sizeof(char*)); |
89 | packet_done(); | 248 | for (i = 0; i < nresp; i++) |
90 | if (strlen(response) == 0) { | 249 | response[i] = packet_get_string(NULL); |
91 | /* | 250 | } |
92 | * if we received an empty response, resend challenge | 251 | packet_done(); |
93 | * with echo enabled | 252 | |
94 | */ | 253 | if (authctxt->valid) { |
95 | char *challenge = get_challenge(authctxt, NULL); | 254 | res = kbdintctxt->device->respond(kbdintctxt->ctxt, |
96 | if (challenge != NULL) { | 255 | nresp, response); |
97 | send_userauth_into_request(authctxt, | 256 | } else { |
98 | challenge, 1); | 257 | res = -1; |
99 | authctxt->postponed = 1; | 258 | } |
100 | } | 259 | |
101 | } else if (authctxt->valid) { | 260 | for (i = 0; i < nresp; i++) { |
102 | authenticated = verify_response(authctxt, response); | 261 | memset(response[i], 'r', strlen(response[i])); |
103 | memset(response, 'r', rlen); | 262 | xfree(response[i]); |
104 | } | 263 | } |
264 | if (response) | ||
105 | xfree(response); | 265 | xfree(response); |
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; | ||
106 | } | 282 | } |
107 | /* unregister callback */ | 283 | |
108 | if (!authctxt->postponed) | 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 */ | ||
109 | dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL); | 294 | dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL); |
110 | 295 | ||
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 | } | ||
111 | userauth_finish(authctxt, authenticated, method); | 305 | userauth_finish(authctxt, authenticated, method); |
306 | xfree(method); | ||
112 | } | 307 | } |