1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Author: Tatu Ylonen <ylo@cs.hut.fi> 3*0Sstevel@tonic-gate * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4*0Sstevel@tonic-gate * All rights reserved 5*0Sstevel@tonic-gate * As far as I am concerned, the code I have written for this software 6*0Sstevel@tonic-gate * can be used freely for any purpose. Any derived versions of this 7*0Sstevel@tonic-gate * software must be clearly marked as such, and if the derived work is 8*0Sstevel@tonic-gate * incompatible with the protocol description in the RFC file, it must be 9*0Sstevel@tonic-gate * called by a name other than "ssh" or "Secure Shell". 10*0Sstevel@tonic-gate */ 11*0Sstevel@tonic-gate 12*0Sstevel@tonic-gate #include "includes.h" 13*0Sstevel@tonic-gate RCSID("$OpenBSD: auth-options.c,v 1.26 2002/07/30 17:03:55 markus Exp $"); 14*0Sstevel@tonic-gate 15*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 16*0Sstevel@tonic-gate 17*0Sstevel@tonic-gate #include "xmalloc.h" 18*0Sstevel@tonic-gate #include "match.h" 19*0Sstevel@tonic-gate #include "log.h" 20*0Sstevel@tonic-gate #include "canohost.h" 21*0Sstevel@tonic-gate #include "channels.h" 22*0Sstevel@tonic-gate #include "auth-options.h" 23*0Sstevel@tonic-gate #include "servconf.h" 24*0Sstevel@tonic-gate #include "misc.h" 25*0Sstevel@tonic-gate #include "monitor_wrap.h" 26*0Sstevel@tonic-gate #include "auth.h" 27*0Sstevel@tonic-gate 28*0Sstevel@tonic-gate /* Flags set authorized_keys flags */ 29*0Sstevel@tonic-gate int no_port_forwarding_flag = 0; 30*0Sstevel@tonic-gate int no_agent_forwarding_flag = 0; 31*0Sstevel@tonic-gate int no_x11_forwarding_flag = 0; 32*0Sstevel@tonic-gate int no_pty_flag = 0; 33*0Sstevel@tonic-gate 34*0Sstevel@tonic-gate /* "command=" option. */ 35*0Sstevel@tonic-gate char *forced_command = NULL; 36*0Sstevel@tonic-gate 37*0Sstevel@tonic-gate /* "environment=" options. */ 38*0Sstevel@tonic-gate struct envstring *custom_environment = NULL; 39*0Sstevel@tonic-gate 40*0Sstevel@tonic-gate extern ServerOptions options; 41*0Sstevel@tonic-gate 42*0Sstevel@tonic-gate void 43*0Sstevel@tonic-gate auth_clear_options(void) 44*0Sstevel@tonic-gate { 45*0Sstevel@tonic-gate no_agent_forwarding_flag = 0; 46*0Sstevel@tonic-gate no_port_forwarding_flag = 0; 47*0Sstevel@tonic-gate no_pty_flag = 0; 48*0Sstevel@tonic-gate no_x11_forwarding_flag = 0; 49*0Sstevel@tonic-gate while (custom_environment) { 50*0Sstevel@tonic-gate struct envstring *ce = custom_environment; 51*0Sstevel@tonic-gate custom_environment = ce->next; 52*0Sstevel@tonic-gate xfree(ce->s); 53*0Sstevel@tonic-gate xfree(ce); 54*0Sstevel@tonic-gate } 55*0Sstevel@tonic-gate if (forced_command) { 56*0Sstevel@tonic-gate xfree(forced_command); 57*0Sstevel@tonic-gate forced_command = NULL; 58*0Sstevel@tonic-gate } 59*0Sstevel@tonic-gate channel_clear_permitted_opens(); 60*0Sstevel@tonic-gate auth_debug_reset(); 61*0Sstevel@tonic-gate } 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate /* 64*0Sstevel@tonic-gate * return 1 if access is granted, 0 if not. 65*0Sstevel@tonic-gate * side effect: sets key option flags 66*0Sstevel@tonic-gate */ 67*0Sstevel@tonic-gate int 68*0Sstevel@tonic-gate auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) 69*0Sstevel@tonic-gate { 70*0Sstevel@tonic-gate const char *cp; 71*0Sstevel@tonic-gate int i; 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate /* reset options */ 74*0Sstevel@tonic-gate auth_clear_options(); 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate if (!opts) 77*0Sstevel@tonic-gate return 1; 78*0Sstevel@tonic-gate 79*0Sstevel@tonic-gate while (*opts && *opts != ' ' && *opts != '\t') { 80*0Sstevel@tonic-gate cp = "no-port-forwarding"; 81*0Sstevel@tonic-gate if (strncasecmp(opts, cp, strlen(cp)) == 0) { 82*0Sstevel@tonic-gate auth_debug_add("Port forwarding disabled."); 83*0Sstevel@tonic-gate no_port_forwarding_flag = 1; 84*0Sstevel@tonic-gate opts += strlen(cp); 85*0Sstevel@tonic-gate goto next_option; 86*0Sstevel@tonic-gate } 87*0Sstevel@tonic-gate cp = "no-agent-forwarding"; 88*0Sstevel@tonic-gate if (strncasecmp(opts, cp, strlen(cp)) == 0) { 89*0Sstevel@tonic-gate auth_debug_add("Agent forwarding disabled."); 90*0Sstevel@tonic-gate no_agent_forwarding_flag = 1; 91*0Sstevel@tonic-gate opts += strlen(cp); 92*0Sstevel@tonic-gate goto next_option; 93*0Sstevel@tonic-gate } 94*0Sstevel@tonic-gate cp = "no-X11-forwarding"; 95*0Sstevel@tonic-gate if (strncasecmp(opts, cp, strlen(cp)) == 0) { 96*0Sstevel@tonic-gate auth_debug_add("X11 forwarding disabled."); 97*0Sstevel@tonic-gate no_x11_forwarding_flag = 1; 98*0Sstevel@tonic-gate opts += strlen(cp); 99*0Sstevel@tonic-gate goto next_option; 100*0Sstevel@tonic-gate } 101*0Sstevel@tonic-gate cp = "no-pty"; 102*0Sstevel@tonic-gate if (strncasecmp(opts, cp, strlen(cp)) == 0) { 103*0Sstevel@tonic-gate auth_debug_add("Pty allocation disabled."); 104*0Sstevel@tonic-gate no_pty_flag = 1; 105*0Sstevel@tonic-gate opts += strlen(cp); 106*0Sstevel@tonic-gate goto next_option; 107*0Sstevel@tonic-gate } 108*0Sstevel@tonic-gate cp = "command=\""; 109*0Sstevel@tonic-gate if (strncasecmp(opts, cp, strlen(cp)) == 0) { 110*0Sstevel@tonic-gate opts += strlen(cp); 111*0Sstevel@tonic-gate forced_command = xmalloc(strlen(opts) + 1); 112*0Sstevel@tonic-gate i = 0; 113*0Sstevel@tonic-gate while (*opts) { 114*0Sstevel@tonic-gate if (*opts == '"') 115*0Sstevel@tonic-gate break; 116*0Sstevel@tonic-gate if (*opts == '\\' && opts[1] == '"') { 117*0Sstevel@tonic-gate opts += 2; 118*0Sstevel@tonic-gate forced_command[i++] = '"'; 119*0Sstevel@tonic-gate continue; 120*0Sstevel@tonic-gate } 121*0Sstevel@tonic-gate forced_command[i++] = *opts++; 122*0Sstevel@tonic-gate } 123*0Sstevel@tonic-gate if (!*opts) { 124*0Sstevel@tonic-gate debug("%.100s, line %lu: missing end quote", 125*0Sstevel@tonic-gate file, linenum); 126*0Sstevel@tonic-gate auth_debug_add("%.100s, line %lu: missing end quote", 127*0Sstevel@tonic-gate file, linenum); 128*0Sstevel@tonic-gate xfree(forced_command); 129*0Sstevel@tonic-gate forced_command = NULL; 130*0Sstevel@tonic-gate goto bad_option; 131*0Sstevel@tonic-gate } 132*0Sstevel@tonic-gate forced_command[i] = 0; 133*0Sstevel@tonic-gate auth_debug_add("Forced command: %.900s", forced_command); 134*0Sstevel@tonic-gate opts++; 135*0Sstevel@tonic-gate goto next_option; 136*0Sstevel@tonic-gate } 137*0Sstevel@tonic-gate cp = "environment=\""; 138*0Sstevel@tonic-gate if (options.permit_user_env && 139*0Sstevel@tonic-gate strncasecmp(opts, cp, strlen(cp)) == 0) { 140*0Sstevel@tonic-gate char *s; 141*0Sstevel@tonic-gate struct envstring *new_envstring; 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate opts += strlen(cp); 144*0Sstevel@tonic-gate s = xmalloc(strlen(opts) + 1); 145*0Sstevel@tonic-gate i = 0; 146*0Sstevel@tonic-gate while (*opts) { 147*0Sstevel@tonic-gate if (*opts == '"') 148*0Sstevel@tonic-gate break; 149*0Sstevel@tonic-gate if (*opts == '\\' && opts[1] == '"') { 150*0Sstevel@tonic-gate opts += 2; 151*0Sstevel@tonic-gate s[i++] = '"'; 152*0Sstevel@tonic-gate continue; 153*0Sstevel@tonic-gate } 154*0Sstevel@tonic-gate s[i++] = *opts++; 155*0Sstevel@tonic-gate } 156*0Sstevel@tonic-gate if (!*opts) { 157*0Sstevel@tonic-gate debug("%.100s, line %lu: missing end quote", 158*0Sstevel@tonic-gate file, linenum); 159*0Sstevel@tonic-gate auth_debug_add("%.100s, line %lu: missing end quote", 160*0Sstevel@tonic-gate file, linenum); 161*0Sstevel@tonic-gate xfree(s); 162*0Sstevel@tonic-gate goto bad_option; 163*0Sstevel@tonic-gate } 164*0Sstevel@tonic-gate s[i] = 0; 165*0Sstevel@tonic-gate auth_debug_add("Adding to environment: %.900s", s); 166*0Sstevel@tonic-gate debug("Adding to environment: %.900s", s); 167*0Sstevel@tonic-gate opts++; 168*0Sstevel@tonic-gate new_envstring = xmalloc(sizeof(struct envstring)); 169*0Sstevel@tonic-gate new_envstring->s = s; 170*0Sstevel@tonic-gate new_envstring->next = custom_environment; 171*0Sstevel@tonic-gate custom_environment = new_envstring; 172*0Sstevel@tonic-gate goto next_option; 173*0Sstevel@tonic-gate } 174*0Sstevel@tonic-gate cp = "from=\""; 175*0Sstevel@tonic-gate if (strncasecmp(opts, cp, strlen(cp)) == 0) { 176*0Sstevel@tonic-gate const char *remote_ip = get_remote_ipaddr(); 177*0Sstevel@tonic-gate const char *remote_host = get_canonical_hostname( 178*0Sstevel@tonic-gate options.verify_reverse_mapping); 179*0Sstevel@tonic-gate char *patterns = xmalloc(strlen(opts) + 1); 180*0Sstevel@tonic-gate 181*0Sstevel@tonic-gate opts += strlen(cp); 182*0Sstevel@tonic-gate i = 0; 183*0Sstevel@tonic-gate while (*opts) { 184*0Sstevel@tonic-gate if (*opts == '"') 185*0Sstevel@tonic-gate break; 186*0Sstevel@tonic-gate if (*opts == '\\' && opts[1] == '"') { 187*0Sstevel@tonic-gate opts += 2; 188*0Sstevel@tonic-gate patterns[i++] = '"'; 189*0Sstevel@tonic-gate continue; 190*0Sstevel@tonic-gate } 191*0Sstevel@tonic-gate patterns[i++] = *opts++; 192*0Sstevel@tonic-gate } 193*0Sstevel@tonic-gate if (!*opts) { 194*0Sstevel@tonic-gate debug("%.100s, line %lu: missing end quote", 195*0Sstevel@tonic-gate file, linenum); 196*0Sstevel@tonic-gate auth_debug_add("%.100s, line %lu: missing end quote", 197*0Sstevel@tonic-gate file, linenum); 198*0Sstevel@tonic-gate xfree(patterns); 199*0Sstevel@tonic-gate goto bad_option; 200*0Sstevel@tonic-gate } 201*0Sstevel@tonic-gate patterns[i] = 0; 202*0Sstevel@tonic-gate opts++; 203*0Sstevel@tonic-gate if (match_host_and_ip(remote_host, remote_ip, 204*0Sstevel@tonic-gate patterns) != 1) { 205*0Sstevel@tonic-gate xfree(patterns); 206*0Sstevel@tonic-gate log("Authentication tried for %.100s with " 207*0Sstevel@tonic-gate "correct key but not from a permitted " 208*0Sstevel@tonic-gate "host (host=%.200s, ip=%.200s).", 209*0Sstevel@tonic-gate pw->pw_name, remote_host, remote_ip); 210*0Sstevel@tonic-gate auth_debug_add("Your host '%.200s' is not " 211*0Sstevel@tonic-gate "permitted to use this key for login.", 212*0Sstevel@tonic-gate remote_host); 213*0Sstevel@tonic-gate /* deny access */ 214*0Sstevel@tonic-gate return 0; 215*0Sstevel@tonic-gate } 216*0Sstevel@tonic-gate xfree(patterns); 217*0Sstevel@tonic-gate /* Host name matches. */ 218*0Sstevel@tonic-gate goto next_option; 219*0Sstevel@tonic-gate } 220*0Sstevel@tonic-gate cp = "permitopen=\""; 221*0Sstevel@tonic-gate if (strncasecmp(opts, cp, strlen(cp)) == 0) { 222*0Sstevel@tonic-gate char host[256], sport[6]; 223*0Sstevel@tonic-gate u_short port; 224*0Sstevel@tonic-gate char *patterns = xmalloc(strlen(opts) + 1); 225*0Sstevel@tonic-gate 226*0Sstevel@tonic-gate opts += strlen(cp); 227*0Sstevel@tonic-gate i = 0; 228*0Sstevel@tonic-gate while (*opts) { 229*0Sstevel@tonic-gate if (*opts == '"') 230*0Sstevel@tonic-gate break; 231*0Sstevel@tonic-gate if (*opts == '\\' && opts[1] == '"') { 232*0Sstevel@tonic-gate opts += 2; 233*0Sstevel@tonic-gate patterns[i++] = '"'; 234*0Sstevel@tonic-gate continue; 235*0Sstevel@tonic-gate } 236*0Sstevel@tonic-gate patterns[i++] = *opts++; 237*0Sstevel@tonic-gate } 238*0Sstevel@tonic-gate if (!*opts) { 239*0Sstevel@tonic-gate debug("%.100s, line %lu: missing end quote", 240*0Sstevel@tonic-gate file, linenum); 241*0Sstevel@tonic-gate auth_debug_add("%.100s, line %lu: missing end quote", 242*0Sstevel@tonic-gate file, linenum); 243*0Sstevel@tonic-gate xfree(patterns); 244*0Sstevel@tonic-gate goto bad_option; 245*0Sstevel@tonic-gate } 246*0Sstevel@tonic-gate patterns[i] = 0; 247*0Sstevel@tonic-gate opts++; 248*0Sstevel@tonic-gate if (sscanf(patterns, "%255[^:]:%5[0-9]", host, sport) != 2 && 249*0Sstevel@tonic-gate sscanf(patterns, "%255[^/]/%5[0-9]", host, sport) != 2) { 250*0Sstevel@tonic-gate debug("%.100s, line %lu: Bad permitopen specification " 251*0Sstevel@tonic-gate "<%.100s>", file, linenum, patterns); 252*0Sstevel@tonic-gate auth_debug_add("%.100s, line %lu: " 253*0Sstevel@tonic-gate "Bad permitopen specification", file, linenum); 254*0Sstevel@tonic-gate xfree(patterns); 255*0Sstevel@tonic-gate goto bad_option; 256*0Sstevel@tonic-gate } 257*0Sstevel@tonic-gate if ((port = a2port(sport)) == 0) { 258*0Sstevel@tonic-gate debug("%.100s, line %lu: Bad permitopen port <%.100s>", 259*0Sstevel@tonic-gate file, linenum, sport); 260*0Sstevel@tonic-gate auth_debug_add("%.100s, line %lu: " 261*0Sstevel@tonic-gate "Bad permitopen port", file, linenum); 262*0Sstevel@tonic-gate xfree(patterns); 263*0Sstevel@tonic-gate goto bad_option; 264*0Sstevel@tonic-gate } 265*0Sstevel@tonic-gate if (options.allow_tcp_forwarding) 266*0Sstevel@tonic-gate channel_add_permitted_opens(host, port); 267*0Sstevel@tonic-gate xfree(patterns); 268*0Sstevel@tonic-gate goto next_option; 269*0Sstevel@tonic-gate } 270*0Sstevel@tonic-gate next_option: 271*0Sstevel@tonic-gate /* 272*0Sstevel@tonic-gate * Skip the comma, and move to the next option 273*0Sstevel@tonic-gate * (or break out if there are no more). 274*0Sstevel@tonic-gate */ 275*0Sstevel@tonic-gate if (!*opts) 276*0Sstevel@tonic-gate fatal("Bugs in auth-options.c option processing."); 277*0Sstevel@tonic-gate if (*opts == ' ' || *opts == '\t') 278*0Sstevel@tonic-gate break; /* End of options. */ 279*0Sstevel@tonic-gate if (*opts != ',') 280*0Sstevel@tonic-gate goto bad_option; 281*0Sstevel@tonic-gate opts++; 282*0Sstevel@tonic-gate /* Process the next option. */ 283*0Sstevel@tonic-gate } 284*0Sstevel@tonic-gate 285*0Sstevel@tonic-gate if (!use_privsep) 286*0Sstevel@tonic-gate auth_debug_send(); 287*0Sstevel@tonic-gate 288*0Sstevel@tonic-gate /* grant access */ 289*0Sstevel@tonic-gate return 1; 290*0Sstevel@tonic-gate 291*0Sstevel@tonic-gate bad_option: 292*0Sstevel@tonic-gate log("Bad options in %.100s file, line %lu: %.50s", 293*0Sstevel@tonic-gate file, linenum, opts); 294*0Sstevel@tonic-gate auth_debug_add("Bad options in %.100s file, line %lu: %.50s", 295*0Sstevel@tonic-gate file, linenum, opts); 296*0Sstevel@tonic-gate 297*0Sstevel@tonic-gate if (!use_privsep) 298*0Sstevel@tonic-gate auth_debug_send(); 299*0Sstevel@tonic-gate 300*0Sstevel@tonic-gate /* deny access */ 301*0Sstevel@tonic-gate return 0; 302*0Sstevel@tonic-gate } 303