summaryrefslogtreecommitdiff
path: root/servconf.c
diff options
context:
space:
mode:
Diffstat (limited to 'servconf.c')
-rw-r--r--servconf.c557
1 files changed, 448 insertions, 109 deletions
diff --git a/servconf.c b/servconf.c
index 60febff99..951bbc4bf 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,118 +296,130 @@ 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 { "gssapicleanupcreds", sGssCleanupCreds, SSHCFG_GLOBAL },
336 { "gssapicleanupcreds", sGssCleanupCreds }, 363 { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
364 { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL },
337#else 365#else
338 { "gssapiauthentication", sUnsupported }, 366 { "gssapiauthentication", sUnsupported, SSHCFG_ALL },
339 { "gssapikeyexchange", sUnsupported }, 367 { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
340 { "gssapicleanupcredentials", sUnsupported }, 368 { "gssapicleanupcreds", sUnsupported, SSHCFG_GLOBAL },
341 { "gssapicleanupcreds", sUnsupported }, 369 { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
370 { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL },
342#endif 371#endif
343 { "gssusesessionccache", sUnsupported }, 372 { "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL },
344 { "gssapiusesessioncredcache", sUnsupported }, 373 { "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL },
345 { "passwordauthentication", sPasswordAuthentication }, 374 { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
346 { "kbdinteractiveauthentication", sKbdInteractiveAuthentication }, 375 { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
347 { "challengeresponseauthentication", sChallengeResponseAuthentication }, 376 { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
348 { "skeyauthentication", sChallengeResponseAuthentication }, /* alias */ 377 { "skeyauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, /* alias */
349 { "checkmail", sDeprecated }, 378 { "checkmail", sDeprecated, SSHCFG_GLOBAL },
350 { "listenaddress", sListenAddress }, 379 { "listenaddress", sListenAddress, SSHCFG_GLOBAL },
351 { "addressfamily", sAddressFamily }, 380 { "addressfamily", sAddressFamily, SSHCFG_GLOBAL },
352 { "printmotd", sPrintMotd }, 381 { "printmotd", sPrintMotd, SSHCFG_GLOBAL },
353 { "printlastlog", sPrintLastLog }, 382 { "printlastlog", sPrintLastLog, SSHCFG_GLOBAL },
354 { "ignorerhosts", sIgnoreRhosts }, 383 { "ignorerhosts", sIgnoreRhosts, SSHCFG_GLOBAL },
355 { "ignoreuserknownhosts", sIgnoreUserKnownHosts }, 384 { "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL },
356 { "x11forwarding", sX11Forwarding }, 385 { "x11forwarding", sX11Forwarding, SSHCFG_ALL },
357 { "x11displayoffset", sX11DisplayOffset }, 386 { "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL },
358 { "x11uselocalhost", sX11UseLocalhost }, 387 { "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
359 { "xauthlocation", sXAuthLocation }, 388 { "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
360 { "strictmodes", sStrictModes }, 389 { "strictmodes", sStrictModes, SSHCFG_GLOBAL },
361 { "permitemptypasswords", sEmptyPasswd }, 390 { "permitemptypasswords", sEmptyPasswd, SSHCFG_GLOBAL },
362 { "permituserenvironment", sPermitUserEnvironment }, 391 { "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
363 { "uselogin", sUseLogin }, 392 { "uselogin", sUseLogin, SSHCFG_GLOBAL },
364 { "compression", sCompression }, 393 { "compression", sCompression, SSHCFG_GLOBAL },
365 { "tcpkeepalive", sTCPKeepAlive }, 394 { "tcpkeepalive", sTCPKeepAlive, SSHCFG_GLOBAL },
366 { "keepalive", sTCPKeepAlive }, /* obsolete alias */ 395 { "keepalive", sTCPKeepAlive, SSHCFG_GLOBAL }, /* obsolete alias */
367 { "allowtcpforwarding", sAllowTcpForwarding }, 396 { "allowtcpforwarding", sAllowTcpForwarding, SSHCFG_ALL },
368 { "allowusers", sAllowUsers }, 397 { "allowusers", sAllowUsers, SSHCFG_GLOBAL },
369 { "denyusers", sDenyUsers }, 398 { "denyusers", sDenyUsers, SSHCFG_GLOBAL },
370 { "allowgroups", sAllowGroups }, 399 { "allowgroups", sAllowGroups, SSHCFG_GLOBAL },
371 { "denygroups", sDenyGroups }, 400 { "denygroups", sDenyGroups, SSHCFG_GLOBAL },
372 { "ciphers", sCiphers }, 401 { "ciphers", sCiphers, SSHCFG_GLOBAL },
373 { "macs", sMacs }, 402 { "macs", sMacs, SSHCFG_GLOBAL },
374 { "protocol", sProtocol }, 403 { "protocol", sProtocol, SSHCFG_GLOBAL },
375 { "gatewayports", sGatewayPorts }, 404 { "gatewayports", sGatewayPorts, SSHCFG_ALL },
376 { "subsystem", sSubsystem }, 405 { "subsystem", sSubsystem, SSHCFG_GLOBAL },
377 { "maxstartups", sMaxStartups }, 406 { "maxstartups", sMaxStartups, SSHCFG_GLOBAL },
378 { "maxauthtries", sMaxAuthTries }, 407 { "maxauthtries", sMaxAuthTries, SSHCFG_GLOBAL },
379 { "banner", sBanner }, 408 { "banner", sBanner, SSHCFG_ALL },
380 { "usedns", sUseDNS }, 409 { "usedns", sUseDNS, SSHCFG_GLOBAL },
381 { "verifyreversemapping", sDeprecated }, 410 { "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL },
382 { "reversemappingcheck", sDeprecated }, 411 { "reversemappingcheck", sDeprecated, SSHCFG_GLOBAL },
383 { "clientaliveinterval", sClientAliveInterval }, 412 { "clientaliveinterval", sClientAliveInterval, SSHCFG_GLOBAL },
384 { "clientalivecountmax", sClientAliveCountMax }, 413 { "clientalivecountmax", sClientAliveCountMax, SSHCFG_GLOBAL },
385 { "authorizedkeysfile", sAuthorizedKeysFile }, 414 { "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_GLOBAL },
386 { "authorizedkeysfile2", sAuthorizedKeysFile2 }, 415 { "authorizedkeysfile2", sAuthorizedKeysFile2, SSHCFG_GLOBAL },
387 { "useprivilegeseparation", sUsePrivilegeSeparation}, 416 { "useprivilegeseparation", sUsePrivilegeSeparation, SSHCFG_GLOBAL },
388 { "acceptenv", sAcceptEnv }, 417 { "acceptenv", sAcceptEnv, SSHCFG_GLOBAL },
389 { "permittunnel", sPermitTunnel }, 418 { "permittunnel", sPermitTunnel, SSHCFG_GLOBAL },
390 { NULL, sBadOption } 419 { "match", sMatch, SSHCFG_ALL },
420 { "permitopen", sPermitOpen, SSHCFG_ALL },
421 { "forcecommand", sForceCommand, SSHCFG_ALL },
422 { NULL, sBadOption, 0 }
391}; 423};
392 424
393/* 425/*
@@ -396,13 +428,15 @@ static struct {
396 428
397static ServerOpCodes 429static ServerOpCodes
398parse_token(const char *cp, const char *filename, 430parse_token(const char *cp, const char *filename,
399 int linenum) 431 int linenum, u_int *flags)
400{ 432{
401 u_int i; 433 u_int i;
402 434
403 for (i = 0; keywords[i].name; i++) 435 for (i = 0; keywords[i].name; i++)
404 if (strcasecmp(cp, keywords[i].name) == 0) 436 if (strcasecmp(cp, keywords[i].name) == 0) {
437 *flags = keywords[i].flags;
405 return keywords[i].opcode; 438 return keywords[i].opcode;
439 }
406 440
407 error("%s: line %d: Bad configuration option: %s", 441 error("%s: line %d: Bad configuration option: %s",
408 filename, linenum, cp); 442 filename, linenum, cp);
@@ -447,18 +481,171 @@ add_one_listen_addr(ServerOptions *options, char *addr, u_short port)
447 options->listen_addrs = aitop; 481 options->listen_addrs = aitop;
448} 482}
449 483
484/*
485 * The strategy for the Match blocks is that the config file is parsed twice.
486 *
487 * The first time is at startup. activep is initialized to 1 and the
488 * directives in the global context are processed and acted on. Hitting a
489 * Match directive unsets activep and the directives inside the block are
490 * checked for syntax only.
491 *
492 * The second time is after a connection has been established but before
493 * authentication. activep is initialized to 2 and global config directives
494 * are ignored since they have already been processed. If the criteria in a
495 * Match block is met, activep is set and the subsequent directives
496 * processed and actioned until EOF or another Match block unsets it. Any
497 * options set are copied into the main server config.
498 *
499 * Potential additions/improvements:
500 * - Add Match support for pre-kex directives, eg Protocol, Ciphers.
501 *
502 * - Add a Tag directive (idea from David Leonard) ala pf, eg:
503 * Match Address 192.168.0.*
504 * Tag trusted
505 * Match Group wheel
506 * Tag trusted
507 * Match Tag trusted
508 * AllowTcpForwarding yes
509 * GatewayPorts clientspecified
510 * [...]
511 *
512 * - Add a PermittedChannelRequests directive
513 * Match Group shell
514 * PermittedChannelRequests session,forwarded-tcpip
515 */
516
517static int
518match_cfg_line_group(const char *grps, int line, const char *user)
519{
520 int result = 0;
521 u_int ngrps = 0;
522 char *arg, *p, *cp, *grplist[MAX_MATCH_GROUPS];
523 struct passwd *pw;
524
525 /*
526 * Even if we do not have a user yet, we still need to check for
527 * valid syntax.
528 */
529 arg = cp = xstrdup(grps);
530 while ((p = strsep(&cp, ",")) != NULL && *p != '\0') {
531 if (ngrps >= MAX_MATCH_GROUPS) {
532 error("line %d: too many groups in Match Group", line);
533 result = -1;
534 goto out;
535 }
536 grplist[ngrps++] = p;
537 }
538
539 if (user == NULL)
540 goto out;
541
542 if ((pw = getpwnam(user)) == NULL) {
543 debug("Can't match group at line %d because user %.100s does "
544 "not exist", line, user);
545 } else if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
546 debug("Can't Match group because user %.100s not in any group "
547 "at line %d", user, line);
548 } else if (ga_match(grplist, ngrps) != 1) {
549 debug("user %.100s does not match group %.100s at line %d",
550 user, arg, line);
551 } else {
552 debug("user %.100s matched group %.100s at line %d", user,
553 arg, line);
554 result = 1;
555 }
556out:
557 ga_free();
558 xfree(arg);
559 return result;
560}
561
562static int
563match_cfg_line(char **condition, int line, const char *user, const char *host,
564 const char *address)
565{
566 int result = 1;
567 char *arg, *attrib, *cp = *condition;
568 size_t len;
569
570 if (user == NULL)
571 debug3("checking syntax for 'Match %s'", cp);
572 else
573 debug3("checking match for '%s' user %s host %s addr %s", cp,
574 user ? user : "(null)", host ? host : "(null)",
575 address ? address : "(null)");
576
577 while ((attrib = strdelim(&cp)) && *attrib != '\0') {
578 if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
579 error("Missing Match criteria for %s", attrib);
580 return -1;
581 }
582 len = strlen(arg);
583 if (strcasecmp(attrib, "user") == 0) {
584 if (!user) {
585 result = 0;
586 continue;
587 }
588 if (match_pattern_list(user, arg, len, 0) != 1)
589 result = 0;
590 else
591 debug("user %.100s matched 'User %.100s' at "
592 "line %d", user, arg, line);
593 } else if (strcasecmp(attrib, "group") == 0) {
594 switch (match_cfg_line_group(arg, line, user)) {
595 case -1:
596 return -1;
597 case 0:
598 result = 0;
599 }
600 } else if (strcasecmp(attrib, "host") == 0) {
601 if (!host) {
602 result = 0;
603 continue;
604 }
605 if (match_hostname(host, arg, len) != 1)
606 result = 0;
607 else
608 debug("connection from %.100s matched 'Host "
609 "%.100s' at line %d", host, arg, line);
610 } else if (strcasecmp(attrib, "address") == 0) {
611 debug("address '%s' arg '%s'", address, arg);
612 if (!address) {
613 result = 0;
614 continue;
615 }
616 if (match_hostname(address, arg, len) != 1)
617 result = 0;
618 else
619 debug("connection from %.100s matched 'Address "
620 "%.100s' at line %d", address, arg, line);
621 } else {
622 error("Unsupported Match attribute %s", attrib);
623 return -1;
624 }
625 }
626 if (user != NULL)
627 debug3("match %sfound", result ? "" : "not ");
628 *condition = cp;
629 return result;
630}
631
632#define WHITESPACE " \t\r\n"
633
450int 634int
451process_server_config_line(ServerOptions *options, char *line, 635process_server_config_line(ServerOptions *options, char *line,
452 const char *filename, int linenum) 636 const char *filename, int linenum, int *activep, const char *user,
637 const char *host, const char *address)
453{ 638{
454 char *cp, **charptr, *arg, *p; 639 char *cp, **charptr, *arg, *p;
455 int *intptr, value, n; 640 int cmdline = 0, *intptr, value, n;
456 ServerOpCodes opcode; 641 ServerOpCodes opcode;
457 u_short port; 642 u_short port;
458 u_int i; 643 u_int i, flags = 0;
644 size_t len;
459 645
460 cp = line; 646 cp = line;
461 arg = strdelim(&cp); 647 if ((arg = strdelim(&cp)) == NULL)
648 return 0;
462 /* Ignore leading whitespace */ 649 /* Ignore leading whitespace */
463 if (*arg == '\0') 650 if (*arg == '\0')
464 arg = strdelim(&cp); 651 arg = strdelim(&cp);
@@ -466,7 +653,25 @@ process_server_config_line(ServerOptions *options, char *line,
466 return 0; 653 return 0;
467 intptr = NULL; 654 intptr = NULL;
468 charptr = NULL; 655 charptr = NULL;
469 opcode = parse_token(arg, filename, linenum); 656 opcode = parse_token(arg, filename, linenum, &flags);
657
658 if (activep == NULL) { /* We are processing a command line directive */
659 cmdline = 1;
660 activep = &cmdline;
661 }
662 if (*activep && opcode != sMatch)
663 debug3("%s:%d setting %s %s", filename, linenum, arg, cp);
664 if (*activep == 0 && !(flags & SSHCFG_MATCH)) {
665 if (user == NULL) {
666 fatal("%s line %d: Directive '%s' is not allowed "
667 "within a Match block", filename, linenum, arg);
668 } else { /* this is a directive we have already processed */
669 while (arg)
670 arg = strdelim(&cp);
671 return 0;
672 }
673 }
674
470 switch (opcode) { 675 switch (opcode) {
471 /* Portable-specific options */ 676 /* Portable-specific options */
472 case sUsePAM: 677 case sUsePAM:
@@ -504,7 +709,7 @@ parse_int:
504 fatal("%s line %d: missing integer value.", 709 fatal("%s line %d: missing integer value.",
505 filename, linenum); 710 filename, linenum);
506 value = atoi(arg); 711 value = atoi(arg);
507 if (*intptr == -1) 712 if (*activep && *intptr == -1)
508 *intptr = value; 713 *intptr = value;
509 break; 714 break;
510 715
@@ -584,7 +789,7 @@ parse_filename:
584 if (!arg || *arg == '\0') 789 if (!arg || *arg == '\0')
585 fatal("%s line %d: missing file name.", 790 fatal("%s line %d: missing file name.",
586 filename, linenum); 791 filename, linenum);
587 if (*charptr == NULL) { 792 if (*activep && *charptr == NULL) {
588 *charptr = tilde_expand_filename(arg, getuid()); 793 *charptr = tilde_expand_filename(arg, getuid());
589 /* increase optional counter */ 794 /* increase optional counter */
590 if (intptr != NULL) 795 if (intptr != NULL)
@@ -635,7 +840,7 @@ parse_flag:
635 else 840 else
636 fatal("%s line %d: Bad yes/no argument: %s", 841 fatal("%s line %d: Bad yes/no argument: %s",
637 filename, linenum, arg); 842 filename, linenum, arg);
638 if (*intptr == -1) 843 if (*activep && *intptr == -1)
639 *intptr = value; 844 *intptr = value;
640 break; 845 break;
641 846
@@ -691,6 +896,10 @@ parse_flag:
691 intptr = &options->gss_cleanup_creds; 896 intptr = &options->gss_cleanup_creds;
692 goto parse_flag; 897 goto parse_flag;
693 898
899 case sGssStrictAcceptor:
900 intptr = &options->gss_strict_acceptor;
901 goto parse_flag;
902
694 case sPasswordAuthentication: 903 case sPasswordAuthentication:
695 intptr = &options->password_authentication; 904 intptr = &options->password_authentication;
696 goto parse_flag; 905 goto parse_flag;
@@ -783,7 +992,7 @@ parse_flag:
783 else 992 else
784 fatal("%s line %d: Bad yes/no/clientspecified " 993 fatal("%s line %d: Bad yes/no/clientspecified "
785 "argument: %s", filename, linenum, arg); 994 "argument: %s", filename, linenum, arg);
786 if (*intptr == -1) 995 if (*activep && *intptr == -1)
787 *intptr = value; 996 *intptr = value;
788 break; 997 break;
789 998
@@ -834,7 +1043,7 @@ parse_flag:
834 case sDenyUsers: 1043 case sDenyUsers:
835 while ((arg = strdelim(&cp)) && *arg != '\0') { 1044 while ((arg = strdelim(&cp)) && *arg != '\0') {
836 if (options->num_deny_users >= MAX_DENY_USERS) 1045 if (options->num_deny_users >= MAX_DENY_USERS)
837 fatal( "%s line %d: too many deny users.", 1046 fatal("%s line %d: too many deny users.",
838 filename, linenum); 1047 filename, linenum);
839 options->deny_users[options->num_deny_users++] = 1048 options->deny_users[options->num_deny_users++] =
840 xstrdup(arg); 1049 xstrdup(arg);
@@ -904,6 +1113,10 @@ parse_flag:
904 if (!arg || *arg == '\0') 1113 if (!arg || *arg == '\0')
905 fatal("%s line %d: Missing subsystem name.", 1114 fatal("%s line %d: Missing subsystem name.",
906 filename, linenum); 1115 filename, linenum);
1116 if (!*activep) {
1117 arg = strdelim(&cp);
1118 break;
1119 }
907 for (i = 0; i < options->num_subsystems; i++) 1120 for (i = 0; i < options->num_subsystems; i++)
908 if (strcmp(arg, options->subsystem_name[i]) == 0) 1121 if (strcmp(arg, options->subsystem_name[i]) == 0)
909 fatal("%s line %d: Subsystem '%s' already defined.", 1122 fatal("%s line %d: Subsystem '%s' already defined.",
@@ -914,6 +1127,17 @@ parse_flag:
914 fatal("%s line %d: Missing subsystem command.", 1127 fatal("%s line %d: Missing subsystem command.",
915 filename, linenum); 1128 filename, linenum);
916 options->subsystem_command[options->num_subsystems] = xstrdup(arg); 1129 options->subsystem_command[options->num_subsystems] = xstrdup(arg);
1130
1131 /* Collect arguments (separate to executable) */
1132 p = xstrdup(arg);
1133 len = strlen(p) + 1;
1134 while ((arg = strdelim(&cp)) != NULL && *arg != '\0') {
1135 len += 1 + strlen(arg);
1136 p = xrealloc(p, 1, len);
1137 strlcat(p, " ", len);
1138 strlcat(p, arg, len);
1139 }
1140 options->subsystem_args[options->num_subsystems] = p;
917 options->num_subsystems++; 1141 options->num_subsystems++;
918 break; 1142 break;
919 1143
@@ -954,7 +1178,7 @@ parse_flag:
954 */ 1178 */
955 case sAuthorizedKeysFile: 1179 case sAuthorizedKeysFile:
956 case sAuthorizedKeysFile2: 1180 case sAuthorizedKeysFile2:
957 charptr = (opcode == sAuthorizedKeysFile ) ? 1181 charptr = (opcode == sAuthorizedKeysFile) ?
958 &options->authorized_keys_file : 1182 &options->authorized_keys_file :
959 &options->authorized_keys_file2; 1183 &options->authorized_keys_file2;
960 goto parse_filename; 1184 goto parse_filename;
@@ -975,6 +1199,8 @@ parse_flag:
975 if (options->num_accept_env >= MAX_ACCEPT_ENV) 1199 if (options->num_accept_env >= MAX_ACCEPT_ENV)
976 fatal("%s line %d: too many allow env.", 1200 fatal("%s line %d: too many allow env.",
977 filename, linenum); 1201 filename, linenum);
1202 if (!*activep)
1203 break;
978 options->accept_env[options->num_accept_env++] = 1204 options->accept_env[options->num_accept_env++] =
979 xstrdup(arg); 1205 xstrdup(arg);
980 } 1206 }
@@ -1002,6 +1228,56 @@ parse_flag:
1002 *intptr = value; 1228 *intptr = value;
1003 break; 1229 break;
1004 1230
1231 case sMatch:
1232 if (cmdline)
1233 fatal("Match directive not supported as a command-line "
1234 "option");
1235 value = match_cfg_line(&cp, linenum, user, host, address);
1236 if (value < 0)
1237 fatal("%s line %d: Bad Match condition", filename,
1238 linenum);
1239 *activep = value;
1240 break;
1241
1242 case sPermitOpen:
1243 arg = strdelim(&cp);
1244 if (!arg || *arg == '\0')
1245 fatal("%s line %d: missing PermitOpen specification",
1246 filename, linenum);
1247 n = options->num_permitted_opens; /* modified later */
1248 if (strcmp(arg, "any") == 0) {
1249 if (*activep && n == -1) {
1250 channel_clear_adm_permitted_opens();
1251 options->num_permitted_opens = 0;
1252 }
1253 break;
1254 }
1255 if (*activep && n == -1)
1256 channel_clear_adm_permitted_opens();
1257 for (; arg != NULL && *arg != '\0'; arg = strdelim(&cp)) {
1258 p = hpdelim(&arg);
1259 if (p == NULL)
1260 fatal("%s line %d: missing host in PermitOpen",
1261 filename, linenum);
1262 p = cleanhostname(p);
1263 if (arg == NULL || (port = a2port(arg)) == 0)
1264 fatal("%s line %d: bad port number in "
1265 "PermitOpen", filename, linenum);
1266 if (*activep && n == -1)
1267 options->num_permitted_opens =
1268 channel_add_adm_permitted_opens(p, port);
1269 }
1270 break;
1271
1272 case sForceCommand:
1273 if (cp == NULL)
1274 fatal("%.200s line %d: Missing argument.", filename,
1275 linenum);
1276 len = strspn(cp, WHITESPACE);
1277 if (*activep && options->adm_forced_command == NULL)
1278 options->adm_forced_command = xstrdup(cp + len);
1279 return 0;
1280
1005 case sDeprecated: 1281 case sDeprecated:
1006 logit("%s line %d: Deprecated option %s", 1282 logit("%s line %d: Deprecated option %s",
1007 filename, linenum, arg); 1283 filename, linenum, arg);
@@ -1058,22 +1334,85 @@ load_server_config(const char *filename, Buffer *conf)
1058} 1334}
1059 1335
1060void 1336void
1061parse_server_config(ServerOptions *options, const char *filename, Buffer *conf) 1337parse_server_match_config(ServerOptions *options, const char *user,
1338 const char *host, const char *address)
1062{ 1339{
1063 int linenum, bad_options = 0; 1340 ServerOptions mo;
1341
1342 initialize_server_options(&mo);
1343 parse_server_config(&mo, "reprocess config", &cfg, user, host, address);
1344 copy_set_server_options(options, &mo, 0);
1345}
1346
1347/* Helper macros */
1348#define M_CP_INTOPT(n) do {\
1349 if (src->n != -1) \
1350 dst->n = src->n; \
1351} while (0)
1352#define M_CP_STROPT(n) do {\
1353 if (src->n != NULL) { \
1354 if (dst->n != NULL) \
1355 xfree(dst->n); \
1356 dst->n = src->n; \
1357 } \
1358} while(0)
1359
1360/*
1361 * Copy any supported values that are set.
1362 *
1363 * If the preauth flag is set, we do not bother copying the the string or
1364 * array values that are not used pre-authentication, because any that we
1365 * do use must be explictly sent in mm_getpwnamallow().
1366 */
1367void
1368copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
1369{
1370 M_CP_INTOPT(password_authentication);
1371 M_CP_INTOPT(gss_authentication);
1372 M_CP_INTOPT(rsa_authentication);
1373 M_CP_INTOPT(pubkey_authentication);
1374 M_CP_INTOPT(kerberos_authentication);
1375 M_CP_INTOPT(hostbased_authentication);
1376 M_CP_INTOPT(kbd_interactive_authentication);
1377
1378 M_CP_INTOPT(allow_tcp_forwarding);
1379 M_CP_INTOPT(gateway_ports);
1380 M_CP_INTOPT(x11_display_offset);
1381 M_CP_INTOPT(x11_forwarding);
1382 M_CP_INTOPT(x11_use_localhost);
1383
1384 M_CP_STROPT(banner);
1385 if (preauth)
1386 return;
1387 M_CP_STROPT(adm_forced_command);
1388}
1389
1390#undef M_CP_INTOPT
1391#undef M_CP_STROPT
1392
1393void
1394parse_server_config(ServerOptions *options, const char *filename, Buffer *conf,
1395 const char *user, const char *host, const char *address)
1396{
1397 int active, linenum, bad_options = 0;
1064 char *cp, *obuf, *cbuf; 1398 char *cp, *obuf, *cbuf;
1065 1399
1066 debug2("%s: config %s len %d", __func__, filename, buffer_len(conf)); 1400 debug2("%s: config %s len %d", __func__, filename, buffer_len(conf));
1067 1401
1068 obuf = cbuf = xstrdup(buffer_ptr(conf)); 1402 obuf = cbuf = xstrdup(buffer_ptr(conf));
1403 active = user ? 0 : 1;
1069 linenum = 1; 1404 linenum = 1;
1070 while ((cp = strsep(&cbuf, "\n")) != NULL) { 1405 while ((cp = strsep(&cbuf, "\n")) != NULL) {
1071 if (process_server_config_line(options, cp, filename, 1406 if (process_server_config_line(options, cp, filename,
1072 linenum++) != 0) 1407 linenum++, &active, user, host, address) != 0)
1073 bad_options++; 1408 bad_options++;
1074 } 1409 }
1075 xfree(obuf); 1410 xfree(obuf);
1076 if (bad_options > 0) 1411 if (bad_options > 0)
1077 fatal("%s: terminating, %d bad configuration options", 1412 fatal("%s: terminating, %d bad configuration options",
1078 filename, bad_options); 1413 filename, bad_options);
1414
1415 /* challenge-response is implemented via keyboard interactive */
1416 if (options->challenge_response_authentication == 1)
1417 options->kbd_interactive_authentication = 1;
1079} 1418}