1 /* $OpenBSD: auth2.c,v 1.121 2009/06/22 05:39:28 dtucker Exp $ */ 2 /* 3 * Copyright (c) 2000 Markus Friedl. 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 26 27 #include <sys/types.h> 28 #include <sys/stat.h> 29 #include <sys/uio.h> 30 31 #include <fcntl.h> 32 #include <pwd.h> 33 #include <stdarg.h> 34 #include <string.h> 35 #include <unistd.h> 36 37 #include "atomicio.h" 38 #include "xmalloc.h" 39 #include "ssh2.h" 40 #include "packet.h" 41 #include "log.h" 42 #include "buffer.h" 43 #include "servconf.h" 44 #include "compat.h" 45 #include "key.h" 46 #include "hostfile.h" 47 #include "auth.h" 48 #include "dispatch.h" 49 #include "pathnames.h" 50 #ifdef GSSAPI 51 #include "ssh-gss.h" 52 #endif 53 #include "monitor_wrap.h" 54 55 /* import */ 56 extern ServerOptions options; 57 extern u_char *session_id2; 58 extern u_int session_id2_len; 59 60 /* methods */ 61 62 extern Authmethod method_none; 63 extern Authmethod method_pubkey; 64 extern Authmethod method_passwd; 65 extern Authmethod method_kbdint; 66 extern Authmethod method_hostbased; 67 #ifdef GSSAPI 68 extern Authmethod method_gssapi; 69 #endif 70 #ifdef JPAKE 71 extern Authmethod method_jpake; 72 #endif 73 74 Authmethod *authmethods[] = { 75 &method_none, 76 &method_pubkey, 77 #ifdef GSSAPI 78 &method_gssapi, 79 #endif 80 #ifdef JPAKE 81 &method_jpake, 82 #endif 83 &method_passwd, 84 &method_kbdint, 85 &method_hostbased, 86 NULL 87 }; 88 89 /* protocol */ 90 91 static void input_service_request(int, u_int32_t, void *); 92 static void input_userauth_request(int, u_int32_t, void *); 93 94 /* helper */ 95 static Authmethod *authmethod_lookup(const char *); 96 static char *authmethods_get(void); 97 98 char * 99 auth2_read_banner(void) 100 { 101 struct stat st; 102 char *banner = NULL; 103 size_t len, n; 104 int fd; 105 106 if ((fd = open(options.banner, O_RDONLY)) == -1) 107 return (NULL); 108 if (fstat(fd, &st) == -1) { 109 close(fd); 110 return (NULL); 111 } 112 if (st.st_size > 1*1024*1024) { 113 close(fd); 114 return (NULL); 115 } 116 117 len = (size_t)st.st_size; /* truncate */ 118 banner = xmalloc(len + 1); 119 n = atomicio(read, fd, banner, len); 120 close(fd); 121 122 if (n != len) { 123 xfree(banner); 124 return (NULL); 125 } 126 banner[n] = '\0'; 127 128 return (banner); 129 } 130 131 static void 132 userauth_banner(void) 133 { 134 char *banner = NULL; 135 136 if (options.banner == NULL || 137 strcasecmp(options.banner, "none") == 0 || 138 (datafellows & SSH_BUG_BANNER) != 0) 139 return; 140 141 if ((banner = PRIVSEP(auth2_read_banner())) == NULL) 142 goto done; 143 144 packet_start(SSH2_MSG_USERAUTH_BANNER); 145 packet_put_cstring(banner); 146 packet_put_cstring(""); /* language, unused */ 147 packet_send(); 148 debug("userauth_banner: sent"); 149 done: 150 if (banner) 151 xfree(banner); 152 } 153 154 /* 155 * loop until authctxt->success == TRUE 156 */ 157 void 158 do_authentication2(Authctxt *authctxt) 159 { 160 dispatch_init(&dispatch_protocol_error); 161 dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request); 162 dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt); 163 } 164 165 /*ARGSUSED*/ 166 static void 167 input_service_request(int type, u_int32_t seq, void *ctxt) 168 { 169 Authctxt *authctxt = ctxt; 170 u_int len; 171 int acceptit = 0; 172 char *service = packet_get_string(&len); 173 packet_check_eom(); 174 175 if (authctxt == NULL) 176 fatal("input_service_request: no authctxt"); 177 178 if (strcmp(service, "ssh-userauth") == 0) { 179 if (!authctxt->success) { 180 acceptit = 1; 181 /* now we can handle user-auth requests */ 182 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request); 183 } 184 } 185 /* XXX all other service requests are denied */ 186 187 if (acceptit) { 188 packet_start(SSH2_MSG_SERVICE_ACCEPT); 189 packet_put_cstring(service); 190 packet_send(); 191 packet_write_wait(); 192 } else { 193 debug("bad service request %s", service); 194 packet_disconnect("bad service request %s", service); 195 } 196 xfree(service); 197 } 198 199 /*ARGSUSED*/ 200 static void 201 input_userauth_request(int type, u_int32_t seq, void *ctxt) 202 { 203 Authctxt *authctxt = ctxt; 204 Authmethod *m = NULL; 205 char *user, *service, *method, *style = NULL; 206 int authenticated = 0; 207 208 if (authctxt == NULL) 209 fatal("input_userauth_request: no authctxt"); 210 211 user = packet_get_string(NULL); 212 service = packet_get_string(NULL); 213 method = packet_get_string(NULL); 214 debug("userauth-request for user %s service %s method %s", user, service, method); 215 debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); 216 217 if ((style = strchr(user, ':')) != NULL) 218 *style++ = 0; 219 220 if (authctxt->attempt++ == 0) { 221 /* setup auth context */ 222 authctxt->pw = PRIVSEP(getpwnamallow(user)); 223 if (authctxt->pw && strcmp(service, "ssh-connection")==0) { 224 authctxt->valid = 1; 225 debug2("input_userauth_request: setting up authctxt for %s", user); 226 } else { 227 logit("input_userauth_request: invalid user %s", user); 228 authctxt->pw = fakepw(); 229 } 230 setproctitle("%s%s", authctxt->valid ? user : "unknown", 231 use_privsep ? " [net]" : ""); 232 authctxt->user = xstrdup(user); 233 authctxt->service = xstrdup(service); 234 authctxt->style = style ? xstrdup(style) : NULL; 235 if (use_privsep) 236 mm_inform_authserv(service, style); 237 userauth_banner(); 238 } else if (strcmp(user, authctxt->user) != 0 || 239 strcmp(service, authctxt->service) != 0) { 240 packet_disconnect("Change of username or service not allowed: " 241 "(%s,%s) -> (%s,%s)", 242 authctxt->user, authctxt->service, user, service); 243 } 244 /* reset state */ 245 auth2_challenge_stop(authctxt); 246 #ifdef JPAKE 247 auth2_jpake_stop(authctxt); 248 #endif 249 250 #ifdef GSSAPI 251 /* XXX move to auth2_gssapi_stop() */ 252 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 253 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); 254 #endif 255 256 authctxt->postponed = 0; 257 258 /* try to authenticate user */ 259 m = authmethod_lookup(method); 260 if (m != NULL && authctxt->failures < options.max_authtries) { 261 debug2("input_userauth_request: try method %s", method); 262 authenticated = m->userauth(authctxt); 263 } 264 userauth_finish(authctxt, authenticated, method); 265 266 xfree(service); 267 xfree(user); 268 xfree(method); 269 } 270 271 void 272 userauth_finish(Authctxt *authctxt, int authenticated, char *method) 273 { 274 char *methods; 275 276 if (!authctxt->valid && authenticated) 277 fatal("INTERNAL ERROR: authenticated invalid user %s", 278 authctxt->user); 279 280 /* Special handling for root */ 281 if (authenticated && authctxt->pw->pw_uid == 0 && 282 !auth_root_allowed(method)) 283 authenticated = 0; 284 285 /* Log before sending the reply */ 286 auth_log(authctxt, authenticated, method, " ssh2"); 287 288 if (authctxt->postponed) 289 return; 290 291 /* XXX todo: check if multiple auth methods are needed */ 292 if (authenticated == 1) { 293 /* turn off userauth */ 294 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore); 295 packet_start(SSH2_MSG_USERAUTH_SUCCESS); 296 packet_send(); 297 packet_write_wait(); 298 /* now we can break out */ 299 authctxt->success = 1; 300 } else { 301 /* Allow initial try of "none" auth without failure penalty */ 302 if (authctxt->attempt > 1 || strcmp(method, "none") != 0) 303 authctxt->failures++; 304 if (authctxt->failures >= options.max_authtries) 305 packet_disconnect(AUTH_FAIL_MSG, authctxt->user); 306 methods = authmethods_get(); 307 packet_start(SSH2_MSG_USERAUTH_FAILURE); 308 packet_put_cstring(methods); 309 packet_put_char(0); /* XXX partial success, unused */ 310 packet_send(); 311 packet_write_wait(); 312 xfree(methods); 313 } 314 } 315 316 static char * 317 authmethods_get(void) 318 { 319 Buffer b; 320 char *list; 321 int i; 322 323 buffer_init(&b); 324 for (i = 0; authmethods[i] != NULL; i++) { 325 if (strcmp(authmethods[i]->name, "none") == 0) 326 continue; 327 if (authmethods[i]->enabled != NULL && 328 *(authmethods[i]->enabled) != 0) { 329 if (buffer_len(&b) > 0) 330 buffer_append(&b, ",", 1); 331 buffer_append(&b, authmethods[i]->name, 332 strlen(authmethods[i]->name)); 333 } 334 } 335 buffer_append(&b, "\0", 1); 336 list = xstrdup(buffer_ptr(&b)); 337 buffer_free(&b); 338 return list; 339 } 340 341 static Authmethod * 342 authmethod_lookup(const char *name) 343 { 344 int i; 345 346 if (name != NULL) 347 for (i = 0; authmethods[i] != NULL; i++) 348 if (authmethods[i]->enabled != NULL && 349 *(authmethods[i]->enabled) != 0 && 350 strcmp(name, authmethods[i]->name) == 0) 351 return authmethods[i]; 352 debug2("Unrecognized authentication method name: %s", 353 name ? name : "NULL"); 354 return NULL; 355 } 356 357