1 /* $OpenBSD: auth-options.c,v 1.44 2009/01/22 10:09:16 djm Exp $ */ 2 /* 3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 5 * All rights reserved 6 * As far as I am concerned, the code I have written for this software 7 * can be used freely for any purpose. Any derived versions of this 8 * software must be clearly marked as such, and if the derived work is 9 * incompatible with the protocol description in the RFC file, it must be 10 * called by a name other than "ssh" or "Secure Shell". 11 */ 12 13 #include <sys/types.h> 14 #include <sys/queue.h> 15 16 #include <netdb.h> 17 #include <pwd.h> 18 #include <string.h> 19 #include <stdio.h> 20 #include <stdarg.h> 21 22 #include "xmalloc.h" 23 #include "match.h" 24 #include "log.h" 25 #include "canohost.h" 26 #include "buffer.h" 27 #include "channels.h" 28 #include "auth-options.h" 29 #include "servconf.h" 30 #include "misc.h" 31 #include "key.h" 32 #include "hostfile.h" 33 #include "auth.h" 34 #ifdef GSSAPI 35 #include "ssh-gss.h" 36 #endif 37 #include "monitor_wrap.h" 38 39 /* Flags set authorized_keys flags */ 40 int no_port_forwarding_flag = 0; 41 int no_agent_forwarding_flag = 0; 42 int no_x11_forwarding_flag = 0; 43 int no_pty_flag = 0; 44 int no_user_rc = 0; 45 46 /* "command=" option. */ 47 char *forced_command = NULL; 48 49 /* "environment=" options. */ 50 struct envstring *custom_environment = NULL; 51 52 /* "tunnel=" option. */ 53 int forced_tun_device = -1; 54 55 extern ServerOptions options; 56 57 void 58 auth_clear_options(void) 59 { 60 no_agent_forwarding_flag = 0; 61 no_port_forwarding_flag = 0; 62 no_pty_flag = 0; 63 no_x11_forwarding_flag = 0; 64 no_user_rc = 0; 65 while (custom_environment) { 66 struct envstring *ce = custom_environment; 67 custom_environment = ce->next; 68 xfree(ce->s); 69 xfree(ce); 70 } 71 if (forced_command) { 72 xfree(forced_command); 73 forced_command = NULL; 74 } 75 forced_tun_device = -1; 76 channel_clear_permitted_opens(); 77 auth_debug_reset(); 78 } 79 80 /* 81 * return 1 if access is granted, 0 if not. 82 * side effect: sets key option flags 83 */ 84 int 85 auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) 86 { 87 const char *cp; 88 int i; 89 90 /* reset options */ 91 auth_clear_options(); 92 93 if (!opts) 94 return 1; 95 96 while (*opts && *opts != ' ' && *opts != '\t') { 97 cp = "no-port-forwarding"; 98 if (strncasecmp(opts, cp, strlen(cp)) == 0) { 99 auth_debug_add("Port forwarding disabled."); 100 no_port_forwarding_flag = 1; 101 opts += strlen(cp); 102 goto next_option; 103 } 104 cp = "no-agent-forwarding"; 105 if (strncasecmp(opts, cp, strlen(cp)) == 0) { 106 auth_debug_add("Agent forwarding disabled."); 107 no_agent_forwarding_flag = 1; 108 opts += strlen(cp); 109 goto next_option; 110 } 111 cp = "no-X11-forwarding"; 112 if (strncasecmp(opts, cp, strlen(cp)) == 0) { 113 auth_debug_add("X11 forwarding disabled."); 114 no_x11_forwarding_flag = 1; 115 opts += strlen(cp); 116 goto next_option; 117 } 118 cp = "no-pty"; 119 if (strncasecmp(opts, cp, strlen(cp)) == 0) { 120 auth_debug_add("Pty allocation disabled."); 121 no_pty_flag = 1; 122 opts += strlen(cp); 123 goto next_option; 124 } 125 cp = "no-user-rc"; 126 if (strncasecmp(opts, cp, strlen(cp)) == 0) { 127 auth_debug_add("User rc file execution disabled."); 128 no_user_rc = 1; 129 opts += strlen(cp); 130 goto next_option; 131 } 132 cp = "command=\""; 133 if (strncasecmp(opts, cp, strlen(cp)) == 0) { 134 opts += strlen(cp); 135 forced_command = xmalloc(strlen(opts) + 1); 136 i = 0; 137 while (*opts) { 138 if (*opts == '"') 139 break; 140 if (*opts == '\\' && opts[1] == '"') { 141 opts += 2; 142 forced_command[i++] = '"'; 143 continue; 144 } 145 forced_command[i++] = *opts++; 146 } 147 if (!*opts) { 148 debug("%.100s, line %lu: missing end quote", 149 file, linenum); 150 auth_debug_add("%.100s, line %lu: missing end quote", 151 file, linenum); 152 xfree(forced_command); 153 forced_command = NULL; 154 goto bad_option; 155 } 156 forced_command[i] = '\0'; 157 auth_debug_add("Forced command: %.900s", forced_command); 158 opts++; 159 goto next_option; 160 } 161 cp = "environment=\""; 162 if (options.permit_user_env && 163 strncasecmp(opts, cp, strlen(cp)) == 0) { 164 char *s; 165 struct envstring *new_envstring; 166 167 opts += strlen(cp); 168 s = xmalloc(strlen(opts) + 1); 169 i = 0; 170 while (*opts) { 171 if (*opts == '"') 172 break; 173 if (*opts == '\\' && opts[1] == '"') { 174 opts += 2; 175 s[i++] = '"'; 176 continue; 177 } 178 s[i++] = *opts++; 179 } 180 if (!*opts) { 181 debug("%.100s, line %lu: missing end quote", 182 file, linenum); 183 auth_debug_add("%.100s, line %lu: missing end quote", 184 file, linenum); 185 xfree(s); 186 goto bad_option; 187 } 188 s[i] = '\0'; 189 auth_debug_add("Adding to environment: %.900s", s); 190 debug("Adding to environment: %.900s", s); 191 opts++; 192 new_envstring = xmalloc(sizeof(struct envstring)); 193 new_envstring->s = s; 194 new_envstring->next = custom_environment; 195 custom_environment = new_envstring; 196 goto next_option; 197 } 198 cp = "from=\""; 199 if (strncasecmp(opts, cp, strlen(cp)) == 0) { 200 const char *remote_ip = get_remote_ipaddr(); 201 const char *remote_host = get_canonical_hostname( 202 options.use_dns); 203 char *patterns = xmalloc(strlen(opts) + 1); 204 205 opts += strlen(cp); 206 i = 0; 207 while (*opts) { 208 if (*opts == '"') 209 break; 210 if (*opts == '\\' && opts[1] == '"') { 211 opts += 2; 212 patterns[i++] = '"'; 213 continue; 214 } 215 patterns[i++] = *opts++; 216 } 217 if (!*opts) { 218 debug("%.100s, line %lu: missing end quote", 219 file, linenum); 220 auth_debug_add("%.100s, line %lu: missing end quote", 221 file, linenum); 222 xfree(patterns); 223 goto bad_option; 224 } 225 patterns[i] = '\0'; 226 opts++; 227 switch (match_host_and_ip(remote_host, remote_ip, 228 patterns)) { 229 case 1: 230 xfree(patterns); 231 /* Host name matches. */ 232 goto next_option; 233 case -1: 234 debug("%.100s, line %lu: invalid criteria", 235 file, linenum); 236 auth_debug_add("%.100s, line %lu: " 237 "invalid criteria", file, linenum); 238 /* FALLTHROUGH */ 239 case 0: 240 xfree(patterns); 241 logit("Authentication tried for %.100s with " 242 "correct key but not from a permitted " 243 "host (host=%.200s, ip=%.200s).", 244 pw->pw_name, remote_host, remote_ip); 245 auth_debug_add("Your host '%.200s' is not " 246 "permitted to use this key for login.", 247 remote_host); 248 break; 249 } 250 /* deny access */ 251 return 0; 252 } 253 cp = "permitopen=\""; 254 if (strncasecmp(opts, cp, strlen(cp)) == 0) { 255 char *host, *p; 256 int port; 257 char *patterns = xmalloc(strlen(opts) + 1); 258 259 opts += strlen(cp); 260 i = 0; 261 while (*opts) { 262 if (*opts == '"') 263 break; 264 if (*opts == '\\' && opts[1] == '"') { 265 opts += 2; 266 patterns[i++] = '"'; 267 continue; 268 } 269 patterns[i++] = *opts++; 270 } 271 if (!*opts) { 272 debug("%.100s, line %lu: missing end quote", 273 file, linenum); 274 auth_debug_add("%.100s, line %lu: missing " 275 "end quote", file, linenum); 276 xfree(patterns); 277 goto bad_option; 278 } 279 patterns[i] = '\0'; 280 opts++; 281 p = patterns; 282 host = hpdelim(&p); 283 if (host == NULL || strlen(host) >= NI_MAXHOST) { 284 debug("%.100s, line %lu: Bad permitopen " 285 "specification <%.100s>", file, linenum, 286 patterns); 287 auth_debug_add("%.100s, line %lu: " 288 "Bad permitopen specification", file, 289 linenum); 290 xfree(patterns); 291 goto bad_option; 292 } 293 host = cleanhostname(host); 294 if (p == NULL || (port = a2port(p)) <= 0) { 295 debug("%.100s, line %lu: Bad permitopen port " 296 "<%.100s>", file, linenum, p ? p : ""); 297 auth_debug_add("%.100s, line %lu: " 298 "Bad permitopen port", file, linenum); 299 xfree(patterns); 300 goto bad_option; 301 } 302 if (options.allow_tcp_forwarding) 303 channel_add_permitted_opens(host, port); 304 xfree(patterns); 305 goto next_option; 306 } 307 cp = "tunnel=\""; 308 if (strncasecmp(opts, cp, strlen(cp)) == 0) { 309 char *tun = NULL; 310 opts += strlen(cp); 311 tun = xmalloc(strlen(opts) + 1); 312 i = 0; 313 while (*opts) { 314 if (*opts == '"') 315 break; 316 tun[i++] = *opts++; 317 } 318 if (!*opts) { 319 debug("%.100s, line %lu: missing end quote", 320 file, linenum); 321 auth_debug_add("%.100s, line %lu: missing end quote", 322 file, linenum); 323 xfree(tun); 324 forced_tun_device = -1; 325 goto bad_option; 326 } 327 tun[i] = '\0'; 328 forced_tun_device = a2tun(tun, NULL); 329 xfree(tun); 330 if (forced_tun_device == SSH_TUNID_ERR) { 331 debug("%.100s, line %lu: invalid tun device", 332 file, linenum); 333 auth_debug_add("%.100s, line %lu: invalid tun device", 334 file, linenum); 335 forced_tun_device = -1; 336 goto bad_option; 337 } 338 auth_debug_add("Forced tun device: %d", forced_tun_device); 339 opts++; 340 goto next_option; 341 } 342 next_option: 343 /* 344 * Skip the comma, and move to the next option 345 * (or break out if there are no more). 346 */ 347 if (!*opts) 348 fatal("Bugs in auth-options.c option processing."); 349 if (*opts == ' ' || *opts == '\t') 350 break; /* End of options. */ 351 if (*opts != ',') 352 goto bad_option; 353 opts++; 354 /* Process the next option. */ 355 } 356 357 if (!use_privsep) 358 auth_debug_send(); 359 360 /* grant access */ 361 return 1; 362 363 bad_option: 364 logit("Bad options in %.100s file, line %lu: %.50s", 365 file, linenum, opts); 366 auth_debug_add("Bad options in %.100s file, line %lu: %.50s", 367 file, linenum, opts); 368 369 if (!use_privsep) 370 auth_debug_send(); 371 372 /* deny access */ 373 return 0; 374 } 375