summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarren Tucker <dtucker@zip.com.au>2006-07-12 22:34:17 +1000
committerDarren Tucker <dtucker@zip.com.au>2006-07-12 22:34:17 +1000
commit4515047e47f26377a46f480ed5929e8ccfa18720 (patch)
treea7485f1794bcab3a46c5f3efcf2a3ba630021be9
parentba724050263c0bca0a7dffa26462d046c4df7e01 (diff)
- dtucker@cvs.openbsd.org 2006/07/12 11:34:58
[sshd.c servconf.h servconf.c sshd_config.5 auth.c] Add support for conditional directives to sshd_config via a "Match" keyword, which works similarly to the "Host" directive in ssh_config. Lines after a Match line override the default set in the main section if the condition on the Match line is true, eg AllowTcpForwarding yes Match User anoncvs AllowTcpForwarding no will allow port forwarding by all users except "anoncvs". Currently only a very small subset of directives are supported. ok djm@
-rw-r--r--ChangeLog14
-rw-r--r--auth.c5
-rw-r--r--servconf.c356
-rw-r--r--servconf.h11
-rw-r--r--sshd.c17
-rw-r--r--sshd_config.523
6 files changed, 314 insertions, 112 deletions
diff --git a/ChangeLog b/ChangeLog
index 2710249f2..5d86e4451 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -43,6 +43,18 @@
43 - stevesk@cvs.openbsd.org 2006/07/11 20:27:56 43 - stevesk@cvs.openbsd.org 2006/07/11 20:27:56
44 [authfile.c ssh.c] 44 [authfile.c ssh.c]
45 need <errno.h> here also (it's also included in <openssl/err.h>) 45 need <errno.h> here also (it's also included in <openssl/err.h>)
46 - dtucker@cvs.openbsd.org 2006/07/12 11:34:58
47 [sshd.c servconf.h servconf.c sshd_config.5 auth.c]
48 Add support for conditional directives to sshd_config via a "Match"
49 keyword, which works similarly to the "Host" directive in ssh_config.
50 Lines after a Match line override the default set in the main section
51 if the condition on the Match line is true, eg
52 AllowTcpForwarding yes
53 Match User anoncvs
54 AllowTcpForwarding no
55 will allow port forwarding by all users except "anoncvs".
56 Currently only a very small subset of directives are supported.
57 ok djm@
46 58
4720060711 5920060711
48 - (dtucker) [configure.ac ssh-keygen.c openbsd-compat/bsd-openpty.c 60 - (dtucker) [configure.ac ssh-keygen.c openbsd-compat/bsd-openpty.c
@@ -4892,4 +4904,4 @@
4892 - (djm) Trim deprecated options from INSTALL. Mention UsePAM 4904 - (djm) Trim deprecated options from INSTALL. Mention UsePAM
4893 - (djm) Fix quote handling in sftp; Patch from admorten AT umich.edu 4905 - (djm) Fix quote handling in sftp; Patch from admorten AT umich.edu
4894 4906
4895$Id: ChangeLog,v 1.4399 2006/07/12 12:24:22 dtucker Exp $ 4907$Id: ChangeLog,v 1.4400 2006/07/12 12:34:17 dtucker Exp $
diff --git a/auth.c b/auth.c
index e5ddc79da..3bca8dc21 100644
--- a/auth.c
+++ b/auth.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: auth.c,v 1.70 2006/07/11 20:07:25 stevesk Exp $ */ 1/* $OpenBSD: auth.c,v 1.71 2006/07/12 11:34:58 dtucker Exp $ */
2/* 2/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * 4 *
@@ -467,6 +467,9 @@ getpwnamallow(const char *user)
467#endif 467#endif
468 struct passwd *pw; 468 struct passwd *pw;
469 469
470 parse_server_match_config(&options, user,
471 get_canonical_hostname(options.use_dns), get_remote_ipaddr());
472
470 pw = getpwnam(user); 473 pw = getpwnam(user);
471 if (pw == NULL) { 474 if (pw == NULL) {
472 logit("Invalid user %.100s from %.100s", 475 logit("Invalid user %.100s from %.100s",
diff --git a/servconf.c b/servconf.c
index c5b933ab9..42ec340f3 100644
--- a/servconf.c
+++ b/servconf.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: servconf.c,v 1.152 2006/07/08 21:47:12 stevesk Exp $ */ 1/* $OpenBSD: servconf.c,v 1.153 2006/07/12 11:34:58 dtucker Exp $ */
2/* 2/*
3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 * All rights reserved 4 * All rights reserved
@@ -25,12 +25,14 @@
25#include "cipher.h" 25#include "cipher.h"
26#include "kex.h" 26#include "kex.h"
27#include "mac.h" 27#include "mac.h"
28#include "match.h"
28 29
29static void add_listen_addr(ServerOptions *, char *, u_short); 30static void add_listen_addr(ServerOptions *, char *, u_short);
30static void add_one_listen_addr(ServerOptions *, char *, u_short); 31static void add_one_listen_addr(ServerOptions *, char *, u_short);
31 32
32/* Use of privilege separation or not */ 33/* Use of privilege separation or not */
33extern int use_privsep; 34extern int use_privsep;
35extern Buffer cfg;
34 36
35/* Initializes the server options to their default values. */ 37/* Initializes the server options to their default values. */
36 38
@@ -105,9 +107,6 @@ initialize_server_options(ServerOptions *options)
105 options->authorized_keys_file2 = NULL; 107 options->authorized_keys_file2 = NULL;
106 options->num_accept_env = 0; 108 options->num_accept_env = 0;
107 options->permit_tun = -1; 109 options->permit_tun = -1;
108
109 /* Needs to be accessable in many places */
110 use_privsep = -1;
111} 110}
112 111
113void 112void
@@ -277,110 +276,116 @@ typedef enum {
277 sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, 276 sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
278 sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, 277 sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
279 sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, 278 sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel,
279 sMatch,
280 sUsePrivilegeSeparation, 280 sUsePrivilegeSeparation,
281 sDeprecated, sUnsupported 281 sDeprecated, sUnsupported
282} ServerOpCodes; 282} ServerOpCodes;
283 283
284#define SSHCFG_GLOBAL 0x01 /* allowed in main section of sshd_config */
285#define SSHCFG_MATCH 0x02 /* allowed inside a Match section */
286#define SSHCFG_ALL (SSHCFG_GLOBAL|SSHCFG_MATCH)
287
284/* Textual representation of the tokens. */ 288/* Textual representation of the tokens. */
285static struct { 289static struct {
286 const char *name; 290 const char *name;
287 ServerOpCodes opcode; 291 ServerOpCodes opcode;
292 u_int flags;
288} keywords[] = { 293} keywords[] = {
289 /* Portable-specific options */ 294 /* Portable-specific options */
290#ifdef USE_PAM 295#ifdef USE_PAM
291 { "usepam", sUsePAM }, 296 { "usepam", sUsePAM, SSHCFG_GLOBAL },
292#else 297#else
293 { "usepam", sUnsupported }, 298 { "usepam", sUnsupported, SSHCFG_GLOBAL },
294#endif 299#endif
295 { "pamauthenticationviakbdint", sDeprecated }, 300 { "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL },
296 /* Standard Options */ 301 /* Standard Options */
297 { "port", sPort }, 302 { "port", sPort, SSHCFG_GLOBAL },
298 { "hostkey", sHostKeyFile }, 303 { "hostkey", sHostKeyFile, SSHCFG_GLOBAL },
299 { "hostdsakey", sHostKeyFile }, /* alias */ 304 { "hostdsakey", sHostKeyFile, SSHCFG_GLOBAL }, /* alias */
300 { "pidfile", sPidFile }, 305 { "pidfile", sPidFile, SSHCFG_GLOBAL },
301 { "serverkeybits", sServerKeyBits }, 306 { "serverkeybits", sServerKeyBits, SSHCFG_GLOBAL },
302 { "logingracetime", sLoginGraceTime }, 307 { "logingracetime", sLoginGraceTime, SSHCFG_GLOBAL },
303 { "keyregenerationinterval", sKeyRegenerationTime }, 308 { "keyregenerationinterval", sKeyRegenerationTime, SSHCFG_GLOBAL },
304 { "permitrootlogin", sPermitRootLogin }, 309 { "permitrootlogin", sPermitRootLogin, SSHCFG_GLOBAL },
305 { "syslogfacility", sLogFacility }, 310 { "syslogfacility", sLogFacility, SSHCFG_GLOBAL },
306 { "loglevel", sLogLevel }, 311 { "loglevel", sLogLevel, SSHCFG_GLOBAL },
307 { "rhostsauthentication", sDeprecated }, 312 { "rhostsauthentication", sDeprecated, SSHCFG_GLOBAL },
308 { "rhostsrsaauthentication", sRhostsRSAAuthentication }, 313 { "rhostsrsaauthentication", sRhostsRSAAuthentication, SSHCFG_GLOBAL },
309 { "hostbasedauthentication", sHostbasedAuthentication }, 314 { "hostbasedauthentication", sHostbasedAuthentication, SSHCFG_GLOBAL },
310 { "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly }, 315 { "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly, SSHCFG_GLOBAL },
311 { "rsaauthentication", sRSAAuthentication }, 316 { "rsaauthentication", sRSAAuthentication, SSHCFG_GLOBAL },
312 { "pubkeyauthentication", sPubkeyAuthentication }, 317 { "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL },
313 { "dsaauthentication", sPubkeyAuthentication }, /* alias */ 318 { "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL }, /* alias */
314#ifdef KRB5 319#ifdef KRB5
315 { "kerberosauthentication", sKerberosAuthentication }, 320 { "kerberosauthentication", sKerberosAuthentication, SSHCFG_GLOBAL },
316 { "kerberosorlocalpasswd", sKerberosOrLocalPasswd }, 321 { "kerberosorlocalpasswd", sKerberosOrLocalPasswd, SSHCFG_GLOBAL },
317 { "kerberosticketcleanup", sKerberosTicketCleanup }, 322 { "kerberosticketcleanup", sKerberosTicketCleanup, SSHCFG_GLOBAL },
318#ifdef USE_AFS 323#ifdef USE_AFS
319 { "kerberosgetafstoken", sKerberosGetAFSToken }, 324 { "kerberosgetafstoken", sKerberosGetAFSToken, SSHCFG_GLOBAL },
320#else 325#else
321 { "kerberosgetafstoken", sUnsupported }, 326 { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
322#endif 327#endif
323#else 328#else
324 { "kerberosauthentication", sUnsupported }, 329 { "kerberosauthentication", sUnsupported, SSHCFG_GLOBAL },
325 { "kerberosorlocalpasswd", sUnsupported }, 330 { "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL },
326 { "kerberosticketcleanup", sUnsupported }, 331 { "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL },
327 { "kerberosgetafstoken", sUnsupported }, 332 { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
328#endif 333#endif
329 { "kerberostgtpassing", sUnsupported }, 334 { "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL },
330 { "afstokenpassing", sUnsupported }, 335 { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
331#ifdef GSSAPI 336#ifdef GSSAPI
332 { "gssapiauthentication", sGssAuthentication }, 337 { "gssapiauthentication", sGssAuthentication, SSHCFG_GLOBAL },
333 { "gssapicleanupcredentials", sGssCleanupCreds }, 338 { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
334#else 339#else
335 { "gssapiauthentication", sUnsupported }, 340 { "gssapiauthentication", sUnsupported, SSHCFG_GLOBAL },
336 { "gssapicleanupcredentials", sUnsupported }, 341 { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
337#endif 342#endif
338 { "passwordauthentication", sPasswordAuthentication }, 343 { "passwordauthentication", sPasswordAuthentication, SSHCFG_GLOBAL },
339 { "kbdinteractiveauthentication", sKbdInteractiveAuthentication }, 344 { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_GLOBAL },
340 { "challengeresponseauthentication", sChallengeResponseAuthentication }, 345 { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
341 { "skeyauthentication", sChallengeResponseAuthentication }, /* alias */ 346 { "skeyauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, /* alias */
342 { "checkmail", sDeprecated }, 347 { "checkmail", sDeprecated, SSHCFG_GLOBAL },
343 { "listenaddress", sListenAddress }, 348 { "listenaddress", sListenAddress, SSHCFG_GLOBAL },
344 { "addressfamily", sAddressFamily }, 349 { "addressfamily", sAddressFamily, SSHCFG_GLOBAL },
345 { "printmotd", sPrintMotd }, 350 { "printmotd", sPrintMotd, SSHCFG_GLOBAL },
346 { "printlastlog", sPrintLastLog }, 351 { "printlastlog", sPrintLastLog, SSHCFG_GLOBAL },
347 { "ignorerhosts", sIgnoreRhosts }, 352 { "ignorerhosts", sIgnoreRhosts, SSHCFG_GLOBAL },
348 { "ignoreuserknownhosts", sIgnoreUserKnownHosts }, 353 { "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL },
349 { "x11forwarding", sX11Forwarding }, 354 { "x11forwarding", sX11Forwarding, SSHCFG_GLOBAL },
350 { "x11displayoffset", sX11DisplayOffset }, 355 { "x11displayoffset", sX11DisplayOffset, SSHCFG_GLOBAL },
351 { "x11uselocalhost", sX11UseLocalhost }, 356 { "x11uselocalhost", sX11UseLocalhost, SSHCFG_GLOBAL },
352 { "xauthlocation", sXAuthLocation }, 357 { "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
353 { "strictmodes", sStrictModes }, 358 { "strictmodes", sStrictModes, SSHCFG_GLOBAL },
354 { "permitemptypasswords", sEmptyPasswd }, 359 { "permitemptypasswords", sEmptyPasswd, SSHCFG_GLOBAL },
355 { "permituserenvironment", sPermitUserEnvironment }, 360 { "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
356 { "uselogin", sUseLogin }, 361 { "uselogin", sUseLogin, SSHCFG_GLOBAL },
357 { "compression", sCompression }, 362 { "compression", sCompression, SSHCFG_GLOBAL },
358 { "tcpkeepalive", sTCPKeepAlive }, 363 { "tcpkeepalive", sTCPKeepAlive, SSHCFG_GLOBAL },
359 { "keepalive", sTCPKeepAlive }, /* obsolete alias */ 364 { "keepalive", sTCPKeepAlive, SSHCFG_GLOBAL }, /* obsolete alias */
360 { "allowtcpforwarding", sAllowTcpForwarding }, 365 { "allowtcpforwarding", sAllowTcpForwarding, SSHCFG_ALL },
361 { "allowusers", sAllowUsers }, 366 { "allowusers", sAllowUsers, SSHCFG_GLOBAL },
362 { "denyusers", sDenyUsers }, 367 { "denyusers", sDenyUsers, SSHCFG_GLOBAL },
363 { "allowgroups", sAllowGroups }, 368 { "allowgroups", sAllowGroups, SSHCFG_GLOBAL },
364 { "denygroups", sDenyGroups }, 369 { "denygroups", sDenyGroups, SSHCFG_GLOBAL },
365 { "ciphers", sCiphers }, 370 { "ciphers", sCiphers, SSHCFG_GLOBAL },
366 { "macs", sMacs }, 371 { "macs", sMacs, SSHCFG_GLOBAL },
367 { "protocol", sProtocol }, 372 { "protocol", sProtocol, SSHCFG_GLOBAL },
368 { "gatewayports", sGatewayPorts }, 373 { "gatewayports", sGatewayPorts, SSHCFG_ALL },
369 { "subsystem", sSubsystem }, 374 { "subsystem", sSubsystem, SSHCFG_GLOBAL },
370 { "maxstartups", sMaxStartups }, 375 { "maxstartups", sMaxStartups, SSHCFG_GLOBAL },
371 { "maxauthtries", sMaxAuthTries }, 376 { "maxauthtries", sMaxAuthTries, SSHCFG_GLOBAL },
372 { "banner", sBanner }, 377 { "banner", sBanner, SSHCFG_GLOBAL },
373 { "usedns", sUseDNS }, 378 { "usedns", sUseDNS, SSHCFG_GLOBAL },
374 { "verifyreversemapping", sDeprecated }, 379 { "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL },
375 { "reversemappingcheck", sDeprecated }, 380 { "reversemappingcheck", sDeprecated, SSHCFG_GLOBAL },
376 { "clientaliveinterval", sClientAliveInterval }, 381 { "clientaliveinterval", sClientAliveInterval, SSHCFG_GLOBAL },
377 { "clientalivecountmax", sClientAliveCountMax }, 382 { "clientalivecountmax", sClientAliveCountMax, SSHCFG_GLOBAL },
378 { "authorizedkeysfile", sAuthorizedKeysFile }, 383 { "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_GLOBAL },
379 { "authorizedkeysfile2", sAuthorizedKeysFile2 }, 384 { "authorizedkeysfile2", sAuthorizedKeysFile2, SSHCFG_GLOBAL },
380 { "useprivilegeseparation", sUsePrivilegeSeparation}, 385 { "useprivilegeseparation", sUsePrivilegeSeparation, SSHCFG_GLOBAL },
381 { "acceptenv", sAcceptEnv }, 386 { "acceptenv", sAcceptEnv, SSHCFG_GLOBAL },
382 { "permittunnel", sPermitTunnel }, 387 { "permittunnel", sPermitTunnel, SSHCFG_GLOBAL },
383 { NULL, sBadOption } 388 { NULL, sBadOption, 0 }
384}; 389};
385 390
386/* 391/*
@@ -389,13 +394,15 @@ static struct {
389 394
390static ServerOpCodes 395static ServerOpCodes
391parse_token(const char *cp, const char *filename, 396parse_token(const char *cp, const char *filename,
392 int linenum) 397 int linenum, u_int *flags)
393{ 398{
394 u_int i; 399 u_int i;
395 400
396 for (i = 0; keywords[i].name; i++) 401 for (i = 0; keywords[i].name; i++)
397 if (strcasecmp(cp, keywords[i].name) == 0) 402 if (strcasecmp(cp, keywords[i].name) == 0) {
403 *flags = keywords[i].flags;
398 return keywords[i].opcode; 404 return keywords[i].opcode;
405 }
399 406
400 error("%s: line %d: Bad configuration option: %s", 407 error("%s: line %d: Bad configuration option: %s",
401 filename, linenum, cp); 408 filename, linenum, cp);
@@ -440,15 +447,112 @@ add_one_listen_addr(ServerOptions *options, char *addr, u_short port)
440 options->listen_addrs = aitop; 447 options->listen_addrs = aitop;
441} 448}
442 449
450/*
451 * The strategy for the Match blocks is that the config file is parsed twice.
452 *
453 * The first time is at startup. activep is initialized to 1 and the
454 * directives in the global context are processed and acted on. Hitting a
455 * Match directive unsets activep and the directives inside the block are
456 * checked for syntax only.
457 *
458 * The second time is after a connection has been established but before
459 * authentication. activep is initialized to 2 and global config directives
460 * are ignored since they have already been processed. If the criteria in a
461 * Match block is met, activep is set and the subsequent directives
462 * processed and actioned until EOF or another Match block unsets it. Any
463 * options set are copied into the main server config.
464 *
465 * Potential additions/improvements:
466 * - Add Match support for pre-kex directives, eg Protocol, Ciphers.
467 *
468 * - Add a Tag directive (idea from David Leonard) ala pf, eg:
469 * Match Address 192.168.0.*
470 * Tag trusted
471 * Match Group wheel
472 * Tag trusted
473 * Match Tag trusted
474 * AllowTcpForwarding yes
475 * GatewayPorts clientspecified
476 * [...]
477 *
478 * - Add a PermittedChannelRequests directive
479 * Match Group shell
480 * PermittedChannelRequests session,forwarded-tcpip
481 */
482
483static int
484match_cfg_line(char **condition, int line, const char *user, const char *host,
485 const char *address)
486{
487 int result = 1;
488 char *arg, *attrib, *cp = *condition;
489 size_t len;
490
491 if (user == NULL)
492 debug3("checking syntax for 'Match %s'", cp);
493 else
494 debug3("checking match for '%s' user %s host %s addr %s", cp,
495 user ? user : "(null)", host ? host : "(null)",
496 address ? address : "(null)");
497
498 while ((attrib = strdelim(&cp)) && *attrib != '\0') {
499 if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
500 error("Missing Match criteria for %s", attrib);
501 return -1;
502 }
503 len = strlen(arg);
504 if (strcasecmp(attrib, "user") == 0) {
505 if (!user) {
506 result = 0;
507 continue;
508 }
509 if (match_pattern_list(user, arg, len, 0) != 1)
510 result = 0;
511 else
512 debug("user %.100s matched 'User %.100s' at "
513 "line %d", user, arg, line);
514 } else if (strcasecmp(attrib, "host") == 0) {
515 if (!host) {
516 result = 0;
517 continue;
518 }
519 if (match_hostname(host, arg, len) != 1)
520 result = 0;
521 else
522 debug("connection from %.100s matched 'Host "
523 "%.100s' at line %d", host, arg, line);
524 } else if (strcasecmp(attrib, "address") == 0) {
525 debug("address '%s' arg '%s'", address, arg);
526 if (!address) {
527 result = 0;
528 continue;
529 }
530 if (match_hostname(address, arg, len) != 1)
531 result = 0;
532 else
533 debug("connection from %.100s matched 'Address "
534 "%.100s' at line %d", address, arg, line);
535 } else {
536 error("Unsupported Match attribute %s", attrib);
537 return -1;
538 }
539 }
540 if (user != NULL)
541 debug3("match %sfound", result ? "" : "not ");
542 *condition = cp;
543 return result;
544}
545
443int 546int
444process_server_config_line(ServerOptions *options, char *line, 547process_server_config_line(ServerOptions *options, char *line,
445 const char *filename, int linenum) 548 const char *filename, int linenum, int *activep, const char *user,
549 const char *host, const char *address)
446{ 550{
447 char *cp, **charptr, *arg, *p; 551 char *cp, **charptr, *arg, *p;
448 int *intptr, value, n; 552 int cmdline = 0, *intptr, value, n;
449 ServerOpCodes opcode; 553 ServerOpCodes opcode;
450 u_short port; 554 u_short port;
451 u_int i; 555 u_int i, flags = 0;
452 size_t len; 556 size_t len;
453 557
454 cp = line; 558 cp = line;
@@ -461,7 +565,25 @@ process_server_config_line(ServerOptions *options, char *line,
461 return 0; 565 return 0;
462 intptr = NULL; 566 intptr = NULL;
463 charptr = NULL; 567 charptr = NULL;
464 opcode = parse_token(arg, filename, linenum); 568 opcode = parse_token(arg, filename, linenum, &flags);
569
570 if (activep == NULL) { /* We are processing a command line directive */
571 cmdline = 1;
572 activep = &cmdline;
573 }
574 if (*activep && opcode != sMatch)
575 debug3("%s:%d setting %s %s", filename, linenum, arg, cp);
576 if (*activep == 0 && !(flags & SSHCFG_MATCH)) {
577 if (user == NULL) {
578 fatal("%s line %d: Directive '%s' is not allowed "
579 "within a Match block", filename, linenum, arg);
580 } else { /* this is a directive we have already processed */
581 while (arg)
582 arg = strdelim(&cp);
583 return 0;
584 }
585 }
586
465 switch (opcode) { 587 switch (opcode) {
466 /* Portable-specific options */ 588 /* Portable-specific options */
467 case sUsePAM: 589 case sUsePAM:
@@ -499,7 +621,7 @@ parse_int:
499 fatal("%s line %d: missing integer value.", 621 fatal("%s line %d: missing integer value.",
500 filename, linenum); 622 filename, linenum);
501 value = atoi(arg); 623 value = atoi(arg);
502 if (*intptr == -1) 624 if (*activep && *intptr == -1)
503 *intptr = value; 625 *intptr = value;
504 break; 626 break;
505 627
@@ -579,7 +701,7 @@ parse_filename:
579 if (!arg || *arg == '\0') 701 if (!arg || *arg == '\0')
580 fatal("%s line %d: missing file name.", 702 fatal("%s line %d: missing file name.",
581 filename, linenum); 703 filename, linenum);
582 if (*charptr == NULL) { 704 if (*activep && *charptr == NULL) {
583 *charptr = tilde_expand_filename(arg, getuid()); 705 *charptr = tilde_expand_filename(arg, getuid());
584 /* increase optional counter */ 706 /* increase optional counter */
585 if (intptr != NULL) 707 if (intptr != NULL)
@@ -630,7 +752,7 @@ parse_flag:
630 else 752 else
631 fatal("%s line %d: Bad yes/no argument: %s", 753 fatal("%s line %d: Bad yes/no argument: %s",
632 filename, linenum, arg); 754 filename, linenum, arg);
633 if (*intptr == -1) 755 if (*activep && *intptr == -1)
634 *intptr = value; 756 *intptr = value;
635 break; 757 break;
636 758
@@ -895,6 +1017,10 @@ parse_flag:
895 if (!arg || *arg == '\0') 1017 if (!arg || *arg == '\0')
896 fatal("%s line %d: Missing subsystem name.", 1018 fatal("%s line %d: Missing subsystem name.",
897 filename, linenum); 1019 filename, linenum);
1020 if (!*activep) {
1021 arg = strdelim(&cp);
1022 break;
1023 }
898 for (i = 0; i < options->num_subsystems; i++) 1024 for (i = 0; i < options->num_subsystems; i++)
899 if (strcmp(arg, options->subsystem_name[i]) == 0) 1025 if (strcmp(arg, options->subsystem_name[i]) == 0)
900 fatal("%s line %d: Subsystem '%s' already defined.", 1026 fatal("%s line %d: Subsystem '%s' already defined.",
@@ -977,6 +1103,8 @@ parse_flag:
977 if (options->num_accept_env >= MAX_ACCEPT_ENV) 1103 if (options->num_accept_env >= MAX_ACCEPT_ENV)
978 fatal("%s line %d: too many allow env.", 1104 fatal("%s line %d: too many allow env.",
979 filename, linenum); 1105 filename, linenum);
1106 if (!*activep)
1107 break;
980 options->accept_env[options->num_accept_env++] = 1108 options->accept_env[options->num_accept_env++] =
981 xstrdup(arg); 1109 xstrdup(arg);
982 } 1110 }
@@ -1004,6 +1132,17 @@ parse_flag:
1004 *intptr = value; 1132 *intptr = value;
1005 break; 1133 break;
1006 1134
1135 case sMatch:
1136 if (cmdline)
1137 fatal("Match directive not supported as a command-line "
1138 "option");
1139 value = match_cfg_line(&cp, linenum, user, host, address);
1140 if (value < 0)
1141 fatal("%s line %d: Bad Match condition", filename,
1142 linenum);
1143 *activep = value;
1144 break;
1145
1007 case sDeprecated: 1146 case sDeprecated:
1008 logit("%s line %d: Deprecated option %s", 1147 logit("%s line %d: Deprecated option %s",
1009 filename, linenum, arg); 1148 filename, linenum, arg);
@@ -1060,18 +1199,41 @@ load_server_config(const char *filename, Buffer *conf)
1060} 1199}
1061 1200
1062void 1201void
1063parse_server_config(ServerOptions *options, const char *filename, Buffer *conf) 1202parse_server_match_config(ServerOptions *options, const char *user,
1203 const char *host, const char *address)
1204{
1205 ServerOptions mo;
1206
1207 initialize_server_options(&mo);
1208 parse_server_config(&mo, "reprocess config", &cfg, user, host, address);
1209 copy_set_server_options(options, &mo);
1210}
1211
1212/* Copy any (supported) values that are set */
1213void
1214copy_set_server_options(ServerOptions *dst, ServerOptions *src)
1215{
1216 if (src->allow_tcp_forwarding != -1)
1217 dst->allow_tcp_forwarding = src->allow_tcp_forwarding;
1218 if (src->gateway_ports != -1)
1219 dst->gateway_ports = src->gateway_ports;
1220}
1221
1222void
1223parse_server_config(ServerOptions *options, const char *filename, Buffer *conf,
1224 const char *user, const char *host, const char *address)
1064{ 1225{
1065 int linenum, bad_options = 0; 1226 int active, linenum, bad_options = 0;
1066 char *cp, *obuf, *cbuf; 1227 char *cp, *obuf, *cbuf;
1067 1228
1068 debug2("%s: config %s len %d", __func__, filename, buffer_len(conf)); 1229 debug2("%s: config %s len %d", __func__, filename, buffer_len(conf));
1069 1230
1070 obuf = cbuf = xstrdup(buffer_ptr(conf)); 1231 obuf = cbuf = xstrdup(buffer_ptr(conf));
1232 active = user ? 0 : 1;
1071 linenum = 1; 1233 linenum = 1;
1072 while ((cp = strsep(&cbuf, "\n")) != NULL) { 1234 while ((cp = strsep(&cbuf, "\n")) != NULL) {
1073 if (process_server_config_line(options, cp, filename, 1235 if (process_server_config_line(options, cp, filename,
1074 linenum++) != 0) 1236 linenum++, &active, user, host, address) != 0)
1075 bad_options++; 1237 bad_options++;
1076 } 1238 }
1077 xfree(obuf); 1239 xfree(obuf);
diff --git a/servconf.h b/servconf.h
index 671050e4c..a74716e6f 100644
--- a/servconf.h
+++ b/servconf.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: servconf.h,v 1.74 2006/07/06 10:47:05 djm Exp $ */ 1/* $OpenBSD: servconf.h,v 1.75 2006/07/12 11:34:58 dtucker Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -142,8 +142,13 @@ typedef struct {
142 142
143void initialize_server_options(ServerOptions *); 143void initialize_server_options(ServerOptions *);
144void fill_default_server_options(ServerOptions *); 144void fill_default_server_options(ServerOptions *);
145int process_server_config_line(ServerOptions *, char *, const char *, int); 145int process_server_config_line(ServerOptions *, char *, const char *, int,
146 int *, const char *, const char *, const char *);
146void load_server_config(const char *, Buffer *); 147void load_server_config(const char *, Buffer *);
147void parse_server_config(ServerOptions *, const char *, Buffer *); 148void parse_server_config(ServerOptions *, const char *, Buffer *,
149 const char *, const char *, const char *);
150void parse_server_match_config(ServerOptions *, const char *, const char *,
151 const char *);
152void copy_set_server_options(ServerOptions *, ServerOptions *);
148 153
149#endif /* SERVCONF_H */ 154#endif /* SERVCONF_H */
diff --git a/sshd.c b/sshd.c
index f3fe9d184..497525df8 100644
--- a/sshd.c
+++ b/sshd.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshd.c,v 1.336 2006/07/11 20:07:25 stevesk Exp $ */ 1/* $OpenBSD: sshd.c,v 1.337 2006/07/12 11:34:58 dtucker Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -219,12 +219,15 @@ int *startup_pipes = NULL;
219int startup_pipe; /* in child */ 219int startup_pipe; /* in child */
220 220
221/* variables used for privilege separation */ 221/* variables used for privilege separation */
222int use_privsep; 222int use_privsep = -1;
223struct monitor *pmonitor = NULL; 223struct monitor *pmonitor = NULL;
224 224
225/* global authentication context */ 225/* global authentication context */
226Authctxt *the_authctxt = NULL; 226Authctxt *the_authctxt = NULL;
227 227
228/* sshd_config buffer */
229Buffer cfg;
230
228/* message to be displayed after login */ 231/* message to be displayed after login */
229Buffer loginmsg; 232Buffer loginmsg;
230 233
@@ -916,7 +919,6 @@ main(int ac, char **av)
916 Key *key; 919 Key *key;
917 Authctxt *authctxt; 920 Authctxt *authctxt;
918 int ret, key_used = 0; 921 int ret, key_used = 0;
919 Buffer cfg;
920 922
921#ifdef HAVE_SECUREWARE 923#ifdef HAVE_SECUREWARE
922 (void)set_auth_parameters(ac, av); 924 (void)set_auth_parameters(ac, av);
@@ -1036,7 +1038,7 @@ main(int ac, char **av)
1036 case 'o': 1038 case 'o':
1037 line = xstrdup(optarg); 1039 line = xstrdup(optarg);
1038 if (process_server_config_line(&options, line, 1040 if (process_server_config_line(&options, line,
1039 "command-line", 0) != 0) 1041 "command-line", 0, NULL, NULL, NULL, NULL) != 0)
1040 exit(1); 1042 exit(1);
1041 xfree(line); 1043 xfree(line);
1042 break; 1044 break;
@@ -1094,11 +1096,8 @@ main(int ac, char **av)
1094 else 1096 else
1095 load_server_config(config_file_name, &cfg); 1097 load_server_config(config_file_name, &cfg);
1096 1098
1097 parse_server_config(&options, 1099 parse_server_config(&options, rexeced_flag ? "rexec" : config_file_name,
1098 rexeced_flag ? "rexec" : config_file_name, &cfg); 1100 &cfg, NULL, NULL, NULL);
1099
1100 if (!rexec_flag)
1101 buffer_free(&cfg);
1102 1101
1103 seed_rng(); 1102 seed_rng();
1104 1103
diff --git a/sshd_config.5 b/sshd_config.5
index 3b639b17d..0b2646027 100644
--- a/sshd_config.5
+++ b/sshd_config.5
@@ -34,7 +34,7 @@
34.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36.\" 36.\"
37.\" $OpenBSD: sshd_config.5,v 1.59 2006/07/06 10:47:05 djm Exp $ 37.\" $OpenBSD: sshd_config.5,v 1.60 2006/07/12 11:34:58 dtucker Exp $
38.Dd September 25, 1999 38.Dd September 25, 1999
39.Dt SSHD_CONFIG 5 39.Dt SSHD_CONFIG 5
40.Os 40.Os
@@ -463,6 +463,27 @@ for data integrity protection.
463Multiple algorithms must be comma-separated. 463Multiple algorithms must be comma-separated.
464The default is: 464The default is:
465.Dq hmac-md5,hmac-sha1,hmac-ripemd160,hmac-sha1-96,hmac-md5-96 . 465.Dq hmac-md5,hmac-sha1,hmac-ripemd160,hmac-sha1-96,hmac-md5-96 .
466.It Cm Match
467Introduces a conditional block. Keywords on lines following a
468.Cm Match
469block are only applied if all of the criteria on the
470.Cm Match
471are satisfied.
472The the arguments to
473.Cm Match
474block are one or more criteria-pattern pairs.
475The available criteria are
476.Cm User ,
477.Cm Host ,
478and
479.Cm Address .
480Only a subset of keywords may be used on the lines following a
481.Cm Match
482keyword.
483Available keywords are
484.Cm AllowTcpForwarding ,
485and
486.Cm GatewayPorts .
466.It Cm MaxAuthTries 487.It Cm MaxAuthTries
467Specifies the maximum number of authentication attempts permitted per 488Specifies the maximum number of authentication attempts permitted per
468connection. 489connection.