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