From 3702396526a2569402696ff7d7c6d0fe2e5a447b Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Tue, 11 Jul 2000 17:31:38 +1000 Subject: [PATCH] - (djm) OpenBSD CVS updates: - markus@cvs.openbsd.org 2000/06/26 03:22:29 [authfd.c] cleanup, less cut&paste - markus@cvs.openbsd.org 2000/06/26 15:59:19 [servconf.c servconf.h session.c sshd.8 sshd.c] MaxStartups: limit number of unauthenticated connections, work by theo and me - deraadt@cvs.openbsd.org 2000/07/05 14:18:07 [session.c] use no_x11_forwarding_flag correctly; provos ok - provos@cvs.openbsd.org 2000/07/05 15:35:57 [sshd.c] typo - aaron@cvs.openbsd.org 2000/07/05 22:06:58 [scp.1 ssh-agent.1 ssh-keygen.1 sshd.8] Insert more missing .El directives. Our troff really should identify these and spit out a warning. - todd@cvs.openbsd.org 2000/07/06 21:55:04 [auth-rsa.c auth2.c ssh-keygen.c] clean code is good code - deraadt@cvs.openbsd.org 2000/07/07 02:14:29 [serverloop.c] sense of port forwarding flag test was backwards - provos@cvs.openbsd.org 2000/07/08 17:17:31 [compat.c readconf.c] replace strtok with strsep; from David Young - deraadt@cvs.openbsd.org 2000/07/08 19:21:15 [auth.h] KNF - ho@cvs.openbsd.org 2000/07/08 19:27:33 [compat.c readconf.c] Better conditions for strsep() ending. - ho@cvs.openbsd.org 2000/07/10 10:27:05 [readconf.c] Get the correct message on errors. (niels@ ok) - ho@cvs.openbsd.org 2000/07/10 10:30:25 [cipher.c kex.c servconf.c] strtok() --> strsep(). (niels@ ok) --- ChangeLog | 39 ++++++++++++ auth-rsa.c | 6 +- auth.h | 2 +- auth2.c | 4 +- authfd.c | 142 +++++++++--------------------------------- cipher.c | 9 +-- compat.c | 8 +-- kex.c | 14 +++-- readconf.c | 152 ++++++++++++++++++++++---------------------- scp.1 | 3 +- servconf.c | 137 +++++++++++++++++++++------------------- servconf.h | 5 +- serverloop.c | 2 +- session.c | 15 +++-- ssh-agent.1 | 3 +- ssh-keygen.1 | 3 +- ssh-keygen.c | 6 +- sshd.8 | 11 +++- sshd.c | 173 ++++++++++++++++++++++++++++++++++----------------- 19 files changed, 392 insertions(+), 342 deletions(-) diff --git a/ChangeLog b/ChangeLog index b73255a21..8481359a7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,6 +10,45 @@ to compile on more platforms (incl NeXT). - (djm) Added bsd-inet_aton and configure support for NeXT - (djm) Misc NeXT fixes from Ben Lindstrom + - (djm) OpenBSD CVS updates: + - markus@cvs.openbsd.org 2000/06/26 03:22:29 + [authfd.c] + cleanup, less cut&paste + - markus@cvs.openbsd.org 2000/06/26 15:59:19 + [servconf.c servconf.h session.c sshd.8 sshd.c] + MaxStartups: limit number of unauthenticated connections, work by + theo and me + - deraadt@cvs.openbsd.org 2000/07/05 14:18:07 + [session.c] + use no_x11_forwarding_flag correctly; provos ok + - provos@cvs.openbsd.org 2000/07/05 15:35:57 + [sshd.c] + typo + - aaron@cvs.openbsd.org 2000/07/05 22:06:58 + [scp.1 ssh-agent.1 ssh-keygen.1 sshd.8] + Insert more missing .El directives. Our troff really should identify + these and spit out a warning. + - todd@cvs.openbsd.org 2000/07/06 21:55:04 + [auth-rsa.c auth2.c ssh-keygen.c] + clean code is good code + - deraadt@cvs.openbsd.org 2000/07/07 02:14:29 + [serverloop.c] + sense of port forwarding flag test was backwards + - provos@cvs.openbsd.org 2000/07/08 17:17:31 + [compat.c readconf.c] + replace strtok with strsep; from David Young + - deraadt@cvs.openbsd.org 2000/07/08 19:21:15 + [auth.h] + KNF + - ho@cvs.openbsd.org 2000/07/08 19:27:33 + [compat.c readconf.c] + Better conditions for strsep() ending. + - ho@cvs.openbsd.org 2000/07/10 10:27:05 + [readconf.c] + Get the correct message on errors. (niels@ ok) + - ho@cvs.openbsd.org 2000/07/10 10:30:25 + [cipher.c kex.c servconf.c] + strtok() --> strsep(). (niels@ ok) 20000709 - (djm) Only enable PAM_TTY kludge for Linux. Problem report from diff --git a/auth-rsa.c b/auth-rsa.c index 1a246f7f2..65f9bf757 100644 --- a/auth-rsa.c +++ b/auth-rsa.c @@ -16,7 +16,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth-rsa.c,v 1.26 2000/06/20 01:39:38 markus Exp $"); +RCSID("$OpenBSD: auth-rsa.c,v 1.27 2000/07/07 03:55:03 todd Exp $"); #include "rsa.h" #include "packet.h" @@ -179,8 +179,8 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n) } if (fail) { fclose(f); - log(buf); - packet_send_debug(buf); + log("%s",buf); + packet_send_debug("%s",buf); restore_uid(); return 0; } diff --git a/auth.h b/auth.h index 72126e099..61b1f2c5c 100644 --- a/auth.h +++ b/auth.h @@ -7,7 +7,7 @@ void do_authentication2(void); struct passwd * auth_get_user(void); -int allowed_user(struct passwd * pw);; +int allowed_user(struct passwd * pw); #define AUTH_FAIL_MAX 6 #define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2) diff --git a/auth2.c b/auth2.c index f20953a86..4926ff8a0 100644 --- a/auth2.c +++ b/auth2.c @@ -27,7 +27,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" -RCSID("$OpenBSD: auth2.c,v 1.11 2000/06/19 00:50:11 markus Exp $"); +RCSID("$OpenBSD: auth2.c,v 1.12 2000/07/07 03:55:03 todd Exp $"); #include #include @@ -489,8 +489,8 @@ user_dsa_key_allowed(struct passwd *pw, Key *key) } } if (fail) { - log(buf); fclose(f); + log("%s",buf); restore_uid(); return 0; } diff --git a/authfd.c b/authfd.c index 69d77d7dd..69fe2ae41 100644 --- a/authfd.c +++ b/authfd.c @@ -14,7 +14,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: authfd.c,v 1.20 2000/06/20 01:39:38 markus Exp $"); +RCSID("$OpenBSD: authfd.c,v 1.21 2000/06/26 09:22:29 markus Exp $"); #include "ssh.h" #include "rsa.h" @@ -26,6 +26,9 @@ RCSID("$OpenBSD: authfd.c,v 1.20 2000/06/20 01:39:38 markus Exp $"); #include +/* helper */ +int ssh_agent_get_reply(AuthenticationConnection *auth); + /* Returns the number of the authentication fd, or -1 if there is none. */ int @@ -344,7 +347,7 @@ ssh_add_identity(AuthenticationConnection *auth, { Buffer buffer; unsigned char buf[8192]; - int len, l, type; + int len; /* Format a message to the agent. */ buffer_init(&buffer); @@ -368,57 +371,11 @@ ssh_add_identity(AuthenticationConnection *auth, atomicio(write, auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) != buffer_len(&buffer)) { error("Error writing to authentication socket."); -error_cleanup: buffer_free(&buffer); return 0; } - /* Wait for response from the agent. First read the length of the - response packet. */ - len = 4; - while (len > 0) { - l = read(auth->fd, buf + 4 - len, len); - if (l <= 0) { - error("Error reading response length from authentication socket."); - goto error_cleanup; - } - len -= l; - } - - /* Extract the length, and check it for sanity. */ - len = GET_32BIT(buf); - if (len > 256 * 1024) - fatal("Add identity response too long: %d", len); - - /* Read the rest of the response in tothe buffer. */ - buffer_clear(&buffer); - while (len > 0) { - l = len; - if (l > sizeof(buf)) - l = sizeof(buf); - l = read(auth->fd, buf, l); - if (l <= 0) { - error("Error reading response from authentication socket."); - goto error_cleanup; - } - buffer_append(&buffer, (char *) buf, l); - len -= l; - } - - /* Get the type of the packet. */ - type = buffer_get_char(&buffer); - switch (type) { - case SSH_AGENT_FAILURE: - buffer_free(&buffer); - return 0; - case SSH_AGENT_SUCCESS: - buffer_free(&buffer); - return 1; - default: - fatal("Bad response to add identity from authentication agent: %d", - type); - } - /* NOTREACHED */ - return 0; + buffer_free(&buffer); + return ssh_agent_get_reply(auth); } /* @@ -430,8 +387,8 @@ int ssh_remove_identity(AuthenticationConnection *auth, RSA *key) { Buffer buffer; - unsigned char buf[8192]; - int len, l, type; + unsigned char buf[5]; + int len; /* Format a message to the agent. */ buffer_init(&buffer); @@ -449,59 +406,11 @@ ssh_remove_identity(AuthenticationConnection *auth, RSA *key) atomicio(write, auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) != buffer_len(&buffer)) { error("Error writing to authentication socket."); -error_cleanup: buffer_free(&buffer); return 0; } - /* - * Wait for response from the agent. First read the length of the - * response packet. - */ - len = 4; - while (len > 0) { - l = read(auth->fd, buf + 4 - len, len); - if (l <= 0) { - error("Error reading response length from authentication socket."); - goto error_cleanup; - } - len -= l; - } - - /* Extract the length, and check it for sanity. */ - len = GET_32BIT(buf); - if (len > 256 * 1024) - fatal("Remove identity response too long: %d", len); - - /* Read the rest of the response in tothe buffer. */ - buffer_clear(&buffer); - while (len > 0) { - l = len; - if (l > sizeof(buf)) - l = sizeof(buf); - l = read(auth->fd, buf, l); - if (l <= 0) { - error("Error reading response from authentication socket."); - goto error_cleanup; - } - buffer_append(&buffer, (char *) buf, l); - len -= l; - } - - /* Get the type of the packet. */ - type = buffer_get_char(&buffer); - switch (type) { - case SSH_AGENT_FAILURE: - buffer_free(&buffer); - return 0; - case SSH_AGENT_SUCCESS: - buffer_free(&buffer); - return 1; - default: - fatal("Bad response to remove identity from authentication agent: %d", - type); - } - /* NOTREACHED */ - return 0; + buffer_free(&buffer); + return ssh_agent_get_reply(auth); } /* @@ -512,9 +421,7 @@ error_cleanup: int ssh_remove_all_identities(AuthenticationConnection *auth) { - Buffer buffer; - unsigned char buf[8192]; - int len, l, type; + unsigned char buf[5]; /* Get the length of the message, and format it in the buffer. */ PUT_32BIT(buf, 1); @@ -525,6 +432,20 @@ ssh_remove_all_identities(AuthenticationConnection *auth) error("Error writing to authentication socket."); return 0; } + return ssh_agent_get_reply(auth); +} + +/* + * Read for reply from agent. returns 1 for success, 0 on error + */ + +int +ssh_agent_get_reply(AuthenticationConnection *auth) +{ + Buffer buffer; + unsigned char buf[8192]; + int len, l, type; + /* * Wait for response from the agent. First read the length of the * response packet. @@ -534,6 +455,7 @@ ssh_remove_all_identities(AuthenticationConnection *auth) l = read(auth->fd, buf + 4 - len, len); if (l <= 0) { error("Error reading response length from authentication socket."); + buffer_free(&buffer); return 0; } len -= l; @@ -542,9 +464,9 @@ ssh_remove_all_identities(AuthenticationConnection *auth) /* Extract the length, and check it for sanity. */ len = GET_32BIT(buf); if (len > 256 * 1024) - fatal("Remove identity response too long: %d", len); + fatal("Response from agent too long: %d", len); - /* Read the rest of the response into the buffer. */ + /* Read the rest of the response in to the buffer. */ buffer_init(&buffer); while (len > 0) { l = len; @@ -562,16 +484,14 @@ ssh_remove_all_identities(AuthenticationConnection *auth) /* Get the type of the packet. */ type = buffer_get_char(&buffer); + buffer_free(&buffer); switch (type) { case SSH_AGENT_FAILURE: - buffer_free(&buffer); return 0; case SSH_AGENT_SUCCESS: - buffer_free(&buffer); return 1; default: - fatal("Bad response to remove identity from authentication agent: %d", - type); + fatal("Bad response from authentication agent: %d", type); } /* NOTREACHED */ return 0; diff --git a/cipher.c b/cipher.c index 97cbd38ca..a44e51d98 100644 --- a/cipher.c +++ b/cipher.c @@ -12,7 +12,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: cipher.c,v 1.28 2000/06/20 01:39:40 markus Exp $"); +RCSID("$OpenBSD: cipher.c,v 1.29 2000/07/10 16:30:25 ho Exp $"); #include "ssh.h" #include "cipher.h" @@ -174,14 +174,15 @@ cipher_name(int cipher) int ciphers_valid(const char *names) { - char *ciphers; + char *ciphers, *cp; char *p; int i; if (names == NULL || strcmp(names, "") == 0) return 0; - ciphers = xstrdup(names); - for ((p = strtok(ciphers, CIPHER_SEP)); p; (p = strtok(NULL, CIPHER_SEP))) { + ciphers = cp = xstrdup(names); + for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0'; + (p = strsep(&cp, CIPHER_SEP))) { i = cipher_number(p); if (i == -1 || !(cipher_mask2() & (1 << i))) { xfree(ciphers); diff --git a/compat.c b/compat.c index e3410d497..595a0a378 100644 --- a/compat.c +++ b/compat.c @@ -28,7 +28,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: compat.c,v 1.17 2000/06/20 01:39:40 markus Exp $"); +RCSID("$OpenBSD: compat.c,v 1.19 2000/07/09 01:27:32 ho Exp $"); #include "ssh.h" #include "packet.h" @@ -81,13 +81,13 @@ compat_datafellows(const char *version) int proto_spec(const char *spec) { - char *s, *p; + char *s, *p, *q; int ret = SSH_PROTO_UNKNOWN; if (spec == NULL) return ret; - s = xstrdup(spec); - for ((p = strtok(s, SEP)); p; (p = strtok(NULL, SEP))) { + q = s = xstrdup(spec); + for ((p = strsep(&q, SEP)); p && *p != '\0'; (p = strsep(&q, SEP))) { switch(atoi(p)) { case 1: if (ret == SSH_PROTO_UNKNOWN) diff --git a/kex.c b/kex.c index b0d47b5b1..b488090b4 100644 --- a/kex.c +++ b/kex.c @@ -28,7 +28,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: kex.c,v 1.8 2000/06/20 01:39:41 markus Exp $"); +RCSID("$OpenBSD: kex.c,v 1.9 2000/07/10 16:30:25 ho Exp $"); #include "ssh.h" #include "ssh2.h" @@ -287,13 +287,14 @@ char * get_match(char *client, char *server) { char *sproposals[MAX_PROP]; - char *c, *s, *p, *ret; + char *c, *s, *p, *ret, *cp, *sp; int i, j, nproposals; - c = xstrdup(client); - s = xstrdup(server); + c = cp = xstrdup(client); + s = sp = xstrdup(server); - for ((p = strtok(s, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) { + for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0'; + (p = strsep(&sp, SEP)), i++) { if (i < MAX_PROP) sproposals[i] = p; else @@ -301,7 +302,8 @@ get_match(char *client, char *server) } nproposals = i; - for ((p = strtok(c, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) { + for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0'; + (p = strsep(&cp, SEP)), i++) { for (j = 0; j < nproposals; j++) { if (strcmp(p, sproposals[j]) == 0) { ret = xstrdup(p); diff --git a/readconf.c b/readconf.c index 6d015a202..28aa0a8b8 100644 --- a/readconf.c +++ b/readconf.c @@ -14,7 +14,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: readconf.c,v 1.37 2000/06/20 01:39:43 markus Exp $"); +RCSID("$OpenBSD: readconf.c,v 1.40 2000/07/10 16:27:05 ho Exp $"); #include "ssh.h" #include "cipher.h" @@ -164,7 +164,7 @@ static struct { { NULL, 0 } }; -/* Characters considered whitespace in strtok calls. */ +/* Characters considered whitespace in strsep calls. */ #define WHITESPACE " \t\r\n=" @@ -237,18 +237,18 @@ process_config_line(Options *options, const char *host, char *line, const char *filename, int linenum, int *activep) { - char buf[256], *cp, *string, **charptr, *cp2; + char buf[256], *s, *string, **charptr, *endofnumber, *keyword, *arg; int opcode, *intptr, value; u_short fwd_port, fwd_host_port; /* Skip leading whitespace. */ - cp = line + strspn(line, WHITESPACE); - if (!*cp || *cp == '\n' || *cp == '#') + s = line + strspn(line, WHITESPACE); + if (!*s || *s == '\n' || *s == '#') return 0; /* Get the keyword. (Each line is supposed to begin with a keyword). */ - cp = strtok(cp, WHITESPACE); - opcode = parse_token(cp, filename, linenum); + keyword = strsep(&s, WHITESPACE); + opcode = parse_token(keyword, filename, linenum); switch (opcode) { case oBadOption: @@ -258,13 +258,13 @@ process_config_line(Options *options, const char *host, case oForwardAgent: intptr = &options->forward_agent; parse_flag: - cp = strtok(NULL, WHITESPACE); - if (!cp) + arg = strsep(&s, WHITESPACE); + if (!arg || *arg == '\0') fatal("%.200s line %d: Missing yes/no argument.", filename, linenum); value = 0; /* To avoid compiler warning... */ - if (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0) + if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) value = 1; - else if (strcmp(cp, "no") == 0 || strcmp(cp, "false") == 0) + else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) value = 0; else fatal("%.200s line %d: Bad yes/no argument.", filename, linenum); @@ -344,16 +344,16 @@ parse_flag: case oStrictHostKeyChecking: intptr = &options->strict_host_key_checking; - cp = strtok(NULL, WHITESPACE); - if (!cp) + arg = strsep(&s, WHITESPACE); + if (!arg || *arg == '\0') fatal("%.200s line %d: Missing yes/no argument.", filename, linenum); value = 0; /* To avoid compiler warning... */ - if (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0) + if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) value = 1; - else if (strcmp(cp, "no") == 0 || strcmp(cp, "false") == 0) + else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) value = 0; - else if (strcmp(cp, "ask") == 0) + else if (strcmp(arg, "ask") == 0) value = 2; else fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum); @@ -379,8 +379,8 @@ parse_flag: case oIdentityFile: case oIdentityFile2: - cp = strtok(NULL, WHITESPACE); - if (!cp) + arg = strsep(&s, WHITESPACE); + if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); if (*activep) { intptr = (opcode == oIdentityFile) ? @@ -392,7 +392,7 @@ parse_flag: charptr = (opcode == oIdentityFile) ? &options->identity_files[*intptr] : &options->identity_files2[*intptr]; - *charptr = xstrdup(cp); + *charptr = xstrdup(arg); *intptr = *intptr + 1; } break; @@ -404,11 +404,11 @@ parse_flag: case oUser: charptr = &options->user; parse_string: - cp = strtok(NULL, WHITESPACE); - if (!cp) + arg = strsep(&s, WHITESPACE); + if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); if (*activep && *charptr == NULL) - *charptr = xstrdup(cp); + *charptr = xstrdup(arg); break; case oGlobalKnownHostsFile: @@ -434,10 +434,10 @@ parse_string: case oProxyCommand: charptr = &options->proxy_command; string = xstrdup(""); - while ((cp = strtok(NULL, WHITESPACE)) != NULL) { - string = xrealloc(string, strlen(string) + strlen(cp) + 2); + while ((arg = strsep(&s, WHITESPACE)) != NULL && *arg != '\0') { + string = xrealloc(string, strlen(string) + strlen(arg) + 2); strcat(string, " "); - strcat(string, cp); + strcat(string, arg); } if (*activep && *charptr == NULL) *charptr = string; @@ -448,15 +448,15 @@ parse_string: case oPort: intptr = &options->port; parse_int: - cp = strtok(NULL, WHITESPACE); - if (!cp) + arg = strsep(&s, WHITESPACE); + if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); - if (cp[0] < '0' || cp[0] > '9') + if (arg[0] < '0' || arg[0] > '9') fatal("%.200s line %d: Bad number.", filename, linenum); /* Octal, decimal, or hex format? */ - value = strtol(cp, &cp2, 0); - if (cp == cp2) + value = strtol(arg, &endofnumber, 0); + if (arg == endofnumber) fatal("%.200s line %d: Bad number.", filename, linenum); if (*activep && *intptr == -1) *intptr = value; @@ -468,65 +468,65 @@ parse_int: case oCipher: intptr = &options->cipher; - cp = strtok(NULL, WHITESPACE); - if (!cp) + arg = strsep(&s, WHITESPACE); + if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); - value = cipher_number(cp); + value = cipher_number(arg); if (value == -1) fatal("%.200s line %d: Bad cipher '%s'.", - filename, linenum, cp ? cp : ""); + filename, linenum, arg ? arg : ""); if (*activep && *intptr == -1) *intptr = value; break; case oCiphers: - cp = strtok(NULL, WHITESPACE); - if (!cp) + arg = strsep(&s, WHITESPACE); + if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); - if (!ciphers_valid(cp)) + if (!ciphers_valid(arg)) fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.", - filename, linenum, cp ? cp : ""); + filename, linenum, arg ? arg : ""); if (*activep && options->ciphers == NULL) - options->ciphers = xstrdup(cp); + options->ciphers = xstrdup(arg); break; case oProtocol: intptr = &options->protocol; - cp = strtok(NULL, WHITESPACE); - if (!cp) + arg = strsep(&s, WHITESPACE); + if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); - value = proto_spec(cp); + value = proto_spec(arg); if (value == SSH_PROTO_UNKNOWN) fatal("%.200s line %d: Bad protocol spec '%s'.", - filename, linenum, cp ? cp : ""); + filename, linenum, arg ? arg : ""); if (*activep && *intptr == SSH_PROTO_UNKNOWN) *intptr = value; break; case oLogLevel: intptr = (int *) &options->log_level; - cp = strtok(NULL, WHITESPACE); - value = log_level_number(cp); + arg = strsep(&s, WHITESPACE); + value = log_level_number(arg); if (value == (LogLevel) - 1) fatal("%.200s line %d: unsupported log level '%s'\n", - filename, linenum, cp ? cp : ""); + filename, linenum, arg ? arg : ""); if (*activep && (LogLevel) * intptr == -1) *intptr = (LogLevel) value; break; case oRemoteForward: - cp = strtok(NULL, WHITESPACE); - if (!cp) + arg = strsep(&s, WHITESPACE); + if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); - if (cp[0] < '0' || cp[0] > '9') + if (arg[0] < '0' || arg[0] > '9') fatal("%.200s line %d: Badly formatted port number.", filename, linenum); - fwd_port = atoi(cp); - cp = strtok(NULL, WHITESPACE); - if (!cp) + fwd_port = atoi(arg); + arg = strsep(&s, WHITESPACE); + if (!arg || *arg == '\0') fatal("%.200s line %d: Missing second argument.", filename, linenum); - if (sscanf(cp, "%255[^:]:%hu", buf, &fwd_host_port) != 2) + if (sscanf(arg, "%255[^:]:%hu", buf, &fwd_host_port) != 2) fatal("%.200s line %d: Badly formatted host:port.", filename, linenum); if (*activep) @@ -534,18 +534,18 @@ parse_int: break; case oLocalForward: - cp = strtok(NULL, WHITESPACE); - if (!cp) + arg = strsep(&s, WHITESPACE); + if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); - if (cp[0] < '0' || cp[0] > '9') + if (arg[0] < '0' || arg[0] > '9') fatal("%.200s line %d: Badly formatted port number.", filename, linenum); - fwd_port = atoi(cp); - cp = strtok(NULL, WHITESPACE); - if (!cp) + fwd_port = atoi(arg); + arg = strsep(&s, WHITESPACE); + if (!arg || *arg == '\0') fatal("%.200s line %d: Missing second argument.", filename, linenum); - if (sscanf(cp, "%255[^:]:%hu", buf, &fwd_host_port) != 2) + if (sscanf(arg, "%255[^:]:%hu", buf, &fwd_host_port) != 2) fatal("%.200s line %d: Badly formatted host:port.", filename, linenum); if (*activep) @@ -554,26 +554,26 @@ parse_int: case oHost: *activep = 0; - while ((cp = strtok(NULL, WHITESPACE)) != NULL) - if (match_pattern(host, cp)) { - debug("Applying options for %.100s", cp); + while ((arg = strsep(&s, WHITESPACE)) != NULL && *arg != '\0') + if (match_pattern(host, arg)) { + debug("Applying options for %.100s", arg); *activep = 1; break; } - /* Avoid garbage check below, as strtok already returned NULL. */ + /* Avoid garbage check below, as strsep is done. */ return 0; case oEscapeChar: intptr = &options->escape_char; - cp = strtok(NULL, WHITESPACE); - if (!cp) + arg = strsep(&s, WHITESPACE); + if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); - if (cp[0] == '^' && cp[2] == 0 && - (unsigned char) cp[1] >= 64 && (unsigned char) cp[1] < 128) - value = (unsigned char) cp[1] & 31; - else if (strlen(cp) == 1) - value = (unsigned char) cp[0]; - else if (strcmp(cp, "none") == 0) + if (arg[0] == '^' && arg[2] == 0 && + (unsigned char) arg[1] >= 64 && (unsigned char) arg[1] < 128) + value = (unsigned char) arg[1] & 31; + else if (strlen(arg) == 1) + value = (unsigned char) arg[0]; + else if (strcmp(arg, "none") == 0) value = -2; else { fatal("%.200s line %d: Bad escape character.", @@ -590,9 +590,11 @@ parse_int: } /* Check that there is no garbage at end of line. */ - if (strtok(NULL, WHITESPACE) != NULL) - fatal("%.200s line %d: garbage at end of line.", - filename, linenum); + if ((arg = strsep(&s, WHITESPACE)) != NULL && *arg != '\0') + { + fatal("%.200s line %d: garbage at end of line; \"%.200s\".", + filename, linenum, arg); + } return 0; } diff --git a/scp.1 b/scp.1 index c90943a06..d2fa546af 100644 --- a/scp.1 +++ b/scp.1 @@ -9,7 +9,7 @@ .\" .\" Created: Sun May 7 00:14:37 1995 ylo .\" -.\" $Id: scp.1,v 1.7 2000/04/13 02:26:37 damien Exp $ +.\" $Id: scp.1,v 1.8 2000/07/11 07:31:38 djm Exp $ .\" .Dd September 25, 1999 .Dt SCP 1 @@ -106,6 +106,7 @@ to use IPv4 addresses only. Forces .Nm to use IPv6 addresses only. +.El .Sh AUTHORS Timo Rinne and Tatu Ylonen .Sh HISTORY diff --git a/servconf.c b/servconf.c index 12cc15260..77ac84527 100644 --- a/servconf.c +++ b/servconf.c @@ -12,7 +12,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: servconf.c,v 1.45 2000/06/20 01:39:44 markus Exp $"); +RCSID("$OpenBSD: servconf.c,v 1.47 2000/07/10 16:30:25 ho Exp $"); #include "ssh.h" #include "servconf.h" @@ -76,6 +76,7 @@ initialize_server_options(ServerOptions *options) options->protocol = SSH_PROTO_UNKNOWN; options->gateway_ports = -1; options->num_subsystems = 0; + options->max_startups = -1; } void @@ -159,6 +160,8 @@ fill_default_server_options(ServerOptions *options) options->protocol = SSH_PROTO_1|SSH_PROTO_2; if (options->gateway_ports == -1) options->gateway_ports = 0; + if (options->max_startups == -1) + options->max_startups = 10; } #define WHITESPACE " \t\r\n=" @@ -183,7 +186,7 @@ typedef enum { sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail, sUseLogin, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups, sIgnoreUserKnownHosts, sHostDSAKeyFile, sCiphers, sProtocol, sPidFile, - sGatewayPorts, sDSAAuthentication, sXAuthLocation, sSubsystem + sGatewayPorts, sDSAAuthentication, sXAuthLocation, sSubsystem, sMaxStartups } ServerOpCodes; /* Textual representation of the tokens. */ @@ -239,6 +242,7 @@ static struct { { "protocol", sProtocol }, { "gatewayports", sGatewayPorts }, { "subsystem", sSubsystem }, + { "maxstartups", sMaxStartups }, { NULL, 0 } }; @@ -300,7 +304,7 @@ read_server_config(ServerOptions *options, const char *filename) { FILE *f; char line[1024]; - char *cp, **charptr; + char *cp, **charptr, *arg; int linenum, *intptr, value; int bad_options = 0; ServerOpCodes opcode; @@ -317,8 +321,8 @@ read_server_config(ServerOptions *options, const char *filename) cp = line + strspn(line, WHITESPACE); if (!*cp || *cp == '#') continue; - cp = strtok(cp, WHITESPACE); - opcode = parse_token(cp, filename, linenum); + arg = strsep(&cp, WHITESPACE); + opcode = parse_token(arg, filename, linenum); switch (opcode) { case sBadOption: bad_options++; @@ -333,23 +337,23 @@ read_server_config(ServerOptions *options, const char *filename) if (options->num_ports >= MAX_PORTS) fatal("%s line %d: too many ports.\n", filename, linenum); - cp = strtok(NULL, WHITESPACE); - if (!cp) + arg = strsep(&cp, WHITESPACE); + if (!arg || *arg == '\0') fatal("%s line %d: missing port number.\n", filename, linenum); - options->ports[options->num_ports++] = atoi(cp); + options->ports[options->num_ports++] = atoi(arg); break; case sServerKeyBits: intptr = &options->server_key_bits; parse_int: - cp = strtok(NULL, WHITESPACE); - if (!cp) { + arg = strsep(&cp, WHITESPACE); + if (!arg || *arg == '\0') { fprintf(stderr, "%s line %d: missing integer value.\n", filename, linenum); exit(1); } - value = atoi(cp); + value = atoi(arg); if (*intptr == -1) *intptr = value; break; @@ -363,11 +367,11 @@ parse_int: goto parse_int; case sListenAddress: - cp = strtok(NULL, WHITESPACE); - if (!cp) + arg = strsep(&cp, WHITESPACE); + if (!arg || *arg == '\0') fatal("%s line %d: missing inet addr.\n", filename, linenum); - add_listen_addr(options, cp); + add_listen_addr(options, arg); break; case sHostKeyFile: @@ -375,14 +379,14 @@ parse_int: charptr = (opcode == sHostKeyFile ) ? &options->host_key_file : &options->host_dsa_key_file; parse_filename: - cp = strtok(NULL, WHITESPACE); - if (!cp) { + arg = strsep(&cp, WHITESPACE); + if (!arg || *arg == '\0') { fprintf(stderr, "%s line %d: missing file name.\n", filename, linenum); exit(1); } if (*charptr == NULL) - *charptr = tilde_expand_filename(cp, getuid()); + *charptr = tilde_expand_filename(arg, getuid()); break; case sPidFile: @@ -392,26 +396,26 @@ parse_filename: case sRandomSeedFile: fprintf(stderr, "%s line %d: \"randomseed\" option is obsolete.\n", filename, linenum); - cp = strtok(NULL, WHITESPACE); + arg = strsep(&cp, WHITESPACE); break; case sPermitRootLogin: intptr = &options->permit_root_login; - cp = strtok(NULL, WHITESPACE); - if (!cp) { + arg = strsep(&cp, WHITESPACE); + if (!arg || *arg == '\0') { fprintf(stderr, "%s line %d: missing yes/without-password/no argument.\n", filename, linenum); exit(1); } - if (strcmp(cp, "without-password") == 0) + if (strcmp(arg, "without-password") == 0) value = 2; - else if (strcmp(cp, "yes") == 0) + else if (strcmp(arg, "yes") == 0) value = 1; - else if (strcmp(cp, "no") == 0) + else if (strcmp(arg, "no") == 0) value = 0; else { fprintf(stderr, "%s line %d: Bad yes/without-password/no argument: %s\n", - filename, linenum, cp); + filename, linenum, arg); exit(1); } if (*intptr == -1) @@ -421,19 +425,19 @@ parse_filename: case sIgnoreRhosts: intptr = &options->ignore_rhosts; parse_flag: - cp = strtok(NULL, WHITESPACE); - if (!cp) { + arg = strsep(&cp, WHITESPACE); + if (!arg || *arg == '\0') { fprintf(stderr, "%s line %d: missing yes/no argument.\n", filename, linenum); exit(1); } - if (strcmp(cp, "yes") == 0) + if (strcmp(arg, "yes") == 0) value = 1; - else if (strcmp(cp, "no") == 0) + else if (strcmp(arg, "no") == 0) value = 0; else { fprintf(stderr, "%s line %d: Bad yes/no argument: %s\n", - filename, linenum, cp); + filename, linenum, arg); exit(1); } if (*intptr == -1) @@ -536,82 +540,82 @@ parse_flag: case sLogFacility: intptr = (int *) &options->log_facility; - cp = strtok(NULL, WHITESPACE); - value = log_facility_number(cp); + arg = strsep(&cp, WHITESPACE); + value = log_facility_number(arg); if (value == (SyslogFacility) - 1) fatal("%.200s line %d: unsupported log facility '%s'\n", - filename, linenum, cp ? cp : ""); + filename, linenum, arg ? arg : ""); if (*intptr == -1) *intptr = (SyslogFacility) value; break; case sLogLevel: intptr = (int *) &options->log_level; - cp = strtok(NULL, WHITESPACE); - value = log_level_number(cp); + arg = strsep(&cp, WHITESPACE); + value = log_level_number(arg); if (value == (LogLevel) - 1) fatal("%.200s line %d: unsupported log level '%s'\n", - filename, linenum, cp ? cp : ""); + filename, linenum, arg ? arg : ""); if (*intptr == -1) *intptr = (LogLevel) value; break; case sAllowUsers: - while ((cp = strtok(NULL, WHITESPACE))) { + while ((arg = strsep(&cp, WHITESPACE)) && *arg != '\0') { if (options->num_allow_users >= MAX_ALLOW_USERS) fatal("%s line %d: too many allow users.\n", filename, linenum); - options->allow_users[options->num_allow_users++] = xstrdup(cp); + options->allow_users[options->num_allow_users++] = xstrdup(arg); } break; case sDenyUsers: - while ((cp = strtok(NULL, WHITESPACE))) { + while ((arg = strsep(&cp, WHITESPACE)) && *arg != '\0') { if (options->num_deny_users >= MAX_DENY_USERS) fatal( "%s line %d: too many deny users.\n", filename, linenum); - options->deny_users[options->num_deny_users++] = xstrdup(cp); + options->deny_users[options->num_deny_users++] = xstrdup(arg); } break; case sAllowGroups: - while ((cp = strtok(NULL, WHITESPACE))) { + while ((arg = strsep(&cp, WHITESPACE)) && *arg != '\0') { if (options->num_allow_groups >= MAX_ALLOW_GROUPS) fatal("%s line %d: too many allow groups.\n", filename, linenum); - options->allow_groups[options->num_allow_groups++] = xstrdup(cp); + options->allow_groups[options->num_allow_groups++] = xstrdup(arg); } break; case sDenyGroups: - while ((cp = strtok(NULL, WHITESPACE))) { + while ((arg = strsep(&cp, WHITESPACE)) && *arg != '\0') { if (options->num_deny_groups >= MAX_DENY_GROUPS) fatal("%s line %d: too many deny groups.\n", filename, linenum); - options->deny_groups[options->num_deny_groups++] = xstrdup(cp); + options->deny_groups[options->num_deny_groups++] = xstrdup(arg); } break; case sCiphers: - cp = strtok(NULL, WHITESPACE); - if (!cp) + arg = strsep(&cp, WHITESPACE); + if (!arg || *arg == '\0') fatal("%s line %d: Missing argument.", filename, linenum); - if (!ciphers_valid(cp)) + if (!ciphers_valid(arg)) fatal("%s line %d: Bad SSH2 cipher spec '%s'.", - filename, linenum, cp ? cp : ""); + filename, linenum, arg ? arg : ""); if (options->ciphers == NULL) - options->ciphers = xstrdup(cp); + options->ciphers = xstrdup(arg); break; case sProtocol: intptr = &options->protocol; - cp = strtok(NULL, WHITESPACE); - if (!cp) + arg = strsep(&cp, WHITESPACE); + if (!arg || *arg == '\0') fatal("%s line %d: Missing argument.", filename, linenum); - value = proto_spec(cp); + value = proto_spec(arg); if (value == SSH_PROTO_UNKNOWN) fatal("%s line %d: Bad protocol spec '%s'.", - filename, linenum, cp ? cp : ""); + filename, linenum, arg ? arg : ""); if (*intptr == SSH_PROTO_UNKNOWN) *intptr = value; break; @@ -621,31 +625,36 @@ parse_flag: fatal("%s line %d: too many subsystems defined.", filename, linenum); } - cp = strtok(NULL, WHITESPACE); - if (!cp) + arg = strsep(&cp, WHITESPACE); + if (!arg || *arg == '\0') fatal("%s line %d: Missing subsystem name.", filename, linenum); for (i = 0; i < options->num_subsystems; i++) - if(strcmp(cp, options->subsystem_name[i]) == 0) + if(strcmp(arg, options->subsystem_name[i]) == 0) fatal("%s line %d: Subsystem '%s' already defined.", - filename, linenum, cp); - options->subsystem_name[options->num_subsystems] = xstrdup(cp); - cp = strtok(NULL, WHITESPACE); - if (!cp) + filename, linenum, arg); + options->subsystem_name[options->num_subsystems] = xstrdup(arg); + arg = strsep(&cp, WHITESPACE); + if (!arg || *arg == '\0') fatal("%s line %d: Missing subsystem command.", filename, linenum); - options->subsystem_command[options->num_subsystems] = xstrdup(cp); + options->subsystem_command[options->num_subsystems] = xstrdup(arg); options->num_subsystems++; break; + case sMaxStartups: + intptr = &options->max_startups; + goto parse_int; + default: fprintf(stderr, "%s line %d: Missing handler for opcode %s (%d)\n", - filename, linenum, cp, opcode); + filename, linenum, arg, opcode); exit(1); } - if (strtok(NULL, WHITESPACE) != NULL) { - fprintf(stderr, "%s line %d: garbage at end of line.\n", - filename, linenum); + if ((arg = strsep(&cp, WHITESPACE)) != NULL && *arg != '\0') { + fprintf(stderr, + "%s line %d: garbage at end of line; \"%.200s\".\n", + filename, linenum, arg); exit(1); } } diff --git a/servconf.h b/servconf.h index c698bc74e..95593722d 100644 --- a/servconf.h +++ b/servconf.h @@ -13,7 +13,7 @@ * */ -/* RCSID("$OpenBSD: servconf.h,v 1.25 2000/06/20 01:39:44 markus Exp $"); */ +/* RCSID("$OpenBSD: servconf.h,v 1.26 2000/06/26 21:59:18 markus Exp $"); */ #ifndef SERVCONF_H #define SERVCONF_H @@ -99,6 +99,9 @@ typedef struct { unsigned int num_subsystems; char *subsystem_name[MAX_SUBSYSTEMS]; char *subsystem_command[MAX_SUBSYSTEMS]; + + int max_startups; + } ServerOptions; /* * Initializes the server options to special values that indicate that they diff --git a/serverloop.c b/serverloop.c index 311a285c3..00617bb81 100644 --- a/serverloop.c +++ b/serverloop.c @@ -722,7 +722,7 @@ input_direct_tcpip(void) originator, originator_port, target, target_port); /* XXX check permission */ - if (! no_port_forwarding_flag) { + if (no_port_forwarding_flag) { xfree(target); xfree(originator); return -1; diff --git a/session.c b/session.c index 7fe2b47f4..96a2d3b52 100644 --- a/session.c +++ b/session.c @@ -8,10 +8,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: session.c,v 1.20 2000/06/18 04:42:54 markus Exp $"); -#if defined(HAVE_USERSEC_H) -#include -#endif +RCSID("$OpenBSD: session.c,v 1.22 2000/07/05 20:18:07 deraadt Exp $"); #include "xmalloc.h" #include "ssh.h" @@ -35,6 +32,10 @@ RCSID("$OpenBSD: session.c,v 1.20 2000/06/18 04:42:54 markus Exp $"); #include #endif /* WITH_IRIX_PROJECT */ +#if defined(HAVE_USERSEC_H) +#include +#endif + #ifdef HAVE_OSF_SIA # include # include @@ -90,6 +91,8 @@ static const char *__progname = "sshd"; extern int log_stderr; extern int debug_flag; +extern int startup_pipe; + /* Local Xauthority file. */ static char *xauthfile; @@ -166,6 +169,7 @@ do_authenticated(struct passwd * pw) * authentication. */ alarm(0); + close(startup_pipe); /* * Inform the channel mechanism that we are the server side and that @@ -1457,7 +1461,7 @@ session_subsystem_req(Session *s) int session_x11_req(Session *s) { - if (!no_port_forwarding_flag) { + if (no_x11_forwarding_flag) { debug("X11 forwarding disabled in user configuration file."); return 0; } @@ -1788,6 +1792,7 @@ do_authenticated2(void) * authentication. */ alarm(0); + close(startup_pipe); server_loop2(); if (xauthfile) xauthfile_cleanup_proc(NULL); diff --git a/ssh-agent.1 b/ssh-agent.1 index 66a475692..47b1e5cc5 100644 --- a/ssh-agent.1 +++ b/ssh-agent.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-agent.1,v 1.12 2000/05/03 18:04:39 markus Exp $ +.\" $OpenBSD: ssh-agent.1,v 1.13 2000/07/06 04:06:56 aaron Exp $ .\" .\" -*- nroff -*- .\" @@ -133,6 +133,7 @@ Unix-domain sockets used to contain the connection to the authentication agent. These sockets should only be readable by the owner. The sockets should get automatically removed when the agent exits. +.El .Sh AUTHOR Tatu Ylonen .Pp diff --git a/ssh-keygen.1 b/ssh-keygen.1 index 9a32ad859..02f52ec65 100644 --- a/ssh-keygen.1 +++ b/ssh-keygen.1 @@ -9,7 +9,7 @@ .\" .\" Created: Sat Apr 22 23:55:14 1995 ylo .\" -.\" $Id: ssh-keygen.1,v 1.15 2000/05/09 01:03:02 damien Exp $ +.\" $Id: ssh-keygen.1,v 1.16 2000/07/11 07:31:38 djm Exp $ .\" .Dd September 25, 1999 .Dt SSH-KEYGEN 1 @@ -188,6 +188,7 @@ The contents of this file should be added to on all machines where you wish to log in using DSA authentication. There is no need to keep the contents of this file secret. +.El .Sh AUTHOR Tatu Ylonen .Pp diff --git a/ssh-keygen.c b/ssh-keygen.c index dbd0443fc..b38ebfb91 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -7,7 +7,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: ssh-keygen.c,v 1.27 2000/06/20 01:39:44 markus Exp $"); +RCSID("$OpenBSD: ssh-keygen.c,v 1.28 2000/07/07 03:55:04 todd Exp $"); #include #include @@ -127,13 +127,13 @@ do_convert_to_ssh2(struct passwd *pw) exit(1); } dsa_make_key_blob(k, &blob, &len); - fprintf(stdout, SSH_COM_MAGIC_BEGIN "\n"); + fprintf(stdout, "%s\n", SSH_COM_MAGIC_BEGIN); fprintf(stdout, "Comment: \"%d-bit DSA, converted from openssh by %s@%s\"\n", BN_num_bits(k->dsa->p), pw->pw_name, hostname); dump_base64(stdout, blob, len); - fprintf(stdout, SSH_COM_MAGIC_END "\n"); + fprintf(stdout, "%s\n", SSH_COM_MAGIC_END); key_free(k); xfree(blob); exit(0); diff --git a/sshd.8 b/sshd.8 index b71378c1e..b6aefe491 100644 --- a/sshd.8 +++ b/sshd.8 @@ -9,7 +9,7 @@ .\" .\" Created: Sat Apr 22 21:55:14 1995 ylo .\" -.\" $Id: sshd.8,v 1.24 2000/06/18 04:50:45 djm Exp $ +.\" $Id: sshd.8,v 1.25 2000/07/11 07:31:39 djm Exp $ .\" .Dd September 25, 1999 .Dt SSHD 8 @@ -435,6 +435,14 @@ QUIET, FATAL, ERROR, INFO, VERBOSE and DEBUG. The default is INFO. Logging with level DEBUG violates the privacy of users and is not recommended. +.It Cm MaxStartups +Specifies the maximum number of concurrent unauthenticated connections to the +.Nm +daemon. +Additional connections will be dropped until authentication succeeds or the +.Cm LoginGraceTime +expires for a connection. +The default is 10. .It Cm PasswordAuthentication Specifies whether password authentication is allowed. The default is @@ -954,6 +962,7 @@ Like This can be used to specify machine-specific login-time initializations globally. This file should be writable only by root, and should be world-readable. +.El .Sh AUTHOR OpenSSH is a derivative of the original (free) ssh 1.2.12 release by Tatu Ylonen, diff --git a/sshd.c b/sshd.c index 93d68404f..fc8b17b9e 100644 --- a/sshd.c +++ b/sshd.c @@ -14,7 +14,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshd.c,v 1.119 2000/06/22 16:32:27 markus Exp $"); +RCSID("$OpenBSD: sshd.c,v 1.121 2000/07/05 21:35:56 provos Exp $"); #include "xmalloc.h" #include "rsa.h" @@ -350,7 +350,7 @@ sshd_exchange_identification(int sock_in, int sock_out) break; } if (remote_minor < 3) { - packet_disconnect("Your ssh version is too old and" + packet_disconnect("Your ssh version is too old and " "is no longer supported. Please install a newer version."); } else if (remote_minor == 3) { /* note that this disables agent-forwarding */ @@ -400,6 +400,9 @@ destroy_sensitive_data(void) key_free(sensitive_data.dsa_host_key); } +int *startup_pipes = NULL; /* options.max_startup sized array of fd ints */ +int startup_pipe; /* in child */ + /* * Main program for the daemon. */ @@ -408,7 +411,7 @@ main(int ac, char **av) { extern char *optarg; extern int optind; - int opt, sock_in = 0, sock_out = 0, newsock, i, fdsetsz, on = 1; + int opt, sock_in = 0, sock_out = 0, newsock, j, i, fdsetsz, on = 1; pid_t pid; socklen_t fromlen; int silent = 0; @@ -421,6 +424,8 @@ main(int ac, char **av) struct addrinfo *ai; char ntop[NI_MAXHOST], strport[NI_MAXSERV]; int listen_sock, maxfd; + int startup_p[2]; + int startups = 0; init_rng(); @@ -746,6 +751,7 @@ main(int ac, char **av) /* Arrange to restart on SIGHUP. The handler needs listen_sock. */ signal(SIGHUP, sighup_handler); + signal(SIGTERM, sigterm_handler); signal(SIGQUIT, sigterm_handler); @@ -753,12 +759,15 @@ main(int ac, char **av) signal(SIGCHLD, main_sigchld_handler); /* setup fd set for listen */ + fdset = NULL; maxfd = 0; for (i = 0; i < num_listen_socks; i++) if (listen_socks[i] > maxfd) maxfd = listen_socks[i]; - fdsetsz = howmany(maxfd, NFDBITS) * sizeof(fd_mask); - fdset = (fd_set *)xmalloc(fdsetsz); + /* pipes connected to unauthenticated childs */ + startup_pipes = xmalloc(options.max_startups * sizeof(int)); + for (i = 0; i < options.max_startups; i++) + startup_pipes[i] = -1; /* * Stay listening for connections until the system crashes or @@ -767,80 +776,128 @@ main(int ac, char **av) for (;;) { if (received_sighup) sighup_restart(); - /* Wait in select until there is a connection. */ + if (fdset != NULL) + xfree(fdset); + fdsetsz = howmany(maxfd, NFDBITS) * sizeof(fd_mask); + fdset = (fd_set *)xmalloc(fdsetsz); memset(fdset, 0, fdsetsz); + for (i = 0; i < num_listen_socks; i++) FD_SET(listen_socks[i], fdset); + for (i = 0; i < options.max_startups; i++) + if (startup_pipes[i] != -1) + FD_SET(startup_pipes[i], fdset); + + /* Wait in select until there is a connection. */ if (select(maxfd + 1, fdset, NULL, NULL, NULL) < 0) { if (errno != EINTR) error("select: %.100s", strerror(errno)); continue; } + for (i = 0; i < options.max_startups; i++) + if (startup_pipes[i] != -1 && + FD_ISSET(startup_pipes[i], fdset)) { + /* + * the read end of the pipe is ready + * if the child has closed the pipe + * after successfull authentication + * or if the child has died + */ + close(startup_pipes[i]); + startup_pipes[i] = -1; + startups--; + } for (i = 0; i < num_listen_socks; i++) { if (!FD_ISSET(listen_socks[i], fdset)) continue; - fromlen = sizeof(from); - newsock = accept(listen_socks[i], (struct sockaddr *)&from, - &fromlen); - if (newsock < 0) { - if (errno != EINTR && errno != EWOULDBLOCK) - error("accept: %.100s", strerror(errno)); - continue; - } - if (fcntl(newsock, F_SETFL, 0) < 0) { - error("newsock del O_NONBLOCK: %s", strerror(errno)); - continue; - } - /* - * Got connection. Fork a child to handle it, unless - * we are in debugging mode. - */ - if (debug_flag) { + fromlen = sizeof(from); + newsock = accept(listen_socks[i], (struct sockaddr *)&from, + &fromlen); + if (newsock < 0) { + if (errno != EINTR && errno != EWOULDBLOCK) + error("accept: %.100s", strerror(errno)); + continue; + } + if (fcntl(newsock, F_SETFL, 0) < 0) { + error("newsock del O_NONBLOCK: %s", strerror(errno)); + continue; + } + if (startups >= options.max_startups) { + close(newsock); + continue; + } + if (pipe(startup_p) == -1) { + close(newsock); + continue; + } + + for (j = 0; j < options.max_startups; j++) + if (startup_pipes[j] == -1) { + startup_pipes[j] = startup_p[0]; + if (maxfd < startup_p[0]) + maxfd = startup_p[0]; + startups++; + break; + } + /* - * In debugging mode. Close the listening - * socket, and start processing the - * connection without forking. + * Got connection. Fork a child to handle it, unless + * we are in debugging mode. */ - debug("Server will not fork when running in debugging mode."); - close_listen_socks(); - sock_in = newsock; - sock_out = newsock; - pid = getpid(); - break; - } else { - /* - * Normal production daemon. Fork, and have - * the child process the connection. The - * parent continues listening. - */ - if ((pid = fork()) == 0) { + if (debug_flag) { /* - * Child. Close the listening socket, and start using the - * accepted socket. Reinitialize logging (since our pid has - * changed). We break out of the loop to handle the connection. + * In debugging mode. Close the listening + * socket, and start processing the + * connection without forking. */ + debug("Server will not fork when running in debugging mode."); close_listen_socks(); sock_in = newsock; sock_out = newsock; - log_init(av0, options.log_level, options.log_facility, log_stderr); + pid = getpid(); break; + } else { + /* + * Normal production daemon. Fork, and have + * the child process the connection. The + * parent continues listening. + */ + if ((pid = fork()) == 0) { + /* + * Child. Close the listening and max_startup + * sockets. Start using the accepted socket. + * Reinitialize logging (since our pid has + * changed). We break out of the loop to handle + * the connection. + */ + startup_pipe = startup_p[1]; + for (j = 0; j < options.max_startups; j++) + if (startup_pipes[j] != -1) + close(startup_pipes[j]); + close_listen_socks(); + sock_in = newsock; + sock_out = newsock; + log_init(av0, options.log_level, options.log_facility, log_stderr); + break; + } } + + /* Parent. Stay in the loop. */ + if (pid < 0) + error("fork: %.100s", strerror(errno)); + else + debug("Forked child %d.", pid); + + close(startup_p[1]); + + /* Mark that the key has been used (it was "given" to the child). */ + key_used = 1; + + arc4random_stir(); + + /* Close the new socket (the child is now taking care of it). */ + close(newsock); } - - /* Parent. Stay in the loop. */ - if (pid < 0) - error("fork: %.100s", strerror(errno)); - else - debug("Forked child %d.", pid); - - /* Mark that the key has been used (it was "given" to the child). */ - key_used = 1; - - arc4random_stir(); - - /* Close the new socket (the child is now taking care of it). */ - close(newsock); - } /* for (i = 0; i < num_listen_socks; i++) */ /* child process check (or debug mode) */ if (num_listen_socks < 0) break;