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