diff options
Diffstat (limited to 'servconf.c')
-rw-r--r-- | servconf.c | 356 |
1 files changed, 259 insertions, 97 deletions
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); |