diff options
author | Colin Watson <cjwatson@debian.org> | 2009-12-29 21:38:40 +0000 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2009-12-29 21:38:40 +0000 |
commit | 1b816ea846aca3ee89e7995373ace609e9518424 (patch) | |
tree | b41cdc8495cae7fa9c2e0f98a5f2e71656b61f9a /servconf.c | |
parent | fa585019a79ebcb4e0202b1c33f87ff1c5c9ce1c (diff) | |
parent | 086ea76990b1e6287c24b6db74adffd4605eb3b0 (diff) |
import openssh-4.6p1-gsskex-20070312.patch
Diffstat (limited to 'servconf.c')
-rw-r--r-- | servconf.c | 549 |
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" |
13 | RCSID("$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 | ||
26 | static void add_listen_addr(ServerOptions *, char *, u_short); | 43 | static void add_listen_addr(ServerOptions *, char *, u_short); |
27 | static void add_one_listen_addr(ServerOptions *, char *, u_short); | 44 | static 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 */ |
30 | extern int use_privsep; | 47 | extern int use_privsep; |
48 | extern 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 | ||
111 | void | 129 | void |
@@ -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. */ |
286 | static struct { | 312 | static 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 | ||
393 | static ServerOpCodes | 425 | static ServerOpCodes |
394 | parse_token(const char *cp, const char *filename, | 426 | parse_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 | |||
513 | static int | ||
514 | match_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 | } | ||
552 | out: | ||
553 | ga_free(); | ||
554 | xfree(arg); | ||
555 | return result; | ||
556 | } | ||
557 | |||
558 | static int | ||
559 | match_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 | |||
446 | int | 630 | int |
447 | process_server_config_line(ServerOptions *options, char *line, | 631 | process_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 | ||
1056 | void | 1332 | void |
1057 | parse_server_config(ServerOptions *options, const char *filename, Buffer *conf) | 1333 | parse_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 | */ | ||
1363 | void | ||
1364 | copy_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 | |||
1389 | void | ||
1390 | parse_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 | } |