1761efaa7SDag-Erling Smørgrav /* $OpenBSD: auth-options.c,v 1.40 2006/08/03 03:34:41 deraadt Exp $ */ 2b66f2d16SKris Kennaway /* 3b66f2d16SKris Kennaway * Author: Tatu Ylonen <ylo@cs.hut.fi> 4b66f2d16SKris Kennaway * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 5b66f2d16SKris Kennaway * All rights reserved 6b66f2d16SKris Kennaway * As far as I am concerned, the code I have written for this software 7b66f2d16SKris Kennaway * can be used freely for any purpose. Any derived versions of this 8b66f2d16SKris Kennaway * software must be clearly marked as such, and if the derived work is 9b66f2d16SKris Kennaway * incompatible with the protocol description in the RFC file, it must be 10b66f2d16SKris Kennaway * called by a name other than "ssh" or "Secure Shell". 11b66f2d16SKris Kennaway */ 12b66f2d16SKris Kennaway 13b66f2d16SKris Kennaway #include "includes.h" 14761efaa7SDag-Erling Smørgrav 15761efaa7SDag-Erling Smørgrav #include <sys/types.h> 16761efaa7SDag-Erling Smørgrav 17761efaa7SDag-Erling Smørgrav #include <netdb.h> 18761efaa7SDag-Erling Smørgrav #include <pwd.h> 19761efaa7SDag-Erling Smørgrav #include <string.h> 20761efaa7SDag-Erling Smørgrav #include <stdio.h> 21761efaa7SDag-Erling Smørgrav #include <stdarg.h> 22b66f2d16SKris Kennaway 23b66f2d16SKris Kennaway #include "xmalloc.h" 24b66f2d16SKris Kennaway #include "match.h" 251e8db6e2SBrian Feldman #include "log.h" 261e8db6e2SBrian Feldman #include "canohost.h" 27761efaa7SDag-Erling Smørgrav #include "buffer.h" 281e8db6e2SBrian Feldman #include "channels.h" 291e8db6e2SBrian Feldman #include "auth-options.h" 301e8db6e2SBrian Feldman #include "servconf.h" 31ae1f160dSDag-Erling Smørgrav #include "misc.h" 32761efaa7SDag-Erling Smørgrav #include "key.h" 33761efaa7SDag-Erling Smørgrav #include "hostfile.h" 34545d5ecaSDag-Erling Smørgrav #include "auth.h" 35761efaa7SDag-Erling Smørgrav #ifdef GSSAPI 36761efaa7SDag-Erling Smørgrav #include "ssh-gss.h" 37761efaa7SDag-Erling Smørgrav #endif 38761efaa7SDag-Erling Smørgrav #include "monitor_wrap.h" 39b66f2d16SKris Kennaway 40b66f2d16SKris Kennaway /* Flags set authorized_keys flags */ 41b66f2d16SKris Kennaway int no_port_forwarding_flag = 0; 42b66f2d16SKris Kennaway int no_agent_forwarding_flag = 0; 43b66f2d16SKris Kennaway int no_x11_forwarding_flag = 0; 44b66f2d16SKris Kennaway int no_pty_flag = 0; 45b66f2d16SKris Kennaway 46b66f2d16SKris Kennaway /* "command=" option. */ 47b66f2d16SKris Kennaway char *forced_command = NULL; 48b66f2d16SKris Kennaway 49b66f2d16SKris Kennaway /* "environment=" options. */ 50b66f2d16SKris Kennaway struct envstring *custom_environment = NULL; 51b66f2d16SKris Kennaway 52021d409fSDag-Erling Smørgrav /* "tunnel=" option. */ 53021d409fSDag-Erling Smørgrav int forced_tun_device = -1; 54021d409fSDag-Erling Smørgrav 551e8db6e2SBrian Feldman extern ServerOptions options; 561e8db6e2SBrian Feldman 575b9b2fafSBrian Feldman void 585b9b2fafSBrian Feldman auth_clear_options(void) 595b9b2fafSBrian Feldman { 605b9b2fafSBrian Feldman no_agent_forwarding_flag = 0; 615b9b2fafSBrian Feldman no_port_forwarding_flag = 0; 625b9b2fafSBrian Feldman no_pty_flag = 0; 635b9b2fafSBrian Feldman no_x11_forwarding_flag = 0; 645b9b2fafSBrian Feldman while (custom_environment) { 655b9b2fafSBrian Feldman struct envstring *ce = custom_environment; 665b9b2fafSBrian Feldman custom_environment = ce->next; 675b9b2fafSBrian Feldman xfree(ce->s); 685b9b2fafSBrian Feldman xfree(ce); 695b9b2fafSBrian Feldman } 705b9b2fafSBrian Feldman if (forced_command) { 715b9b2fafSBrian Feldman xfree(forced_command); 725b9b2fafSBrian Feldman forced_command = NULL; 735b9b2fafSBrian Feldman } 74021d409fSDag-Erling Smørgrav forced_tun_device = -1; 751e8db6e2SBrian Feldman channel_clear_permitted_opens(); 76545d5ecaSDag-Erling Smørgrav auth_debug_reset(); 775b9b2fafSBrian Feldman } 785b9b2fafSBrian Feldman 791e8db6e2SBrian Feldman /* 801e8db6e2SBrian Feldman * return 1 if access is granted, 0 if not. 811e8db6e2SBrian Feldman * side effect: sets key option flags 821e8db6e2SBrian Feldman */ 83b66f2d16SKris Kennaway int 841e8db6e2SBrian Feldman auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) 85b66f2d16SKris Kennaway { 86b66f2d16SKris Kennaway const char *cp; 871e8db6e2SBrian Feldman int i; 885b9b2fafSBrian Feldman 895b9b2fafSBrian Feldman /* reset options */ 905b9b2fafSBrian Feldman auth_clear_options(); 915b9b2fafSBrian Feldman 921e8db6e2SBrian Feldman if (!opts) 931e8db6e2SBrian Feldman return 1; 941e8db6e2SBrian Feldman 951e8db6e2SBrian Feldman while (*opts && *opts != ' ' && *opts != '\t') { 96b66f2d16SKris Kennaway cp = "no-port-forwarding"; 971e8db6e2SBrian Feldman if (strncasecmp(opts, cp, strlen(cp)) == 0) { 98545d5ecaSDag-Erling Smørgrav auth_debug_add("Port forwarding disabled."); 99b66f2d16SKris Kennaway no_port_forwarding_flag = 1; 1001e8db6e2SBrian Feldman opts += strlen(cp); 101b66f2d16SKris Kennaway goto next_option; 102b66f2d16SKris Kennaway } 103b66f2d16SKris Kennaway cp = "no-agent-forwarding"; 1041e8db6e2SBrian Feldman if (strncasecmp(opts, cp, strlen(cp)) == 0) { 105545d5ecaSDag-Erling Smørgrav auth_debug_add("Agent forwarding disabled."); 106b66f2d16SKris Kennaway no_agent_forwarding_flag = 1; 1071e8db6e2SBrian Feldman opts += strlen(cp); 108b66f2d16SKris Kennaway goto next_option; 109b66f2d16SKris Kennaway } 110b66f2d16SKris Kennaway cp = "no-X11-forwarding"; 1111e8db6e2SBrian Feldman if (strncasecmp(opts, cp, strlen(cp)) == 0) { 112545d5ecaSDag-Erling Smørgrav auth_debug_add("X11 forwarding disabled."); 113b66f2d16SKris Kennaway no_x11_forwarding_flag = 1; 1141e8db6e2SBrian Feldman opts += strlen(cp); 115b66f2d16SKris Kennaway goto next_option; 116b66f2d16SKris Kennaway } 117b66f2d16SKris Kennaway cp = "no-pty"; 1181e8db6e2SBrian Feldman if (strncasecmp(opts, cp, strlen(cp)) == 0) { 119545d5ecaSDag-Erling Smørgrav auth_debug_add("Pty allocation disabled."); 120b66f2d16SKris Kennaway no_pty_flag = 1; 1211e8db6e2SBrian Feldman opts += strlen(cp); 122b66f2d16SKris Kennaway goto next_option; 123b66f2d16SKris Kennaway } 124b66f2d16SKris Kennaway cp = "command=\""; 1251e8db6e2SBrian Feldman if (strncasecmp(opts, cp, strlen(cp)) == 0) { 1261e8db6e2SBrian Feldman opts += strlen(cp); 1271e8db6e2SBrian Feldman forced_command = xmalloc(strlen(opts) + 1); 128b66f2d16SKris Kennaway i = 0; 1291e8db6e2SBrian Feldman while (*opts) { 1301e8db6e2SBrian Feldman if (*opts == '"') 131b66f2d16SKris Kennaway break; 1321e8db6e2SBrian Feldman if (*opts == '\\' && opts[1] == '"') { 1331e8db6e2SBrian Feldman opts += 2; 134b66f2d16SKris Kennaway forced_command[i++] = '"'; 135b66f2d16SKris Kennaway continue; 136b66f2d16SKris Kennaway } 1371e8db6e2SBrian Feldman forced_command[i++] = *opts++; 138b66f2d16SKris Kennaway } 1391e8db6e2SBrian Feldman if (!*opts) { 140b66f2d16SKris Kennaway debug("%.100s, line %lu: missing end quote", 1411e8db6e2SBrian Feldman file, linenum); 142545d5ecaSDag-Erling Smørgrav auth_debug_add("%.100s, line %lu: missing end quote", 1431e8db6e2SBrian Feldman file, linenum); 1441e8db6e2SBrian Feldman xfree(forced_command); 1451e8db6e2SBrian Feldman forced_command = NULL; 1461e8db6e2SBrian Feldman goto bad_option; 147b66f2d16SKris Kennaway } 148761efaa7SDag-Erling Smørgrav forced_command[i] = '\0'; 149545d5ecaSDag-Erling Smørgrav auth_debug_add("Forced command: %.900s", forced_command); 1501e8db6e2SBrian Feldman opts++; 151b66f2d16SKris Kennaway goto next_option; 152b66f2d16SKris Kennaway } 153b66f2d16SKris Kennaway cp = "environment=\""; 1544b17dab0SDag-Erling Smørgrav if (options.permit_user_env && 1554b17dab0SDag-Erling Smørgrav strncasecmp(opts, cp, strlen(cp)) == 0) { 156b66f2d16SKris Kennaway char *s; 157b66f2d16SKris Kennaway struct envstring *new_envstring; 1581e8db6e2SBrian Feldman 1591e8db6e2SBrian Feldman opts += strlen(cp); 1601e8db6e2SBrian Feldman s = xmalloc(strlen(opts) + 1); 161b66f2d16SKris Kennaway i = 0; 1621e8db6e2SBrian Feldman while (*opts) { 1631e8db6e2SBrian Feldman if (*opts == '"') 164b66f2d16SKris Kennaway break; 1651e8db6e2SBrian Feldman if (*opts == '\\' && opts[1] == '"') { 1661e8db6e2SBrian Feldman opts += 2; 167b66f2d16SKris Kennaway s[i++] = '"'; 168b66f2d16SKris Kennaway continue; 169b66f2d16SKris Kennaway } 1701e8db6e2SBrian Feldman s[i++] = *opts++; 171b66f2d16SKris Kennaway } 1721e8db6e2SBrian Feldman if (!*opts) { 173b66f2d16SKris Kennaway debug("%.100s, line %lu: missing end quote", 1741e8db6e2SBrian Feldman file, linenum); 175545d5ecaSDag-Erling Smørgrav auth_debug_add("%.100s, line %lu: missing end quote", 1761e8db6e2SBrian Feldman file, linenum); 1771e8db6e2SBrian Feldman xfree(s); 1781e8db6e2SBrian Feldman goto bad_option; 179b66f2d16SKris Kennaway } 180761efaa7SDag-Erling Smørgrav s[i] = '\0'; 181545d5ecaSDag-Erling Smørgrav auth_debug_add("Adding to environment: %.900s", s); 182b66f2d16SKris Kennaway debug("Adding to environment: %.900s", s); 1831e8db6e2SBrian Feldman opts++; 184b66f2d16SKris Kennaway new_envstring = xmalloc(sizeof(struct envstring)); 185b66f2d16SKris Kennaway new_envstring->s = s; 186b66f2d16SKris Kennaway new_envstring->next = custom_environment; 187b66f2d16SKris Kennaway custom_environment = new_envstring; 188b66f2d16SKris Kennaway goto next_option; 189b66f2d16SKris Kennaway } 190b66f2d16SKris Kennaway cp = "from=\""; 1911e8db6e2SBrian Feldman if (strncasecmp(opts, cp, strlen(cp)) == 0) { 1921e8db6e2SBrian Feldman const char *remote_ip = get_remote_ipaddr(); 1931e8db6e2SBrian Feldman const char *remote_host = get_canonical_hostname( 194d95e11bfSDag-Erling Smørgrav options.use_dns); 1951e8db6e2SBrian Feldman char *patterns = xmalloc(strlen(opts) + 1); 1961e8db6e2SBrian Feldman 1971e8db6e2SBrian Feldman opts += strlen(cp); 198b66f2d16SKris Kennaway i = 0; 1991e8db6e2SBrian Feldman while (*opts) { 2001e8db6e2SBrian Feldman if (*opts == '"') 201b66f2d16SKris Kennaway break; 2021e8db6e2SBrian Feldman if (*opts == '\\' && opts[1] == '"') { 2031e8db6e2SBrian Feldman opts += 2; 204b66f2d16SKris Kennaway patterns[i++] = '"'; 205b66f2d16SKris Kennaway continue; 206b66f2d16SKris Kennaway } 2071e8db6e2SBrian Feldman patterns[i++] = *opts++; 208b66f2d16SKris Kennaway } 2091e8db6e2SBrian Feldman if (!*opts) { 210b66f2d16SKris Kennaway debug("%.100s, line %lu: missing end quote", 2111e8db6e2SBrian Feldman file, linenum); 212545d5ecaSDag-Erling Smørgrav auth_debug_add("%.100s, line %lu: missing end quote", 2131e8db6e2SBrian Feldman file, linenum); 2141e8db6e2SBrian Feldman xfree(patterns); 2151e8db6e2SBrian Feldman goto bad_option; 216b66f2d16SKris Kennaway } 217761efaa7SDag-Erling Smørgrav patterns[i] = '\0'; 2181e8db6e2SBrian Feldman opts++; 219ae1f160dSDag-Erling Smørgrav if (match_host_and_ip(remote_host, remote_ip, 220ae1f160dSDag-Erling Smørgrav patterns) != 1) { 221b66f2d16SKris Kennaway xfree(patterns); 222d95e11bfSDag-Erling Smørgrav logit("Authentication tried for %.100s with " 2231e8db6e2SBrian Feldman "correct key but not from a permitted " 2241e8db6e2SBrian Feldman "host (host=%.200s, ip=%.200s).", 2251e8db6e2SBrian Feldman pw->pw_name, remote_host, remote_ip); 226545d5ecaSDag-Erling Smørgrav auth_debug_add("Your host '%.200s' is not " 2271e8db6e2SBrian Feldman "permitted to use this key for login.", 2281e8db6e2SBrian Feldman remote_host); 229b66f2d16SKris Kennaway /* deny access */ 230b66f2d16SKris Kennaway return 0; 231b66f2d16SKris Kennaway } 232ae1f160dSDag-Erling Smørgrav xfree(patterns); 233b66f2d16SKris Kennaway /* Host name matches. */ 234b66f2d16SKris Kennaway goto next_option; 235b66f2d16SKris Kennaway } 2361e8db6e2SBrian Feldman cp = "permitopen=\""; 2371e8db6e2SBrian Feldman if (strncasecmp(opts, cp, strlen(cp)) == 0) { 2385e8dbd04SDag-Erling Smørgrav char *host, *p; 2391e8db6e2SBrian Feldman u_short port; 2401e8db6e2SBrian Feldman char *patterns = xmalloc(strlen(opts) + 1); 2411e8db6e2SBrian Feldman 2421e8db6e2SBrian Feldman opts += strlen(cp); 2431e8db6e2SBrian Feldman i = 0; 2441e8db6e2SBrian Feldman while (*opts) { 2451e8db6e2SBrian Feldman if (*opts == '"') 2461e8db6e2SBrian Feldman break; 2471e8db6e2SBrian Feldman if (*opts == '\\' && opts[1] == '"') { 2481e8db6e2SBrian Feldman opts += 2; 2491e8db6e2SBrian Feldman patterns[i++] = '"'; 2501e8db6e2SBrian Feldman continue; 2511e8db6e2SBrian Feldman } 2521e8db6e2SBrian Feldman patterns[i++] = *opts++; 2531e8db6e2SBrian Feldman } 2541e8db6e2SBrian Feldman if (!*opts) { 2551e8db6e2SBrian Feldman debug("%.100s, line %lu: missing end quote", 2561e8db6e2SBrian Feldman file, linenum); 2575e8dbd04SDag-Erling Smørgrav auth_debug_add("%.100s, line %lu: missing " 2585e8dbd04SDag-Erling Smørgrav "end quote", file, linenum); 2591e8db6e2SBrian Feldman xfree(patterns); 2601e8db6e2SBrian Feldman goto bad_option; 2611e8db6e2SBrian Feldman } 262761efaa7SDag-Erling Smørgrav patterns[i] = '\0'; 2631e8db6e2SBrian Feldman opts++; 2645e8dbd04SDag-Erling Smørgrav p = patterns; 2655e8dbd04SDag-Erling Smørgrav host = hpdelim(&p); 2665e8dbd04SDag-Erling Smørgrav if (host == NULL || strlen(host) >= NI_MAXHOST) { 2675e8dbd04SDag-Erling Smørgrav debug("%.100s, line %lu: Bad permitopen " 2685e8dbd04SDag-Erling Smørgrav "specification <%.100s>", file, linenum, 2695e8dbd04SDag-Erling Smørgrav patterns); 270545d5ecaSDag-Erling Smørgrav auth_debug_add("%.100s, line %lu: " 2715e8dbd04SDag-Erling Smørgrav "Bad permitopen specification", file, 2725e8dbd04SDag-Erling Smørgrav linenum); 2731e8db6e2SBrian Feldman xfree(patterns); 2741e8db6e2SBrian Feldman goto bad_option; 2751e8db6e2SBrian Feldman } 2765e8dbd04SDag-Erling Smørgrav host = cleanhostname(host); 2775e8dbd04SDag-Erling Smørgrav if (p == NULL || (port = a2port(p)) == 0) { 2785e8dbd04SDag-Erling Smørgrav debug("%.100s, line %lu: Bad permitopen port " 2795e8dbd04SDag-Erling Smørgrav "<%.100s>", file, linenum, p ? p : ""); 280545d5ecaSDag-Erling Smørgrav auth_debug_add("%.100s, line %lu: " 281ae1f160dSDag-Erling Smørgrav "Bad permitopen port", file, linenum); 2821e8db6e2SBrian Feldman xfree(patterns); 2831e8db6e2SBrian Feldman goto bad_option; 2841e8db6e2SBrian Feldman } 2851e8db6e2SBrian Feldman if (options.allow_tcp_forwarding) 286ae1f160dSDag-Erling Smørgrav channel_add_permitted_opens(host, port); 2871e8db6e2SBrian Feldman xfree(patterns); 2881e8db6e2SBrian Feldman goto next_option; 2891e8db6e2SBrian Feldman } 290021d409fSDag-Erling Smørgrav cp = "tunnel=\""; 291021d409fSDag-Erling Smørgrav if (strncasecmp(opts, cp, strlen(cp)) == 0) { 292021d409fSDag-Erling Smørgrav char *tun = NULL; 293021d409fSDag-Erling Smørgrav opts += strlen(cp); 294021d409fSDag-Erling Smørgrav tun = xmalloc(strlen(opts) + 1); 295021d409fSDag-Erling Smørgrav i = 0; 296021d409fSDag-Erling Smørgrav while (*opts) { 297021d409fSDag-Erling Smørgrav if (*opts == '"') 298021d409fSDag-Erling Smørgrav break; 299021d409fSDag-Erling Smørgrav tun[i++] = *opts++; 300021d409fSDag-Erling Smørgrav } 301021d409fSDag-Erling Smørgrav if (!*opts) { 302021d409fSDag-Erling Smørgrav debug("%.100s, line %lu: missing end quote", 303021d409fSDag-Erling Smørgrav file, linenum); 304021d409fSDag-Erling Smørgrav auth_debug_add("%.100s, line %lu: missing end quote", 305021d409fSDag-Erling Smørgrav file, linenum); 306021d409fSDag-Erling Smørgrav xfree(tun); 307021d409fSDag-Erling Smørgrav forced_tun_device = -1; 308021d409fSDag-Erling Smørgrav goto bad_option; 309021d409fSDag-Erling Smørgrav } 310761efaa7SDag-Erling Smørgrav tun[i] = '\0'; 311021d409fSDag-Erling Smørgrav forced_tun_device = a2tun(tun, NULL); 312021d409fSDag-Erling Smørgrav xfree(tun); 313021d409fSDag-Erling Smørgrav if (forced_tun_device == SSH_TUNID_ERR) { 314021d409fSDag-Erling Smørgrav debug("%.100s, line %lu: invalid tun device", 315021d409fSDag-Erling Smørgrav file, linenum); 316021d409fSDag-Erling Smørgrav auth_debug_add("%.100s, line %lu: invalid tun device", 317021d409fSDag-Erling Smørgrav file, linenum); 318021d409fSDag-Erling Smørgrav forced_tun_device = -1; 319021d409fSDag-Erling Smørgrav goto bad_option; 320021d409fSDag-Erling Smørgrav } 321021d409fSDag-Erling Smørgrav auth_debug_add("Forced tun device: %d", forced_tun_device); 322021d409fSDag-Erling Smørgrav opts++; 323021d409fSDag-Erling Smørgrav goto next_option; 324021d409fSDag-Erling Smørgrav } 325b66f2d16SKris Kennaway next_option: 326b66f2d16SKris Kennaway /* 327b66f2d16SKris Kennaway * Skip the comma, and move to the next option 328b66f2d16SKris Kennaway * (or break out if there are no more). 329b66f2d16SKris Kennaway */ 3301e8db6e2SBrian Feldman if (!*opts) 331b66f2d16SKris Kennaway fatal("Bugs in auth-options.c option processing."); 3321e8db6e2SBrian Feldman if (*opts == ' ' || *opts == '\t') 333b66f2d16SKris Kennaway break; /* End of options. */ 3341e8db6e2SBrian Feldman if (*opts != ',') 335b66f2d16SKris Kennaway goto bad_option; 3361e8db6e2SBrian Feldman opts++; 337b66f2d16SKris Kennaway /* Process the next option. */ 338b66f2d16SKris Kennaway } 339545d5ecaSDag-Erling Smørgrav 340545d5ecaSDag-Erling Smørgrav if (!use_privsep) 341545d5ecaSDag-Erling Smørgrav auth_debug_send(); 342545d5ecaSDag-Erling Smørgrav 343b66f2d16SKris Kennaway /* grant access */ 344b66f2d16SKris Kennaway return 1; 345b66f2d16SKris Kennaway 346b66f2d16SKris Kennaway bad_option: 347d95e11bfSDag-Erling Smørgrav logit("Bad options in %.100s file, line %lu: %.50s", 3481e8db6e2SBrian Feldman file, linenum, opts); 349545d5ecaSDag-Erling Smørgrav auth_debug_add("Bad options in %.100s file, line %lu: %.50s", 3501e8db6e2SBrian Feldman file, linenum, opts); 351545d5ecaSDag-Erling Smørgrav 352545d5ecaSDag-Erling Smørgrav if (!use_privsep) 353545d5ecaSDag-Erling Smørgrav auth_debug_send(); 354545d5ecaSDag-Erling Smørgrav 355b66f2d16SKris Kennaway /* deny access */ 356b66f2d16SKris Kennaway return 0; 357b66f2d16SKris Kennaway } 358