1*bc5531deSDag-Erling Smørgrav /* $OpenBSD: auth-options.c,v 1.65 2015/01/14 10:30:34 markus 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 23d4af9e69SDag-Erling Smørgrav #include "openbsd-compat/sys-queue.h" 24*bc5531deSDag-Erling Smørgrav 25*bc5531deSDag-Erling Smørgrav #include "key.h" /* XXX for typedef */ 26*bc5531deSDag-Erling Smørgrav #include "buffer.h" /* XXX for typedef */ 27b66f2d16SKris Kennaway #include "xmalloc.h" 28b66f2d16SKris Kennaway #include "match.h" 29*bc5531deSDag-Erling Smørgrav #include "ssherr.h" 301e8db6e2SBrian Feldman #include "log.h" 311e8db6e2SBrian Feldman #include "canohost.h" 32*bc5531deSDag-Erling Smørgrav #include "sshbuf.h" 33a0ee8cc6SDag-Erling Smørgrav #include "misc.h" 341e8db6e2SBrian Feldman #include "channels.h" 351e8db6e2SBrian Feldman #include "servconf.h" 36*bc5531deSDag-Erling Smørgrav #include "sshkey.h" 37e2f6069cSDag-Erling Smørgrav #include "auth-options.h" 38761efaa7SDag-Erling Smørgrav #include "hostfile.h" 39545d5ecaSDag-Erling Smørgrav #include "auth.h" 40b66f2d16SKris Kennaway 41b66f2d16SKris Kennaway /* Flags set authorized_keys flags */ 42b66f2d16SKris Kennaway int no_port_forwarding_flag = 0; 43b66f2d16SKris Kennaway int no_agent_forwarding_flag = 0; 44b66f2d16SKris Kennaway int no_x11_forwarding_flag = 0; 45b66f2d16SKris Kennaway int no_pty_flag = 0; 46d4af9e69SDag-Erling Smørgrav int no_user_rc = 0; 47b15c8340SDag-Erling Smørgrav int key_is_cert_authority = 0; 48b66f2d16SKris Kennaway 49b66f2d16SKris Kennaway /* "command=" option. */ 50b66f2d16SKris Kennaway char *forced_command = NULL; 51b66f2d16SKris Kennaway 52b66f2d16SKris Kennaway /* "environment=" options. */ 53b66f2d16SKris Kennaway struct envstring *custom_environment = NULL; 54b66f2d16SKris Kennaway 55021d409fSDag-Erling Smørgrav /* "tunnel=" option. */ 56021d409fSDag-Erling Smørgrav int forced_tun_device = -1; 57021d409fSDag-Erling Smørgrav 58e2f6069cSDag-Erling Smørgrav /* "principals=" option. */ 59e2f6069cSDag-Erling Smørgrav char *authorized_principals = NULL; 60e2f6069cSDag-Erling Smørgrav 611e8db6e2SBrian Feldman extern ServerOptions options; 621e8db6e2SBrian Feldman 635b9b2fafSBrian Feldman void 645b9b2fafSBrian Feldman auth_clear_options(void) 655b9b2fafSBrian Feldman { 665b9b2fafSBrian Feldman no_agent_forwarding_flag = 0; 675b9b2fafSBrian Feldman no_port_forwarding_flag = 0; 685b9b2fafSBrian Feldman no_pty_flag = 0; 695b9b2fafSBrian Feldman no_x11_forwarding_flag = 0; 70d4af9e69SDag-Erling Smørgrav no_user_rc = 0; 71b15c8340SDag-Erling Smørgrav key_is_cert_authority = 0; 725b9b2fafSBrian Feldman while (custom_environment) { 735b9b2fafSBrian Feldman struct envstring *ce = custom_environment; 745b9b2fafSBrian Feldman custom_environment = ce->next; 75e4a9863fSDag-Erling Smørgrav free(ce->s); 76e4a9863fSDag-Erling Smørgrav free(ce); 775b9b2fafSBrian Feldman } 785b9b2fafSBrian Feldman if (forced_command) { 79e4a9863fSDag-Erling Smørgrav free(forced_command); 805b9b2fafSBrian Feldman forced_command = NULL; 815b9b2fafSBrian Feldman } 82e2f6069cSDag-Erling Smørgrav if (authorized_principals) { 83e4a9863fSDag-Erling Smørgrav free(authorized_principals); 84e2f6069cSDag-Erling Smørgrav authorized_principals = NULL; 85e2f6069cSDag-Erling Smørgrav } 86021d409fSDag-Erling Smørgrav forced_tun_device = -1; 871e8db6e2SBrian Feldman channel_clear_permitted_opens(); 885b9b2fafSBrian Feldman } 895b9b2fafSBrian Feldman 901e8db6e2SBrian Feldman /* 911e8db6e2SBrian Feldman * return 1 if access is granted, 0 if not. 921e8db6e2SBrian Feldman * side effect: sets key option flags 931e8db6e2SBrian Feldman */ 94b66f2d16SKris Kennaway int 951e8db6e2SBrian Feldman auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) 96b66f2d16SKris Kennaway { 97b66f2d16SKris Kennaway const char *cp; 981e8db6e2SBrian Feldman int i; 995b9b2fafSBrian Feldman 1005b9b2fafSBrian Feldman /* reset options */ 1015b9b2fafSBrian Feldman auth_clear_options(); 1025b9b2fafSBrian Feldman 1031e8db6e2SBrian Feldman if (!opts) 1041e8db6e2SBrian Feldman return 1; 1051e8db6e2SBrian Feldman 1061e8db6e2SBrian Feldman while (*opts && *opts != ' ' && *opts != '\t') { 107b15c8340SDag-Erling Smørgrav cp = "cert-authority"; 108b15c8340SDag-Erling Smørgrav if (strncasecmp(opts, cp, strlen(cp)) == 0) { 109b15c8340SDag-Erling Smørgrav key_is_cert_authority = 1; 110b15c8340SDag-Erling Smørgrav opts += strlen(cp); 111b15c8340SDag-Erling Smørgrav goto next_option; 112b15c8340SDag-Erling Smørgrav } 113b66f2d16SKris Kennaway cp = "no-port-forwarding"; 1141e8db6e2SBrian Feldman if (strncasecmp(opts, cp, strlen(cp)) == 0) { 115545d5ecaSDag-Erling Smørgrav auth_debug_add("Port forwarding disabled."); 116b66f2d16SKris Kennaway no_port_forwarding_flag = 1; 1171e8db6e2SBrian Feldman opts += strlen(cp); 118b66f2d16SKris Kennaway goto next_option; 119b66f2d16SKris Kennaway } 120b66f2d16SKris Kennaway cp = "no-agent-forwarding"; 1211e8db6e2SBrian Feldman if (strncasecmp(opts, cp, strlen(cp)) == 0) { 122545d5ecaSDag-Erling Smørgrav auth_debug_add("Agent forwarding disabled."); 123b66f2d16SKris Kennaway no_agent_forwarding_flag = 1; 1241e8db6e2SBrian Feldman opts += strlen(cp); 125b66f2d16SKris Kennaway goto next_option; 126b66f2d16SKris Kennaway } 127b66f2d16SKris Kennaway cp = "no-X11-forwarding"; 1281e8db6e2SBrian Feldman if (strncasecmp(opts, cp, strlen(cp)) == 0) { 129545d5ecaSDag-Erling Smørgrav auth_debug_add("X11 forwarding disabled."); 130b66f2d16SKris Kennaway no_x11_forwarding_flag = 1; 1311e8db6e2SBrian Feldman opts += strlen(cp); 132b66f2d16SKris Kennaway goto next_option; 133b66f2d16SKris Kennaway } 134b66f2d16SKris Kennaway cp = "no-pty"; 1351e8db6e2SBrian Feldman if (strncasecmp(opts, cp, strlen(cp)) == 0) { 136545d5ecaSDag-Erling Smørgrav auth_debug_add("Pty allocation disabled."); 137b66f2d16SKris Kennaway no_pty_flag = 1; 1381e8db6e2SBrian Feldman opts += strlen(cp); 139b66f2d16SKris Kennaway goto next_option; 140b66f2d16SKris Kennaway } 141d4af9e69SDag-Erling Smørgrav cp = "no-user-rc"; 142d4af9e69SDag-Erling Smørgrav if (strncasecmp(opts, cp, strlen(cp)) == 0) { 143d4af9e69SDag-Erling Smørgrav auth_debug_add("User rc file execution disabled."); 144d4af9e69SDag-Erling Smørgrav no_user_rc = 1; 145d4af9e69SDag-Erling Smørgrav opts += strlen(cp); 146d4af9e69SDag-Erling Smørgrav goto next_option; 147d4af9e69SDag-Erling Smørgrav } 148b66f2d16SKris Kennaway cp = "command=\""; 1491e8db6e2SBrian Feldman if (strncasecmp(opts, cp, strlen(cp)) == 0) { 1501e8db6e2SBrian Feldman opts += strlen(cp); 151e2f6069cSDag-Erling Smørgrav if (forced_command != NULL) 152e4a9863fSDag-Erling Smørgrav free(forced_command); 1531e8db6e2SBrian Feldman forced_command = xmalloc(strlen(opts) + 1); 154b66f2d16SKris Kennaway i = 0; 1551e8db6e2SBrian Feldman while (*opts) { 1561e8db6e2SBrian Feldman if (*opts == '"') 157b66f2d16SKris Kennaway break; 1581e8db6e2SBrian Feldman if (*opts == '\\' && opts[1] == '"') { 1591e8db6e2SBrian Feldman opts += 2; 160b66f2d16SKris Kennaway forced_command[i++] = '"'; 161b66f2d16SKris Kennaway continue; 162b66f2d16SKris Kennaway } 1631e8db6e2SBrian Feldman forced_command[i++] = *opts++; 164b66f2d16SKris Kennaway } 1651e8db6e2SBrian Feldman if (!*opts) { 166b66f2d16SKris Kennaway debug("%.100s, line %lu: missing end quote", 1671e8db6e2SBrian Feldman file, linenum); 168545d5ecaSDag-Erling Smørgrav auth_debug_add("%.100s, line %lu: missing end quote", 1691e8db6e2SBrian Feldman file, linenum); 170e4a9863fSDag-Erling Smørgrav free(forced_command); 1711e8db6e2SBrian Feldman forced_command = NULL; 1721e8db6e2SBrian Feldman goto bad_option; 173b66f2d16SKris Kennaway } 174761efaa7SDag-Erling Smørgrav forced_command[i] = '\0'; 1754a421b63SDag-Erling Smørgrav auth_debug_add("Forced command."); 1761e8db6e2SBrian Feldman opts++; 177b66f2d16SKris Kennaway goto next_option; 178b66f2d16SKris Kennaway } 179e2f6069cSDag-Erling Smørgrav cp = "principals=\""; 180e2f6069cSDag-Erling Smørgrav if (strncasecmp(opts, cp, strlen(cp)) == 0) { 181e2f6069cSDag-Erling Smørgrav opts += strlen(cp); 182e2f6069cSDag-Erling Smørgrav if (authorized_principals != NULL) 183e4a9863fSDag-Erling Smørgrav free(authorized_principals); 184e2f6069cSDag-Erling Smørgrav authorized_principals = xmalloc(strlen(opts) + 1); 185e2f6069cSDag-Erling Smørgrav i = 0; 186e2f6069cSDag-Erling Smørgrav while (*opts) { 187e2f6069cSDag-Erling Smørgrav if (*opts == '"') 188e2f6069cSDag-Erling Smørgrav break; 189e2f6069cSDag-Erling Smørgrav if (*opts == '\\' && opts[1] == '"') { 190e2f6069cSDag-Erling Smørgrav opts += 2; 191e2f6069cSDag-Erling Smørgrav authorized_principals[i++] = '"'; 192e2f6069cSDag-Erling Smørgrav continue; 193e2f6069cSDag-Erling Smørgrav } 194e2f6069cSDag-Erling Smørgrav authorized_principals[i++] = *opts++; 195e2f6069cSDag-Erling Smørgrav } 196e2f6069cSDag-Erling Smørgrav if (!*opts) { 197e2f6069cSDag-Erling Smørgrav debug("%.100s, line %lu: missing end quote", 198e2f6069cSDag-Erling Smørgrav file, linenum); 199e2f6069cSDag-Erling Smørgrav auth_debug_add("%.100s, line %lu: missing end quote", 200e2f6069cSDag-Erling Smørgrav file, linenum); 201e4a9863fSDag-Erling Smørgrav free(authorized_principals); 202e2f6069cSDag-Erling Smørgrav authorized_principals = NULL; 203e2f6069cSDag-Erling Smørgrav goto bad_option; 204e2f6069cSDag-Erling Smørgrav } 205e2f6069cSDag-Erling Smørgrav authorized_principals[i] = '\0'; 206e2f6069cSDag-Erling Smørgrav auth_debug_add("principals: %.900s", 207e2f6069cSDag-Erling Smørgrav authorized_principals); 208e2f6069cSDag-Erling Smørgrav opts++; 209e2f6069cSDag-Erling Smørgrav goto next_option; 210e2f6069cSDag-Erling Smørgrav } 211b66f2d16SKris Kennaway cp = "environment=\""; 2124b17dab0SDag-Erling Smørgrav if (options.permit_user_env && 2134b17dab0SDag-Erling Smørgrav strncasecmp(opts, cp, strlen(cp)) == 0) { 214b66f2d16SKris Kennaway char *s; 215b66f2d16SKris Kennaway struct envstring *new_envstring; 2161e8db6e2SBrian Feldman 2171e8db6e2SBrian Feldman opts += strlen(cp); 2181e8db6e2SBrian Feldman s = xmalloc(strlen(opts) + 1); 219b66f2d16SKris Kennaway i = 0; 2201e8db6e2SBrian Feldman while (*opts) { 2211e8db6e2SBrian Feldman if (*opts == '"') 222b66f2d16SKris Kennaway break; 2231e8db6e2SBrian Feldman if (*opts == '\\' && opts[1] == '"') { 2241e8db6e2SBrian Feldman opts += 2; 225b66f2d16SKris Kennaway s[i++] = '"'; 226b66f2d16SKris Kennaway continue; 227b66f2d16SKris Kennaway } 2281e8db6e2SBrian Feldman s[i++] = *opts++; 229b66f2d16SKris Kennaway } 2301e8db6e2SBrian Feldman if (!*opts) { 231b66f2d16SKris Kennaway debug("%.100s, line %lu: missing end quote", 2321e8db6e2SBrian Feldman file, linenum); 233545d5ecaSDag-Erling Smørgrav auth_debug_add("%.100s, line %lu: missing end quote", 2341e8db6e2SBrian Feldman file, linenum); 235e4a9863fSDag-Erling Smørgrav free(s); 2361e8db6e2SBrian Feldman goto bad_option; 237b66f2d16SKris Kennaway } 238761efaa7SDag-Erling Smørgrav s[i] = '\0'; 239545d5ecaSDag-Erling Smørgrav auth_debug_add("Adding to environment: %.900s", s); 240b66f2d16SKris Kennaway debug("Adding to environment: %.900s", s); 2411e8db6e2SBrian Feldman opts++; 2420a37d4a3SXin LI new_envstring = xcalloc(1, sizeof(struct envstring)); 243b66f2d16SKris Kennaway new_envstring->s = s; 244b66f2d16SKris Kennaway new_envstring->next = custom_environment; 245b66f2d16SKris Kennaway custom_environment = new_envstring; 246b66f2d16SKris Kennaway goto next_option; 247b66f2d16SKris Kennaway } 248b66f2d16SKris Kennaway cp = "from=\""; 2491e8db6e2SBrian Feldman if (strncasecmp(opts, cp, strlen(cp)) == 0) { 2501e8db6e2SBrian Feldman const char *remote_ip = get_remote_ipaddr(); 2511e8db6e2SBrian Feldman const char *remote_host = get_canonical_hostname( 252d95e11bfSDag-Erling Smørgrav options.use_dns); 2531e8db6e2SBrian Feldman char *patterns = xmalloc(strlen(opts) + 1); 2541e8db6e2SBrian Feldman 2551e8db6e2SBrian Feldman opts += strlen(cp); 256b66f2d16SKris Kennaway i = 0; 2571e8db6e2SBrian Feldman while (*opts) { 2581e8db6e2SBrian Feldman if (*opts == '"') 259b66f2d16SKris Kennaway break; 2601e8db6e2SBrian Feldman if (*opts == '\\' && opts[1] == '"') { 2611e8db6e2SBrian Feldman opts += 2; 262b66f2d16SKris Kennaway patterns[i++] = '"'; 263b66f2d16SKris Kennaway continue; 264b66f2d16SKris Kennaway } 2651e8db6e2SBrian Feldman patterns[i++] = *opts++; 266b66f2d16SKris Kennaway } 2671e8db6e2SBrian Feldman if (!*opts) { 268b66f2d16SKris Kennaway debug("%.100s, line %lu: missing end quote", 2691e8db6e2SBrian Feldman file, linenum); 270545d5ecaSDag-Erling Smørgrav auth_debug_add("%.100s, line %lu: missing end quote", 2711e8db6e2SBrian Feldman file, linenum); 272e4a9863fSDag-Erling Smørgrav free(patterns); 2731e8db6e2SBrian Feldman goto bad_option; 274b66f2d16SKris Kennaway } 275761efaa7SDag-Erling Smørgrav patterns[i] = '\0'; 2761e8db6e2SBrian Feldman opts++; 277d4af9e69SDag-Erling Smørgrav switch (match_host_and_ip(remote_host, remote_ip, 278d4af9e69SDag-Erling Smørgrav patterns)) { 279d4af9e69SDag-Erling Smørgrav case 1: 280e4a9863fSDag-Erling Smørgrav free(patterns); 281d4af9e69SDag-Erling Smørgrav /* Host name matches. */ 282d4af9e69SDag-Erling Smørgrav goto next_option; 283d4af9e69SDag-Erling Smørgrav case -1: 284d4af9e69SDag-Erling Smørgrav debug("%.100s, line %lu: invalid criteria", 285d4af9e69SDag-Erling Smørgrav file, linenum); 286d4af9e69SDag-Erling Smørgrav auth_debug_add("%.100s, line %lu: " 287d4af9e69SDag-Erling Smørgrav "invalid criteria", file, linenum); 288d4af9e69SDag-Erling Smørgrav /* FALLTHROUGH */ 289d4af9e69SDag-Erling Smørgrav case 0: 290e4a9863fSDag-Erling Smørgrav free(patterns); 291d95e11bfSDag-Erling Smørgrav logit("Authentication tried for %.100s with " 2921e8db6e2SBrian Feldman "correct key but not from a permitted " 2931e8db6e2SBrian Feldman "host (host=%.200s, ip=%.200s).", 2941e8db6e2SBrian Feldman pw->pw_name, remote_host, remote_ip); 295545d5ecaSDag-Erling Smørgrav auth_debug_add("Your host '%.200s' is not " 2961e8db6e2SBrian Feldman "permitted to use this key for login.", 2971e8db6e2SBrian Feldman remote_host); 298d4af9e69SDag-Erling Smørgrav break; 299d4af9e69SDag-Erling Smørgrav } 300b66f2d16SKris Kennaway /* deny access */ 301b66f2d16SKris Kennaway return 0; 302b66f2d16SKris Kennaway } 3031e8db6e2SBrian Feldman cp = "permitopen=\""; 3041e8db6e2SBrian Feldman if (strncasecmp(opts, cp, strlen(cp)) == 0) { 3055e8dbd04SDag-Erling Smørgrav char *host, *p; 306cce7d346SDag-Erling Smørgrav int port; 3071e8db6e2SBrian Feldman char *patterns = xmalloc(strlen(opts) + 1); 3081e8db6e2SBrian Feldman 3091e8db6e2SBrian Feldman opts += strlen(cp); 3101e8db6e2SBrian Feldman i = 0; 3111e8db6e2SBrian Feldman while (*opts) { 3121e8db6e2SBrian Feldman if (*opts == '"') 3131e8db6e2SBrian Feldman break; 3141e8db6e2SBrian Feldman if (*opts == '\\' && opts[1] == '"') { 3151e8db6e2SBrian Feldman opts += 2; 3161e8db6e2SBrian Feldman patterns[i++] = '"'; 3171e8db6e2SBrian Feldman continue; 3181e8db6e2SBrian Feldman } 3191e8db6e2SBrian Feldman patterns[i++] = *opts++; 3201e8db6e2SBrian Feldman } 3211e8db6e2SBrian Feldman if (!*opts) { 3221e8db6e2SBrian Feldman debug("%.100s, line %lu: missing end quote", 3231e8db6e2SBrian Feldman file, linenum); 3245e8dbd04SDag-Erling Smørgrav auth_debug_add("%.100s, line %lu: missing " 3255e8dbd04SDag-Erling Smørgrav "end quote", file, linenum); 326e4a9863fSDag-Erling Smørgrav free(patterns); 3271e8db6e2SBrian Feldman goto bad_option; 3281e8db6e2SBrian Feldman } 329761efaa7SDag-Erling Smørgrav patterns[i] = '\0'; 3301e8db6e2SBrian Feldman opts++; 3315e8dbd04SDag-Erling Smørgrav p = patterns; 332a0ee8cc6SDag-Erling Smørgrav /* XXX - add streamlocal support */ 3335e8dbd04SDag-Erling Smørgrav host = hpdelim(&p); 3345e8dbd04SDag-Erling Smørgrav if (host == NULL || strlen(host) >= NI_MAXHOST) { 3355e8dbd04SDag-Erling Smørgrav debug("%.100s, line %lu: Bad permitopen " 3365e8dbd04SDag-Erling Smørgrav "specification <%.100s>", file, linenum, 3375e8dbd04SDag-Erling Smørgrav patterns); 338545d5ecaSDag-Erling Smørgrav auth_debug_add("%.100s, line %lu: " 3395e8dbd04SDag-Erling Smørgrav "Bad permitopen specification", file, 3405e8dbd04SDag-Erling Smørgrav linenum); 341e4a9863fSDag-Erling Smørgrav free(patterns); 3421e8db6e2SBrian Feldman goto bad_option; 3431e8db6e2SBrian Feldman } 3445e8dbd04SDag-Erling Smørgrav host = cleanhostname(host); 345462c32cbSDag-Erling Smørgrav if (p == NULL || (port = permitopen_port(p)) < 0) { 3465e8dbd04SDag-Erling Smørgrav debug("%.100s, line %lu: Bad permitopen port " 3475e8dbd04SDag-Erling Smørgrav "<%.100s>", file, linenum, p ? p : ""); 348545d5ecaSDag-Erling Smørgrav auth_debug_add("%.100s, line %lu: " 349ae1f160dSDag-Erling Smørgrav "Bad permitopen port", file, linenum); 350e4a9863fSDag-Erling Smørgrav free(patterns); 3511e8db6e2SBrian Feldman goto bad_option; 3521e8db6e2SBrian Feldman } 3536888a9beSDag-Erling Smørgrav if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0) 354ae1f160dSDag-Erling Smørgrav channel_add_permitted_opens(host, port); 355e4a9863fSDag-Erling Smørgrav free(patterns); 3561e8db6e2SBrian Feldman goto next_option; 3571e8db6e2SBrian Feldman } 358021d409fSDag-Erling Smørgrav cp = "tunnel=\""; 359021d409fSDag-Erling Smørgrav if (strncasecmp(opts, cp, strlen(cp)) == 0) { 360021d409fSDag-Erling Smørgrav char *tun = NULL; 361021d409fSDag-Erling Smørgrav opts += strlen(cp); 362021d409fSDag-Erling Smørgrav tun = xmalloc(strlen(opts) + 1); 363021d409fSDag-Erling Smørgrav i = 0; 364021d409fSDag-Erling Smørgrav while (*opts) { 365021d409fSDag-Erling Smørgrav if (*opts == '"') 366021d409fSDag-Erling Smørgrav break; 367021d409fSDag-Erling Smørgrav tun[i++] = *opts++; 368021d409fSDag-Erling Smørgrav } 369021d409fSDag-Erling Smørgrav if (!*opts) { 370021d409fSDag-Erling Smørgrav debug("%.100s, line %lu: missing end quote", 371021d409fSDag-Erling Smørgrav file, linenum); 372021d409fSDag-Erling Smørgrav auth_debug_add("%.100s, line %lu: missing end quote", 373021d409fSDag-Erling Smørgrav file, linenum); 374e4a9863fSDag-Erling Smørgrav free(tun); 375021d409fSDag-Erling Smørgrav forced_tun_device = -1; 376021d409fSDag-Erling Smørgrav goto bad_option; 377021d409fSDag-Erling Smørgrav } 378761efaa7SDag-Erling Smørgrav tun[i] = '\0'; 379021d409fSDag-Erling Smørgrav forced_tun_device = a2tun(tun, NULL); 380e4a9863fSDag-Erling Smørgrav free(tun); 381021d409fSDag-Erling Smørgrav if (forced_tun_device == SSH_TUNID_ERR) { 382021d409fSDag-Erling Smørgrav debug("%.100s, line %lu: invalid tun device", 383021d409fSDag-Erling Smørgrav file, linenum); 384021d409fSDag-Erling Smørgrav auth_debug_add("%.100s, line %lu: invalid tun device", 385021d409fSDag-Erling Smørgrav file, linenum); 386021d409fSDag-Erling Smørgrav forced_tun_device = -1; 387021d409fSDag-Erling Smørgrav goto bad_option; 388021d409fSDag-Erling Smørgrav } 389021d409fSDag-Erling Smørgrav auth_debug_add("Forced tun device: %d", forced_tun_device); 390021d409fSDag-Erling Smørgrav opts++; 391021d409fSDag-Erling Smørgrav goto next_option; 392021d409fSDag-Erling Smørgrav } 393b66f2d16SKris Kennaway next_option: 394b66f2d16SKris Kennaway /* 395b66f2d16SKris Kennaway * Skip the comma, and move to the next option 396b66f2d16SKris Kennaway * (or break out if there are no more). 397b66f2d16SKris Kennaway */ 3981e8db6e2SBrian Feldman if (!*opts) 399b66f2d16SKris Kennaway fatal("Bugs in auth-options.c option processing."); 4001e8db6e2SBrian Feldman if (*opts == ' ' || *opts == '\t') 401b66f2d16SKris Kennaway break; /* End of options. */ 4021e8db6e2SBrian Feldman if (*opts != ',') 403b66f2d16SKris Kennaway goto bad_option; 4041e8db6e2SBrian Feldman opts++; 405b66f2d16SKris Kennaway /* Process the next option. */ 406b66f2d16SKris Kennaway } 407545d5ecaSDag-Erling Smørgrav 408b66f2d16SKris Kennaway /* grant access */ 409b66f2d16SKris Kennaway return 1; 410b66f2d16SKris Kennaway 411b66f2d16SKris Kennaway bad_option: 412d95e11bfSDag-Erling Smørgrav logit("Bad options in %.100s file, line %lu: %.50s", 4131e8db6e2SBrian Feldman file, linenum, opts); 414545d5ecaSDag-Erling Smørgrav auth_debug_add("Bad options in %.100s file, line %lu: %.50s", 4151e8db6e2SBrian Feldman file, linenum, opts); 416545d5ecaSDag-Erling Smørgrav 417b66f2d16SKris Kennaway /* deny access */ 418b66f2d16SKris Kennaway return 0; 419b66f2d16SKris Kennaway } 420b15c8340SDag-Erling Smørgrav 421e2f6069cSDag-Erling Smørgrav #define OPTIONS_CRITICAL 1 422e2f6069cSDag-Erling Smørgrav #define OPTIONS_EXTENSIONS 2 423e2f6069cSDag-Erling Smørgrav static int 424*bc5531deSDag-Erling Smørgrav parse_option_list(struct sshbuf *oblob, struct passwd *pw, 425e2f6069cSDag-Erling Smørgrav u_int which, int crit, 426e2f6069cSDag-Erling Smørgrav int *cert_no_port_forwarding_flag, 427e2f6069cSDag-Erling Smørgrav int *cert_no_agent_forwarding_flag, 428e2f6069cSDag-Erling Smørgrav int *cert_no_x11_forwarding_flag, 429e2f6069cSDag-Erling Smørgrav int *cert_no_pty_flag, 430e2f6069cSDag-Erling Smørgrav int *cert_no_user_rc, 431e2f6069cSDag-Erling Smørgrav char **cert_forced_command, 432e2f6069cSDag-Erling Smørgrav int *cert_source_address_done) 433b15c8340SDag-Erling Smørgrav { 434e2f6069cSDag-Erling Smørgrav char *command, *allowed; 435e2f6069cSDag-Erling Smørgrav const char *remote_ip; 436e4a9863fSDag-Erling Smørgrav char *name = NULL; 437*bc5531deSDag-Erling Smørgrav struct sshbuf *c = NULL, *data = NULL; 438*bc5531deSDag-Erling Smørgrav int r, ret = -1, result, found; 439b15c8340SDag-Erling Smørgrav 440*bc5531deSDag-Erling Smørgrav if ((c = sshbuf_fromb(oblob)) == NULL) { 441*bc5531deSDag-Erling Smørgrav error("%s: sshbuf_fromb failed", __func__); 442b15c8340SDag-Erling Smørgrav goto out; 443b15c8340SDag-Erling Smørgrav } 444*bc5531deSDag-Erling Smørgrav 445*bc5531deSDag-Erling Smørgrav while (sshbuf_len(c) > 0) { 446*bc5531deSDag-Erling Smørgrav sshbuf_free(data); 447*bc5531deSDag-Erling Smørgrav data = NULL; 448*bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_cstring(c, &name, NULL)) != 0 || 449*bc5531deSDag-Erling Smørgrav (r = sshbuf_froms(c, &data)) != 0) { 450*bc5531deSDag-Erling Smørgrav error("Unable to parse certificate options: %s", 451*bc5531deSDag-Erling Smørgrav ssh_err(r)); 452*bc5531deSDag-Erling Smørgrav goto out; 453*bc5531deSDag-Erling Smørgrav } 454*bc5531deSDag-Erling Smørgrav debug3("found certificate option \"%.100s\" len %zu", 455*bc5531deSDag-Erling Smørgrav name, sshbuf_len(data)); 456e2f6069cSDag-Erling Smørgrav found = 0; 457e2f6069cSDag-Erling Smørgrav if ((which & OPTIONS_EXTENSIONS) != 0) { 458e2f6069cSDag-Erling Smørgrav if (strcmp(name, "permit-X11-forwarding") == 0) { 459e2f6069cSDag-Erling Smørgrav *cert_no_x11_forwarding_flag = 0; 460e2f6069cSDag-Erling Smørgrav found = 1; 461e2f6069cSDag-Erling Smørgrav } else if (strcmp(name, 462e2f6069cSDag-Erling Smørgrav "permit-agent-forwarding") == 0) { 463e2f6069cSDag-Erling Smørgrav *cert_no_agent_forwarding_flag = 0; 464e2f6069cSDag-Erling Smørgrav found = 1; 465e2f6069cSDag-Erling Smørgrav } else if (strcmp(name, 466e2f6069cSDag-Erling Smørgrav "permit-port-forwarding") == 0) { 467e2f6069cSDag-Erling Smørgrav *cert_no_port_forwarding_flag = 0; 468e2f6069cSDag-Erling Smørgrav found = 1; 469e2f6069cSDag-Erling Smørgrav } else if (strcmp(name, "permit-pty") == 0) { 470e2f6069cSDag-Erling Smørgrav *cert_no_pty_flag = 0; 471e2f6069cSDag-Erling Smørgrav found = 1; 472e2f6069cSDag-Erling Smørgrav } else if (strcmp(name, "permit-user-rc") == 0) { 473e2f6069cSDag-Erling Smørgrav *cert_no_user_rc = 0; 474e2f6069cSDag-Erling Smørgrav found = 1; 475e2f6069cSDag-Erling Smørgrav } 476e2f6069cSDag-Erling Smørgrav } 477e2f6069cSDag-Erling Smørgrav if (!found && (which & OPTIONS_CRITICAL) != 0) { 478e2f6069cSDag-Erling Smørgrav if (strcmp(name, "force-command") == 0) { 479*bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_cstring(data, &command, 480*bc5531deSDag-Erling Smørgrav NULL)) != 0) { 481*bc5531deSDag-Erling Smørgrav error("Unable to parse \"%s\" " 482*bc5531deSDag-Erling Smørgrav "section: %s", name, ssh_err(r)); 483b15c8340SDag-Erling Smørgrav goto out; 484b15c8340SDag-Erling Smørgrav } 485e2f6069cSDag-Erling Smørgrav if (*cert_forced_command != NULL) { 486b15c8340SDag-Erling Smørgrav error("Certificate has multiple " 487e2f6069cSDag-Erling Smørgrav "force-command options"); 488e4a9863fSDag-Erling Smørgrav free(command); 489b15c8340SDag-Erling Smørgrav goto out; 490b15c8340SDag-Erling Smørgrav } 491e2f6069cSDag-Erling Smørgrav *cert_forced_command = command; 492e2f6069cSDag-Erling Smørgrav found = 1; 493e2f6069cSDag-Erling Smørgrav } 494e2f6069cSDag-Erling Smørgrav if (strcmp(name, "source-address") == 0) { 495*bc5531deSDag-Erling Smørgrav if ((r = sshbuf_get_cstring(data, &allowed, 496*bc5531deSDag-Erling Smørgrav NULL)) != 0) { 497*bc5531deSDag-Erling Smørgrav error("Unable to parse \"%s\" " 498*bc5531deSDag-Erling Smørgrav "section: %s", name, ssh_err(r)); 499b15c8340SDag-Erling Smørgrav goto out; 500b15c8340SDag-Erling Smørgrav } 501e2f6069cSDag-Erling Smørgrav if ((*cert_source_address_done)++) { 502b15c8340SDag-Erling Smørgrav error("Certificate has multiple " 503e2f6069cSDag-Erling Smørgrav "source-address options"); 504e4a9863fSDag-Erling Smørgrav free(allowed); 505b15c8340SDag-Erling Smørgrav goto out; 506b15c8340SDag-Erling Smørgrav } 507e2f6069cSDag-Erling Smørgrav remote_ip = get_remote_ipaddr(); 508f7167e0eSDag-Erling Smørgrav result = addr_match_cidr_list(remote_ip, 509f7167e0eSDag-Erling Smørgrav allowed); 510f7167e0eSDag-Erling Smørgrav free(allowed); 511f7167e0eSDag-Erling Smørgrav switch (result) { 512b15c8340SDag-Erling Smørgrav case 1: 513b15c8340SDag-Erling Smørgrav /* accepted */ 514b15c8340SDag-Erling Smørgrav break; 515b15c8340SDag-Erling Smørgrav case 0: 516b15c8340SDag-Erling Smørgrav /* no match */ 517e2f6069cSDag-Erling Smørgrav logit("Authentication tried for %.100s " 518e2f6069cSDag-Erling Smørgrav "with valid certificate but not " 519e2f6069cSDag-Erling Smørgrav "from a permitted host " 520e2f6069cSDag-Erling Smørgrav "(ip=%.200s).", pw->pw_name, 521e2f6069cSDag-Erling Smørgrav remote_ip); 522e2f6069cSDag-Erling Smørgrav auth_debug_add("Your address '%.200s' " 523e2f6069cSDag-Erling Smørgrav "is not permitted to use this " 524e2f6069cSDag-Erling Smørgrav "certificate for login.", 525e2f6069cSDag-Erling Smørgrav remote_ip); 526b15c8340SDag-Erling Smørgrav goto out; 527b15c8340SDag-Erling Smørgrav case -1: 528f7167e0eSDag-Erling Smørgrav default: 529e2f6069cSDag-Erling Smørgrav error("Certificate source-address " 530e2f6069cSDag-Erling Smørgrav "contents invalid"); 531b15c8340SDag-Erling Smørgrav goto out; 532b15c8340SDag-Erling Smørgrav } 533e2f6069cSDag-Erling Smørgrav found = 1; 534e2f6069cSDag-Erling Smørgrav } 535b15c8340SDag-Erling Smørgrav } 536b15c8340SDag-Erling Smørgrav 537e2f6069cSDag-Erling Smørgrav if (!found) { 538e2f6069cSDag-Erling Smørgrav if (crit) { 539e2f6069cSDag-Erling Smørgrav error("Certificate critical option \"%s\" " 540e2f6069cSDag-Erling Smørgrav "is not supported", name); 541e2f6069cSDag-Erling Smørgrav goto out; 542e2f6069cSDag-Erling Smørgrav } else { 543e2f6069cSDag-Erling Smørgrav logit("Certificate extension \"%s\" " 544e2f6069cSDag-Erling Smørgrav "is not supported", name); 545e2f6069cSDag-Erling Smørgrav } 546*bc5531deSDag-Erling Smørgrav } else if (sshbuf_len(data) != 0) { 547e2f6069cSDag-Erling Smørgrav error("Certificate option \"%s\" corrupt " 548b15c8340SDag-Erling Smørgrav "(extra data)", name); 549b15c8340SDag-Erling Smørgrav goto out; 550b15c8340SDag-Erling Smørgrav } 551e4a9863fSDag-Erling Smørgrav free(name); 552e4a9863fSDag-Erling Smørgrav name = NULL; 553b15c8340SDag-Erling Smørgrav } 554e2f6069cSDag-Erling Smørgrav /* successfully parsed all options */ 555b15c8340SDag-Erling Smørgrav ret = 0; 556b15c8340SDag-Erling Smørgrav 557e2f6069cSDag-Erling Smørgrav out: 558e2f6069cSDag-Erling Smørgrav if (ret != 0 && 559e2f6069cSDag-Erling Smørgrav cert_forced_command != NULL && 560e2f6069cSDag-Erling Smørgrav *cert_forced_command != NULL) { 561e4a9863fSDag-Erling Smørgrav free(*cert_forced_command); 562e2f6069cSDag-Erling Smørgrav *cert_forced_command = NULL; 563e2f6069cSDag-Erling Smørgrav } 564e2f6069cSDag-Erling Smørgrav if (name != NULL) 565e4a9863fSDag-Erling Smørgrav free(name); 566*bc5531deSDag-Erling Smørgrav sshbuf_free(data); 567*bc5531deSDag-Erling Smørgrav sshbuf_free(c); 568e2f6069cSDag-Erling Smørgrav return ret; 569e2f6069cSDag-Erling Smørgrav } 570e2f6069cSDag-Erling Smørgrav 571e2f6069cSDag-Erling Smørgrav /* 572e2f6069cSDag-Erling Smørgrav * Set options from critical certificate options. These supersede user key 573e2f6069cSDag-Erling Smørgrav * options so this must be called after auth_parse_options(). 574e2f6069cSDag-Erling Smørgrav */ 575e2f6069cSDag-Erling Smørgrav int 576*bc5531deSDag-Erling Smørgrav auth_cert_options(struct sshkey *k, struct passwd *pw) 577e2f6069cSDag-Erling Smørgrav { 578e2f6069cSDag-Erling Smørgrav int cert_no_port_forwarding_flag = 1; 579e2f6069cSDag-Erling Smørgrav int cert_no_agent_forwarding_flag = 1; 580e2f6069cSDag-Erling Smørgrav int cert_no_x11_forwarding_flag = 1; 581e2f6069cSDag-Erling Smørgrav int cert_no_pty_flag = 1; 582e2f6069cSDag-Erling Smørgrav int cert_no_user_rc = 1; 583e2f6069cSDag-Erling Smørgrav char *cert_forced_command = NULL; 584e2f6069cSDag-Erling Smørgrav int cert_source_address_done = 0; 585e2f6069cSDag-Erling Smørgrav 586*bc5531deSDag-Erling Smørgrav if (sshkey_cert_is_legacy(k)) { 587e2f6069cSDag-Erling Smørgrav /* All options are in the one field for v00 certs */ 588*bc5531deSDag-Erling Smørgrav if (parse_option_list(k->cert->critical, pw, 589e2f6069cSDag-Erling Smørgrav OPTIONS_CRITICAL|OPTIONS_EXTENSIONS, 1, 590e2f6069cSDag-Erling Smørgrav &cert_no_port_forwarding_flag, 591e2f6069cSDag-Erling Smørgrav &cert_no_agent_forwarding_flag, 592e2f6069cSDag-Erling Smørgrav &cert_no_x11_forwarding_flag, 593e2f6069cSDag-Erling Smørgrav &cert_no_pty_flag, 594e2f6069cSDag-Erling Smørgrav &cert_no_user_rc, 595e2f6069cSDag-Erling Smørgrav &cert_forced_command, 596e2f6069cSDag-Erling Smørgrav &cert_source_address_done) == -1) 597e2f6069cSDag-Erling Smørgrav return -1; 598e2f6069cSDag-Erling Smørgrav } else { 599e2f6069cSDag-Erling Smørgrav /* Separate options and extensions for v01 certs */ 600*bc5531deSDag-Erling Smørgrav if (parse_option_list(k->cert->critical, pw, 601e2f6069cSDag-Erling Smørgrav OPTIONS_CRITICAL, 1, NULL, NULL, NULL, NULL, NULL, 602e2f6069cSDag-Erling Smørgrav &cert_forced_command, 603e2f6069cSDag-Erling Smørgrav &cert_source_address_done) == -1) 604e2f6069cSDag-Erling Smørgrav return -1; 605*bc5531deSDag-Erling Smørgrav if (parse_option_list(k->cert->extensions, pw, 606e2f6069cSDag-Erling Smørgrav OPTIONS_EXTENSIONS, 1, 607e2f6069cSDag-Erling Smørgrav &cert_no_port_forwarding_flag, 608e2f6069cSDag-Erling Smørgrav &cert_no_agent_forwarding_flag, 609e2f6069cSDag-Erling Smørgrav &cert_no_x11_forwarding_flag, 610e2f6069cSDag-Erling Smørgrav &cert_no_pty_flag, 611e2f6069cSDag-Erling Smørgrav &cert_no_user_rc, 612e2f6069cSDag-Erling Smørgrav NULL, NULL) == -1) 613e2f6069cSDag-Erling Smørgrav return -1; 614e2f6069cSDag-Erling Smørgrav } 615e2f6069cSDag-Erling Smørgrav 616b15c8340SDag-Erling Smørgrav no_port_forwarding_flag |= cert_no_port_forwarding_flag; 617b15c8340SDag-Erling Smørgrav no_agent_forwarding_flag |= cert_no_agent_forwarding_flag; 618b15c8340SDag-Erling Smørgrav no_x11_forwarding_flag |= cert_no_x11_forwarding_flag; 619b15c8340SDag-Erling Smørgrav no_pty_flag |= cert_no_pty_flag; 620b15c8340SDag-Erling Smørgrav no_user_rc |= cert_no_user_rc; 621b15c8340SDag-Erling Smørgrav /* CA-specified forced command supersedes key option */ 622b15c8340SDag-Erling Smørgrav if (cert_forced_command != NULL) { 623b15c8340SDag-Erling Smørgrav if (forced_command != NULL) 624e4a9863fSDag-Erling Smørgrav free(forced_command); 625b15c8340SDag-Erling Smørgrav forced_command = cert_forced_command; 626b15c8340SDag-Erling Smørgrav } 627e2f6069cSDag-Erling Smørgrav return 0; 628b15c8340SDag-Erling Smørgrav } 629b15c8340SDag-Erling Smørgrav 630