summaryrefslogtreecommitdiff
path: root/servconf.c
diff options
context:
space:
mode:
Diffstat (limited to 'servconf.c')
-rw-r--r--servconf.c549
1 files changed, 444 insertions, 105 deletions
diff --git a/servconf.c b/servconf.c
index 219a0300f..26adf0140 100644
--- a/servconf.c
+++ b/servconf.c
@@ -1,3 +1,4 @@
1/* $OpenBSD: servconf.c,v 1.170 2007/03/01 10:28:02 dtucker Exp $ */
1/* 2/*
2 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
3 * All rights reserved 4 * All rights reserved
@@ -10,24 +11,41 @@
10 */ 11 */
11 12
12#include "includes.h" 13#include "includes.h"
13RCSID("$OpenBSD: servconf.c,v 1.146 2005/12/08 18:34:11 reyk Exp $");
14 14
15#include <sys/types.h>
16#include <sys/socket.h>
17
18#include <netdb.h>
19#include <pwd.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <signal.h>
24#include <unistd.h>
25#include <stdarg.h>
26
27#include "xmalloc.h"
15#include "ssh.h" 28#include "ssh.h"
16#include "log.h" 29#include "log.h"
30#include "buffer.h"
17#include "servconf.h" 31#include "servconf.h"
18#include "xmalloc.h"
19#include "compat.h" 32#include "compat.h"
20#include "pathnames.h" 33#include "pathnames.h"
21#include "misc.h" 34#include "misc.h"
22#include "cipher.h" 35#include "cipher.h"
36#include "key.h"
23#include "kex.h" 37#include "kex.h"
24#include "mac.h" 38#include "mac.h"
39#include "match.h"
40#include "channels.h"
41#include "groupaccess.h"
25 42
26static void add_listen_addr(ServerOptions *, char *, u_short); 43static void add_listen_addr(ServerOptions *, char *, u_short);
27static void add_one_listen_addr(ServerOptions *, char *, u_short); 44static void add_one_listen_addr(ServerOptions *, char *, u_short);
28 45
29/* Use of privilege separation or not */ 46/* Use of privilege separation or not */
30extern int use_privsep; 47extern int use_privsep;
48extern Buffer cfg;
31 49
32/* Initializes the server options to their default values. */ 50/* Initializes the server options to their default values. */
33 51
@@ -74,6 +92,7 @@ initialize_server_options(ServerOptions *options)
74 options->gss_authentication=-1; 92 options->gss_authentication=-1;
75 options->gss_keyex = -1; 93 options->gss_keyex = -1;
76 options->gss_cleanup_creds = -1; 94 options->gss_cleanup_creds = -1;
95 options->gss_strict_acceptor = -1;
77 options->password_authentication = -1; 96 options->password_authentication = -1;
78 options->kbd_interactive_authentication = -1; 97 options->kbd_interactive_authentication = -1;
79 options->challenge_response_authentication = -1; 98 options->challenge_response_authentication = -1;
@@ -103,9 +122,8 @@ initialize_server_options(ServerOptions *options)
103 options->authorized_keys_file2 = NULL; 122 options->authorized_keys_file2 = NULL;
104 options->num_accept_env = 0; 123 options->num_accept_env = 0;
105 options->permit_tun = -1; 124 options->permit_tun = -1;
106 125 options->num_permitted_opens = -1;
107 /* Needs to be accessable in many places */ 126 options->adm_forced_command = NULL;
108 use_privsep = -1;
109} 127}
110 128
111void 129void
@@ -192,6 +210,8 @@ fill_default_server_options(ServerOptions *options)
192 options->gss_keyex = 0; 210 options->gss_keyex = 0;
193 if (options->gss_cleanup_creds == -1) 211 if (options->gss_cleanup_creds == -1)
194 options->gss_cleanup_creds = 1; 212 options->gss_cleanup_creds = 1;
213 if (options->gss_strict_acceptor == -1)
214 options->gss_strict_acceptor = 1;
195 if (options->password_authentication == -1) 215 if (options->password_authentication == -1)
196 options->password_authentication = 1; 216 options->password_authentication = 1;
197 if (options->kbd_interactive_authentication == -1) 217 if (options->kbd_interactive_authentication == -1)
@@ -276,114 +296,126 @@ typedef enum {
276 sBanner, sUseDNS, sHostbasedAuthentication, 296 sBanner, sUseDNS, sHostbasedAuthentication,
277 sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, 297 sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
278 sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, 298 sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
279 sGssAuthentication, sGssKeyEx, sGssCleanupCreds, 299 sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
300 sGssKeyEx,
280 sAcceptEnv, sPermitTunnel, 301 sAcceptEnv, sPermitTunnel,
302 sMatch, sPermitOpen, sForceCommand,
281 sUsePrivilegeSeparation, 303 sUsePrivilegeSeparation,
282 sDeprecated, sUnsupported 304 sDeprecated, sUnsupported
283} ServerOpCodes; 305} ServerOpCodes;
284 306
307#define SSHCFG_GLOBAL 0x01 /* allowed in main section of sshd_config */
308#define SSHCFG_MATCH 0x02 /* allowed inside a Match section */
309#define SSHCFG_ALL (SSHCFG_GLOBAL|SSHCFG_MATCH)
310
285/* Textual representation of the tokens. */ 311/* Textual representation of the tokens. */
286static struct { 312static struct {
287 const char *name; 313 const char *name;
288 ServerOpCodes opcode; 314 ServerOpCodes opcode;
315 u_int flags;
289} keywords[] = { 316} keywords[] = {
290 /* Portable-specific options */ 317 /* Portable-specific options */
291#ifdef USE_PAM 318#ifdef USE_PAM
292 { "usepam", sUsePAM }, 319 { "usepam", sUsePAM, SSHCFG_GLOBAL },
293#else 320#else
294 { "usepam", sUnsupported }, 321 { "usepam", sUnsupported, SSHCFG_GLOBAL },
295#endif 322#endif
296 { "pamauthenticationviakbdint", sDeprecated }, 323 { "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL },
297 /* Standard Options */ 324 /* Standard Options */
298 { "port", sPort }, 325 { "port", sPort, SSHCFG_GLOBAL },
299 { "hostkey", sHostKeyFile }, 326 { "hostkey", sHostKeyFile, SSHCFG_GLOBAL },
300 { "hostdsakey", sHostKeyFile }, /* alias */ 327 { "hostdsakey", sHostKeyFile, SSHCFG_GLOBAL }, /* alias */
301 { "pidfile", sPidFile }, 328 { "pidfile", sPidFile, SSHCFG_GLOBAL },
302 { "serverkeybits", sServerKeyBits }, 329 { "serverkeybits", sServerKeyBits, SSHCFG_GLOBAL },
303 { "logingracetime", sLoginGraceTime }, 330 { "logingracetime", sLoginGraceTime, SSHCFG_GLOBAL },
304 { "keyregenerationinterval", sKeyRegenerationTime }, 331 { "keyregenerationinterval", sKeyRegenerationTime, SSHCFG_GLOBAL },
305 { "permitrootlogin", sPermitRootLogin }, 332 { "permitrootlogin", sPermitRootLogin, SSHCFG_GLOBAL },
306 { "syslogfacility", sLogFacility }, 333 { "syslogfacility", sLogFacility, SSHCFG_GLOBAL },
307 { "loglevel", sLogLevel }, 334 { "loglevel", sLogLevel, SSHCFG_GLOBAL },
308 { "rhostsauthentication", sDeprecated }, 335 { "rhostsauthentication", sDeprecated, SSHCFG_GLOBAL },
309 { "rhostsrsaauthentication", sRhostsRSAAuthentication }, 336 { "rhostsrsaauthentication", sRhostsRSAAuthentication, SSHCFG_ALL },
310 { "hostbasedauthentication", sHostbasedAuthentication }, 337 { "hostbasedauthentication", sHostbasedAuthentication, SSHCFG_ALL },
311 { "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly }, 338 { "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly, SSHCFG_GLOBAL },
312 { "rsaauthentication", sRSAAuthentication }, 339 { "rsaauthentication", sRSAAuthentication, SSHCFG_ALL },
313 { "pubkeyauthentication", sPubkeyAuthentication }, 340 { "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_ALL },
314 { "dsaauthentication", sPubkeyAuthentication }, /* alias */ 341 { "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL }, /* alias */
315#ifdef KRB5 342#ifdef KRB5
316 { "kerberosauthentication", sKerberosAuthentication }, 343 { "kerberosauthentication", sKerberosAuthentication, SSHCFG_ALL },
317 { "kerberosorlocalpasswd", sKerberosOrLocalPasswd }, 344 { "kerberosorlocalpasswd", sKerberosOrLocalPasswd, SSHCFG_GLOBAL },
318 { "kerberosticketcleanup", sKerberosTicketCleanup }, 345 { "kerberosticketcleanup", sKerberosTicketCleanup, SSHCFG_GLOBAL },
319#ifdef USE_AFS 346#ifdef USE_AFS
320 { "kerberosgetafstoken", sKerberosGetAFSToken }, 347 { "kerberosgetafstoken", sKerberosGetAFSToken, SSHCFG_GLOBAL },
321#else 348#else
322 { "kerberosgetafstoken", sUnsupported }, 349 { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
323#endif 350#endif
324#else 351#else
325 { "kerberosauthentication", sUnsupported }, 352 { "kerberosauthentication", sUnsupported, SSHCFG_ALL },
326 { "kerberosorlocalpasswd", sUnsupported }, 353 { "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL },
327 { "kerberosticketcleanup", sUnsupported }, 354 { "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL },
328 { "kerberosgetafstoken", sUnsupported }, 355 { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
329#endif 356#endif
330 { "kerberostgtpassing", sUnsupported }, 357 { "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL },
331 { "afstokenpassing", sUnsupported }, 358 { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
332#ifdef GSSAPI 359#ifdef GSSAPI
333 { "gssapiauthentication", sGssAuthentication }, 360 { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
334 { "gssapikeyexchange", sGssKeyEx }, 361 { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
335 { "gssapicleanupcredentials", sGssCleanupCreds }, 362 { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
363 { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL },
336#else 364#else
337 { "gssapiauthentication", sUnsupported }, 365 { "gssapiauthentication", sUnsupported, SSHCFG_ALL },
338 { "gssapikeyexchange", sUnsupported }, 366 { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
339 { "gssapicleanupcredentials", sUnsupported }, 367 { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
368 { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL },
340#endif 369#endif
341 { "passwordauthentication", sPasswordAuthentication }, 370 { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
342 { "kbdinteractiveauthentication", sKbdInteractiveAuthentication }, 371 { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
343 { "challengeresponseauthentication", sChallengeResponseAuthentication }, 372 { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
344 { "skeyauthentication", sChallengeResponseAuthentication }, /* alias */ 373 { "skeyauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, /* alias */
345 { "checkmail", sDeprecated }, 374 { "checkmail", sDeprecated, SSHCFG_GLOBAL },
346 { "listenaddress", sListenAddress }, 375 { "listenaddress", sListenAddress, SSHCFG_GLOBAL },
347 { "addressfamily", sAddressFamily }, 376 { "addressfamily", sAddressFamily, SSHCFG_GLOBAL },
348 { "printmotd", sPrintMotd }, 377 { "printmotd", sPrintMotd, SSHCFG_GLOBAL },
349 { "printlastlog", sPrintLastLog }, 378 { "printlastlog", sPrintLastLog, SSHCFG_GLOBAL },
350 { "ignorerhosts", sIgnoreRhosts }, 379 { "ignorerhosts", sIgnoreRhosts, SSHCFG_GLOBAL },
351 { "ignoreuserknownhosts", sIgnoreUserKnownHosts }, 380 { "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL },
352 { "x11forwarding", sX11Forwarding }, 381 { "x11forwarding", sX11Forwarding, SSHCFG_ALL },
353 { "x11displayoffset", sX11DisplayOffset }, 382 { "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL },
354 { "x11uselocalhost", sX11UseLocalhost }, 383 { "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
355 { "xauthlocation", sXAuthLocation }, 384 { "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
356 { "strictmodes", sStrictModes }, 385 { "strictmodes", sStrictModes, SSHCFG_GLOBAL },
357 { "permitemptypasswords", sEmptyPasswd }, 386 { "permitemptypasswords", sEmptyPasswd, SSHCFG_GLOBAL },
358 { "permituserenvironment", sPermitUserEnvironment }, 387 { "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
359 { "uselogin", sUseLogin }, 388 { "uselogin", sUseLogin, SSHCFG_GLOBAL },
360 { "compression", sCompression }, 389 { "compression", sCompression, SSHCFG_GLOBAL },
361 { "tcpkeepalive", sTCPKeepAlive }, 390 { "tcpkeepalive", sTCPKeepAlive, SSHCFG_GLOBAL },
362 { "keepalive", sTCPKeepAlive }, /* obsolete alias */ 391 { "keepalive", sTCPKeepAlive, SSHCFG_GLOBAL }, /* obsolete alias */
363 { "allowtcpforwarding", sAllowTcpForwarding }, 392 { "allowtcpforwarding", sAllowTcpForwarding, SSHCFG_ALL },
364 { "allowusers", sAllowUsers }, 393 { "allowusers", sAllowUsers, SSHCFG_GLOBAL },
365 { "denyusers", sDenyUsers }, 394 { "denyusers", sDenyUsers, SSHCFG_GLOBAL },
366 { "allowgroups", sAllowGroups }, 395 { "allowgroups", sAllowGroups, SSHCFG_GLOBAL },
367 { "denygroups", sDenyGroups }, 396 { "denygroups", sDenyGroups, SSHCFG_GLOBAL },
368 { "ciphers", sCiphers }, 397 { "ciphers", sCiphers, SSHCFG_GLOBAL },
369 { "macs", sMacs }, 398 { "macs", sMacs, SSHCFG_GLOBAL },
370 { "protocol", sProtocol }, 399 { "protocol", sProtocol, SSHCFG_GLOBAL },
371 { "gatewayports", sGatewayPorts }, 400 { "gatewayports", sGatewayPorts, SSHCFG_ALL },
372 { "subsystem", sSubsystem }, 401 { "subsystem", sSubsystem, SSHCFG_GLOBAL },
373 { "maxstartups", sMaxStartups }, 402 { "maxstartups", sMaxStartups, SSHCFG_GLOBAL },
374 { "maxauthtries", sMaxAuthTries }, 403 { "maxauthtries", sMaxAuthTries, SSHCFG_GLOBAL },
375 { "banner", sBanner }, 404 { "banner", sBanner, SSHCFG_ALL },
376 { "usedns", sUseDNS }, 405 { "usedns", sUseDNS, SSHCFG_GLOBAL },
377 { "verifyreversemapping", sDeprecated }, 406 { "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL },
378 { "reversemappingcheck", sDeprecated }, 407 { "reversemappingcheck", sDeprecated, SSHCFG_GLOBAL },
379 { "clientaliveinterval", sClientAliveInterval }, 408 { "clientaliveinterval", sClientAliveInterval, SSHCFG_GLOBAL },
380 { "clientalivecountmax", sClientAliveCountMax }, 409 { "clientalivecountmax", sClientAliveCountMax, SSHCFG_GLOBAL },
381 { "authorizedkeysfile", sAuthorizedKeysFile }, 410 { "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_GLOBAL },
382 { "authorizedkeysfile2", sAuthorizedKeysFile2 }, 411 { "authorizedkeysfile2", sAuthorizedKeysFile2, SSHCFG_GLOBAL },
383 { "useprivilegeseparation", sUsePrivilegeSeparation}, 412 { "useprivilegeseparation", sUsePrivilegeSeparation, SSHCFG_GLOBAL },
384 { "acceptenv", sAcceptEnv }, 413 { "acceptenv", sAcceptEnv, SSHCFG_GLOBAL },
385 { "permittunnel", sPermitTunnel }, 414 { "permittunnel", sPermitTunnel, SSHCFG_GLOBAL },
386 { NULL, sBadOption } 415 { "match", sMatch, SSHCFG_ALL },
416 { "permitopen", sPermitOpen, SSHCFG_ALL },
417 { "forcecommand", sForceCommand, SSHCFG_ALL },
418 { NULL, sBadOption, 0 }
387}; 419};
388 420
389/* 421/*
@@ -392,13 +424,15 @@ static struct {
392 424
393static ServerOpCodes 425static ServerOpCodes
394parse_token(const char *cp, const char *filename, 426parse_token(const char *cp, const char *filename,
395 int linenum) 427 int linenum, u_int *flags)
396{ 428{
397 u_int i; 429 u_int i;
398 430
399 for (i = 0; keywords[i].name; i++) 431 for (i = 0; keywords[i].name; i++)
400 if (strcasecmp(cp, keywords[i].name) == 0) 432 if (strcasecmp(cp, keywords[i].name) == 0) {
433 *flags = keywords[i].flags;
401 return keywords[i].opcode; 434 return keywords[i].opcode;
435 }
402 436
403 error("%s: line %d: Bad configuration option: %s", 437 error("%s: line %d: Bad configuration option: %s",
404 filename, linenum, cp); 438 filename, linenum, cp);
@@ -443,18 +477,171 @@ add_one_listen_addr(ServerOptions *options, char *addr, u_short port)
443 options->listen_addrs = aitop; 477 options->listen_addrs = aitop;
444} 478}
445 479
480/*
481 * The strategy for the Match blocks is that the config file is parsed twice.
482 *
483 * The first time is at startup. activep is initialized to 1 and the
484 * directives in the global context are processed and acted on. Hitting a
485 * Match directive unsets activep and the directives inside the block are
486 * checked for syntax only.
487 *
488 * The second time is after a connection has been established but before
489 * authentication. activep is initialized to 2 and global config directives
490 * are ignored since they have already been processed. If the criteria in a
491 * Match block is met, activep is set and the subsequent directives
492 * processed and actioned until EOF or another Match block unsets it. Any
493 * options set are copied into the main server config.
494 *
495 * Potential additions/improvements:
496 * - Add Match support for pre-kex directives, eg Protocol, Ciphers.
497 *
498 * - Add a Tag directive (idea from David Leonard) ala pf, eg:
499 * Match Address 192.168.0.*
500 * Tag trusted
501 * Match Group wheel
502 * Tag trusted
503 * Match Tag trusted
504 * AllowTcpForwarding yes
505 * GatewayPorts clientspecified
506 * [...]
507 *
508 * - Add a PermittedChannelRequests directive
509 * Match Group shell
510 * PermittedChannelRequests session,forwarded-tcpip
511 */
512
513static int
514match_cfg_line_group(const char *grps, int line, const char *user)
515{
516 int result = 0;
517 u_int ngrps = 0;
518 char *arg, *p, *cp, *grplist[MAX_MATCH_GROUPS];
519 struct passwd *pw;
520
521 /*
522 * Even if we do not have a user yet, we still need to check for
523 * valid syntax.
524 */
525 arg = cp = xstrdup(grps);
526 while ((p = strsep(&cp, ",")) != NULL && *p != '\0') {
527 if (ngrps >= MAX_MATCH_GROUPS) {
528 error("line %d: too many groups in Match Group", line);
529 result = -1;
530 goto out;
531 }
532 grplist[ngrps++] = p;
533 }
534
535 if (user == NULL)
536 goto out;
537
538 if ((pw = getpwnam(user)) == NULL) {
539 debug("Can't match group at line %d because user %.100s does "
540 "not exist", line, user);
541 } else if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
542 debug("Can't Match group because user %.100s not in any group "
543 "at line %d", user, line);
544 } else if (ga_match(grplist, ngrps) != 1) {
545 debug("user %.100s does not match group %.100s at line %d",
546 user, arg, line);
547 } else {
548 debug("user %.100s matched group %.100s at line %d", user,
549 arg, line);
550 result = 1;
551 }
552out:
553 ga_free();
554 xfree(arg);
555 return result;
556}
557
558static int
559match_cfg_line(char **condition, int line, const char *user, const char *host,
560 const char *address)
561{
562 int result = 1;
563 char *arg, *attrib, *cp = *condition;
564 size_t len;
565
566 if (user == NULL)
567 debug3("checking syntax for 'Match %s'", cp);
568 else
569 debug3("checking match for '%s' user %s host %s addr %s", cp,
570 user ? user : "(null)", host ? host : "(null)",
571 address ? address : "(null)");
572
573 while ((attrib = strdelim(&cp)) && *attrib != '\0') {
574 if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
575 error("Missing Match criteria for %s", attrib);
576 return -1;
577 }
578 len = strlen(arg);
579 if (strcasecmp(attrib, "user") == 0) {
580 if (!user) {
581 result = 0;
582 continue;
583 }
584 if (match_pattern_list(user, arg, len, 0) != 1)
585 result = 0;
586 else
587 debug("user %.100s matched 'User %.100s' at "
588 "line %d", user, arg, line);
589 } else if (strcasecmp(attrib, "group") == 0) {
590 switch (match_cfg_line_group(arg, line, user)) {
591 case -1:
592 return -1;
593 case 0:
594 result = 0;
595 }
596 } else if (strcasecmp(attrib, "host") == 0) {
597 if (!host) {
598 result = 0;
599 continue;
600 }
601 if (match_hostname(host, arg, len) != 1)
602 result = 0;
603 else
604 debug("connection from %.100s matched 'Host "
605 "%.100s' at line %d", host, arg, line);
606 } else if (strcasecmp(attrib, "address") == 0) {
607 debug("address '%s' arg '%s'", address, arg);
608 if (!address) {
609 result = 0;
610 continue;
611 }
612 if (match_hostname(address, arg, len) != 1)
613 result = 0;
614 else
615 debug("connection from %.100s matched 'Address "
616 "%.100s' at line %d", address, arg, line);
617 } else {
618 error("Unsupported Match attribute %s", attrib);
619 return -1;
620 }
621 }
622 if (user != NULL)
623 debug3("match %sfound", result ? "" : "not ");
624 *condition = cp;
625 return result;
626}
627
628#define WHITESPACE " \t\r\n"
629
446int 630int
447process_server_config_line(ServerOptions *options, char *line, 631process_server_config_line(ServerOptions *options, char *line,
448 const char *filename, int linenum) 632 const char *filename, int linenum, int *activep, const char *user,
633 const char *host, const char *address)
449{ 634{
450 char *cp, **charptr, *arg, *p; 635 char *cp, **charptr, *arg, *p;
451 int *intptr, value, n; 636 int cmdline = 0, *intptr, value, n;
452 ServerOpCodes opcode; 637 ServerOpCodes opcode;
453 u_short port; 638 u_short port;
454 u_int i; 639 u_int i, flags = 0;
640 size_t len;
455 641
456 cp = line; 642 cp = line;
457 arg = strdelim(&cp); 643 if ((arg = strdelim(&cp)) == NULL)
644 return 0;
458 /* Ignore leading whitespace */ 645 /* Ignore leading whitespace */
459 if (*arg == '\0') 646 if (*arg == '\0')
460 arg = strdelim(&cp); 647 arg = strdelim(&cp);
@@ -462,7 +649,25 @@ process_server_config_line(ServerOptions *options, char *line,
462 return 0; 649 return 0;
463 intptr = NULL; 650 intptr = NULL;
464 charptr = NULL; 651 charptr = NULL;
465 opcode = parse_token(arg, filename, linenum); 652 opcode = parse_token(arg, filename, linenum, &flags);
653
654 if (activep == NULL) { /* We are processing a command line directive */
655 cmdline = 1;
656 activep = &cmdline;
657 }
658 if (*activep && opcode != sMatch)
659 debug3("%s:%d setting %s %s", filename, linenum, arg, cp);
660 if (*activep == 0 && !(flags & SSHCFG_MATCH)) {
661 if (user == NULL) {
662 fatal("%s line %d: Directive '%s' is not allowed "
663 "within a Match block", filename, linenum, arg);
664 } else { /* this is a directive we have already processed */
665 while (arg)
666 arg = strdelim(&cp);
667 return 0;
668 }
669 }
670
466 switch (opcode) { 671 switch (opcode) {
467 /* Portable-specific options */ 672 /* Portable-specific options */
468 case sUsePAM: 673 case sUsePAM:
@@ -500,7 +705,7 @@ parse_int:
500 fatal("%s line %d: missing integer value.", 705 fatal("%s line %d: missing integer value.",
501 filename, linenum); 706 filename, linenum);
502 value = atoi(arg); 707 value = atoi(arg);
503 if (*intptr == -1) 708 if (*activep && *intptr == -1)
504 *intptr = value; 709 *intptr = value;
505 break; 710 break;
506 711
@@ -580,7 +785,7 @@ parse_filename:
580 if (!arg || *arg == '\0') 785 if (!arg || *arg == '\0')
581 fatal("%s line %d: missing file name.", 786 fatal("%s line %d: missing file name.",
582 filename, linenum); 787 filename, linenum);
583 if (*charptr == NULL) { 788 if (*activep && *charptr == NULL) {
584 *charptr = tilde_expand_filename(arg, getuid()); 789 *charptr = tilde_expand_filename(arg, getuid());
585 /* increase optional counter */ 790 /* increase optional counter */
586 if (intptr != NULL) 791 if (intptr != NULL)
@@ -631,7 +836,7 @@ parse_flag:
631 else 836 else
632 fatal("%s line %d: Bad yes/no argument: %s", 837 fatal("%s line %d: Bad yes/no argument: %s",
633 filename, linenum, arg); 838 filename, linenum, arg);
634 if (*intptr == -1) 839 if (*activep && *intptr == -1)
635 *intptr = value; 840 *intptr = value;
636 break; 841 break;
637 842
@@ -687,6 +892,10 @@ parse_flag:
687 intptr = &options->gss_cleanup_creds; 892 intptr = &options->gss_cleanup_creds;
688 goto parse_flag; 893 goto parse_flag;
689 894
895 case sGssStrictAcceptor:
896 intptr = &options->gss_strict_acceptor;
897 goto parse_flag;
898
690 case sPasswordAuthentication: 899 case sPasswordAuthentication:
691 intptr = &options->password_authentication; 900 intptr = &options->password_authentication;
692 goto parse_flag; 901 goto parse_flag;
@@ -779,7 +988,7 @@ parse_flag:
779 else 988 else
780 fatal("%s line %d: Bad yes/no/clientspecified " 989 fatal("%s line %d: Bad yes/no/clientspecified "
781 "argument: %s", filename, linenum, arg); 990 "argument: %s", filename, linenum, arg);
782 if (*intptr == -1) 991 if (*activep && *intptr == -1)
783 *intptr = value; 992 *intptr = value;
784 break; 993 break;
785 994
@@ -830,7 +1039,7 @@ parse_flag:
830 case sDenyUsers: 1039 case sDenyUsers:
831 while ((arg = strdelim(&cp)) && *arg != '\0') { 1040 while ((arg = strdelim(&cp)) && *arg != '\0') {
832 if (options->num_deny_users >= MAX_DENY_USERS) 1041 if (options->num_deny_users >= MAX_DENY_USERS)
833 fatal( "%s line %d: too many deny users.", 1042 fatal("%s line %d: too many deny users.",
834 filename, linenum); 1043 filename, linenum);
835 options->deny_users[options->num_deny_users++] = 1044 options->deny_users[options->num_deny_users++] =
836 xstrdup(arg); 1045 xstrdup(arg);
@@ -900,6 +1109,10 @@ parse_flag:
900 if (!arg || *arg == '\0') 1109 if (!arg || *arg == '\0')
901 fatal("%s line %d: Missing subsystem name.", 1110 fatal("%s line %d: Missing subsystem name.",
902 filename, linenum); 1111 filename, linenum);
1112 if (!*activep) {
1113 arg = strdelim(&cp);
1114 break;
1115 }
903 for (i = 0; i < options->num_subsystems; i++) 1116 for (i = 0; i < options->num_subsystems; i++)
904 if (strcmp(arg, options->subsystem_name[i]) == 0) 1117 if (strcmp(arg, options->subsystem_name[i]) == 0)
905 fatal("%s line %d: Subsystem '%s' already defined.", 1118 fatal("%s line %d: Subsystem '%s' already defined.",
@@ -910,6 +1123,17 @@ parse_flag:
910 fatal("%s line %d: Missing subsystem command.", 1123 fatal("%s line %d: Missing subsystem command.",
911 filename, linenum); 1124 filename, linenum);
912 options->subsystem_command[options->num_subsystems] = xstrdup(arg); 1125 options->subsystem_command[options->num_subsystems] = xstrdup(arg);
1126
1127 /* Collect arguments (separate to executable) */
1128 p = xstrdup(arg);
1129 len = strlen(p) + 1;
1130 while ((arg = strdelim(&cp)) != NULL && *arg != '\0') {
1131 len += 1 + strlen(arg);
1132 p = xrealloc(p, 1, len);
1133 strlcat(p, " ", len);
1134 strlcat(p, arg, len);
1135 }
1136 options->subsystem_args[options->num_subsystems] = p;
913 options->num_subsystems++; 1137 options->num_subsystems++;
914 break; 1138 break;
915 1139
@@ -950,7 +1174,7 @@ parse_flag:
950 */ 1174 */
951 case sAuthorizedKeysFile: 1175 case sAuthorizedKeysFile:
952 case sAuthorizedKeysFile2: 1176 case sAuthorizedKeysFile2:
953 charptr = (opcode == sAuthorizedKeysFile ) ? 1177 charptr = (opcode == sAuthorizedKeysFile) ?
954 &options->authorized_keys_file : 1178 &options->authorized_keys_file :
955 &options->authorized_keys_file2; 1179 &options->authorized_keys_file2;
956 goto parse_filename; 1180 goto parse_filename;
@@ -971,6 +1195,8 @@ parse_flag:
971 if (options->num_accept_env >= MAX_ACCEPT_ENV) 1195 if (options->num_accept_env >= MAX_ACCEPT_ENV)
972 fatal("%s line %d: too many allow env.", 1196 fatal("%s line %d: too many allow env.",
973 filename, linenum); 1197 filename, linenum);
1198 if (!*activep)
1199 break;
974 options->accept_env[options->num_accept_env++] = 1200 options->accept_env[options->num_accept_env++] =
975 xstrdup(arg); 1201 xstrdup(arg);
976 } 1202 }
@@ -998,6 +1224,56 @@ parse_flag:
998 *intptr = value; 1224 *intptr = value;
999 break; 1225 break;
1000 1226
1227 case sMatch:
1228 if (cmdline)
1229 fatal("Match directive not supported as a command-line "
1230 "option");
1231 value = match_cfg_line(&cp, linenum, user, host, address);
1232 if (value < 0)
1233 fatal("%s line %d: Bad Match condition", filename,
1234 linenum);
1235 *activep = value;
1236 break;
1237
1238 case sPermitOpen:
1239 arg = strdelim(&cp);
1240 if (!arg || *arg == '\0')
1241 fatal("%s line %d: missing PermitOpen specification",
1242 filename, linenum);
1243 n = options->num_permitted_opens; /* modified later */
1244 if (strcmp(arg, "any") == 0) {
1245 if (*activep && n == -1) {
1246 channel_clear_adm_permitted_opens();
1247 options->num_permitted_opens = 0;
1248 }
1249 break;
1250 }
1251 if (*activep && n == -1)
1252 channel_clear_adm_permitted_opens();
1253 for (; arg != NULL && *arg != '\0'; arg = strdelim(&cp)) {
1254 p = hpdelim(&arg);
1255 if (p == NULL)
1256 fatal("%s line %d: missing host in PermitOpen",
1257 filename, linenum);
1258 p = cleanhostname(p);
1259 if (arg == NULL || (port = a2port(arg)) == 0)
1260 fatal("%s line %d: bad port number in "
1261 "PermitOpen", filename, linenum);
1262 if (*activep && n == -1)
1263 options->num_permitted_opens =
1264 channel_add_adm_permitted_opens(p, port);
1265 }
1266 break;
1267
1268 case sForceCommand:
1269 if (cp == NULL)
1270 fatal("%.200s line %d: Missing argument.", filename,
1271 linenum);
1272 len = strspn(cp, WHITESPACE);
1273 if (*activep && options->adm_forced_command == NULL)
1274 options->adm_forced_command = xstrdup(cp + len);
1275 return 0;
1276
1001 case sDeprecated: 1277 case sDeprecated:
1002 logit("%s line %d: Deprecated option %s", 1278 logit("%s line %d: Deprecated option %s",
1003 filename, linenum, arg); 1279 filename, linenum, arg);
@@ -1054,22 +1330,85 @@ load_server_config(const char *filename, Buffer *conf)
1054} 1330}
1055 1331
1056void 1332void
1057parse_server_config(ServerOptions *options, const char *filename, Buffer *conf) 1333parse_server_match_config(ServerOptions *options, const char *user,
1334 const char *host, const char *address)
1058{ 1335{
1059 int linenum, bad_options = 0; 1336 ServerOptions mo;
1337
1338 initialize_server_options(&mo);
1339 parse_server_config(&mo, "reprocess config", &cfg, user, host, address);
1340 copy_set_server_options(options, &mo, 0);
1341}
1342
1343/* Helper macros */
1344#define M_CP_INTOPT(n) do {\
1345 if (src->n != -1) \
1346 dst->n = src->n; \
1347} while (0)
1348#define M_CP_STROPT(n) do {\
1349 if (src->n != NULL) { \
1350 if (dst->n != NULL) \
1351 xfree(dst->n); \
1352 dst->n = src->n; \
1353 } \
1354} while(0)
1355
1356/*
1357 * Copy any supported values that are set.
1358 *
1359 * If the preauth flag is set, we do not bother copying the the string or
1360 * array values that are not used pre-authentication, because any that we
1361 * do use must be explictly sent in mm_getpwnamallow().
1362 */
1363void
1364copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
1365{
1366 M_CP_INTOPT(password_authentication);
1367 M_CP_INTOPT(gss_authentication);
1368 M_CP_INTOPT(rsa_authentication);
1369 M_CP_INTOPT(pubkey_authentication);
1370 M_CP_INTOPT(kerberos_authentication);
1371 M_CP_INTOPT(hostbased_authentication);
1372 M_CP_INTOPT(kbd_interactive_authentication);
1373
1374 M_CP_INTOPT(allow_tcp_forwarding);
1375 M_CP_INTOPT(gateway_ports);
1376 M_CP_INTOPT(x11_display_offset);
1377 M_CP_INTOPT(x11_forwarding);
1378 M_CP_INTOPT(x11_use_localhost);
1379
1380 M_CP_STROPT(banner);
1381 if (preauth)
1382 return;
1383 M_CP_STROPT(adm_forced_command);
1384}
1385
1386#undef M_CP_INTOPT
1387#undef M_CP_STROPT
1388
1389void
1390parse_server_config(ServerOptions *options, const char *filename, Buffer *conf,
1391 const char *user, const char *host, const char *address)
1392{
1393 int active, linenum, bad_options = 0;
1060 char *cp, *obuf, *cbuf; 1394 char *cp, *obuf, *cbuf;
1061 1395
1062 debug2("%s: config %s len %d", __func__, filename, buffer_len(conf)); 1396 debug2("%s: config %s len %d", __func__, filename, buffer_len(conf));
1063 1397
1064 obuf = cbuf = xstrdup(buffer_ptr(conf)); 1398 obuf = cbuf = xstrdup(buffer_ptr(conf));
1399 active = user ? 0 : 1;
1065 linenum = 1; 1400 linenum = 1;
1066 while ((cp = strsep(&cbuf, "\n")) != NULL) { 1401 while ((cp = strsep(&cbuf, "\n")) != NULL) {
1067 if (process_server_config_line(options, cp, filename, 1402 if (process_server_config_line(options, cp, filename,
1068 linenum++) != 0) 1403 linenum++, &active, user, host, address) != 0)
1069 bad_options++; 1404 bad_options++;
1070 } 1405 }
1071 xfree(obuf); 1406 xfree(obuf);
1072 if (bad_options > 0) 1407 if (bad_options > 0)
1073 fatal("%s: terminating, %d bad configuration options", 1408 fatal("%s: terminating, %d bad configuration options",
1074 filename, bad_options); 1409 filename, bad_options);
1410
1411 /* challenge-response is implemented via keyboard interactive */
1412 if (options->challenge_response_authentication == 1)
1413 options->kbd_interactive_authentication = 1;
1075} 1414}