diff options
author | Damien Miller <djm@mindrot.org> | 2013-10-15 12:13:05 +1100 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2013-10-15 12:13:05 +1100 |
commit | 194fd904d8597a274b93e075b2047afdf5a175d4 (patch) | |
tree | e8bd17b8455a41b3dc493b2b69933b8ef0cbfff7 | |
parent | 71df752de2a04f423b1cd18d961a79f4fbccbcee (diff) |
- djm@cvs.openbsd.org 2013/10/14 22:22:05
[readconf.c readconf.h ssh-keysign.c ssh.c ssh_config.5]
add a "Match" keyword to ssh_config that allows matching on hostname,
user and result of arbitrary commands. "nice work" markus@
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | readconf.c | 227 | ||||
-rw-r--r-- | readconf.h | 12 | ||||
-rw-r--r-- | ssh-keysign.c | 4 | ||||
-rw-r--r-- | ssh.c | 22 | ||||
-rw-r--r-- | ssh_config.5 | 52 |
6 files changed, 287 insertions, 34 deletions
@@ -33,6 +33,10 @@ | |||
33 | [session.c session.h] | 33 | [session.c session.h] |
34 | Add logging of session starts in a useful format; ok markus@ feedback and | 34 | Add logging of session starts in a useful format; ok markus@ feedback and |
35 | ok dtucker@ | 35 | ok dtucker@ |
36 | - djm@cvs.openbsd.org 2013/10/14 22:22:05 | ||
37 | [readconf.c readconf.h ssh-keysign.c ssh.c ssh_config.5] | ||
38 | add a "Match" keyword to ssh_config that allows matching on hostname, | ||
39 | user and result of arbitrary commands. "nice work" markus@ | ||
36 | 40 | ||
37 | 20131010 | 41 | 20131010 |
38 | - (dtucker) OpenBSD CVS Sync | 42 | - (dtucker) OpenBSD CVS Sync |
diff --git a/readconf.c b/readconf.c index 7450081cd..f7b912ef6 100644 --- a/readconf.c +++ b/readconf.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: readconf.c,v 1.205 2013/08/20 00:11:37 djm Exp $ */ | 1 | /* $OpenBSD: readconf.c,v 1.206 2013/10/14 22:22:02 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -17,6 +17,7 @@ | |||
17 | #include <sys/types.h> | 17 | #include <sys/types.h> |
18 | #include <sys/stat.h> | 18 | #include <sys/stat.h> |
19 | #include <sys/socket.h> | 19 | #include <sys/socket.h> |
20 | #include <sys/wait.h> | ||
20 | 21 | ||
21 | #include <netinet/in.h> | 22 | #include <netinet/in.h> |
22 | #include <netinet/in_systm.h> | 23 | #include <netinet/in_systm.h> |
@@ -24,7 +25,10 @@ | |||
24 | 25 | ||
25 | #include <ctype.h> | 26 | #include <ctype.h> |
26 | #include <errno.h> | 27 | #include <errno.h> |
28 | #include <fcntl.h> | ||
27 | #include <netdb.h> | 29 | #include <netdb.h> |
30 | #include <paths.h> | ||
31 | #include <pwd.h> | ||
28 | #include <signal.h> | 32 | #include <signal.h> |
29 | #include <stdarg.h> | 33 | #include <stdarg.h> |
30 | #include <stdio.h> | 34 | #include <stdio.h> |
@@ -47,6 +51,7 @@ | |||
47 | #include "buffer.h" | 51 | #include "buffer.h" |
48 | #include "kex.h" | 52 | #include "kex.h" |
49 | #include "mac.h" | 53 | #include "mac.h" |
54 | #include "uidswap.h" | ||
50 | 55 | ||
51 | /* Format of the configuration file: | 56 | /* Format of the configuration file: |
52 | 57 | ||
@@ -115,12 +120,13 @@ | |||
115 | 120 | ||
116 | typedef enum { | 121 | typedef enum { |
117 | oBadOption, | 122 | oBadOption, |
123 | oHost, oMatch, | ||
118 | oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout, | 124 | oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout, |
119 | oGatewayPorts, oExitOnForwardFailure, | 125 | oGatewayPorts, oExitOnForwardFailure, |
120 | oPasswordAuthentication, oRSAAuthentication, | 126 | oPasswordAuthentication, oRSAAuthentication, |
121 | oChallengeResponseAuthentication, oXAuthLocation, | 127 | oChallengeResponseAuthentication, oXAuthLocation, |
122 | oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward, | 128 | oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward, |
123 | oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand, | 129 | oUser, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand, |
124 | oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts, | 130 | oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts, |
125 | oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression, | 131 | oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression, |
126 | oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts, | 132 | oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts, |
@@ -194,6 +200,7 @@ static struct { | |||
194 | { "localforward", oLocalForward }, | 200 | { "localforward", oLocalForward }, |
195 | { "user", oUser }, | 201 | { "user", oUser }, |
196 | { "host", oHost }, | 202 | { "host", oHost }, |
203 | { "match", oMatch }, | ||
197 | { "escapechar", oEscapeChar }, | 204 | { "escapechar", oEscapeChar }, |
198 | { "globalknownhostsfile", oGlobalKnownHostsFile }, | 205 | { "globalknownhostsfile", oGlobalKnownHostsFile }, |
199 | { "globalknownhostsfile2", oDeprecated }, | 206 | { "globalknownhostsfile2", oDeprecated }, |
@@ -349,10 +356,188 @@ add_identity_file(Options *options, const char *dir, const char *filename, | |||
349 | options->identity_files[options->num_identity_files++] = path; | 356 | options->identity_files[options->num_identity_files++] = path; |
350 | } | 357 | } |
351 | 358 | ||
359 | int | ||
360 | default_ssh_port(void) | ||
361 | { | ||
362 | static int port; | ||
363 | struct servent *sp; | ||
364 | |||
365 | if (port == 0) { | ||
366 | sp = getservbyname(SSH_SERVICE_NAME, "tcp"); | ||
367 | port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT; | ||
368 | } | ||
369 | return port; | ||
370 | } | ||
371 | |||
352 | /* | 372 | /* |
353 | * Returns the number of the token pointed to by cp or oBadOption. | 373 | * Execute a command in a shell. |
374 | * Return its exit status or -1 on abnormal exit. | ||
354 | */ | 375 | */ |
376 | static int | ||
377 | execute_in_shell(const char *cmd) | ||
378 | { | ||
379 | char *shell, *command_string; | ||
380 | pid_t pid; | ||
381 | int devnull, status; | ||
382 | extern uid_t original_real_uid; | ||
355 | 383 | ||
384 | if ((shell = getenv("SHELL")) == NULL) | ||
385 | shell = _PATH_BSHELL; | ||
386 | |||
387 | /* | ||
388 | * Use "exec" to avoid "sh -c" processes on some platforms | ||
389 | * (e.g. Solaris) | ||
390 | */ | ||
391 | xasprintf(&command_string, "exec %s", cmd); | ||
392 | |||
393 | /* Need this to redirect subprocess stdin/out */ | ||
394 | if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) | ||
395 | fatal("open(/dev/null): %s", strerror(errno)); | ||
396 | |||
397 | debug("Executing command: '%.500s'", cmd); | ||
398 | |||
399 | /* Fork and execute the command. */ | ||
400 | if ((pid = fork()) == 0) { | ||
401 | char *argv[4]; | ||
402 | |||
403 | /* Child. Permanently give up superuser privileges. */ | ||
404 | permanently_drop_suid(original_real_uid); | ||
405 | |||
406 | /* Redirect child stdin and stdout. Leave stderr */ | ||
407 | if (dup2(devnull, STDIN_FILENO) == -1) | ||
408 | fatal("dup2: %s", strerror(errno)); | ||
409 | if (dup2(devnull, STDOUT_FILENO) == -1) | ||
410 | fatal("dup2: %s", strerror(errno)); | ||
411 | if (devnull > STDERR_FILENO) | ||
412 | close(devnull); | ||
413 | closefrom(STDERR_FILENO + 1); | ||
414 | |||
415 | argv[0] = shell; | ||
416 | argv[1] = "-c"; | ||
417 | argv[2] = command_string; | ||
418 | argv[3] = NULL; | ||
419 | |||
420 | execv(argv[0], argv); | ||
421 | error("Unable to execute '%.100s': %s", cmd, strerror(errno)); | ||
422 | /* Die with signal to make this error apparent to parent. */ | ||
423 | signal(SIGTERM, SIG_DFL); | ||
424 | kill(getpid(), SIGTERM); | ||
425 | _exit(1); | ||
426 | } | ||
427 | /* Parent. */ | ||
428 | if (pid < 0) | ||
429 | fatal("%s: fork: %.100s", __func__, strerror(errno)); | ||
430 | |||
431 | close(devnull); | ||
432 | free(command_string); | ||
433 | |||
434 | while (waitpid(pid, &status, 0) == -1) { | ||
435 | if (errno != EINTR && errno != EAGAIN) | ||
436 | fatal("%s: waitpid: %s", __func__, strerror(errno)); | ||
437 | } | ||
438 | if (!WIFEXITED(status)) { | ||
439 | error("command '%.100s' exited abnormally", cmd); | ||
440 | return -1; | ||
441 | } | ||
442 | debug3("command returned status %d", WEXITSTATUS(status)); | ||
443 | return WEXITSTATUS(status); | ||
444 | } | ||
445 | |||
446 | /* | ||
447 | * Parse and execute a Match directive. | ||
448 | */ | ||
449 | static int | ||
450 | match_cfg_line(Options *options, char **condition, struct passwd *pw, | ||
451 | const char *host_arg, const char *filename, int linenum) | ||
452 | { | ||
453 | char *arg, *attrib, *cmd, *cp = *condition; | ||
454 | const char *ruser, *host; | ||
455 | int r, port, result = 1; | ||
456 | size_t len; | ||
457 | char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; | ||
458 | |||
459 | /* | ||
460 | * Configuration is likely to be incomplete at this point so we | ||
461 | * must be prepared to use default values. | ||
462 | */ | ||
463 | port = options->port <= 0 ? default_ssh_port() : options->port; | ||
464 | ruser = options->user == NULL ? pw->pw_name : options->user; | ||
465 | host = options->hostname == NULL ? host_arg : options->hostname; | ||
466 | |||
467 | debug3("checking match for '%s' host %s", cp, host); | ||
468 | while ((attrib = strdelim(&cp)) && *attrib != '\0') { | ||
469 | if ((arg = strdelim(&cp)) == NULL || *arg == '\0') { | ||
470 | error("Missing Match criteria for %s", attrib); | ||
471 | return -1; | ||
472 | } | ||
473 | len = strlen(arg); | ||
474 | if (strcasecmp(attrib, "host") == 0) { | ||
475 | if (match_hostname(host, arg, len) != 1) | ||
476 | result = 0; | ||
477 | else | ||
478 | debug("%.200s line %d: matched 'Host %.100s' ", | ||
479 | filename, linenum, host); | ||
480 | } else if (strcasecmp(attrib, "originalhost") == 0) { | ||
481 | if (match_hostname(host_arg, arg, len) != 1) | ||
482 | result = 0; | ||
483 | else | ||
484 | debug("%.200s line %d: matched " | ||
485 | "'OriginalHost %.100s' ", | ||
486 | filename, linenum, host_arg); | ||
487 | } else if (strcasecmp(attrib, "user") == 0) { | ||
488 | if (match_pattern_list(ruser, arg, len, 0) != 1) | ||
489 | result = 0; | ||
490 | else | ||
491 | debug("%.200s line %d: matched 'User %.100s' ", | ||
492 | filename, linenum, ruser); | ||
493 | } else if (strcasecmp(attrib, "localuser") == 0) { | ||
494 | if (match_pattern_list(pw->pw_name, arg, len, 0) != 1) | ||
495 | result = 0; | ||
496 | else | ||
497 | debug("%.200s line %d: matched " | ||
498 | "'LocalUser %.100s' ", | ||
499 | filename, linenum, pw->pw_name); | ||
500 | } else if (strcasecmp(attrib, "command") == 0) { | ||
501 | if (gethostname(thishost, sizeof(thishost)) == -1) | ||
502 | fatal("gethostname: %s", strerror(errno)); | ||
503 | strlcpy(shorthost, thishost, sizeof(shorthost)); | ||
504 | shorthost[strcspn(thishost, ".")] = '\0'; | ||
505 | snprintf(portstr, sizeof(portstr), "%d", port); | ||
506 | |||
507 | cmd = percent_expand(arg, | ||
508 | "L", shorthost, | ||
509 | "d", pw->pw_dir, | ||
510 | "h", host, | ||
511 | "l", thishost, | ||
512 | "n", host_arg, | ||
513 | "p", portstr, | ||
514 | "r", ruser, | ||
515 | "u", pw->pw_name, | ||
516 | (char *)NULL); | ||
517 | r = execute_in_shell(cmd); | ||
518 | if (r == -1) { | ||
519 | fatal("%.200s line %d: match command '%.100s' " | ||
520 | "error", filename, linenum, cmd); | ||
521 | } else if (r == 0) { | ||
522 | debug("%.200s line %d: matched " | ||
523 | "'Command \"%.100s\"' ", | ||
524 | filename, linenum, cmd); | ||
525 | } else | ||
526 | result = 0; | ||
527 | free(cmd); | ||
528 | } else { | ||
529 | error("Unsupported Match attribute %s", attrib); | ||
530 | return -1; | ||
531 | } | ||
532 | } | ||
533 | debug3("match %sfound", result ? "" : "not "); | ||
534 | *condition = cp; | ||
535 | return result; | ||
536 | } | ||
537 | |||
538 | /* | ||
539 | * Returns the number of the token pointed to by cp or oBadOption. | ||
540 | */ | ||
356 | static OpCodes | 541 | static OpCodes |
357 | parse_token(const char *cp, const char *filename, int linenum, | 542 | parse_token(const char *cp, const char *filename, int linenum, |
358 | const char *ignored_unknown) | 543 | const char *ignored_unknown) |
@@ -375,21 +560,24 @@ parse_token(const char *cp, const char *filename, int linenum, | |||
375 | * only sets those values that have not already been set. | 560 | * only sets those values that have not already been set. |
376 | */ | 561 | */ |
377 | #define WHITESPACE " \t\r\n" | 562 | #define WHITESPACE " \t\r\n" |
378 | |||
379 | int | 563 | int |
380 | process_config_line(Options *options, const char *host, | 564 | process_config_line(Options *options, struct passwd *pw, const char *host, |
381 | char *line, const char *filename, int linenum, | 565 | char *line, const char *filename, int linenum, int *activep, int userconfig) |
382 | int *activep, int userconfig) | ||
383 | { | 566 | { |
384 | char *s, **charptr, *endofnumber, *keyword, *arg, *arg2; | 567 | char *s, **charptr, *endofnumber, *keyword, *arg, *arg2; |
385 | char **cpptr, fwdarg[256]; | 568 | char **cpptr, fwdarg[256]; |
386 | u_int i, *uintptr, max_entries = 0; | 569 | u_int i, *uintptr, max_entries = 0; |
387 | int negated, opcode, *intptr, value, value2; | 570 | int negated, opcode, *intptr, value, value2, cmdline = 0; |
388 | LogLevel *log_level_ptr; | 571 | LogLevel *log_level_ptr; |
389 | long long val64; | 572 | long long val64; |
390 | size_t len; | 573 | size_t len; |
391 | Forward fwd; | 574 | Forward fwd; |
392 | 575 | ||
576 | if (activep == NULL) { /* We are processing a command line directive */ | ||
577 | cmdline = 1; | ||
578 | activep = &cmdline; | ||
579 | } | ||
580 | |||
393 | /* Strip trailing whitespace */ | 581 | /* Strip trailing whitespace */ |
394 | for (len = strlen(line) - 1; len > 0; len--) { | 582 | for (len = strlen(line) - 1; len > 0; len--) { |
395 | if (strchr(WHITESPACE, line[len]) == NULL) | 583 | if (strchr(WHITESPACE, line[len]) == NULL) |
@@ -828,6 +1016,9 @@ parse_int: | |||
828 | goto parse_flag; | 1016 | goto parse_flag; |
829 | 1017 | ||
830 | case oHost: | 1018 | case oHost: |
1019 | if (cmdline) | ||
1020 | fatal("Host directive not supported as a command-line " | ||
1021 | "option"); | ||
831 | *activep = 0; | 1022 | *activep = 0; |
832 | arg2 = NULL; | 1023 | arg2 = NULL; |
833 | while ((arg = strdelim(&s)) != NULL && *arg != '\0') { | 1024 | while ((arg = strdelim(&s)) != NULL && *arg != '\0') { |
@@ -854,6 +1045,18 @@ parse_int: | |||
854 | /* Avoid garbage check below, as strdelim is done. */ | 1045 | /* Avoid garbage check below, as strdelim is done. */ |
855 | return 0; | 1046 | return 0; |
856 | 1047 | ||
1048 | case oMatch: | ||
1049 | if (cmdline) | ||
1050 | fatal("Host directive not supported as a command-line " | ||
1051 | "option"); | ||
1052 | value = match_cfg_line(options, &s, pw, host, | ||
1053 | filename, linenum); | ||
1054 | if (value < 0) | ||
1055 | fatal("%.200s line %d: Bad Match condition", filename, | ||
1056 | linenum); | ||
1057 | *activep = value; | ||
1058 | break; | ||
1059 | |||
857 | case oEscapeChar: | 1060 | case oEscapeChar: |
858 | intptr = &options->escape_char; | 1061 | intptr = &options->escape_char; |
859 | arg = strdelim(&s); | 1062 | arg = strdelim(&s); |
@@ -1107,8 +1310,8 @@ parse_int: | |||
1107 | */ | 1310 | */ |
1108 | 1311 | ||
1109 | int | 1312 | int |
1110 | read_config_file(const char *filename, const char *host, Options *options, | 1313 | read_config_file(const char *filename, struct passwd *pw, const char *host, |
1111 | int flags) | 1314 | Options *options, int flags) |
1112 | { | 1315 | { |
1113 | FILE *f; | 1316 | FILE *f; |
1114 | char line[1024]; | 1317 | char line[1024]; |
@@ -1139,8 +1342,8 @@ read_config_file(const char *filename, const char *host, Options *options, | |||
1139 | while (fgets(line, sizeof(line), f)) { | 1342 | while (fgets(line, sizeof(line), f)) { |
1140 | /* Update line number counter. */ | 1343 | /* Update line number counter. */ |
1141 | linenum++; | 1344 | linenum++; |
1142 | if (process_config_line(options, host, line, filename, linenum, | 1345 | if (process_config_line(options, pw, host, line, filename, |
1143 | &active, flags & SSHCONF_USERCONF) != 0) | 1346 | linenum, &active, flags & SSHCONF_USERCONF) != 0) |
1144 | bad_options++; | 1347 | bad_options++; |
1145 | } | 1348 | } |
1146 | fclose(f); | 1349 | fclose(f); |
diff --git a/readconf.h b/readconf.h index ca4a042ad..cde8b5242 100644 --- a/readconf.h +++ b/readconf.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: readconf.h,v 1.96 2013/08/20 00:11:38 djm Exp $ */ | 1 | /* $OpenBSD: readconf.h,v 1.97 2013/10/14 22:22:03 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -159,12 +159,12 @@ typedef struct { | |||
159 | 159 | ||
160 | void initialize_options(Options *); | 160 | void initialize_options(Options *); |
161 | void fill_default_options(Options *); | 161 | void fill_default_options(Options *); |
162 | int read_config_file(const char *, const char *, Options *, int); | 162 | int process_config_line(Options *, struct passwd *, const char *, char *, |
163 | const char *, int, int *, int); | ||
164 | int read_config_file(const char *, struct passwd *, const char *, | ||
165 | Options *, int); | ||
163 | int parse_forward(Forward *, const char *, int, int); | 166 | int parse_forward(Forward *, const char *, int, int); |
164 | 167 | int default_ssh_port(void); | |
165 | int | ||
166 | process_config_line(Options *, const char *, char *, const char *, int, int *, | ||
167 | int); | ||
168 | 168 | ||
169 | void add_local_forward(Options *, const Forward *); | 169 | void add_local_forward(Options *, const Forward *); |
170 | void add_remote_forward(Options *, const Forward *); | 170 | void add_remote_forward(Options *, const Forward *); |
diff --git a/ssh-keysign.c b/ssh-keysign.c index 9a6653c7c..b67ed1ead 100644 --- a/ssh-keysign.c +++ b/ssh-keysign.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-keysign.c,v 1.37 2013/05/17 00:13:14 djm Exp $ */ | 1 | /* $OpenBSD: ssh-keysign.c,v 1.38 2013/10/14 22:22:04 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2002 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2002 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -187,7 +187,7 @@ main(int argc, char **argv) | |||
187 | 187 | ||
188 | /* verify that ssh-keysign is enabled by the admin */ | 188 | /* verify that ssh-keysign is enabled by the admin */ |
189 | initialize_options(&options); | 189 | initialize_options(&options); |
190 | (void)read_config_file(_PATH_HOST_CONFIG_FILE, "", &options, 0); | 190 | (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, "", &options, 0); |
191 | fill_default_options(&options); | 191 | fill_default_options(&options); |
192 | if (options.enable_ssh_keysign != 1) | 192 | if (options.enable_ssh_keysign != 1) |
193 | fatal("ssh-keysign not enabled in %s", | 193 | fatal("ssh-keysign not enabled in %s", |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh.c,v 1.381 2013/07/25 00:29:10 djm Exp $ */ | 1 | /* $OpenBSD: ssh.c,v 1.382 2013/10/14 22:22:04 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -242,7 +242,7 @@ main(int ac, char **av) | |||
242 | char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; | 242 | char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; |
243 | struct stat st; | 243 | struct stat st; |
244 | struct passwd *pw; | 244 | struct passwd *pw; |
245 | int dummy, timeout_ms; | 245 | int timeout_ms; |
246 | extern int optind, optreset; | 246 | extern int optind, optreset; |
247 | extern char *optarg; | 247 | extern char *optarg; |
248 | 248 | ||
@@ -595,10 +595,9 @@ main(int ac, char **av) | |||
595 | options.request_tty = REQUEST_TTY_NO; | 595 | options.request_tty = REQUEST_TTY_NO; |
596 | break; | 596 | break; |
597 | case 'o': | 597 | case 'o': |
598 | dummy = 1; | ||
599 | line = xstrdup(optarg); | 598 | line = xstrdup(optarg); |
600 | if (process_config_line(&options, host ? host : "", | 599 | if (process_config_line(&options, pw, host ? host : "", |
601 | line, "command-line", 0, &dummy, SSHCONF_USERCONF) | 600 | line, "command-line", 0, NULL, SSHCONF_USERCONF) |
602 | != 0) | 601 | != 0) |
603 | exit(255); | 602 | exit(255); |
604 | free(line); | 603 | free(line); |
@@ -703,18 +702,19 @@ main(int ac, char **av) | |||
703 | */ | 702 | */ |
704 | if (config != NULL) { | 703 | if (config != NULL) { |
705 | if (strcasecmp(config, "none") != 0 && | 704 | if (strcasecmp(config, "none") != 0 && |
706 | !read_config_file(config, host, &options, SSHCONF_USERCONF)) | 705 | !read_config_file(config, pw, host, &options, |
706 | SSHCONF_USERCONF)) | ||
707 | fatal("Can't open user config file %.100s: " | 707 | fatal("Can't open user config file %.100s: " |
708 | "%.100s", config, strerror(errno)); | 708 | "%.100s", config, strerror(errno)); |
709 | } else { | 709 | } else { |
710 | r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, | 710 | r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, |
711 | _PATH_SSH_USER_CONFFILE); | 711 | _PATH_SSH_USER_CONFFILE); |
712 | if (r > 0 && (size_t)r < sizeof(buf)) | 712 | if (r > 0 && (size_t)r < sizeof(buf)) |
713 | (void)read_config_file(buf, host, &options, | 713 | (void)read_config_file(buf, pw, host, &options, |
714 | SSHCONF_CHECKPERM|SSHCONF_USERCONF); | 714 | SSHCONF_CHECKPERM|SSHCONF_USERCONF); |
715 | 715 | ||
716 | /* Read systemwide configuration file after user config. */ | 716 | /* Read systemwide configuration file after user config. */ |
717 | (void)read_config_file(_PATH_HOST_CONFIG_FILE, host, | 717 | (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, host, |
718 | &options, 0); | 718 | &options, 0); |
719 | } | 719 | } |
720 | 720 | ||
@@ -752,10 +752,8 @@ main(int ac, char **av) | |||
752 | options.user = xstrdup(pw->pw_name); | 752 | options.user = xstrdup(pw->pw_name); |
753 | 753 | ||
754 | /* Get default port if port has not been set. */ | 754 | /* Get default port if port has not been set. */ |
755 | if (options.port == 0) { | 755 | if (options.port == 0) |
756 | sp = getservbyname(SSH_SERVICE_NAME, "tcp"); | 756 | options.port = default_ssh_port(); |
757 | options.port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT; | ||
758 | } | ||
759 | 757 | ||
760 | /* preserve host name given on command line for %n expansion */ | 758 | /* preserve host name given on command line for %n expansion */ |
761 | host_arg = host; | 759 | host_arg = host; |
diff --git a/ssh_config.5 b/ssh_config.5 index 9ddd6b8a6..f35f468f4 100644 --- a/ssh_config.5 +++ b/ssh_config.5 | |||
@@ -33,8 +33,8 @@ | |||
33 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 33 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
34 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 34 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
35 | .\" | 35 | .\" |
36 | .\" $OpenBSD: ssh_config.5,v 1.168 2013/08/20 06:56:07 jmc Exp $ | 36 | .\" $OpenBSD: ssh_config.5,v 1.169 2013/10/14 22:22:05 djm Exp $ |
37 | .Dd $Mdocdate: August 20 2013 $ | 37 | .Dd $Mdocdate: October 14 2013 $ |
38 | .Dt SSH_CONFIG 5 | 38 | .Dt SSH_CONFIG 5 |
39 | .Os | 39 | .Os |
40 | .Sh NAME | 40 | .Sh NAME |
@@ -100,6 +100,8 @@ keywords are case-insensitive and arguments are case-sensitive): | |||
100 | .It Cm Host | 100 | .It Cm Host |
101 | Restricts the following declarations (up to the next | 101 | Restricts the following declarations (up to the next |
102 | .Cm Host | 102 | .Cm Host |
103 | or | ||
104 | .Cm Match | ||
103 | keyword) to be only for those hosts that match one of the patterns | 105 | keyword) to be only for those hosts that match one of the patterns |
104 | given after the keyword. | 106 | given after the keyword. |
105 | If more than one pattern is provided, they should be separated by whitespace. | 107 | If more than one pattern is provided, they should be separated by whitespace. |
@@ -124,6 +126,52 @@ matches. | |||
124 | See | 126 | See |
125 | .Sx PATTERNS | 127 | .Sx PATTERNS |
126 | for more information on patterns. | 128 | for more information on patterns. |
129 | .It Cm Match | ||
130 | Restricts the following declarations (up to the next | ||
131 | .Cm Host | ||
132 | or | ||
133 | .Cm Match | ||
134 | keyword) to be used only when the conditions following the | ||
135 | .Cm Match | ||
136 | keyword are satisfied. | ||
137 | Match conditions are specified using one or more keyword/criteria pairs. | ||
138 | The available keywords are: | ||
139 | .Cm command , | ||
140 | .Cm host , | ||
141 | .Cm originalhost , | ||
142 | .Cm user , | ||
143 | and | ||
144 | .Cm localuser . | ||
145 | .Pp | ||
146 | The criteria for the | ||
147 | .Cm command | ||
148 | keyword is a path to a command that is executed. | ||
149 | If the command returns a zero exit status then the condition is considered true. | ||
150 | Commands containing whitespace characters must be quoted. | ||
151 | .Pp | ||
152 | The other keywords' criteria must be single entries or comma-separated | ||
153 | lists and may use the wildcard and negation operators described in the | ||
154 | .Sx PATTERNS | ||
155 | section. | ||
156 | The criteria for the | ||
157 | .Cm host | ||
158 | keyword are matched against the target hostname, after any substitution | ||
159 | by the | ||
160 | .Cm Hostname | ||
161 | option. | ||
162 | The | ||
163 | .Cm originalhost | ||
164 | keyword matches against the hostname as it was specified on the command-line. | ||
165 | The | ||
166 | .Cm user | ||
167 | keyword matches against the target username on the remote host. | ||
168 | The | ||
169 | .Cm localuser | ||
170 | keyword matches against the name of the local user running | ||
171 | .Xr ssh 1 | ||
172 | (this keyword may be useful in system-wide | ||
173 | .Nm | ||
174 | files). | ||
127 | .It Cm AddressFamily | 175 | .It Cm AddressFamily |
128 | Specifies which address family to use when connecting. | 176 | Specifies which address family to use when connecting. |
129 | Valid arguments are | 177 | Valid arguments are |