diff options
author | Darren Tucker <dtucker@zip.com.au> | 2006-07-12 22:34:17 +1000 |
---|---|---|
committer | Darren Tucker <dtucker@zip.com.au> | 2006-07-12 22:34:17 +1000 |
commit | 4515047e47f26377a46f480ed5929e8ccfa18720 (patch) | |
tree | a7485f1794bcab3a46c5f3efcf2a3ba630021be9 | |
parent | ba724050263c0bca0a7dffa26462d046c4df7e01 (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-- | ChangeLog | 14 | ||||
-rw-r--r-- | auth.c | 5 | ||||
-rw-r--r-- | servconf.c | 356 | ||||
-rw-r--r-- | servconf.h | 11 | ||||
-rw-r--r-- | sshd.c | 17 | ||||
-rw-r--r-- | sshd_config.5 | 23 |
6 files changed, 314 insertions, 112 deletions
@@ -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 | ||
47 | 20060711 | 59 | 20060711 |
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 $ |
@@ -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 | ||
29 | static void add_listen_addr(ServerOptions *, char *, u_short); | 30 | static void add_listen_addr(ServerOptions *, char *, u_short); |
30 | static void add_one_listen_addr(ServerOptions *, char *, u_short); | 31 | static 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 */ |
33 | extern int use_privsep; | 34 | extern int use_privsep; |
35 | extern 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 | ||
113 | void | 112 | void |
@@ -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. */ |
285 | static struct { | 289 | static 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 | ||
390 | static ServerOpCodes | 395 | static ServerOpCodes |
391 | parse_token(const char *cp, const char *filename, | 396 | parse_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 | |||
483 | static int | ||
484 | match_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 | |||
443 | int | 546 | int |
444 | process_server_config_line(ServerOptions *options, char *line, | 547 | process_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 | ||
1062 | void | 1201 | void |
1063 | parse_server_config(ServerOptions *options, const char *filename, Buffer *conf) | 1202 | parse_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 */ | ||
1213 | void | ||
1214 | copy_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 | |||
1222 | void | ||
1223 | parse_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 | ||
143 | void initialize_server_options(ServerOptions *); | 143 | void initialize_server_options(ServerOptions *); |
144 | void fill_default_server_options(ServerOptions *); | 144 | void fill_default_server_options(ServerOptions *); |
145 | int process_server_config_line(ServerOptions *, char *, const char *, int); | 145 | int process_server_config_line(ServerOptions *, char *, const char *, int, |
146 | int *, const char *, const char *, const char *); | ||
146 | void load_server_config(const char *, Buffer *); | 147 | void load_server_config(const char *, Buffer *); |
147 | void parse_server_config(ServerOptions *, const char *, Buffer *); | 148 | void parse_server_config(ServerOptions *, const char *, Buffer *, |
149 | const char *, const char *, const char *); | ||
150 | void parse_server_match_config(ServerOptions *, const char *, const char *, | ||
151 | const char *); | ||
152 | void copy_set_server_options(ServerOptions *, ServerOptions *); | ||
148 | 153 | ||
149 | #endif /* SERVCONF_H */ | 154 | #endif /* SERVCONF_H */ |
@@ -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; | |||
219 | int startup_pipe; /* in child */ | 219 | int startup_pipe; /* in child */ |
220 | 220 | ||
221 | /* variables used for privilege separation */ | 221 | /* variables used for privilege separation */ |
222 | int use_privsep; | 222 | int use_privsep = -1; |
223 | struct monitor *pmonitor = NULL; | 223 | struct monitor *pmonitor = NULL; |
224 | 224 | ||
225 | /* global authentication context */ | 225 | /* global authentication context */ |
226 | Authctxt *the_authctxt = NULL; | 226 | Authctxt *the_authctxt = NULL; |
227 | 227 | ||
228 | /* sshd_config buffer */ | ||
229 | Buffer cfg; | ||
230 | |||
228 | /* message to be displayed after login */ | 231 | /* message to be displayed after login */ |
229 | Buffer loginmsg; | 232 | Buffer 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. | |||
463 | Multiple algorithms must be comma-separated. | 463 | Multiple algorithms must be comma-separated. |
464 | The default is: | 464 | The 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 | ||
467 | Introduces a conditional block. Keywords on lines following a | ||
468 | .Cm Match | ||
469 | block are only applied if all of the criteria on the | ||
470 | .Cm Match | ||
471 | are satisfied. | ||
472 | The the arguments to | ||
473 | .Cm Match | ||
474 | block are one or more criteria-pattern pairs. | ||
475 | The available criteria are | ||
476 | .Cm User , | ||
477 | .Cm Host , | ||
478 | and | ||
479 | .Cm Address . | ||
480 | Only a subset of keywords may be used on the lines following a | ||
481 | .Cm Match | ||
482 | keyword. | ||
483 | Available keywords are | ||
484 | .Cm AllowTcpForwarding , | ||
485 | and | ||
486 | .Cm GatewayPorts . | ||
466 | .It Cm MaxAuthTries | 487 | .It Cm MaxAuthTries |
467 | Specifies the maximum number of authentication attempts permitted per | 488 | Specifies the maximum number of authentication attempts permitted per |
468 | connection. | 489 | connection. |