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