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