summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog39
-rw-r--r--auth-rsa.c6
-rw-r--r--auth.h2
-rw-r--r--auth2.c4
-rw-r--r--authfd.c142
-rw-r--r--cipher.c9
-rw-r--r--compat.c8
-rw-r--r--kex.c14
-rw-r--r--readconf.c152
-rw-r--r--scp.13
-rw-r--r--servconf.c137
-rw-r--r--servconf.h5
-rw-r--r--serverloop.c2
-rw-r--r--session.c15
-rw-r--r--ssh-agent.13
-rw-r--r--ssh-keygen.13
-rw-r--r--ssh-keygen.c6
-rw-r--r--sshd.811
-rw-r--r--sshd.c167
19 files changed, 389 insertions, 339 deletions
diff --git a/ChangeLog b/ChangeLog
index b73255a21..8481359a7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -10,6 +10,45 @@
10 to compile on more platforms (incl NeXT). 10 to compile on more platforms (incl NeXT).
11 - (djm) Added bsd-inet_aton and configure support for NeXT 11 - (djm) Added bsd-inet_aton and configure support for NeXT
12 - (djm) Misc NeXT fixes from Ben Lindstrom <mouring@pconline.com> 12 - (djm) Misc NeXT fixes from Ben Lindstrom <mouring@pconline.com>
13 - (djm) OpenBSD CVS updates:
14 - markus@cvs.openbsd.org 2000/06/26 03:22:29
15 [authfd.c]
16 cleanup, less cut&paste
17 - markus@cvs.openbsd.org 2000/06/26 15:59:19
18 [servconf.c servconf.h session.c sshd.8 sshd.c]
19 MaxStartups: limit number of unauthenticated connections, work by
20 theo and me
21 - deraadt@cvs.openbsd.org 2000/07/05 14:18:07
22 [session.c]
23 use no_x11_forwarding_flag correctly; provos ok
24 - provos@cvs.openbsd.org 2000/07/05 15:35:57
25 [sshd.c]
26 typo
27 - aaron@cvs.openbsd.org 2000/07/05 22:06:58
28 [scp.1 ssh-agent.1 ssh-keygen.1 sshd.8]
29 Insert more missing .El directives. Our troff really should identify
30 these and spit out a warning.
31 - todd@cvs.openbsd.org 2000/07/06 21:55:04
32 [auth-rsa.c auth2.c ssh-keygen.c]
33 clean code is good code
34 - deraadt@cvs.openbsd.org 2000/07/07 02:14:29
35 [serverloop.c]
36 sense of port forwarding flag test was backwards
37 - provos@cvs.openbsd.org 2000/07/08 17:17:31
38 [compat.c readconf.c]
39 replace strtok with strsep; from David Young <dyoung@onthejob.net>
40 - deraadt@cvs.openbsd.org 2000/07/08 19:21:15
41 [auth.h]
42 KNF
43 - ho@cvs.openbsd.org 2000/07/08 19:27:33
44 [compat.c readconf.c]
45 Better conditions for strsep() ending.
46 - ho@cvs.openbsd.org 2000/07/10 10:27:05
47 [readconf.c]
48 Get the correct message on errors. (niels@ ok)
49 - ho@cvs.openbsd.org 2000/07/10 10:30:25
50 [cipher.c kex.c servconf.c]
51 strtok() --> strsep(). (niels@ ok)
13 52
1420000709 5320000709
15 - (djm) Only enable PAM_TTY kludge for Linux. Problem report from 54 - (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 @@
16 */ 16 */
17 17
18#include "includes.h" 18#include "includes.h"
19RCSID("$OpenBSD: auth-rsa.c,v 1.26 2000/06/20 01:39:38 markus Exp $"); 19RCSID("$OpenBSD: auth-rsa.c,v 1.27 2000/07/07 03:55:03 todd Exp $");
20 20
21#include "rsa.h" 21#include "rsa.h"
22#include "packet.h" 22#include "packet.h"
@@ -179,8 +179,8 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
179 } 179 }
180 if (fail) { 180 if (fail) {
181 fclose(f); 181 fclose(f);
182 log(buf); 182 log("%s",buf);
183 packet_send_debug(buf); 183 packet_send_debug("%s",buf);
184 restore_uid(); 184 restore_uid();
185 return 0; 185 return 0;
186 } 186 }
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);
7struct passwd * 7struct passwd *
8auth_get_user(void); 8auth_get_user(void);
9 9
10int allowed_user(struct passwd * pw);; 10int allowed_user(struct passwd * pw);
11 11
12#define AUTH_FAIL_MAX 6 12#define AUTH_FAIL_MAX 6
13#define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2) 13#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 @@
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */ 28 */
29#include "includes.h" 29#include "includes.h"
30RCSID("$OpenBSD: auth2.c,v 1.11 2000/06/19 00:50:11 markus Exp $"); 30RCSID("$OpenBSD: auth2.c,v 1.12 2000/07/07 03:55:03 todd Exp $");
31 31
32#include <openssl/dsa.h> 32#include <openssl/dsa.h>
33#include <openssl/rsa.h> 33#include <openssl/rsa.h>
@@ -489,8 +489,8 @@ user_dsa_key_allowed(struct passwd *pw, Key *key)
489 } 489 }
490 } 490 }
491 if (fail) { 491 if (fail) {
492 log(buf);
493 fclose(f); 492 fclose(f);
493 log("%s",buf);
494 restore_uid(); 494 restore_uid();
495 return 0; 495 return 0;
496 } 496 }
diff --git a/authfd.c b/authfd.c
index 69d77d7dd..69fe2ae41 100644
--- a/authfd.c
+++ b/authfd.c
@@ -14,7 +14,7 @@
14 */ 14 */
15 15
16#include "includes.h" 16#include "includes.h"
17RCSID("$OpenBSD: authfd.c,v 1.20 2000/06/20 01:39:38 markus Exp $"); 17RCSID("$OpenBSD: authfd.c,v 1.21 2000/06/26 09:22:29 markus Exp $");
18 18
19#include "ssh.h" 19#include "ssh.h"
20#include "rsa.h" 20#include "rsa.h"
@@ -26,6 +26,9 @@ RCSID("$OpenBSD: authfd.c,v 1.20 2000/06/20 01:39:38 markus Exp $");
26 26
27#include <openssl/rsa.h> 27#include <openssl/rsa.h>
28 28
29/* helper */
30int ssh_agent_get_reply(AuthenticationConnection *auth);
31
29/* Returns the number of the authentication fd, or -1 if there is none. */ 32/* Returns the number of the authentication fd, or -1 if there is none. */
30 33
31int 34int
@@ -344,7 +347,7 @@ ssh_add_identity(AuthenticationConnection *auth,
344{ 347{
345 Buffer buffer; 348 Buffer buffer;
346 unsigned char buf[8192]; 349 unsigned char buf[8192];
347 int len, l, type; 350 int len;
348 351
349 /* Format a message to the agent. */ 352 /* Format a message to the agent. */
350 buffer_init(&buffer); 353 buffer_init(&buffer);
@@ -368,57 +371,11 @@ ssh_add_identity(AuthenticationConnection *auth,
368 atomicio(write, auth->fd, buffer_ptr(&buffer), 371 atomicio(write, auth->fd, buffer_ptr(&buffer),
369 buffer_len(&buffer)) != buffer_len(&buffer)) { 372 buffer_len(&buffer)) != buffer_len(&buffer)) {
370 error("Error writing to authentication socket."); 373 error("Error writing to authentication socket.");
371error_cleanup:
372 buffer_free(&buffer); 374 buffer_free(&buffer);
373 return 0; 375 return 0;
374 } 376 }
375 /* Wait for response from the agent. First read the length of the 377 buffer_free(&buffer);
376 response packet. */ 378 return ssh_agent_get_reply(auth);
377 len = 4;
378 while (len > 0) {
379 l = read(auth->fd, buf + 4 - len, len);
380 if (l <= 0) {
381 error("Error reading response length from authentication socket.");
382 goto error_cleanup;
383 }
384 len -= l;
385 }
386
387 /* Extract the length, and check it for sanity. */
388 len = GET_32BIT(buf);
389 if (len > 256 * 1024)
390 fatal("Add identity response too long: %d", len);
391
392 /* Read the rest of the response in tothe buffer. */
393 buffer_clear(&buffer);
394 while (len > 0) {
395 l = len;
396 if (l > sizeof(buf))
397 l = sizeof(buf);
398 l = read(auth->fd, buf, l);
399 if (l <= 0) {
400 error("Error reading response from authentication socket.");
401 goto error_cleanup;
402 }
403 buffer_append(&buffer, (char *) buf, l);
404 len -= l;
405 }
406
407 /* Get the type of the packet. */
408 type = buffer_get_char(&buffer);
409 switch (type) {
410 case SSH_AGENT_FAILURE:
411 buffer_free(&buffer);
412 return 0;
413 case SSH_AGENT_SUCCESS:
414 buffer_free(&buffer);
415 return 1;
416 default:
417 fatal("Bad response to add identity from authentication agent: %d",
418 type);
419 }
420 /* NOTREACHED */
421 return 0;
422} 379}
423 380
424/* 381/*
@@ -430,8 +387,8 @@ int
430ssh_remove_identity(AuthenticationConnection *auth, RSA *key) 387ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
431{ 388{
432 Buffer buffer; 389 Buffer buffer;
433 unsigned char buf[8192]; 390 unsigned char buf[5];
434 int len, l, type; 391 int len;
435 392
436 /* Format a message to the agent. */ 393 /* Format a message to the agent. */
437 buffer_init(&buffer); 394 buffer_init(&buffer);
@@ -449,59 +406,11 @@ ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
449 atomicio(write, auth->fd, buffer_ptr(&buffer), 406 atomicio(write, auth->fd, buffer_ptr(&buffer),
450 buffer_len(&buffer)) != buffer_len(&buffer)) { 407 buffer_len(&buffer)) != buffer_len(&buffer)) {
451 error("Error writing to authentication socket."); 408 error("Error writing to authentication socket.");
452error_cleanup:
453 buffer_free(&buffer); 409 buffer_free(&buffer);
454 return 0; 410 return 0;
455 } 411 }
456 /* 412 buffer_free(&buffer);
457 * Wait for response from the agent. First read the length of the 413 return ssh_agent_get_reply(auth);
458 * response packet.
459 */
460 len = 4;
461 while (len > 0) {
462 l = read(auth->fd, buf + 4 - len, len);
463 if (l <= 0) {
464 error("Error reading response length from authentication socket.");
465 goto error_cleanup;
466 }
467 len -= l;
468 }
469
470 /* Extract the length, and check it for sanity. */
471 len = GET_32BIT(buf);
472 if (len > 256 * 1024)
473 fatal("Remove identity response too long: %d", len);
474
475 /* Read the rest of the response in tothe buffer. */
476 buffer_clear(&buffer);
477 while (len > 0) {
478 l = len;
479 if (l > sizeof(buf))
480 l = sizeof(buf);
481 l = read(auth->fd, buf, l);
482 if (l <= 0) {
483 error("Error reading response from authentication socket.");
484 goto error_cleanup;
485 }
486 buffer_append(&buffer, (char *) buf, l);
487 len -= l;
488 }
489
490 /* Get the type of the packet. */
491 type = buffer_get_char(&buffer);
492 switch (type) {
493 case SSH_AGENT_FAILURE:
494 buffer_free(&buffer);
495 return 0;
496 case SSH_AGENT_SUCCESS:
497 buffer_free(&buffer);
498 return 1;
499 default:
500 fatal("Bad response to remove identity from authentication agent: %d",
501 type);
502 }
503 /* NOTREACHED */
504 return 0;
505} 414}
506 415
507/* 416/*
@@ -512,9 +421,7 @@ error_cleanup:
512int 421int
513ssh_remove_all_identities(AuthenticationConnection *auth) 422ssh_remove_all_identities(AuthenticationConnection *auth)
514{ 423{
515 Buffer buffer; 424 unsigned char buf[5];
516 unsigned char buf[8192];
517 int len, l, type;
518 425
519 /* Get the length of the message, and format it in the buffer. */ 426 /* Get the length of the message, and format it in the buffer. */
520 PUT_32BIT(buf, 1); 427 PUT_32BIT(buf, 1);
@@ -525,6 +432,20 @@ ssh_remove_all_identities(AuthenticationConnection *auth)
525 error("Error writing to authentication socket."); 432 error("Error writing to authentication socket.");
526 return 0; 433 return 0;
527 } 434 }
435 return ssh_agent_get_reply(auth);
436}
437
438/*
439 * Read for reply from agent. returns 1 for success, 0 on error
440 */
441
442int
443ssh_agent_get_reply(AuthenticationConnection *auth)
444{
445 Buffer buffer;
446 unsigned char buf[8192];
447 int len, l, type;
448
528 /* 449 /*
529 * Wait for response from the agent. First read the length of the 450 * Wait for response from the agent. First read the length of the
530 * response packet. 451 * response packet.
@@ -534,6 +455,7 @@ ssh_remove_all_identities(AuthenticationConnection *auth)
534 l = read(auth->fd, buf + 4 - len, len); 455 l = read(auth->fd, buf + 4 - len, len);
535 if (l <= 0) { 456 if (l <= 0) {
536 error("Error reading response length from authentication socket."); 457 error("Error reading response length from authentication socket.");
458 buffer_free(&buffer);
537 return 0; 459 return 0;
538 } 460 }
539 len -= l; 461 len -= l;
@@ -542,9 +464,9 @@ ssh_remove_all_identities(AuthenticationConnection *auth)
542 /* Extract the length, and check it for sanity. */ 464 /* Extract the length, and check it for sanity. */
543 len = GET_32BIT(buf); 465 len = GET_32BIT(buf);
544 if (len > 256 * 1024) 466 if (len > 256 * 1024)
545 fatal("Remove identity response too long: %d", len); 467 fatal("Response from agent too long: %d", len);
546 468
547 /* Read the rest of the response into the buffer. */ 469 /* Read the rest of the response in to the buffer. */
548 buffer_init(&buffer); 470 buffer_init(&buffer);
549 while (len > 0) { 471 while (len > 0) {
550 l = len; 472 l = len;
@@ -562,16 +484,14 @@ ssh_remove_all_identities(AuthenticationConnection *auth)
562 484
563 /* Get the type of the packet. */ 485 /* Get the type of the packet. */
564 type = buffer_get_char(&buffer); 486 type = buffer_get_char(&buffer);
487 buffer_free(&buffer);
565 switch (type) { 488 switch (type) {
566 case SSH_AGENT_FAILURE: 489 case SSH_AGENT_FAILURE:
567 buffer_free(&buffer);
568 return 0; 490 return 0;
569 case SSH_AGENT_SUCCESS: 491 case SSH_AGENT_SUCCESS:
570 buffer_free(&buffer);
571 return 1; 492 return 1;
572 default: 493 default:
573 fatal("Bad response to remove identity from authentication agent: %d", 494 fatal("Bad response from authentication agent: %d", type);
574 type);
575 } 495 }
576 /* NOTREACHED */ 496 /* NOTREACHED */
577 return 0; 497 return 0;
diff --git a/cipher.c b/cipher.c
index 97cbd38ca..a44e51d98 100644
--- a/cipher.c
+++ b/cipher.c
@@ -12,7 +12,7 @@
12 */ 12 */
13 13
14#include "includes.h" 14#include "includes.h"
15RCSID("$OpenBSD: cipher.c,v 1.28 2000/06/20 01:39:40 markus Exp $"); 15RCSID("$OpenBSD: cipher.c,v 1.29 2000/07/10 16:30:25 ho Exp $");
16 16
17#include "ssh.h" 17#include "ssh.h"
18#include "cipher.h" 18#include "cipher.h"
@@ -174,14 +174,15 @@ cipher_name(int cipher)
174int 174int
175ciphers_valid(const char *names) 175ciphers_valid(const char *names)
176{ 176{
177 char *ciphers; 177 char *ciphers, *cp;
178 char *p; 178 char *p;
179 int i; 179 int i;
180 180
181 if (names == NULL || strcmp(names, "") == 0) 181 if (names == NULL || strcmp(names, "") == 0)
182 return 0; 182 return 0;
183 ciphers = xstrdup(names); 183 ciphers = cp = xstrdup(names);
184 for ((p = strtok(ciphers, CIPHER_SEP)); p; (p = strtok(NULL, CIPHER_SEP))) { 184 for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0';
185 (p = strsep(&cp, CIPHER_SEP))) {
185 i = cipher_number(p); 186 i = cipher_number(p);
186 if (i == -1 || !(cipher_mask2() & (1 << i))) { 187 if (i == -1 || !(cipher_mask2() & (1 << i))) {
187 xfree(ciphers); 188 xfree(ciphers);
diff --git a/compat.c b/compat.c
index e3410d497..595a0a378 100644
--- a/compat.c
+++ b/compat.c
@@ -28,7 +28,7 @@
28 */ 28 */
29 29
30#include "includes.h" 30#include "includes.h"
31RCSID("$OpenBSD: compat.c,v 1.17 2000/06/20 01:39:40 markus Exp $"); 31RCSID("$OpenBSD: compat.c,v 1.19 2000/07/09 01:27:32 ho Exp $");
32 32
33#include "ssh.h" 33#include "ssh.h"
34#include "packet.h" 34#include "packet.h"
@@ -81,13 +81,13 @@ compat_datafellows(const char *version)
81int 81int
82proto_spec(const char *spec) 82proto_spec(const char *spec)
83{ 83{
84 char *s, *p; 84 char *s, *p, *q;
85 int ret = SSH_PROTO_UNKNOWN; 85 int ret = SSH_PROTO_UNKNOWN;
86 86
87 if (spec == NULL) 87 if (spec == NULL)
88 return ret; 88 return ret;
89 s = xstrdup(spec); 89 q = s = xstrdup(spec);
90 for ((p = strtok(s, SEP)); p; (p = strtok(NULL, SEP))) { 90 for ((p = strsep(&q, SEP)); p && *p != '\0'; (p = strsep(&q, SEP))) {
91 switch(atoi(p)) { 91 switch(atoi(p)) {
92 case 1: 92 case 1:
93 if (ret == SSH_PROTO_UNKNOWN) 93 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 @@
28 */ 28 */
29 29
30#include "includes.h" 30#include "includes.h"
31RCSID("$OpenBSD: kex.c,v 1.8 2000/06/20 01:39:41 markus Exp $"); 31RCSID("$OpenBSD: kex.c,v 1.9 2000/07/10 16:30:25 ho Exp $");
32 32
33#include "ssh.h" 33#include "ssh.h"
34#include "ssh2.h" 34#include "ssh2.h"
@@ -287,13 +287,14 @@ char *
287get_match(char *client, char *server) 287get_match(char *client, char *server)
288{ 288{
289 char *sproposals[MAX_PROP]; 289 char *sproposals[MAX_PROP];
290 char *c, *s, *p, *ret; 290 char *c, *s, *p, *ret, *cp, *sp;
291 int i, j, nproposals; 291 int i, j, nproposals;
292 292
293 c = xstrdup(client); 293 c = cp = xstrdup(client);
294 s = xstrdup(server); 294 s = sp = xstrdup(server);
295 295
296 for ((p = strtok(s, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) { 296 for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0';
297 (p = strsep(&sp, SEP)), i++) {
297 if (i < MAX_PROP) 298 if (i < MAX_PROP)
298 sproposals[i] = p; 299 sproposals[i] = p;
299 else 300 else
@@ -301,7 +302,8 @@ get_match(char *client, char *server)
301 } 302 }
302 nproposals = i; 303 nproposals = i;
303 304
304 for ((p = strtok(c, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) { 305 for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0';
306 (p = strsep(&cp, SEP)), i++) {
305 for (j = 0; j < nproposals; j++) { 307 for (j = 0; j < nproposals; j++) {
306 if (strcmp(p, sproposals[j]) == 0) { 308 if (strcmp(p, sproposals[j]) == 0) {
307 ret = xstrdup(p); 309 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 @@
14 */ 14 */
15 15
16#include "includes.h" 16#include "includes.h"
17RCSID("$OpenBSD: readconf.c,v 1.37 2000/06/20 01:39:43 markus Exp $"); 17RCSID("$OpenBSD: readconf.c,v 1.40 2000/07/10 16:27:05 ho Exp $");
18 18
19#include "ssh.h" 19#include "ssh.h"
20#include "cipher.h" 20#include "cipher.h"
@@ -164,7 +164,7 @@ static struct {
164 { NULL, 0 } 164 { NULL, 0 }
165}; 165};
166 166
167/* Characters considered whitespace in strtok calls. */ 167/* Characters considered whitespace in strsep calls. */
168#define WHITESPACE " \t\r\n=" 168#define WHITESPACE " \t\r\n="
169 169
170 170
@@ -237,18 +237,18 @@ process_config_line(Options *options, const char *host,
237 char *line, const char *filename, int linenum, 237 char *line, const char *filename, int linenum,
238 int *activep) 238 int *activep)
239{ 239{
240 char buf[256], *cp, *string, **charptr, *cp2; 240 char buf[256], *s, *string, **charptr, *endofnumber, *keyword, *arg;
241 int opcode, *intptr, value; 241 int opcode, *intptr, value;
242 u_short fwd_port, fwd_host_port; 242 u_short fwd_port, fwd_host_port;
243 243
244 /* Skip leading whitespace. */ 244 /* Skip leading whitespace. */
245 cp = line + strspn(line, WHITESPACE); 245 s = line + strspn(line, WHITESPACE);
246 if (!*cp || *cp == '\n' || *cp == '#') 246 if (!*s || *s == '\n' || *s == '#')
247 return 0; 247 return 0;
248 248
249 /* Get the keyword. (Each line is supposed to begin with a keyword). */ 249 /* Get the keyword. (Each line is supposed to begin with a keyword). */
250 cp = strtok(cp, WHITESPACE); 250 keyword = strsep(&s, WHITESPACE);
251 opcode = parse_token(cp, filename, linenum); 251 opcode = parse_token(keyword, filename, linenum);
252 252
253 switch (opcode) { 253 switch (opcode) {
254 case oBadOption: 254 case oBadOption:
@@ -258,13 +258,13 @@ process_config_line(Options *options, const char *host,
258 case oForwardAgent: 258 case oForwardAgent:
259 intptr = &options->forward_agent; 259 intptr = &options->forward_agent;
260parse_flag: 260parse_flag:
261 cp = strtok(NULL, WHITESPACE); 261 arg = strsep(&s, WHITESPACE);
262 if (!cp) 262 if (!arg || *arg == '\0')
263 fatal("%.200s line %d: Missing yes/no argument.", filename, linenum); 263 fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
264 value = 0; /* To avoid compiler warning... */ 264 value = 0; /* To avoid compiler warning... */
265 if (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0) 265 if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
266 value = 1; 266 value = 1;
267 else if (strcmp(cp, "no") == 0 || strcmp(cp, "false") == 0) 267 else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
268 value = 0; 268 value = 0;
269 else 269 else
270 fatal("%.200s line %d: Bad yes/no argument.", filename, linenum); 270 fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
@@ -344,16 +344,16 @@ parse_flag:
344 344
345 case oStrictHostKeyChecking: 345 case oStrictHostKeyChecking:
346 intptr = &options->strict_host_key_checking; 346 intptr = &options->strict_host_key_checking;
347 cp = strtok(NULL, WHITESPACE); 347 arg = strsep(&s, WHITESPACE);
348 if (!cp) 348 if (!arg || *arg == '\0')
349 fatal("%.200s line %d: Missing yes/no argument.", 349 fatal("%.200s line %d: Missing yes/no argument.",
350 filename, linenum); 350 filename, linenum);
351 value = 0; /* To avoid compiler warning... */ 351 value = 0; /* To avoid compiler warning... */
352 if (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0) 352 if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
353 value = 1; 353 value = 1;
354 else if (strcmp(cp, "no") == 0 || strcmp(cp, "false") == 0) 354 else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
355 value = 0; 355 value = 0;
356 else if (strcmp(cp, "ask") == 0) 356 else if (strcmp(arg, "ask") == 0)
357 value = 2; 357 value = 2;
358 else 358 else
359 fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum); 359 fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
@@ -379,8 +379,8 @@ parse_flag:
379 379
380 case oIdentityFile: 380 case oIdentityFile:
381 case oIdentityFile2: 381 case oIdentityFile2:
382 cp = strtok(NULL, WHITESPACE); 382 arg = strsep(&s, WHITESPACE);
383 if (!cp) 383 if (!arg || *arg == '\0')
384 fatal("%.200s line %d: Missing argument.", filename, linenum); 384 fatal("%.200s line %d: Missing argument.", filename, linenum);
385 if (*activep) { 385 if (*activep) {
386 intptr = (opcode == oIdentityFile) ? 386 intptr = (opcode == oIdentityFile) ?
@@ -392,7 +392,7 @@ parse_flag:
392 charptr = (opcode == oIdentityFile) ? 392 charptr = (opcode == oIdentityFile) ?
393 &options->identity_files[*intptr] : 393 &options->identity_files[*intptr] :
394 &options->identity_files2[*intptr]; 394 &options->identity_files2[*intptr];
395 *charptr = xstrdup(cp); 395 *charptr = xstrdup(arg);
396 *intptr = *intptr + 1; 396 *intptr = *intptr + 1;
397 } 397 }
398 break; 398 break;
@@ -404,11 +404,11 @@ parse_flag:
404 case oUser: 404 case oUser:
405 charptr = &options->user; 405 charptr = &options->user;
406parse_string: 406parse_string:
407 cp = strtok(NULL, WHITESPACE); 407 arg = strsep(&s, WHITESPACE);
408 if (!cp) 408 if (!arg || *arg == '\0')
409 fatal("%.200s line %d: Missing argument.", filename, linenum); 409 fatal("%.200s line %d: Missing argument.", filename, linenum);
410 if (*activep && *charptr == NULL) 410 if (*activep && *charptr == NULL)
411 *charptr = xstrdup(cp); 411 *charptr = xstrdup(arg);
412 break; 412 break;
413 413
414 case oGlobalKnownHostsFile: 414 case oGlobalKnownHostsFile:
@@ -434,10 +434,10 @@ parse_string:
434 case oProxyCommand: 434 case oProxyCommand:
435 charptr = &options->proxy_command; 435 charptr = &options->proxy_command;
436 string = xstrdup(""); 436 string = xstrdup("");
437 while ((cp = strtok(NULL, WHITESPACE)) != NULL) { 437 while ((arg = strsep(&s, WHITESPACE)) != NULL && *arg != '\0') {
438 string = xrealloc(string, strlen(string) + strlen(cp) + 2); 438 string = xrealloc(string, strlen(string) + strlen(arg) + 2);
439 strcat(string, " "); 439 strcat(string, " ");
440 strcat(string, cp); 440 strcat(string, arg);
441 } 441 }
442 if (*activep && *charptr == NULL) 442 if (*activep && *charptr == NULL)
443 *charptr = string; 443 *charptr = string;
@@ -448,15 +448,15 @@ parse_string:
448 case oPort: 448 case oPort:
449 intptr = &options->port; 449 intptr = &options->port;
450parse_int: 450parse_int:
451 cp = strtok(NULL, WHITESPACE); 451 arg = strsep(&s, WHITESPACE);
452 if (!cp) 452 if (!arg || *arg == '\0')
453 fatal("%.200s line %d: Missing argument.", filename, linenum); 453 fatal("%.200s line %d: Missing argument.", filename, linenum);
454 if (cp[0] < '0' || cp[0] > '9') 454 if (arg[0] < '0' || arg[0] > '9')
455 fatal("%.200s line %d: Bad number.", filename, linenum); 455 fatal("%.200s line %d: Bad number.", filename, linenum);
456 456
457 /* Octal, decimal, or hex format? */ 457 /* Octal, decimal, or hex format? */
458 value = strtol(cp, &cp2, 0); 458 value = strtol(arg, &endofnumber, 0);
459 if (cp == cp2) 459 if (arg == endofnumber)
460 fatal("%.200s line %d: Bad number.", filename, linenum); 460 fatal("%.200s line %d: Bad number.", filename, linenum);
461 if (*activep && *intptr == -1) 461 if (*activep && *intptr == -1)
462 *intptr = value; 462 *intptr = value;
@@ -468,65 +468,65 @@ parse_int:
468 468
469 case oCipher: 469 case oCipher:
470 intptr = &options->cipher; 470 intptr = &options->cipher;
471 cp = strtok(NULL, WHITESPACE); 471 arg = strsep(&s, WHITESPACE);
472 if (!cp) 472 if (!arg || *arg == '\0')
473 fatal("%.200s line %d: Missing argument.", filename, linenum); 473 fatal("%.200s line %d: Missing argument.", filename, linenum);
474 value = cipher_number(cp); 474 value = cipher_number(arg);
475 if (value == -1) 475 if (value == -1)
476 fatal("%.200s line %d: Bad cipher '%s'.", 476 fatal("%.200s line %d: Bad cipher '%s'.",
477 filename, linenum, cp ? cp : "<NONE>"); 477 filename, linenum, arg ? arg : "<NONE>");
478 if (*activep && *intptr == -1) 478 if (*activep && *intptr == -1)
479 *intptr = value; 479 *intptr = value;
480 break; 480 break;
481 481
482 case oCiphers: 482 case oCiphers:
483 cp = strtok(NULL, WHITESPACE); 483 arg = strsep(&s, WHITESPACE);
484 if (!cp) 484 if (!arg || *arg == '\0')
485 fatal("%.200s line %d: Missing argument.", filename, linenum); 485 fatal("%.200s line %d: Missing argument.", filename, linenum);
486 if (!ciphers_valid(cp)) 486 if (!ciphers_valid(arg))
487 fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.", 487 fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
488 filename, linenum, cp ? cp : "<NONE>"); 488 filename, linenum, arg ? arg : "<NONE>");
489 if (*activep && options->ciphers == NULL) 489 if (*activep && options->ciphers == NULL)
490 options->ciphers = xstrdup(cp); 490 options->ciphers = xstrdup(arg);
491 break; 491 break;
492 492
493 case oProtocol: 493 case oProtocol:
494 intptr = &options->protocol; 494 intptr = &options->protocol;
495 cp = strtok(NULL, WHITESPACE); 495 arg = strsep(&s, WHITESPACE);
496 if (!cp) 496 if (!arg || *arg == '\0')
497 fatal("%.200s line %d: Missing argument.", filename, linenum); 497 fatal("%.200s line %d: Missing argument.", filename, linenum);
498 value = proto_spec(cp); 498 value = proto_spec(arg);
499 if (value == SSH_PROTO_UNKNOWN) 499 if (value == SSH_PROTO_UNKNOWN)
500 fatal("%.200s line %d: Bad protocol spec '%s'.", 500 fatal("%.200s line %d: Bad protocol spec '%s'.",
501 filename, linenum, cp ? cp : "<NONE>"); 501 filename, linenum, arg ? arg : "<NONE>");
502 if (*activep && *intptr == SSH_PROTO_UNKNOWN) 502 if (*activep && *intptr == SSH_PROTO_UNKNOWN)
503 *intptr = value; 503 *intptr = value;
504 break; 504 break;
505 505
506 case oLogLevel: 506 case oLogLevel:
507 intptr = (int *) &options->log_level; 507 intptr = (int *) &options->log_level;
508 cp = strtok(NULL, WHITESPACE); 508 arg = strsep(&s, WHITESPACE);
509 value = log_level_number(cp); 509 value = log_level_number(arg);
510 if (value == (LogLevel) - 1) 510 if (value == (LogLevel) - 1)
511 fatal("%.200s line %d: unsupported log level '%s'\n", 511 fatal("%.200s line %d: unsupported log level '%s'\n",
512 filename, linenum, cp ? cp : "<NONE>"); 512 filename, linenum, arg ? arg : "<NONE>");
513 if (*activep && (LogLevel) * intptr == -1) 513 if (*activep && (LogLevel) * intptr == -1)
514 *intptr = (LogLevel) value; 514 *intptr = (LogLevel) value;
515 break; 515 break;
516 516
517 case oRemoteForward: 517 case oRemoteForward:
518 cp = strtok(NULL, WHITESPACE); 518 arg = strsep(&s, WHITESPACE);
519 if (!cp) 519 if (!arg || *arg == '\0')
520 fatal("%.200s line %d: Missing argument.", filename, linenum); 520 fatal("%.200s line %d: Missing argument.", filename, linenum);
521 if (cp[0] < '0' || cp[0] > '9') 521 if (arg[0] < '0' || arg[0] > '9')
522 fatal("%.200s line %d: Badly formatted port number.", 522 fatal("%.200s line %d: Badly formatted port number.",
523 filename, linenum); 523 filename, linenum);
524 fwd_port = atoi(cp); 524 fwd_port = atoi(arg);
525 cp = strtok(NULL, WHITESPACE); 525 arg = strsep(&s, WHITESPACE);
526 if (!cp) 526 if (!arg || *arg == '\0')
527 fatal("%.200s line %d: Missing second argument.", 527 fatal("%.200s line %d: Missing second argument.",
528 filename, linenum); 528 filename, linenum);
529 if (sscanf(cp, "%255[^:]:%hu", buf, &fwd_host_port) != 2) 529 if (sscanf(arg, "%255[^:]:%hu", buf, &fwd_host_port) != 2)
530 fatal("%.200s line %d: Badly formatted host:port.", 530 fatal("%.200s line %d: Badly formatted host:port.",
531 filename, linenum); 531 filename, linenum);
532 if (*activep) 532 if (*activep)
@@ -534,18 +534,18 @@ parse_int:
534 break; 534 break;
535 535
536 case oLocalForward: 536 case oLocalForward:
537 cp = strtok(NULL, WHITESPACE); 537 arg = strsep(&s, WHITESPACE);
538 if (!cp) 538 if (!arg || *arg == '\0')
539 fatal("%.200s line %d: Missing argument.", filename, linenum); 539 fatal("%.200s line %d: Missing argument.", filename, linenum);
540 if (cp[0] < '0' || cp[0] > '9') 540 if (arg[0] < '0' || arg[0] > '9')
541 fatal("%.200s line %d: Badly formatted port number.", 541 fatal("%.200s line %d: Badly formatted port number.",
542 filename, linenum); 542 filename, linenum);
543 fwd_port = atoi(cp); 543 fwd_port = atoi(arg);
544 cp = strtok(NULL, WHITESPACE); 544 arg = strsep(&s, WHITESPACE);
545 if (!cp) 545 if (!arg || *arg == '\0')
546 fatal("%.200s line %d: Missing second argument.", 546 fatal("%.200s line %d: Missing second argument.",
547 filename, linenum); 547 filename, linenum);
548 if (sscanf(cp, "%255[^:]:%hu", buf, &fwd_host_port) != 2) 548 if (sscanf(arg, "%255[^:]:%hu", buf, &fwd_host_port) != 2)
549 fatal("%.200s line %d: Badly formatted host:port.", 549 fatal("%.200s line %d: Badly formatted host:port.",
550 filename, linenum); 550 filename, linenum);
551 if (*activep) 551 if (*activep)
@@ -554,26 +554,26 @@ parse_int:
554 554
555 case oHost: 555 case oHost:
556 *activep = 0; 556 *activep = 0;
557 while ((cp = strtok(NULL, WHITESPACE)) != NULL) 557 while ((arg = strsep(&s, WHITESPACE)) != NULL && *arg != '\0')
558 if (match_pattern(host, cp)) { 558 if (match_pattern(host, arg)) {
559 debug("Applying options for %.100s", cp); 559 debug("Applying options for %.100s", arg);
560 *activep = 1; 560 *activep = 1;
561 break; 561 break;
562 } 562 }
563 /* Avoid garbage check below, as strtok already returned NULL. */ 563 /* Avoid garbage check below, as strsep is done. */
564 return 0; 564 return 0;
565 565
566 case oEscapeChar: 566 case oEscapeChar:
567 intptr = &options->escape_char; 567 intptr = &options->escape_char;
568 cp = strtok(NULL, WHITESPACE); 568 arg = strsep(&s, WHITESPACE);
569 if (!cp) 569 if (!arg || *arg == '\0')
570 fatal("%.200s line %d: Missing argument.", filename, linenum); 570 fatal("%.200s line %d: Missing argument.", filename, linenum);
571 if (cp[0] == '^' && cp[2] == 0 && 571 if (arg[0] == '^' && arg[2] == 0 &&
572 (unsigned char) cp[1] >= 64 && (unsigned char) cp[1] < 128) 572 (unsigned char) arg[1] >= 64 && (unsigned char) arg[1] < 128)
573 value = (unsigned char) cp[1] & 31; 573 value = (unsigned char) arg[1] & 31;
574 else if (strlen(cp) == 1) 574 else if (strlen(arg) == 1)
575 value = (unsigned char) cp[0]; 575 value = (unsigned char) arg[0];
576 else if (strcmp(cp, "none") == 0) 576 else if (strcmp(arg, "none") == 0)
577 value = -2; 577 value = -2;
578 else { 578 else {
579 fatal("%.200s line %d: Bad escape character.", 579 fatal("%.200s line %d: Bad escape character.",
@@ -590,9 +590,11 @@ parse_int:
590 } 590 }
591 591
592 /* Check that there is no garbage at end of line. */ 592 /* Check that there is no garbage at end of line. */
593 if (strtok(NULL, WHITESPACE) != NULL) 593 if ((arg = strsep(&s, WHITESPACE)) != NULL && *arg != '\0')
594 fatal("%.200s line %d: garbage at end of line.", 594 {
595 filename, linenum); 595 fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
596 filename, linenum, arg);
597 }
596 return 0; 598 return 0;
597} 599}
598 600
diff --git a/scp.1 b/scp.1
index c90943a06..d2fa546af 100644
--- a/scp.1
+++ b/scp.1
@@ -9,7 +9,7 @@
9.\" 9.\"
10.\" Created: Sun May 7 00:14:37 1995 ylo 10.\" Created: Sun May 7 00:14:37 1995 ylo
11.\" 11.\"
12.\" $Id: scp.1,v 1.7 2000/04/13 02:26:37 damien Exp $ 12.\" $Id: scp.1,v 1.8 2000/07/11 07:31:38 djm Exp $
13.\" 13.\"
14.Dd September 25, 1999 14.Dd September 25, 1999
15.Dt SCP 1 15.Dt SCP 1
@@ -106,6 +106,7 @@ to use IPv4 addresses only.
106Forces 106Forces
107.Nm 107.Nm
108to use IPv6 addresses only. 108to use IPv6 addresses only.
109.El
109.Sh AUTHORS 110.Sh AUTHORS
110Timo Rinne <tri@iki.fi> and Tatu Ylonen <ylo@cs.hut.fi> 111Timo Rinne <tri@iki.fi> and Tatu Ylonen <ylo@cs.hut.fi>
111.Sh HISTORY 112.Sh HISTORY
diff --git a/servconf.c b/servconf.c
index 12cc15260..77ac84527 100644
--- a/servconf.c
+++ b/servconf.c
@@ -12,7 +12,7 @@
12 */ 12 */
13 13
14#include "includes.h" 14#include "includes.h"
15RCSID("$OpenBSD: servconf.c,v 1.45 2000/06/20 01:39:44 markus Exp $"); 15RCSID("$OpenBSD: servconf.c,v 1.47 2000/07/10 16:30:25 ho Exp $");
16 16
17#include "ssh.h" 17#include "ssh.h"
18#include "servconf.h" 18#include "servconf.h"
@@ -76,6 +76,7 @@ initialize_server_options(ServerOptions *options)
76 options->protocol = SSH_PROTO_UNKNOWN; 76 options->protocol = SSH_PROTO_UNKNOWN;
77 options->gateway_ports = -1; 77 options->gateway_ports = -1;
78 options->num_subsystems = 0; 78 options->num_subsystems = 0;
79 options->max_startups = -1;
79} 80}
80 81
81void 82void
@@ -159,6 +160,8 @@ fill_default_server_options(ServerOptions *options)
159 options->protocol = SSH_PROTO_1|SSH_PROTO_2; 160 options->protocol = SSH_PROTO_1|SSH_PROTO_2;
160 if (options->gateway_ports == -1) 161 if (options->gateway_ports == -1)
161 options->gateway_ports = 0; 162 options->gateway_ports = 0;
163 if (options->max_startups == -1)
164 options->max_startups = 10;
162} 165}
163 166
164#define WHITESPACE " \t\r\n=" 167#define WHITESPACE " \t\r\n="
@@ -183,7 +186,7 @@ typedef enum {
183 sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail, 186 sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail,
184 sUseLogin, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups, 187 sUseLogin, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
185 sIgnoreUserKnownHosts, sHostDSAKeyFile, sCiphers, sProtocol, sPidFile, 188 sIgnoreUserKnownHosts, sHostDSAKeyFile, sCiphers, sProtocol, sPidFile,
186 sGatewayPorts, sDSAAuthentication, sXAuthLocation, sSubsystem 189 sGatewayPorts, sDSAAuthentication, sXAuthLocation, sSubsystem, sMaxStartups
187} ServerOpCodes; 190} ServerOpCodes;
188 191
189/* Textual representation of the tokens. */ 192/* Textual representation of the tokens. */
@@ -239,6 +242,7 @@ static struct {
239 { "protocol", sProtocol }, 242 { "protocol", sProtocol },
240 { "gatewayports", sGatewayPorts }, 243 { "gatewayports", sGatewayPorts },
241 { "subsystem", sSubsystem }, 244 { "subsystem", sSubsystem },
245 { "maxstartups", sMaxStartups },
242 { NULL, 0 } 246 { NULL, 0 }
243}; 247};
244 248
@@ -300,7 +304,7 @@ read_server_config(ServerOptions *options, const char *filename)
300{ 304{
301 FILE *f; 305 FILE *f;
302 char line[1024]; 306 char line[1024];
303 char *cp, **charptr; 307 char *cp, **charptr, *arg;
304 int linenum, *intptr, value; 308 int linenum, *intptr, value;
305 int bad_options = 0; 309 int bad_options = 0;
306 ServerOpCodes opcode; 310 ServerOpCodes opcode;
@@ -317,8 +321,8 @@ read_server_config(ServerOptions *options, const char *filename)
317 cp = line + strspn(line, WHITESPACE); 321 cp = line + strspn(line, WHITESPACE);
318 if (!*cp || *cp == '#') 322 if (!*cp || *cp == '#')
319 continue; 323 continue;
320 cp = strtok(cp, WHITESPACE); 324 arg = strsep(&cp, WHITESPACE);
321 opcode = parse_token(cp, filename, linenum); 325 opcode = parse_token(arg, filename, linenum);
322 switch (opcode) { 326 switch (opcode) {
323 case sBadOption: 327 case sBadOption:
324 bad_options++; 328 bad_options++;
@@ -333,23 +337,23 @@ read_server_config(ServerOptions *options, const char *filename)
333 if (options->num_ports >= MAX_PORTS) 337 if (options->num_ports >= MAX_PORTS)
334 fatal("%s line %d: too many ports.\n", 338 fatal("%s line %d: too many ports.\n",
335 filename, linenum); 339 filename, linenum);
336 cp = strtok(NULL, WHITESPACE); 340 arg = strsep(&cp, WHITESPACE);
337 if (!cp) 341 if (!arg || *arg == '\0')
338 fatal("%s line %d: missing port number.\n", 342 fatal("%s line %d: missing port number.\n",
339 filename, linenum); 343 filename, linenum);
340 options->ports[options->num_ports++] = atoi(cp); 344 options->ports[options->num_ports++] = atoi(arg);
341 break; 345 break;
342 346
343 case sServerKeyBits: 347 case sServerKeyBits:
344 intptr = &options->server_key_bits; 348 intptr = &options->server_key_bits;
345parse_int: 349parse_int:
346 cp = strtok(NULL, WHITESPACE); 350 arg = strsep(&cp, WHITESPACE);
347 if (!cp) { 351 if (!arg || *arg == '\0') {
348 fprintf(stderr, "%s line %d: missing integer value.\n", 352 fprintf(stderr, "%s line %d: missing integer value.\n",
349 filename, linenum); 353 filename, linenum);
350 exit(1); 354 exit(1);
351 } 355 }
352 value = atoi(cp); 356 value = atoi(arg);
353 if (*intptr == -1) 357 if (*intptr == -1)
354 *intptr = value; 358 *intptr = value;
355 break; 359 break;
@@ -363,11 +367,11 @@ parse_int:
363 goto parse_int; 367 goto parse_int;
364 368
365 case sListenAddress: 369 case sListenAddress:
366 cp = strtok(NULL, WHITESPACE); 370 arg = strsep(&cp, WHITESPACE);
367 if (!cp) 371 if (!arg || *arg == '\0')
368 fatal("%s line %d: missing inet addr.\n", 372 fatal("%s line %d: missing inet addr.\n",
369 filename, linenum); 373 filename, linenum);
370 add_listen_addr(options, cp); 374 add_listen_addr(options, arg);
371 break; 375 break;
372 376
373 case sHostKeyFile: 377 case sHostKeyFile:
@@ -375,14 +379,14 @@ parse_int:
375 charptr = (opcode == sHostKeyFile ) ? 379 charptr = (opcode == sHostKeyFile ) ?
376 &options->host_key_file : &options->host_dsa_key_file; 380 &options->host_key_file : &options->host_dsa_key_file;
377parse_filename: 381parse_filename:
378 cp = strtok(NULL, WHITESPACE); 382 arg = strsep(&cp, WHITESPACE);
379 if (!cp) { 383 if (!arg || *arg == '\0') {
380 fprintf(stderr, "%s line %d: missing file name.\n", 384 fprintf(stderr, "%s line %d: missing file name.\n",
381 filename, linenum); 385 filename, linenum);
382 exit(1); 386 exit(1);
383 } 387 }
384 if (*charptr == NULL) 388 if (*charptr == NULL)
385 *charptr = tilde_expand_filename(cp, getuid()); 389 *charptr = tilde_expand_filename(arg, getuid());
386 break; 390 break;
387 391
388 case sPidFile: 392 case sPidFile:
@@ -392,26 +396,26 @@ parse_filename:
392 case sRandomSeedFile: 396 case sRandomSeedFile:
393 fprintf(stderr, "%s line %d: \"randomseed\" option is obsolete.\n", 397 fprintf(stderr, "%s line %d: \"randomseed\" option is obsolete.\n",
394 filename, linenum); 398 filename, linenum);
395 cp = strtok(NULL, WHITESPACE); 399 arg = strsep(&cp, WHITESPACE);
396 break; 400 break;
397 401
398 case sPermitRootLogin: 402 case sPermitRootLogin:
399 intptr = &options->permit_root_login; 403 intptr = &options->permit_root_login;
400 cp = strtok(NULL, WHITESPACE); 404 arg = strsep(&cp, WHITESPACE);
401 if (!cp) { 405 if (!arg || *arg == '\0') {
402 fprintf(stderr, "%s line %d: missing yes/without-password/no argument.\n", 406 fprintf(stderr, "%s line %d: missing yes/without-password/no argument.\n",
403 filename, linenum); 407 filename, linenum);
404 exit(1); 408 exit(1);
405 } 409 }
406 if (strcmp(cp, "without-password") == 0) 410 if (strcmp(arg, "without-password") == 0)
407 value = 2; 411 value = 2;
408 else if (strcmp(cp, "yes") == 0) 412 else if (strcmp(arg, "yes") == 0)
409 value = 1; 413 value = 1;
410 else if (strcmp(cp, "no") == 0) 414 else if (strcmp(arg, "no") == 0)
411 value = 0; 415 value = 0;
412 else { 416 else {
413 fprintf(stderr, "%s line %d: Bad yes/without-password/no argument: %s\n", 417 fprintf(stderr, "%s line %d: Bad yes/without-password/no argument: %s\n",
414 filename, linenum, cp); 418 filename, linenum, arg);
415 exit(1); 419 exit(1);
416 } 420 }
417 if (*intptr == -1) 421 if (*intptr == -1)
@@ -421,19 +425,19 @@ parse_filename:
421 case sIgnoreRhosts: 425 case sIgnoreRhosts:
422 intptr = &options->ignore_rhosts; 426 intptr = &options->ignore_rhosts;
423parse_flag: 427parse_flag:
424 cp = strtok(NULL, WHITESPACE); 428 arg = strsep(&cp, WHITESPACE);
425 if (!cp) { 429 if (!arg || *arg == '\0') {
426 fprintf(stderr, "%s line %d: missing yes/no argument.\n", 430 fprintf(stderr, "%s line %d: missing yes/no argument.\n",
427 filename, linenum); 431 filename, linenum);
428 exit(1); 432 exit(1);
429 } 433 }
430 if (strcmp(cp, "yes") == 0) 434 if (strcmp(arg, "yes") == 0)
431 value = 1; 435 value = 1;
432 else if (strcmp(cp, "no") == 0) 436 else if (strcmp(arg, "no") == 0)
433 value = 0; 437 value = 0;
434 else { 438 else {
435 fprintf(stderr, "%s line %d: Bad yes/no argument: %s\n", 439 fprintf(stderr, "%s line %d: Bad yes/no argument: %s\n",
436 filename, linenum, cp); 440 filename, linenum, arg);
437 exit(1); 441 exit(1);
438 } 442 }
439 if (*intptr == -1) 443 if (*intptr == -1)
@@ -536,82 +540,82 @@ parse_flag:
536 540
537 case sLogFacility: 541 case sLogFacility:
538 intptr = (int *) &options->log_facility; 542 intptr = (int *) &options->log_facility;
539 cp = strtok(NULL, WHITESPACE); 543 arg = strsep(&cp, WHITESPACE);
540 value = log_facility_number(cp); 544 value = log_facility_number(arg);
541 if (value == (SyslogFacility) - 1) 545 if (value == (SyslogFacility) - 1)
542 fatal("%.200s line %d: unsupported log facility '%s'\n", 546 fatal("%.200s line %d: unsupported log facility '%s'\n",
543 filename, linenum, cp ? cp : "<NONE>"); 547 filename, linenum, arg ? arg : "<NONE>");
544 if (*intptr == -1) 548 if (*intptr == -1)
545 *intptr = (SyslogFacility) value; 549 *intptr = (SyslogFacility) value;
546 break; 550 break;
547 551
548 case sLogLevel: 552 case sLogLevel:
549 intptr = (int *) &options->log_level; 553 intptr = (int *) &options->log_level;
550 cp = strtok(NULL, WHITESPACE); 554 arg = strsep(&cp, WHITESPACE);
551 value = log_level_number(cp); 555 value = log_level_number(arg);
552 if (value == (LogLevel) - 1) 556 if (value == (LogLevel) - 1)
553 fatal("%.200s line %d: unsupported log level '%s'\n", 557 fatal("%.200s line %d: unsupported log level '%s'\n",
554 filename, linenum, cp ? cp : "<NONE>"); 558 filename, linenum, arg ? arg : "<NONE>");
555 if (*intptr == -1) 559 if (*intptr == -1)
556 *intptr = (LogLevel) value; 560 *intptr = (LogLevel) value;
557 break; 561 break;
558 562
559 case sAllowUsers: 563 case sAllowUsers:
560 while ((cp = strtok(NULL, WHITESPACE))) { 564 while ((arg = strsep(&cp, WHITESPACE)) && *arg != '\0') {
561 if (options->num_allow_users >= MAX_ALLOW_USERS) 565 if (options->num_allow_users >= MAX_ALLOW_USERS)
562 fatal("%s line %d: too many allow users.\n", 566 fatal("%s line %d: too many allow users.\n",
563 filename, linenum); 567 filename, linenum);
564 options->allow_users[options->num_allow_users++] = xstrdup(cp); 568 options->allow_users[options->num_allow_users++] = xstrdup(arg);
565 } 569 }
566 break; 570 break;
567 571
568 case sDenyUsers: 572 case sDenyUsers:
569 while ((cp = strtok(NULL, WHITESPACE))) { 573 while ((arg = strsep(&cp, WHITESPACE)) && *arg != '\0') {
570 if (options->num_deny_users >= MAX_DENY_USERS) 574 if (options->num_deny_users >= MAX_DENY_USERS)
571 fatal( "%s line %d: too many deny users.\n", 575 fatal( "%s line %d: too many deny users.\n",
572 filename, linenum); 576 filename, linenum);
573 options->deny_users[options->num_deny_users++] = xstrdup(cp); 577 options->deny_users[options->num_deny_users++] = xstrdup(arg);
574 } 578 }
575 break; 579 break;
576 580
577 case sAllowGroups: 581 case sAllowGroups:
578 while ((cp = strtok(NULL, WHITESPACE))) { 582 while ((arg = strsep(&cp, WHITESPACE)) && *arg != '\0') {
579 if (options->num_allow_groups >= MAX_ALLOW_GROUPS) 583 if (options->num_allow_groups >= MAX_ALLOW_GROUPS)
580 fatal("%s line %d: too many allow groups.\n", 584 fatal("%s line %d: too many allow groups.\n",
581 filename, linenum); 585 filename, linenum);
582 options->allow_groups[options->num_allow_groups++] = xstrdup(cp); 586 options->allow_groups[options->num_allow_groups++] = xstrdup(arg);
583 } 587 }
584 break; 588 break;
585 589
586 case sDenyGroups: 590 case sDenyGroups:
587 while ((cp = strtok(NULL, WHITESPACE))) { 591 while ((arg = strsep(&cp, WHITESPACE)) && *arg != '\0') {
588 if (options->num_deny_groups >= MAX_DENY_GROUPS) 592 if (options->num_deny_groups >= MAX_DENY_GROUPS)
589 fatal("%s line %d: too many deny groups.\n", 593 fatal("%s line %d: too many deny groups.\n",
590 filename, linenum); 594 filename, linenum);
591 options->deny_groups[options->num_deny_groups++] = xstrdup(cp); 595 options->deny_groups[options->num_deny_groups++] = xstrdup(arg);
592 } 596 }
593 break; 597 break;
594 598
595 case sCiphers: 599 case sCiphers:
596 cp = strtok(NULL, WHITESPACE); 600 arg = strsep(&cp, WHITESPACE);
597 if (!cp) 601 if (!arg || *arg == '\0')
598 fatal("%s line %d: Missing argument.", filename, linenum); 602 fatal("%s line %d: Missing argument.", filename, linenum);
599 if (!ciphers_valid(cp)) 603 if (!ciphers_valid(arg))
600 fatal("%s line %d: Bad SSH2 cipher spec '%s'.", 604 fatal("%s line %d: Bad SSH2 cipher spec '%s'.",
601 filename, linenum, cp ? cp : "<NONE>"); 605 filename, linenum, arg ? arg : "<NONE>");
602 if (options->ciphers == NULL) 606 if (options->ciphers == NULL)
603 options->ciphers = xstrdup(cp); 607 options->ciphers = xstrdup(arg);
604 break; 608 break;
605 609
606 case sProtocol: 610 case sProtocol:
607 intptr = &options->protocol; 611 intptr = &options->protocol;
608 cp = strtok(NULL, WHITESPACE); 612 arg = strsep(&cp, WHITESPACE);
609 if (!cp) 613 if (!arg || *arg == '\0')
610 fatal("%s line %d: Missing argument.", filename, linenum); 614 fatal("%s line %d: Missing argument.", filename, linenum);
611 value = proto_spec(cp); 615 value = proto_spec(arg);
612 if (value == SSH_PROTO_UNKNOWN) 616 if (value == SSH_PROTO_UNKNOWN)
613 fatal("%s line %d: Bad protocol spec '%s'.", 617 fatal("%s line %d: Bad protocol spec '%s'.",
614 filename, linenum, cp ? cp : "<NONE>"); 618 filename, linenum, arg ? arg : "<NONE>");
615 if (*intptr == SSH_PROTO_UNKNOWN) 619 if (*intptr == SSH_PROTO_UNKNOWN)
616 *intptr = value; 620 *intptr = value;
617 break; 621 break;
@@ -621,31 +625,36 @@ parse_flag:
621 fatal("%s line %d: too many subsystems defined.", 625 fatal("%s line %d: too many subsystems defined.",
622 filename, linenum); 626 filename, linenum);
623 } 627 }
624 cp = strtok(NULL, WHITESPACE); 628 arg = strsep(&cp, WHITESPACE);
625 if (!cp) 629 if (!arg || *arg == '\0')
626 fatal("%s line %d: Missing subsystem name.", 630 fatal("%s line %d: Missing subsystem name.",
627 filename, linenum); 631 filename, linenum);
628 for (i = 0; i < options->num_subsystems; i++) 632 for (i = 0; i < options->num_subsystems; i++)
629 if(strcmp(cp, options->subsystem_name[i]) == 0) 633 if(strcmp(arg, options->subsystem_name[i]) == 0)
630 fatal("%s line %d: Subsystem '%s' already defined.", 634 fatal("%s line %d: Subsystem '%s' already defined.",
631 filename, linenum, cp); 635 filename, linenum, arg);
632 options->subsystem_name[options->num_subsystems] = xstrdup(cp); 636 options->subsystem_name[options->num_subsystems] = xstrdup(arg);
633 cp = strtok(NULL, WHITESPACE); 637 arg = strsep(&cp, WHITESPACE);
634 if (!cp) 638 if (!arg || *arg == '\0')
635 fatal("%s line %d: Missing subsystem command.", 639 fatal("%s line %d: Missing subsystem command.",
636 filename, linenum); 640 filename, linenum);
637 options->subsystem_command[options->num_subsystems] = xstrdup(cp); 641 options->subsystem_command[options->num_subsystems] = xstrdup(arg);
638 options->num_subsystems++; 642 options->num_subsystems++;
639 break; 643 break;
640 644
645 case sMaxStartups:
646 intptr = &options->max_startups;
647 goto parse_int;
648
641 default: 649 default:
642 fprintf(stderr, "%s line %d: Missing handler for opcode %s (%d)\n", 650 fprintf(stderr, "%s line %d: Missing handler for opcode %s (%d)\n",
643 filename, linenum, cp, opcode); 651 filename, linenum, arg, opcode);
644 exit(1); 652 exit(1);
645 } 653 }
646 if (strtok(NULL, WHITESPACE) != NULL) { 654 if ((arg = strsep(&cp, WHITESPACE)) != NULL && *arg != '\0') {
647 fprintf(stderr, "%s line %d: garbage at end of line.\n", 655 fprintf(stderr,
648 filename, linenum); 656 "%s line %d: garbage at end of line; \"%.200s\".\n",
657 filename, linenum, arg);
649 exit(1); 658 exit(1);
650 } 659 }
651 } 660 }
diff --git a/servconf.h b/servconf.h
index c698bc74e..95593722d 100644
--- a/servconf.h
+++ b/servconf.h
@@ -13,7 +13,7 @@
13 * 13 *
14 */ 14 */
15 15
16/* RCSID("$OpenBSD: servconf.h,v 1.25 2000/06/20 01:39:44 markus Exp $"); */ 16/* RCSID("$OpenBSD: servconf.h,v 1.26 2000/06/26 21:59:18 markus Exp $"); */
17 17
18#ifndef SERVCONF_H 18#ifndef SERVCONF_H
19#define SERVCONF_H 19#define SERVCONF_H
@@ -99,6 +99,9 @@ typedef struct {
99 unsigned int num_subsystems; 99 unsigned int num_subsystems;
100 char *subsystem_name[MAX_SUBSYSTEMS]; 100 char *subsystem_name[MAX_SUBSYSTEMS];
101 char *subsystem_command[MAX_SUBSYSTEMS]; 101 char *subsystem_command[MAX_SUBSYSTEMS];
102
103 int max_startups;
104
102} ServerOptions; 105} ServerOptions;
103/* 106/*
104 * Initializes the server options to special values that indicate that they 107 * 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)
722 originator, originator_port, target, target_port); 722 originator, originator_port, target, target_port);
723 723
724 /* XXX check permission */ 724 /* XXX check permission */
725 if (! no_port_forwarding_flag) { 725 if (no_port_forwarding_flag) {
726 xfree(target); 726 xfree(target);
727 xfree(originator); 727 xfree(originator);
728 return -1; 728 return -1;
diff --git a/session.c b/session.c
index 7fe2b47f4..96a2d3b52 100644
--- a/session.c
+++ b/session.c
@@ -8,10 +8,7 @@
8 */ 8 */
9 9
10#include "includes.h" 10#include "includes.h"
11RCSID("$OpenBSD: session.c,v 1.20 2000/06/18 04:42:54 markus Exp $"); 11RCSID("$OpenBSD: session.c,v 1.22 2000/07/05 20:18:07 deraadt Exp $");
12#if defined(HAVE_USERSEC_H)
13#include <usersec.h>
14#endif
15 12
16#include "xmalloc.h" 13#include "xmalloc.h"
17#include "ssh.h" 14#include "ssh.h"
@@ -35,6 +32,10 @@ RCSID("$OpenBSD: session.c,v 1.20 2000/06/18 04:42:54 markus Exp $");
35#include <proj.h> 32#include <proj.h>
36#endif /* WITH_IRIX_PROJECT */ 33#endif /* WITH_IRIX_PROJECT */
37 34
35#if defined(HAVE_USERSEC_H)
36#include <usersec.h>
37#endif
38
38#ifdef HAVE_OSF_SIA 39#ifdef HAVE_OSF_SIA
39# include <sia.h> 40# include <sia.h>
40# include <siad.h> 41# include <siad.h>
@@ -90,6 +91,8 @@ static const char *__progname = "sshd";
90extern int log_stderr; 91extern int log_stderr;
91extern int debug_flag; 92extern int debug_flag;
92 93
94extern int startup_pipe;
95
93/* Local Xauthority file. */ 96/* Local Xauthority file. */
94static char *xauthfile; 97static char *xauthfile;
95 98
@@ -166,6 +169,7 @@ do_authenticated(struct passwd * pw)
166 * authentication. 169 * authentication.
167 */ 170 */
168 alarm(0); 171 alarm(0);
172 close(startup_pipe);
169 173
170 /* 174 /*
171 * Inform the channel mechanism that we are the server side and that 175 * Inform the channel mechanism that we are the server side and that
@@ -1457,7 +1461,7 @@ session_subsystem_req(Session *s)
1457int 1461int
1458session_x11_req(Session *s) 1462session_x11_req(Session *s)
1459{ 1463{
1460 if (!no_port_forwarding_flag) { 1464 if (no_x11_forwarding_flag) {
1461 debug("X11 forwarding disabled in user configuration file."); 1465 debug("X11 forwarding disabled in user configuration file.");
1462 return 0; 1466 return 0;
1463 } 1467 }
@@ -1788,6 +1792,7 @@ do_authenticated2(void)
1788 * authentication. 1792 * authentication.
1789 */ 1793 */
1790 alarm(0); 1794 alarm(0);
1795 close(startup_pipe);
1791 server_loop2(); 1796 server_loop2();
1792 if (xauthfile) 1797 if (xauthfile)
1793 xauthfile_cleanup_proc(NULL); 1798 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 @@
1.\" $OpenBSD: ssh-agent.1,v 1.12 2000/05/03 18:04:39 markus Exp $ 1.\" $OpenBSD: ssh-agent.1,v 1.13 2000/07/06 04:06:56 aaron Exp $
2.\" 2.\"
3.\" -*- nroff -*- 3.\" -*- nroff -*-
4.\" 4.\"
@@ -133,6 +133,7 @@ Unix-domain sockets used to contain the connection to the
133authentication agent. 133authentication agent.
134These sockets should only be readable by the owner. 134These sockets should only be readable by the owner.
135The sockets should get automatically removed when the agent exits. 135The sockets should get automatically removed when the agent exits.
136.El
136.Sh AUTHOR 137.Sh AUTHOR
137Tatu Ylonen <ylo@cs.hut.fi> 138Tatu Ylonen <ylo@cs.hut.fi>
138.Pp 139.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 @@
9.\" 9.\"
10.\" Created: Sat Apr 22 23:55:14 1995 ylo 10.\" Created: Sat Apr 22 23:55:14 1995 ylo
11.\" 11.\"
12.\" $Id: ssh-keygen.1,v 1.15 2000/05/09 01:03:02 damien Exp $ 12.\" $Id: ssh-keygen.1,v 1.16 2000/07/11 07:31:38 djm Exp $
13.\" 13.\"
14.Dd September 25, 1999 14.Dd September 25, 1999
15.Dt SSH-KEYGEN 1 15.Dt SSH-KEYGEN 1
@@ -188,6 +188,7 @@ The contents of this file should be added to
188on all machines 188on all machines
189where you wish to log in using DSA authentication. 189where you wish to log in using DSA authentication.
190There is no need to keep the contents of this file secret. 190There is no need to keep the contents of this file secret.
191.El
191.Sh AUTHOR 192.Sh AUTHOR
192Tatu Ylonen <ylo@cs.hut.fi> 193Tatu Ylonen <ylo@cs.hut.fi>
193.Pp 194.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 @@
7 */ 7 */
8 8
9#include "includes.h" 9#include "includes.h"
10RCSID("$OpenBSD: ssh-keygen.c,v 1.27 2000/06/20 01:39:44 markus Exp $"); 10RCSID("$OpenBSD: ssh-keygen.c,v 1.28 2000/07/07 03:55:04 todd Exp $");
11 11
12#include <openssl/evp.h> 12#include <openssl/evp.h>
13#include <openssl/pem.h> 13#include <openssl/pem.h>
@@ -127,13 +127,13 @@ do_convert_to_ssh2(struct passwd *pw)
127 exit(1); 127 exit(1);
128 } 128 }
129 dsa_make_key_blob(k, &blob, &len); 129 dsa_make_key_blob(k, &blob, &len);
130 fprintf(stdout, SSH_COM_MAGIC_BEGIN "\n"); 130 fprintf(stdout, "%s\n", SSH_COM_MAGIC_BEGIN);
131 fprintf(stdout, 131 fprintf(stdout,
132 "Comment: \"%d-bit DSA, converted from openssh by %s@%s\"\n", 132 "Comment: \"%d-bit DSA, converted from openssh by %s@%s\"\n",
133 BN_num_bits(k->dsa->p), 133 BN_num_bits(k->dsa->p),
134 pw->pw_name, hostname); 134 pw->pw_name, hostname);
135 dump_base64(stdout, blob, len); 135 dump_base64(stdout, blob, len);
136 fprintf(stdout, SSH_COM_MAGIC_END "\n"); 136 fprintf(stdout, "%s\n", SSH_COM_MAGIC_END);
137 key_free(k); 137 key_free(k);
138 xfree(blob); 138 xfree(blob);
139 exit(0); 139 exit(0);
diff --git a/sshd.8 b/sshd.8
index b71378c1e..b6aefe491 100644
--- a/sshd.8
+++ b/sshd.8
@@ -9,7 +9,7 @@
9.\" 9.\"
10.\" Created: Sat Apr 22 21:55:14 1995 ylo 10.\" Created: Sat Apr 22 21:55:14 1995 ylo
11.\" 11.\"
12.\" $Id: sshd.8,v 1.24 2000/06/18 04:50:45 djm Exp $ 12.\" $Id: sshd.8,v 1.25 2000/07/11 07:31:39 djm Exp $
13.\" 13.\"
14.Dd September 25, 1999 14.Dd September 25, 1999
15.Dt SSHD 8 15.Dt SSHD 8
@@ -435,6 +435,14 @@ QUIET, FATAL, ERROR, INFO, VERBOSE and DEBUG.
435The default is INFO. 435The default is INFO.
436Logging with level DEBUG violates the privacy of users 436Logging with level DEBUG violates the privacy of users
437and is not recommended. 437and is not recommended.
438.It Cm MaxStartups
439Specifies the maximum number of concurrent unauthenticated connections to the
440.Nm
441daemon.
442Additional connections will be dropped until authentication succeeds or the
443.Cm LoginGraceTime
444expires for a connection.
445The default is 10.
438.It Cm PasswordAuthentication 446.It Cm PasswordAuthentication
439Specifies whether password authentication is allowed. 447Specifies whether password authentication is allowed.
440The default is 448The default is
@@ -954,6 +962,7 @@ Like
954This can be used to specify 962This can be used to specify
955machine-specific login-time initializations globally. 963machine-specific login-time initializations globally.
956This file should be writable only by root, and should be world-readable. 964This file should be writable only by root, and should be world-readable.
965.El
957.Sh AUTHOR 966.Sh AUTHOR
958OpenSSH 967OpenSSH
959is a derivative of the original (free) ssh 1.2.12 release by Tatu Ylonen, 968is 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 @@
14 */ 14 */
15 15
16#include "includes.h" 16#include "includes.h"
17RCSID("$OpenBSD: sshd.c,v 1.119 2000/06/22 16:32:27 markus Exp $"); 17RCSID("$OpenBSD: sshd.c,v 1.121 2000/07/05 21:35:56 provos Exp $");
18 18
19#include "xmalloc.h" 19#include "xmalloc.h"
20#include "rsa.h" 20#include "rsa.h"
@@ -350,7 +350,7 @@ sshd_exchange_identification(int sock_in, int sock_out)
350 break; 350 break;
351 } 351 }
352 if (remote_minor < 3) { 352 if (remote_minor < 3) {
353 packet_disconnect("Your ssh version is too old and" 353 packet_disconnect("Your ssh version is too old and "
354 "is no longer supported. Please install a newer version."); 354 "is no longer supported. Please install a newer version.");
355 } else if (remote_minor == 3) { 355 } else if (remote_minor == 3) {
356 /* note that this disables agent-forwarding */ 356 /* note that this disables agent-forwarding */
@@ -400,6 +400,9 @@ destroy_sensitive_data(void)
400 key_free(sensitive_data.dsa_host_key); 400 key_free(sensitive_data.dsa_host_key);
401} 401}
402 402
403int *startup_pipes = NULL; /* options.max_startup sized array of fd ints */
404int startup_pipe; /* in child */
405
403/* 406/*
404 * Main program for the daemon. 407 * Main program for the daemon.
405 */ 408 */
@@ -408,7 +411,7 @@ main(int ac, char **av)
408{ 411{
409 extern char *optarg; 412 extern char *optarg;
410 extern int optind; 413 extern int optind;
411 int opt, sock_in = 0, sock_out = 0, newsock, i, fdsetsz, on = 1; 414 int opt, sock_in = 0, sock_out = 0, newsock, j, i, fdsetsz, on = 1;
412 pid_t pid; 415 pid_t pid;
413 socklen_t fromlen; 416 socklen_t fromlen;
414 int silent = 0; 417 int silent = 0;
@@ -421,6 +424,8 @@ main(int ac, char **av)
421 struct addrinfo *ai; 424 struct addrinfo *ai;
422 char ntop[NI_MAXHOST], strport[NI_MAXSERV]; 425 char ntop[NI_MAXHOST], strport[NI_MAXSERV];
423 int listen_sock, maxfd; 426 int listen_sock, maxfd;
427 int startup_p[2];
428 int startups = 0;
424 429
425 init_rng(); 430 init_rng();
426 431
@@ -746,6 +751,7 @@ main(int ac, char **av)
746 751
747 /* Arrange to restart on SIGHUP. The handler needs listen_sock. */ 752 /* Arrange to restart on SIGHUP. The handler needs listen_sock. */
748 signal(SIGHUP, sighup_handler); 753 signal(SIGHUP, sighup_handler);
754
749 signal(SIGTERM, sigterm_handler); 755 signal(SIGTERM, sigterm_handler);
750 signal(SIGQUIT, sigterm_handler); 756 signal(SIGQUIT, sigterm_handler);
751 757
@@ -753,12 +759,15 @@ main(int ac, char **av)
753 signal(SIGCHLD, main_sigchld_handler); 759 signal(SIGCHLD, main_sigchld_handler);
754 760
755 /* setup fd set for listen */ 761 /* setup fd set for listen */
762 fdset = NULL;
756 maxfd = 0; 763 maxfd = 0;
757 for (i = 0; i < num_listen_socks; i++) 764 for (i = 0; i < num_listen_socks; i++)
758 if (listen_socks[i] > maxfd) 765 if (listen_socks[i] > maxfd)
759 maxfd = listen_socks[i]; 766 maxfd = listen_socks[i];
760 fdsetsz = howmany(maxfd, NFDBITS) * sizeof(fd_mask); 767 /* pipes connected to unauthenticated childs */
761 fdset = (fd_set *)xmalloc(fdsetsz); 768 startup_pipes = xmalloc(options.max_startups * sizeof(int));
769 for (i = 0; i < options.max_startups; i++)
770 startup_pipes[i] = -1;
762 771
763 /* 772 /*
764 * Stay listening for connections until the system crashes or 773 * Stay listening for connections until the system crashes or
@@ -767,80 +776,128 @@ main(int ac, char **av)
767 for (;;) { 776 for (;;) {
768 if (received_sighup) 777 if (received_sighup)
769 sighup_restart(); 778 sighup_restart();
770 /* Wait in select until there is a connection. */ 779 if (fdset != NULL)
780 xfree(fdset);
781 fdsetsz = howmany(maxfd, NFDBITS) * sizeof(fd_mask);
782 fdset = (fd_set *)xmalloc(fdsetsz);
771 memset(fdset, 0, fdsetsz); 783 memset(fdset, 0, fdsetsz);
784
772 for (i = 0; i < num_listen_socks; i++) 785 for (i = 0; i < num_listen_socks; i++)
773 FD_SET(listen_socks[i], fdset); 786 FD_SET(listen_socks[i], fdset);
787 for (i = 0; i < options.max_startups; i++)
788 if (startup_pipes[i] != -1)
789 FD_SET(startup_pipes[i], fdset);
790
791 /* Wait in select until there is a connection. */
774 if (select(maxfd + 1, fdset, NULL, NULL, NULL) < 0) { 792 if (select(maxfd + 1, fdset, NULL, NULL, NULL) < 0) {
775 if (errno != EINTR) 793 if (errno != EINTR)
776 error("select: %.100s", strerror(errno)); 794 error("select: %.100s", strerror(errno));
777 continue; 795 continue;
778 } 796 }
797 for (i = 0; i < options.max_startups; i++)
798 if (startup_pipes[i] != -1 &&
799 FD_ISSET(startup_pipes[i], fdset)) {
800 /*
801 * the read end of the pipe is ready
802 * if the child has closed the pipe
803 * after successfull authentication
804 * or if the child has died
805 */
806 close(startup_pipes[i]);
807 startup_pipes[i] = -1;
808 startups--;
809 }
779 for (i = 0; i < num_listen_socks; i++) { 810 for (i = 0; i < num_listen_socks; i++) {
780 if (!FD_ISSET(listen_socks[i], fdset)) 811 if (!FD_ISSET(listen_socks[i], fdset))
781 continue; 812 continue;
782 fromlen = sizeof(from); 813 fromlen = sizeof(from);
783 newsock = accept(listen_socks[i], (struct sockaddr *)&from, 814 newsock = accept(listen_socks[i], (struct sockaddr *)&from,
784 &fromlen); 815 &fromlen);
785 if (newsock < 0) { 816 if (newsock < 0) {
786 if (errno != EINTR && errno != EWOULDBLOCK) 817 if (errno != EINTR && errno != EWOULDBLOCK)
787 error("accept: %.100s", strerror(errno)); 818 error("accept: %.100s", strerror(errno));
788 continue; 819 continue;
789 } 820 }
790 if (fcntl(newsock, F_SETFL, 0) < 0) { 821 if (fcntl(newsock, F_SETFL, 0) < 0) {
791 error("newsock del O_NONBLOCK: %s", strerror(errno)); 822 error("newsock del O_NONBLOCK: %s", strerror(errno));
792 continue; 823 continue;
793 } 824 }
794 /* 825 if (startups >= options.max_startups) {
795 * Got connection. Fork a child to handle it, unless 826 close(newsock);
796 * we are in debugging mode. 827 continue;
797 */ 828 }
798 if (debug_flag) { 829 if (pipe(startup_p) == -1) {
799 /* 830 close(newsock);
800 * In debugging mode. Close the listening 831 continue;
801 * socket, and start processing the 832 }
802 * connection without forking. 833
803 */ 834 for (j = 0; j < options.max_startups; j++)
804 debug("Server will not fork when running in debugging mode."); 835 if (startup_pipes[j] == -1) {
805 close_listen_socks(); 836 startup_pipes[j] = startup_p[0];
806 sock_in = newsock; 837 if (maxfd < startup_p[0])
807 sock_out = newsock; 838 maxfd = startup_p[0];
808 pid = getpid(); 839 startups++;
809 break; 840 break;
810 } else { 841 }
842
811 /* 843 /*
812 * Normal production daemon. Fork, and have 844 * Got connection. Fork a child to handle it, unless
813 * the child process the connection. The 845 * we are in debugging mode.
814 * parent continues listening.
815 */ 846 */
816 if ((pid = fork()) == 0) { 847 if (debug_flag) {
817 /* 848 /*
818 * Child. Close the listening socket, and start using the 849 * In debugging mode. Close the listening
819 * accepted socket. Reinitialize logging (since our pid has 850 * socket, and start processing the
820 * changed). We break out of the loop to handle the connection. 851 * connection without forking.
821 */ 852 */
853 debug("Server will not fork when running in debugging mode.");
822 close_listen_socks(); 854 close_listen_socks();
823 sock_in = newsock; 855 sock_in = newsock;
824 sock_out = newsock; 856 sock_out = newsock;
825 log_init(av0, options.log_level, options.log_facility, log_stderr); 857 pid = getpid();
826 break; 858 break;
859 } else {
860 /*
861 * Normal production daemon. Fork, and have
862 * the child process the connection. The
863 * parent continues listening.
864 */
865 if ((pid = fork()) == 0) {
866 /*
867 * Child. Close the listening and max_startup
868 * sockets. Start using the accepted socket.
869 * Reinitialize logging (since our pid has
870 * changed). We break out of the loop to handle
871 * the connection.
872 */
873 startup_pipe = startup_p[1];
874 for (j = 0; j < options.max_startups; j++)
875 if (startup_pipes[j] != -1)
876 close(startup_pipes[j]);
877 close_listen_socks();
878 sock_in = newsock;
879 sock_out = newsock;
880 log_init(av0, options.log_level, options.log_facility, log_stderr);
881 break;
882 }
827 } 883 }
828 }
829 884
830 /* Parent. Stay in the loop. */ 885 /* Parent. Stay in the loop. */
831 if (pid < 0) 886 if (pid < 0)
832 error("fork: %.100s", strerror(errno)); 887 error("fork: %.100s", strerror(errno));
833 else 888 else
834 debug("Forked child %d.", pid); 889 debug("Forked child %d.", pid);
835 890
836 /* Mark that the key has been used (it was "given" to the child). */ 891 close(startup_p[1]);
837 key_used = 1;
838 892
839 arc4random_stir(); 893 /* Mark that the key has been used (it was "given" to the child). */
894 key_used = 1;
840 895
841 /* Close the new socket (the child is now taking care of it). */ 896 arc4random_stir();
842 close(newsock); 897
843 } /* for (i = 0; i < num_listen_socks; i++) */ 898 /* Close the new socket (the child is now taking care of it). */
899 close(newsock);
900 }
844 /* child process check (or debug mode) */ 901 /* child process check (or debug mode) */
845 if (num_listen_socks < 0) 902 if (num_listen_socks < 0)
846 break; 903 break;