diff options
Diffstat (limited to 'auth2.c')
-rw-r--r-- | auth2.c | 428 |
1 files changed, 286 insertions, 142 deletions
@@ -23,7 +23,12 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include "includes.h" | 25 | #include "includes.h" |
26 | RCSID("$OpenBSD: auth2.c,v 1.16 2000/09/27 21:41:34 markus Exp $"); | 26 | RCSID("$OpenBSD: auth2.c,v 1.19 2000/10/11 20:27:23 markus Exp $"); |
27 | |||
28 | #ifdef HAVE_OSF_SIA | ||
29 | # include <sia.h> | ||
30 | # include <siad.h> | ||
31 | #endif | ||
27 | 32 | ||
28 | #include <openssl/dsa.h> | 33 | #include <openssl/dsa.h> |
29 | #include <openssl/rsa.h> | 34 | #include <openssl/rsa.h> |
@@ -35,7 +40,6 @@ RCSID("$OpenBSD: auth2.c,v 1.16 2000/09/27 21:41:34 markus Exp $"); | |||
35 | #include "pty.h" | 40 | #include "pty.h" |
36 | #include "packet.h" | 41 | #include "packet.h" |
37 | #include "buffer.h" | 42 | #include "buffer.h" |
38 | #include "cipher.h" | ||
39 | #include "servconf.h" | 43 | #include "servconf.h" |
40 | #include "compat.h" | 44 | #include "compat.h" |
41 | #include "channels.h" | 45 | #include "channels.h" |
@@ -52,59 +56,85 @@ RCSID("$OpenBSD: auth2.c,v 1.16 2000/09/27 21:41:34 markus Exp $"); | |||
52 | #include "uidswap.h" | 56 | #include "uidswap.h" |
53 | #include "auth-options.h" | 57 | #include "auth-options.h" |
54 | 58 | ||
55 | #ifdef HAVE_OSF_SIA | ||
56 | # include <sia.h> | ||
57 | # include <siad.h> | ||
58 | #endif | ||
59 | |||
60 | /* import */ | 59 | /* import */ |
61 | extern ServerOptions options; | 60 | extern ServerOptions options; |
62 | extern unsigned char *session_id2; | 61 | extern unsigned char *session_id2; |
63 | extern int session_id2_len; | 62 | extern int session_id2_len; |
64 | 63 | ||
64 | #ifdef WITH_AIXAUTHENTICATE | ||
65 | extern char *aixloginmsg; | ||
66 | #endif | ||
67 | #ifdef HAVE_OSF_SIA | ||
68 | extern int saved_argc; | ||
69 | extern char **saved_argv; | ||
70 | #endif | ||
71 | |||
72 | static Authctxt *x_authctxt = NULL; | ||
73 | static int one = 1; | ||
74 | |||
75 | typedef struct Authmethod Authmethod; | ||
76 | struct Authmethod { | ||
77 | char *name; | ||
78 | int (*userauth)(Authctxt *authctxt); | ||
79 | int *enabled; | ||
80 | }; | ||
81 | |||
65 | /* protocol */ | 82 | /* protocol */ |
66 | 83 | ||
67 | void input_service_request(int type, int plen, void *ctxt); | 84 | void input_service_request(int type, int plen, void *ctxt); |
68 | void input_userauth_request(int type, int plen, void *ctxt); | 85 | void input_userauth_request(int type, int plen, void *ctxt); |
69 | void protocol_error(int type, int plen, void *ctxt); | 86 | void protocol_error(int type, int plen, void *ctxt); |
70 | 87 | ||
71 | /* auth */ | ||
72 | int ssh2_auth_none(struct passwd *pw); | ||
73 | int ssh2_auth_password(struct passwd *pw); | ||
74 | int ssh2_auth_pubkey(struct passwd *pw, char *service); | ||
75 | 88 | ||
76 | /* helper */ | 89 | /* helper */ |
77 | struct passwd* auth_set_user(char *u, char *s); | 90 | Authmethod *authmethod_lookup(const char *name); |
91 | struct passwd *pwcopy(struct passwd *pw); | ||
78 | int user_dsa_key_allowed(struct passwd *pw, Key *key); | 92 | int user_dsa_key_allowed(struct passwd *pw, Key *key); |
93 | char *authmethods_get(void); | ||
79 | 94 | ||
80 | typedef struct Authctxt Authctxt; | 95 | /* auth */ |
81 | struct Authctxt { | 96 | int userauth_none(Authctxt *authctxt); |
82 | char *user; | 97 | int userauth_passwd(Authctxt *authctxt); |
83 | char *service; | 98 | int userauth_pubkey(Authctxt *authctxt); |
84 | struct passwd pw; | 99 | int userauth_kbdint(Authctxt *authctxt); |
85 | int valid; | 100 | |
101 | Authmethod authmethods[] = { | ||
102 | {"none", | ||
103 | userauth_none, | ||
104 | &one}, | ||
105 | {"publickey", | ||
106 | userauth_pubkey, | ||
107 | &options.dsa_authentication}, | ||
108 | {"keyboard-interactive", | ||
109 | userauth_kbdint, | ||
110 | &options.kbd_interactive_authentication}, | ||
111 | {"password", | ||
112 | userauth_passwd, | ||
113 | &options.password_authentication}, | ||
114 | {NULL, NULL, NULL} | ||
86 | }; | 115 | }; |
87 | static Authctxt *authctxt = NULL; | ||
88 | static int userauth_success = 0; | ||
89 | 116 | ||
90 | /* | 117 | /* |
91 | * loop until userauth_success == TRUE | 118 | * loop until authctxt->success == TRUE |
92 | */ | 119 | */ |
93 | 120 | ||
94 | void | 121 | void |
95 | do_authentication2() | 122 | do_authentication2() |
96 | { | 123 | { |
97 | /* turn off skey/kerberos, not supported by SSH2 */ | 124 | Authctxt *authctxt = xmalloc(sizeof(*authctxt)); |
98 | #ifdef SKEY | 125 | memset(authctxt, 'a', sizeof(*authctxt)); |
99 | options.skey_authentication = 0; | 126 | authctxt->valid = 0; |
100 | #endif | 127 | authctxt->attempt = 0; |
128 | authctxt->success = 0; | ||
129 | x_authctxt = authctxt; /*XXX*/ | ||
130 | |||
101 | #ifdef KRB4 | 131 | #ifdef KRB4 |
132 | /* turn off kerberos, not supported by SSH2 */ | ||
102 | options.kerberos_authentication = 0; | 133 | options.kerberos_authentication = 0; |
103 | #endif | 134 | #endif |
104 | |||
105 | dispatch_init(&protocol_error); | 135 | dispatch_init(&protocol_error); |
106 | dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request); | 136 | dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request); |
107 | dispatch_run(DISPATCH_BLOCK, &userauth_success, NULL); | 137 | dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt); |
108 | do_authenticated2(); | 138 | do_authenticated2(); |
109 | } | 139 | } |
110 | 140 | ||
@@ -121,13 +151,17 @@ protocol_error(int type, int plen, void *ctxt) | |||
121 | void | 151 | void |
122 | input_service_request(int type, int plen, void *ctxt) | 152 | input_service_request(int type, int plen, void *ctxt) |
123 | { | 153 | { |
154 | Authctxt *authctxt = ctxt; | ||
124 | unsigned int len; | 155 | unsigned int len; |
125 | int accept = 0; | 156 | int accept = 0; |
126 | char *service = packet_get_string(&len); | 157 | char *service = packet_get_string(&len); |
127 | packet_done(); | 158 | packet_done(); |
128 | 159 | ||
160 | if (authctxt == NULL) | ||
161 | fatal("input_service_request: no authctxt"); | ||
162 | |||
129 | if (strcmp(service, "ssh-userauth") == 0) { | 163 | if (strcmp(service, "ssh-userauth") == 0) { |
130 | if (!userauth_success) { | 164 | if (!authctxt->success) { |
131 | accept = 1; | 165 | accept = 1; |
132 | /* now we can handle user-auth requests */ | 166 | /* now we can handle user-auth requests */ |
133 | dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request); | 167 | dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request); |
@@ -150,65 +184,99 @@ input_service_request(int type, int plen, void *ctxt) | |||
150 | void | 184 | void |
151 | input_userauth_request(int type, int plen, void *ctxt) | 185 | input_userauth_request(int type, int plen, void *ctxt) |
152 | { | 186 | { |
153 | static void (*authlog) (const char *fmt,...) = verbose; | 187 | Authctxt *authctxt = ctxt; |
154 | static int attempt = 0; | 188 | Authmethod *m = NULL; |
155 | unsigned int len; | 189 | char *user, *service, *method; |
156 | int authenticated = 0; | 190 | int authenticated = 0; |
157 | char *user, *service, *method, *authmsg = NULL; | ||
158 | struct passwd *pw; | ||
159 | #ifdef WITH_AIXAUTHENTICATE | ||
160 | extern char *aixloginmsg; | ||
161 | #endif /* WITH_AIXAUTHENTICATE */ | ||
162 | 191 | ||
163 | user = packet_get_string(&len); | 192 | if (authctxt == NULL) |
164 | service = packet_get_string(&len); | 193 | fatal("input_userauth_request: no authctxt"); |
165 | method = packet_get_string(&len); | 194 | if (authctxt->attempt++ >= AUTH_FAIL_MAX) { |
166 | if (++attempt == AUTH_FAIL_MAX) { | ||
167 | #ifdef WITH_AIXAUTHENTICATE | 195 | #ifdef WITH_AIXAUTHENTICATE |
168 | loginfailed(user,get_canonical_hostname(),"ssh"); | 196 | loginfailed(user,get_canonical_hostname(),"ssh"); |
169 | #endif /* WITH_AIXAUTHENTICATE */ | 197 | #endif /* WITH_AIXAUTHENTICATE */ |
170 | packet_disconnect("too many failed userauth_requests"); | 198 | packet_disconnect("too many failed userauth_requests"); |
171 | } | 199 | } |
172 | debug("userauth-request for user %s service %s method %s", user, service, method); | ||
173 | 200 | ||
174 | /* XXX we only allow the ssh-connection service */ | 201 | user = packet_get_string(NULL); |
175 | pw = auth_set_user(user, service); | 202 | service = packet_get_string(NULL); |
176 | if (pw && strcmp(service, "ssh-connection")==0) { | 203 | method = packet_get_string(NULL); |
177 | if (strcmp(method, "none") == 0) { | 204 | debug("userauth-request for user %s service %s method %s", user, service, method); |
178 | authenticated = ssh2_auth_none(pw); | 205 | debug("attempt #%d", authctxt->attempt); |
179 | } else if (strcmp(method, "password") == 0) { | 206 | |
180 | authenticated = ssh2_auth_password(pw); | 207 | if (authctxt->attempt == 1) { |
181 | } else if (strcmp(method, "publickey") == 0) { | 208 | /* setup auth context */ |
182 | authenticated = ssh2_auth_pubkey(pw, service); | 209 | struct passwd *pw = NULL; |
210 | setproctitle("%s", user); | ||
211 | pw = getpwnam(user); | ||
212 | if (pw && allowed_user(pw) && strcmp(service, "ssh-connection")==0) { | ||
213 | authctxt->pw = pwcopy(pw); | ||
214 | authctxt->valid = 1; | ||
215 | debug2("input_userauth_request: setting up authctxt for %s", user); | ||
216 | #ifdef USE_PAM | ||
217 | start_pam(pw); | ||
218 | #endif | ||
219 | } else { | ||
220 | log("input_userauth_request: illegal user %s", user); | ||
221 | } | ||
222 | authctxt->user = xstrdup(user); | ||
223 | authctxt->service = xstrdup(service); | ||
224 | } else if (authctxt->valid) { | ||
225 | if (strcmp(user, authctxt->user) != 0 || | ||
226 | strcmp(service, authctxt->service) != 0) { | ||
227 | log("input_userauth_request: missmatch: (%s,%s)!=(%s,%s)", | ||
228 | user, service, authctxt->user, authctxt->service); | ||
229 | authctxt->valid = 0; | ||
183 | } | 230 | } |
184 | } | 231 | } |
185 | 232 | ||
186 | #ifdef HAVE_CYGWIN | 233 | m = authmethod_lookup(method); |
187 | if (authenticated && !check_nt_auth(strcmp(method, "password") == 0, pw->pw_uid)) { | 234 | if (m != NULL) { |
188 | packet_disconnect("Authentication rejected for uid %d.", | 235 | debug2("input_userauth_request: try method %s", method); |
189 | (int) pw->pw_uid); | 236 | authenticated = m->userauth(authctxt); |
237 | } else { | ||
238 | debug2("input_userauth_request: unsupported method %s", method); | ||
239 | } | ||
240 | if (!authctxt->valid && authenticated == 1) { | ||
241 | log("input_userauth_request: INTERNAL ERROR: authenticated invalid user %s service %s", user, method); | ||
190 | authenticated = 0; | 242 | authenticated = 0; |
191 | } | 243 | } |
192 | #endif | ||
193 | 244 | ||
194 | if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) { | 245 | /* Special handling for root */ |
246 | if (authenticated == 1 && | ||
247 | authctxt->valid && authctxt->pw->pw_uid == 0 && !options.permit_root_login) { | ||
195 | authenticated = 0; | 248 | authenticated = 0; |
196 | log("ROOT LOGIN REFUSED FROM %.200s", | 249 | log("ROOT LOGIN REFUSED FROM %.200s", get_canonical_hostname()); |
197 | get_canonical_hostname()); | ||
198 | } | 250 | } |
199 | 251 | ||
200 | #ifdef USE_PAM | 252 | #ifdef USE_PAM |
201 | if (authenticated && !do_pam_account(pw->pw_name, NULL)) | 253 | if (authenticated && !do_pam_account(authctxt->pw->pw_name, NULL)) |
202 | authenticated = 0; | 254 | authenticated = 0; |
203 | #endif /* USE_PAM */ | 255 | #endif /* USE_PAM */ |
204 | 256 | ||
257 | /* Log before sending the reply */ | ||
258 | userauth_log(authctxt, authenticated, method); | ||
259 | userauth_reply(authctxt, authenticated); | ||
260 | |||
261 | xfree(service); | ||
262 | xfree(user); | ||
263 | xfree(method); | ||
264 | } | ||
265 | |||
266 | |||
267 | void | ||
268 | userauth_log(Authctxt *authctxt, int authenticated, char *method) | ||
269 | { | ||
270 | void (*authlog) (const char *fmt,...) = verbose; | ||
271 | char *user = NULL, *authmsg = NULL; | ||
272 | |||
205 | /* Raise logging level */ | 273 | /* Raise logging level */ |
206 | if (authenticated == 1 || | 274 | if (authenticated == 1 || |
207 | attempt == AUTH_FAIL_LOG || | 275 | !authctxt->valid || |
276 | authctxt->attempt >= AUTH_FAIL_LOG || | ||
208 | strcmp(method, "password") == 0) | 277 | strcmp(method, "password") == 0) |
209 | authlog = log; | 278 | authlog = log; |
210 | 279 | ||
211 | /* Log before sending the reply */ | ||
212 | if (authenticated == 1) { | 280 | if (authenticated == 1) { |
213 | authmsg = "Accepted"; | 281 | authmsg = "Accepted"; |
214 | } else if (authenticated == 0) { | 282 | } else if (authenticated == 0) { |
@@ -216,18 +284,29 @@ input_userauth_request(int type, int plen, void *ctxt) | |||
216 | } else { | 284 | } else { |
217 | authmsg = "Postponed"; | 285 | authmsg = "Postponed"; |
218 | } | 286 | } |
287 | |||
288 | if (authctxt->valid) { | ||
289 | user = authctxt->pw->pw_uid == 0 ? "ROOT" : authctxt->user; | ||
290 | } else { | ||
291 | user = "NOUSER"; | ||
292 | } | ||
293 | |||
219 | authlog("%s %s for %.200s from %.200s port %d ssh2", | 294 | authlog("%s %s for %.200s from %.200s port %d ssh2", |
220 | authmsg, | 295 | authmsg, |
221 | method, | 296 | method, |
222 | pw && pw->pw_uid == 0 ? "ROOT" : user, | 297 | user, |
223 | get_remote_ipaddr(), | 298 | get_remote_ipaddr(), |
224 | get_remote_port()); | 299 | get_remote_port()); |
300 | } | ||
225 | 301 | ||
302 | void | ||
303 | userauth_reply(Authctxt *authctxt, int authenticated) | ||
304 | { | ||
226 | /* XXX todo: check if multiple auth methods are needed */ | 305 | /* XXX todo: check if multiple auth methods are needed */ |
227 | if (authenticated == 1) { | 306 | if (authenticated == 1) { |
228 | #ifdef WITH_AIXAUTHENTICATE | 307 | #ifdef WITH_AIXAUTHENTICATE |
229 | /* We don't have a pty yet, so just label the line as "ssh" */ | 308 | /* We don't have a pty yet, so just label the line as "ssh" */ |
230 | if (loginsuccess(user,get_canonical_hostname(),"ssh", | 309 | if (loginsuccess(user, get_canonical_hostname(), "ssh", |
231 | &aixloginmsg) < 0) | 310 | &aixloginmsg) < 0) |
232 | aixloginmsg = NULL; | 311 | aixloginmsg = NULL; |
233 | #endif /* WITH_AIXAUTHENTICATE */ | 312 | #endif /* WITH_AIXAUTHENTICATE */ |
@@ -237,73 +316,106 @@ input_userauth_request(int type, int plen, void *ctxt) | |||
237 | packet_send(); | 316 | packet_send(); |
238 | packet_write_wait(); | 317 | packet_write_wait(); |
239 | /* now we can break out */ | 318 | /* now we can break out */ |
240 | userauth_success = 1; | 319 | authctxt->success = 1; |
241 | } else if (authenticated == 0) { | 320 | } else if (authenticated == 0) { |
321 | char *methods = authmethods_get(); | ||
242 | packet_start(SSH2_MSG_USERAUTH_FAILURE); | 322 | packet_start(SSH2_MSG_USERAUTH_FAILURE); |
243 | packet_put_cstring("publickey,password"); /* XXX dynamic */ | 323 | packet_put_cstring(methods); |
244 | packet_put_char(0); /* XXX partial success, unused */ | 324 | packet_put_char(0); /* XXX partial success, unused */ |
245 | packet_send(); | 325 | packet_send(); |
246 | packet_write_wait(); | 326 | packet_write_wait(); |
327 | xfree(methods); | ||
328 | } else { | ||
329 | /* do nothing, we did already send a reply */ | ||
247 | } | 330 | } |
248 | |||
249 | xfree(service); | ||
250 | xfree(user); | ||
251 | xfree(method); | ||
252 | } | 331 | } |
253 | 332 | ||
254 | int | 333 | int |
255 | ssh2_auth_none(struct passwd *pw) | 334 | userauth_none(Authctxt *authctxt) |
256 | { | 335 | { |
257 | #ifdef HAVE_OSF_SIA | 336 | /* disable method "none", only allowed one time */ |
258 | extern int saved_argc; | 337 | Authmethod *m = authmethod_lookup("none"); |
259 | extern char **saved_argv; | 338 | if (m != NULL) |
260 | #endif | 339 | m->enabled = NULL; |
261 | |||
262 | packet_done(); | 340 | packet_done(); |
263 | 341 | ||
342 | if (authctxt->valid == 0) | ||
343 | return(0); | ||
344 | |||
345 | #ifdef HAVE_CYGWIN | ||
346 | if (check_nt_auth(1, authctxt->pw->pw_uid) == 0) | ||
347 | return(0); | ||
348 | #endif | ||
264 | #ifdef USE_PAM | 349 | #ifdef USE_PAM |
265 | return auth_pam_password(pw, ""); | 350 | return auth_pam_password(authctxt->pw, ""); |
266 | #elif defined(HAVE_OSF_SIA) | 351 | #elif defined(HAVE_OSF_SIA) |
267 | return(sia_validate_user(NULL, saved_argc, saved_argv, | 352 | return (sia_validate_user(NULL, saved_argc, saved_argv, |
268 | get_canonical_hostname(), pw->pw_name, NULL, 0, NULL, | 353 | get_canonical_hostname(), authctxt->pw->pw_name, NULL, |
269 | "") == SIASUCCESS); | 354 | 0, NULL, "") == SIASUCCESS); |
270 | #else /* !HAVE_OSF_SIA && !USE_PAM */ | 355 | #else /* !HAVE_OSF_SIA && !USE_PAM */ |
271 | return auth_password(pw, ""); | 356 | return auth_password(authctxt->pw, ""); |
272 | #endif /* USE_PAM */ | 357 | #endif /* USE_PAM */ |
273 | } | 358 | } |
359 | |||
274 | int | 360 | int |
275 | ssh2_auth_password(struct passwd *pw) | 361 | userauth_passwd(Authctxt *authctxt) |
276 | { | 362 | { |
277 | char *password; | 363 | char *password; |
278 | int authenticated = 0; | 364 | int authenticated = 0; |
279 | int change; | 365 | int change; |
280 | unsigned int len; | 366 | unsigned int len; |
281 | #ifdef HAVE_OSF_SIA | ||
282 | extern int saved_argc; | ||
283 | extern char **saved_argv; | ||
284 | #endif | ||
285 | change = packet_get_char(); | 367 | change = packet_get_char(); |
286 | if (change) | 368 | if (change) |
287 | log("password change not supported"); | 369 | log("password change not supported"); |
288 | password = packet_get_string(&len); | 370 | password = packet_get_string(&len); |
289 | packet_done(); | 371 | packet_done(); |
290 | if (options.password_authentication && | 372 | if (authctxt->valid && |
373 | #ifdef HAVE_CYGWIN | ||
374 | check_nt_auth(1, authctxt->pw->pw_uid) && | ||
375 | #endif | ||
291 | #ifdef USE_PAM | 376 | #ifdef USE_PAM |
292 | auth_pam_password(pw, password) == 1) | 377 | auth_pam_password(authctxt->pw, password) == 1) |
293 | #elif defined(HAVE_OSF_SIA) | 378 | #elif defined(HAVE_OSF_SIA) |
294 | sia_validate_user(NULL, saved_argc, saved_argv, | 379 | sia_validate_user(NULL, saved_argc, saved_argv, |
295 | get_canonical_hostname(), pw->pw_name, NULL, 0, | 380 | get_canonical_hostname(), authctxt->pw->pw_name, NULL, 0, |
296 | NULL, password) == SIASUCCESS) | 381 | NULL, password) == SIASUCCESS) |
297 | #else /* !USE_PAM && !HAVE_OSF_SIA */ | 382 | #else /* !USE_PAM && !HAVE_OSF_SIA */ |
298 | auth_password(pw, password) == 1) | 383 | auth_password(authctxt->pw, password) == 1) |
299 | #endif /* USE_PAM */ | 384 | #endif /* USE_PAM */ |
300 | authenticated = 1; | 385 | authenticated = 1; |
301 | memset(password, 0, len); | 386 | memset(password, 0, len); |
302 | xfree(password); | 387 | xfree(password); |
303 | return authenticated; | 388 | return authenticated; |
304 | } | 389 | } |
390 | |||
391 | int | ||
392 | userauth_kbdint(Authctxt *authctxt) | ||
393 | { | ||
394 | int authenticated = 0; | ||
395 | char *lang = NULL; | ||
396 | char *devs = NULL; | ||
397 | |||
398 | lang = packet_get_string(NULL); | ||
399 | devs = packet_get_string(NULL); | ||
400 | packet_done(); | ||
401 | |||
402 | debug("keyboard-interactive language %s devs %s", lang, devs); | ||
403 | #ifdef SKEY | ||
404 | /* XXX hardcoded, we should look at devs */ | ||
405 | if (options.skey_authentication != 0) | ||
406 | authenticated = auth2_skey(authctxt); | ||
407 | #endif | ||
408 | xfree(lang); | ||
409 | xfree(devs); | ||
410 | #ifdef HAVE_CYGWIN | ||
411 | if (check_nt_auth(0, authctxt->pw->pw_uid) == 0) | ||
412 | return(0); | ||
413 | #endif | ||
414 | return authenticated; | ||
415 | } | ||
416 | |||
305 | int | 417 | int |
306 | ssh2_auth_pubkey(struct passwd *pw, char *service) | 418 | userauth_pubkey(Authctxt *authctxt) |
307 | { | 419 | { |
308 | Buffer b; | 420 | Buffer b; |
309 | Key *key; | 421 | Key *key; |
@@ -312,15 +424,15 @@ ssh2_auth_pubkey(struct passwd *pw, char *service) | |||
312 | int have_sig; | 424 | int have_sig; |
313 | int authenticated = 0; | 425 | int authenticated = 0; |
314 | 426 | ||
315 | if (options.dsa_authentication == 0) { | 427 | if (!authctxt->valid) { |
316 | debug("pubkey auth disabled"); | 428 | debug2("userauth_pubkey: disabled because of invalid user"); |
317 | return 0; | 429 | return 0; |
318 | } | 430 | } |
319 | have_sig = packet_get_char(); | 431 | have_sig = packet_get_char(); |
320 | pkalg = packet_get_string(&alen); | 432 | pkalg = packet_get_string(&alen); |
321 | if (strcmp(pkalg, KEX_DSS) != 0) { | 433 | if (strcmp(pkalg, KEX_DSS) != 0) { |
322 | xfree(pkalg); | ||
323 | log("bad pkalg %s", pkalg); /*XXX*/ | 434 | log("bad pkalg %s", pkalg); /*XXX*/ |
435 | xfree(pkalg); | ||
324 | return 0; | 436 | return 0; |
325 | } | 437 | } |
326 | pkblob = packet_get_string(&blen); | 438 | pkblob = packet_get_string(&blen); |
@@ -337,11 +449,11 @@ ssh2_auth_pubkey(struct passwd *pw, char *service) | |||
337 | } | 449 | } |
338 | /* reconstruct packet */ | 450 | /* reconstruct packet */ |
339 | buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); | 451 | buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); |
340 | buffer_put_cstring(&b, pw->pw_name); | 452 | buffer_put_cstring(&b, authctxt->user); |
341 | buffer_put_cstring(&b, | 453 | buffer_put_cstring(&b, |
342 | datafellows & SSH_BUG_PUBKEYAUTH ? | 454 | datafellows & SSH_BUG_PUBKEYAUTH ? |
343 | "ssh-userauth" : | 455 | "ssh-userauth" : |
344 | service); | 456 | authctxt->service); |
345 | buffer_put_cstring(&b, "publickey"); | 457 | buffer_put_cstring(&b, "publickey"); |
346 | buffer_put_char(&b, have_sig); | 458 | buffer_put_char(&b, have_sig); |
347 | buffer_put_cstring(&b, KEX_DSS); | 459 | buffer_put_cstring(&b, KEX_DSS); |
@@ -350,15 +462,15 @@ ssh2_auth_pubkey(struct passwd *pw, char *service) | |||
350 | buffer_dump(&b); | 462 | buffer_dump(&b); |
351 | #endif | 463 | #endif |
352 | /* test for correct signature */ | 464 | /* test for correct signature */ |
353 | if (user_dsa_key_allowed(pw, key) && | 465 | if (user_dsa_key_allowed(authctxt->pw, key) && |
354 | dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1) | 466 | dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1) |
355 | authenticated = 1; | 467 | authenticated = 1; |
356 | buffer_clear(&b); | 468 | buffer_clear(&b); |
357 | xfree(sig); | 469 | xfree(sig); |
358 | } else { | 470 | } else { |
471 | debug("test whether pkalg/pkblob are acceptable"); | ||
359 | packet_done(); | 472 | packet_done(); |
360 | debug("test key..."); | 473 | |
361 | /* test whether pkalg/pkblob are acceptable */ | ||
362 | /* XXX fake reply and always send PK_OK ? */ | 474 | /* XXX fake reply and always send PK_OK ? */ |
363 | /* | 475 | /* |
364 | * XXX this allows testing whether a user is allowed | 476 | * XXX this allows testing whether a user is allowed |
@@ -367,7 +479,7 @@ ssh2_auth_pubkey(struct passwd *pw, char *service) | |||
367 | * if a user is not allowed to login. is this an | 479 | * if a user is not allowed to login. is this an |
368 | * issue? -markus | 480 | * issue? -markus |
369 | */ | 481 | */ |
370 | if (user_dsa_key_allowed(pw, key)) { | 482 | if (user_dsa_key_allowed(authctxt->pw, key)) { |
371 | packet_start(SSH2_MSG_USERAUTH_PK_OK); | 483 | packet_start(SSH2_MSG_USERAUTH_PK_OK); |
372 | packet_put_string(pkalg, alen); | 484 | packet_put_string(pkalg, alen); |
373 | packet_put_string(pkblob, blen); | 485 | packet_put_string(pkblob, blen); |
@@ -376,61 +488,73 @@ ssh2_auth_pubkey(struct passwd *pw, char *service) | |||
376 | authenticated = -1; | 488 | authenticated = -1; |
377 | } | 489 | } |
378 | } | 490 | } |
491 | if (authenticated != 1) | ||
492 | auth_clear_options(); | ||
379 | key_free(key); | 493 | key_free(key); |
380 | } | 494 | } |
381 | xfree(pkalg); | 495 | xfree(pkalg); |
382 | xfree(pkblob); | 496 | xfree(pkblob); |
497 | #ifdef HAVE_CYGWIN | ||
498 | if (check_nt_auth(0, authctxt->pw->pw_uid) == 0) | ||
499 | return(0); | ||
500 | #endif | ||
383 | return authenticated; | 501 | return authenticated; |
384 | } | 502 | } |
385 | 503 | ||
386 | /* set and get current user */ | 504 | /* get current user */ |
387 | 505 | ||
388 | struct passwd* | 506 | struct passwd* |
389 | auth_get_user(void) | 507 | auth_get_user(void) |
390 | { | 508 | { |
391 | return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL; | 509 | return (x_authctxt != NULL && x_authctxt->valid) ? x_authctxt->pw : NULL; |
392 | } | 510 | } |
393 | 511 | ||
394 | struct passwd* | 512 | #define DELIM "," |
395 | auth_set_user(char *u, char *s) | 513 | |
514 | char * | ||
515 | authmethods_get(void) | ||
396 | { | 516 | { |
397 | struct passwd *pw, *copy; | 517 | Authmethod *method = NULL; |
398 | 518 | unsigned int size = 0; | |
399 | if (authctxt == NULL) { | 519 | char *list; |
400 | authctxt = xmalloc(sizeof(*authctxt)); | 520 | |
401 | authctxt->valid = 0; | 521 | for (method = authmethods; method->name != NULL; method++) { |
402 | authctxt->user = xstrdup(u); | 522 | if (strcmp(method->name, "none") == 0) |
403 | authctxt->service = xstrdup(s); | 523 | continue; |
404 | setproctitle("%s", u); | 524 | if (method->enabled != NULL && *(method->enabled) != 0) { |
405 | pw = getpwnam(u); | 525 | if (size != 0) |
406 | if (!pw || !allowed_user(pw)) { | 526 | size += strlen(DELIM); |
407 | log("auth_set_user: illegal user %s", u); | 527 | size += strlen(method->name); |
408 | return NULL; | ||
409 | } | 528 | } |
410 | #ifdef USE_PAM | 529 | } |
411 | start_pam(pw); | 530 | size++; /* trailing '\0' */ |
412 | #endif | 531 | list = xmalloc(size); |
413 | copy = &authctxt->pw; | 532 | list[0] = '\0'; |
414 | memset(copy, 0, sizeof(*copy)); | 533 | |
415 | copy->pw_name = xstrdup(pw->pw_name); | 534 | for (method = authmethods; method->name != NULL; method++) { |
416 | copy->pw_passwd = xstrdup(pw->pw_passwd); | 535 | if (strcmp(method->name, "none") == 0) |
417 | copy->pw_uid = pw->pw_uid; | 536 | continue; |
418 | copy->pw_gid = pw->pw_gid; | 537 | if (method->enabled != NULL && *(method->enabled) != 0) { |
419 | #ifdef HAVE_PW_CLASS_IN_PASSWD | 538 | if (list[0] != '\0') |
420 | copy->pw_class = xstrdup(pw->pw_class); | 539 | strlcat(list, DELIM, size); |
421 | #endif | 540 | strlcat(list, method->name, size); |
422 | copy->pw_dir = xstrdup(pw->pw_dir); | ||
423 | copy->pw_shell = xstrdup(pw->pw_shell); | ||
424 | authctxt->valid = 1; | ||
425 | } else { | ||
426 | if (strcmp(u, authctxt->user) != 0 || | ||
427 | strcmp(s, authctxt->service) != 0) { | ||
428 | log("auth_set_user: missmatch: (%s,%s)!=(%s,%s)", | ||
429 | u, s, authctxt->user, authctxt->service); | ||
430 | return NULL; | ||
431 | } | 541 | } |
432 | } | 542 | } |
433 | return auth_get_user(); | 543 | return list; |
544 | } | ||
545 | |||
546 | Authmethod * | ||
547 | authmethod_lookup(const char *name) | ||
548 | { | ||
549 | Authmethod *method = NULL; | ||
550 | if (name != NULL) | ||
551 | for (method = authmethods; method->name != NULL; method++) | ||
552 | if (method->enabled != NULL && | ||
553 | *(method->enabled) != 0 && | ||
554 | strcmp(name, method->name) == 0) | ||
555 | return method; | ||
556 | debug2("Unrecognized authentication method name: %s", name ? name : "NULL"); | ||
557 | return NULL; | ||
434 | } | 558 | } |
435 | 559 | ||
436 | /* return 1 if user allows given key */ | 560 | /* return 1 if user allows given key */ |
@@ -445,6 +569,9 @@ user_dsa_key_allowed(struct passwd *pw, Key *key) | |||
445 | struct stat st; | 569 | struct stat st; |
446 | Key *found; | 570 | Key *found; |
447 | 571 | ||
572 | if (pw == NULL) | ||
573 | return 0; | ||
574 | |||
448 | /* Temporarily use the user's uid. */ | 575 | /* Temporarily use the user's uid. */ |
449 | temporarily_use_uid(pw->pw_uid); | 576 | temporarily_use_uid(pw->pw_uid); |
450 | 577 | ||
@@ -550,3 +677,20 @@ user_dsa_key_allowed(struct passwd *pw, Key *key) | |||
550 | key_free(found); | 677 | key_free(found); |
551 | return found_key; | 678 | return found_key; |
552 | } | 679 | } |
680 | |||
681 | struct passwd * | ||
682 | pwcopy(struct passwd *pw) | ||
683 | { | ||
684 | struct passwd *copy = xmalloc(sizeof(*copy)); | ||
685 | memset(copy, 0, sizeof(*copy)); | ||
686 | copy->pw_name = xstrdup(pw->pw_name); | ||
687 | copy->pw_passwd = xstrdup(pw->pw_passwd); | ||
688 | copy->pw_uid = pw->pw_uid; | ||
689 | copy->pw_gid = pw->pw_gid; | ||
690 | #ifdef HAVE_PW_CLASS_IN_PASSWD | ||
691 | copy->pw_class = xstrdup(pw->pw_class); | ||
692 | #endif | ||
693 | copy->pw_dir = xstrdup(pw->pw_dir); | ||
694 | copy->pw_shell = xstrdup(pw->pw_shell); | ||
695 | return copy; | ||
696 | } | ||