1 /* 2 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. All advertising materials mentioning features or use of this software 13 * must display the following acknowledgement: 14 * This product includes software developed by Markus Friedl. 15 * 4. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * 29 * $FreeBSD$ 30 */ 31 #include "includes.h" 32 RCSID("$OpenBSD: auth2.c,v 1.8 2000/05/08 17:42:24 markus Exp $"); 33 34 #include <openssl/dsa.h> 35 #include <openssl/rsa.h> 36 #include <openssl/evp.h> 37 38 #include "xmalloc.h" 39 #include "rsa.h" 40 #include "ssh.h" 41 #include "pty.h" 42 #include "packet.h" 43 #include "buffer.h" 44 #include "cipher.h" 45 #include "servconf.h" 46 #include "compat.h" 47 #include "channels.h" 48 #include "bufaux.h" 49 #include "ssh2.h" 50 #include "auth.h" 51 #include "session.h" 52 #include "dispatch.h" 53 #include "auth.h" 54 #include "key.h" 55 #include "kex.h" 56 57 #include "dsa.h" 58 #include "uidswap.h" 59 60 /* import */ 61 extern ServerOptions options; 62 extern unsigned char *session_id2; 63 extern int session_id2_len; 64 65 /* protocol */ 66 67 void input_service_request(int type, int plen); 68 void input_userauth_request(int type, int plen); 69 void protocol_error(int type, int plen); 70 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, unsigned char *raw, unsigned int rlen); 75 76 /* helper */ 77 struct passwd* auth_set_user(char *u, char *s); 78 int user_dsa_key_allowed(struct passwd *pw, Key *key); 79 80 typedef struct Authctxt Authctxt; 81 struct Authctxt { 82 char *user; 83 char *service; 84 struct passwd pw; 85 int valid; 86 }; 87 static Authctxt *authctxt = NULL; 88 static int userauth_success = 0; 89 90 /* 91 * loop until userauth_success == TRUE 92 */ 93 94 void 95 do_authentication2() 96 { 97 /* turn off skey/kerberos, not supported by SSH2 */ 98 #ifdef SKEY 99 options.skey_authentication = 0; 100 #endif 101 #ifdef KRB4 102 options.krb4_authentication = 0; 103 #endif 104 105 dispatch_init(&protocol_error); 106 dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request); 107 dispatch_run(DISPATCH_BLOCK, &userauth_success); 108 do_authenticated2(); 109 } 110 111 void 112 protocol_error(int type, int plen) 113 { 114 log("auth: protocol error: type %d plen %d", type, plen); 115 packet_start(SSH2_MSG_UNIMPLEMENTED); 116 packet_put_int(0); 117 packet_send(); 118 packet_write_wait(); 119 } 120 121 void 122 input_service_request(int type, int plen) 123 { 124 unsigned int len; 125 int accept = 0; 126 char *service = packet_get_string(&len); 127 packet_done(); 128 129 if (strcmp(service, "ssh-userauth") == 0) { 130 if (!userauth_success) { 131 accept = 1; 132 /* now we can handle user-auth requests */ 133 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request); 134 } 135 } 136 /* XXX all other service requests are denied */ 137 138 if (accept) { 139 packet_start(SSH2_MSG_SERVICE_ACCEPT); 140 packet_put_cstring(service); 141 packet_send(); 142 packet_write_wait(); 143 } else { 144 debug("bad service request %s", service); 145 packet_disconnect("bad service request %s", service); 146 } 147 xfree(service); 148 } 149 150 void 151 input_userauth_request(int type, int plen) 152 { 153 static void (*authlog) (const char *fmt,...) = verbose; 154 static int attempt = 0; 155 unsigned int len, rlen; 156 int authenticated = 0; 157 char *raw, *user, *service, *method, *authmsg = NULL; 158 struct passwd *pw; 159 160 if (++attempt == AUTH_FAIL_MAX) 161 packet_disconnect("too many failed userauth_requests"); 162 163 raw = packet_get_raw(&rlen); 164 if (plen != rlen) 165 fatal("plen != rlen"); 166 user = packet_get_string(&len); 167 service = packet_get_string(&len); 168 method = packet_get_string(&len); 169 debug("userauth-request for user %s service %s method %s", user, service, method); 170 171 /* XXX we only allow the ssh-connection service */ 172 pw = auth_set_user(user, service); 173 if (pw && strcmp(service, "ssh-connection")==0) { 174 if (strcmp(method, "none") == 0) { 175 authenticated = ssh2_auth_none(pw); 176 } else if (strcmp(method, "password") == 0) { 177 authenticated = ssh2_auth_password(pw); 178 } else if (strcmp(method, "publickey") == 0) { 179 authenticated = ssh2_auth_pubkey(pw, raw, rlen); 180 } 181 } 182 if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) { 183 authenticated = 0; 184 log("ROOT LOGIN REFUSED FROM %.200s", 185 get_canonical_hostname()); 186 } 187 188 /* Raise logging level */ 189 if (authenticated == 1 || 190 attempt == AUTH_FAIL_LOG || 191 strcmp(method, "password") == 0) 192 authlog = log; 193 194 /* Log before sending the reply */ 195 if (authenticated == 1) { 196 authmsg = "Accepted"; 197 } else if (authenticated == 0) { 198 authmsg = "Failed"; 199 } else { 200 authmsg = "Postponed"; 201 } 202 authlog("%s %s for %.200s from %.200s port %d ssh2", 203 authmsg, 204 method, 205 pw && pw->pw_uid == 0 ? "ROOT" : user, 206 get_remote_ipaddr(), 207 get_remote_port()); 208 209 /* XXX todo: check if multiple auth methods are needed */ 210 if (authenticated == 1) { 211 /* turn off userauth */ 212 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error); 213 packet_start(SSH2_MSG_USERAUTH_SUCCESS); 214 packet_send(); 215 packet_write_wait(); 216 /* now we can break out */ 217 userauth_success = 1; 218 } else if (authenticated == 0) { 219 packet_start(SSH2_MSG_USERAUTH_FAILURE); 220 packet_put_cstring("publickey,password"); /* XXX dynamic */ 221 packet_put_char(0); /* XXX partial success, unused */ 222 packet_send(); 223 packet_write_wait(); 224 } 225 226 xfree(service); 227 xfree(user); 228 xfree(method); 229 } 230 231 int 232 ssh2_auth_none(struct passwd *pw) 233 { 234 packet_done(); 235 return auth_password(pw, ""); 236 } 237 int 238 ssh2_auth_password(struct passwd *pw) 239 { 240 char *password; 241 int authenticated = 0; 242 int change; 243 unsigned int len; 244 change = packet_get_char(); 245 if (change) 246 log("password change not supported"); 247 password = packet_get_string(&len); 248 packet_done(); 249 if (options.password_authentication && 250 auth_password(pw, password) == 1) 251 authenticated = 1; 252 memset(password, 0, len); 253 xfree(password); 254 return authenticated; 255 } 256 int 257 ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen) 258 { 259 Buffer b; 260 Key *key; 261 char *pkalg, *pkblob, *sig; 262 unsigned int alen, blen, slen; 263 int have_sig; 264 int authenticated = 0; 265 266 if (options.dsa_authentication == 0) { 267 debug("pubkey auth disabled"); 268 return 0; 269 } 270 if (datafellows & SSH_BUG_PUBKEYAUTH) { 271 log("bug compatibility with ssh-2.0.13 pubkey not implemented"); 272 return 0; 273 } 274 have_sig = packet_get_char(); 275 pkalg = packet_get_string(&alen); 276 if (strcmp(pkalg, KEX_DSS) != 0) { 277 xfree(pkalg); 278 log("bad pkalg %s", pkalg); /*XXX*/ 279 return 0; 280 } 281 pkblob = packet_get_string(&blen); 282 key = dsa_key_from_blob(pkblob, blen); 283 if (key != NULL) { 284 if (have_sig) { 285 sig = packet_get_string(&slen); 286 packet_done(); 287 buffer_init(&b); 288 buffer_append(&b, session_id2, session_id2_len); 289 buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); 290 if (slen + 4 > rlen) 291 fatal("bad rlen/slen"); 292 buffer_append(&b, raw, rlen - slen - 4); 293 #ifdef DEBUG_DSS 294 buffer_dump(&b); 295 #endif 296 /* test for correct signature */ 297 if (user_dsa_key_allowed(pw, key) && 298 dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1) 299 authenticated = 1; 300 buffer_clear(&b); 301 xfree(sig); 302 } else { 303 packet_done(); 304 debug("test key..."); 305 /* test whether pkalg/pkblob are acceptable */ 306 /* XXX fake reply and always send PK_OK ? */ 307 /* 308 * XXX this allows testing whether a user is allowed 309 * to login: if you happen to have a valid pubkey this 310 * message is sent. the message is NEVER sent at all 311 * if a user is not allowed to login. is this an 312 * issue? -markus 313 */ 314 if (user_dsa_key_allowed(pw, key)) { 315 packet_start(SSH2_MSG_USERAUTH_PK_OK); 316 packet_put_string(pkalg, alen); 317 packet_put_string(pkblob, blen); 318 packet_send(); 319 packet_write_wait(); 320 authenticated = -1; 321 } 322 } 323 key_free(key); 324 } 325 xfree(pkalg); 326 xfree(pkblob); 327 return authenticated; 328 } 329 330 /* set and get current user */ 331 332 struct passwd* 333 auth_get_user(void) 334 { 335 return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL; 336 } 337 338 struct passwd* 339 auth_set_user(char *u, char *s) 340 { 341 struct passwd *pw, *copy; 342 343 if (authctxt == NULL) { 344 authctxt = xmalloc(sizeof(*authctxt)); 345 authctxt->valid = 0; 346 authctxt->user = xstrdup(u); 347 authctxt->service = xstrdup(s); 348 setproctitle("%s", u); 349 pw = getpwnam(u); 350 if (!pw || !allowed_user(pw)) { 351 log("auth_set_user: illegal user %s", u); 352 return NULL; 353 } 354 copy = &authctxt->pw; 355 memset(copy, 0, sizeof(*copy)); 356 copy->pw_name = xstrdup(pw->pw_name); 357 copy->pw_passwd = xstrdup(pw->pw_passwd); 358 copy->pw_uid = pw->pw_uid; 359 copy->pw_gid = pw->pw_gid; 360 copy->pw_dir = xstrdup(pw->pw_dir); 361 copy->pw_shell = xstrdup(pw->pw_shell); 362 copy->pw_class = xstrdup(pw->pw_class); 363 copy->pw_expire = pw->pw_expire; 364 copy->pw_change = pw->pw_change; 365 authctxt->valid = 1; 366 } else { 367 if (strcmp(u, authctxt->user) != 0 || 368 strcmp(s, authctxt->service) != 0) { 369 log("auth_set_user: missmatch: (%s,%s)!=(%s,%s)", 370 u, s, authctxt->user, authctxt->service); 371 return NULL; 372 } 373 } 374 return auth_get_user(); 375 } 376 377 /* return 1 if user allows given key */ 378 int 379 user_dsa_key_allowed(struct passwd *pw, Key *key) 380 { 381 char line[8192], file[1024]; 382 int found_key = 0; 383 unsigned int bits = -1; 384 FILE *f; 385 unsigned long linenum = 0; 386 struct stat st; 387 Key *found; 388 389 /* Temporarily use the user's uid. */ 390 temporarily_use_uid(pw->pw_uid); 391 392 /* The authorized keys. */ 393 snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir, 394 SSH_USER_PERMITTED_KEYS2); 395 396 /* Fail quietly if file does not exist */ 397 if (stat(file, &st) < 0) { 398 /* Restore the privileged uid. */ 399 restore_uid(); 400 return 0; 401 } 402 /* Open the file containing the authorized keys. */ 403 f = fopen(file, "r"); 404 if (!f) { 405 /* Restore the privileged uid. */ 406 restore_uid(); 407 return 0; 408 } 409 if (options.strict_modes) { 410 int fail = 0; 411 char buf[1024]; 412 /* Check open file in order to avoid open/stat races */ 413 if (fstat(fileno(f), &st) < 0 || 414 (st.st_uid != 0 && st.st_uid != pw->pw_uid) || 415 (st.st_mode & 022) != 0) { 416 snprintf(buf, sizeof buf, "DSA authentication refused for %.100s: " 417 "bad ownership or modes for '%s'.", pw->pw_name, file); 418 fail = 1; 419 } else { 420 /* Check path to SSH_USER_PERMITTED_KEYS */ 421 int i; 422 static const char *check[] = { 423 "", SSH_USER_DIR, NULL 424 }; 425 for (i = 0; check[i]; i++) { 426 snprintf(line, sizeof line, "%.500s/%.100s", 427 pw->pw_dir, check[i]); 428 if (stat(line, &st) < 0 || 429 (st.st_uid != 0 && st.st_uid != pw->pw_uid) || 430 (st.st_mode & 022) != 0) { 431 snprintf(buf, sizeof buf, 432 "DSA authentication refused for %.100s: " 433 "bad ownership or modes for '%s'.", 434 pw->pw_name, line); 435 fail = 1; 436 break; 437 } 438 } 439 } 440 if (fail) { 441 log(buf); 442 fclose(f); 443 restore_uid(); 444 return 0; 445 } 446 } 447 found_key = 0; 448 found = key_new(KEY_DSA); 449 450 while (fgets(line, sizeof(line), f)) { 451 char *cp; 452 linenum++; 453 /* Skip leading whitespace, empty and comment lines. */ 454 for (cp = line; *cp == ' ' || *cp == '\t'; cp++) 455 ; 456 if (!*cp || *cp == '\n' || *cp == '#') 457 continue; 458 bits = key_read(found, &cp); 459 if (bits == 0) 460 continue; 461 if (key_equal(found, key)) { 462 found_key = 1; 463 debug("matching key found: file %s, line %ld", 464 file, linenum); 465 break; 466 } 467 } 468 restore_uid(); 469 fclose(f); 470 key_free(found); 471 return found_key; 472 } 473