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