xref: /freebsd/crypto/openssh/servconf.c (revision b601c69bdbe8755d26570261d7fd4c02ee4eff74)
1 /*
2  *
3  * servconf.c
4  *
5  * Author: Tatu Ylonen <ylo@cs.hut.fi>
6  *
7  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8  *                    All rights reserved
9  *
10  * Created: Mon Aug 21 15:48:58 1995 ylo
11  *
12  * $FreeBSD$
13  */
14 
15 #include "includes.h"
16 RCSID("$Id: servconf.c,v 1.41 2000/05/22 18:42:01 markus Exp $");
17 
18 #include "ssh.h"
19 #include "servconf.h"
20 #include "xmalloc.h"
21 #include "compat.h"
22 
23 /* add listen address */
24 void add_listen_addr(ServerOptions *options, char *addr);
25 
26 /* Initializes the server options to their default values. */
27 
28 void
29 initialize_server_options(ServerOptions *options)
30 {
31 	memset(options, 0, sizeof(*options));
32 	options->num_ports = 0;
33 	options->ports_from_cmdline = 0;
34 	options->listen_addrs = NULL;
35 	options->host_key_file = NULL;
36 	options->host_dsa_key_file = NULL;
37 	options->pid_file = NULL;
38 	options->server_key_bits = -1;
39 	options->login_grace_time = -1;
40 	options->key_regeneration_time = -1;
41 	options->permit_root_login = -1;
42 	options->ignore_rhosts = -1;
43 	options->ignore_user_known_hosts = -1;
44 	options->print_motd = -1;
45 	options->check_mail = -1;
46 	options->x11_forwarding = -1;
47 	options->x11_display_offset = -1;
48 	options->strict_modes = -1;
49 	options->keepalives = -1;
50 	options->log_facility = (SyslogFacility) - 1;
51 	options->log_level = (LogLevel) - 1;
52 	options->rhosts_authentication = -1;
53 	options->rhosts_rsa_authentication = -1;
54 	options->rsa_authentication = -1;
55 	options->dsa_authentication = -1;
56 #ifdef KRB4
57 	options->krb4_authentication = -1;
58 	options->krb4_or_local_passwd = -1;
59 	options->krb4_ticket_cleanup = -1;
60 #endif
61 #ifdef KRB5
62 	options->krb5_authentication = -1;
63 	options->krb5_tgt_passing = -1;
64 #endif /* KRB5 */
65 #ifdef AFS
66 	options->krb4_tgt_passing = -1;
67 	options->afs_token_passing = -1;
68 #endif
69 	options->password_authentication = -1;
70 #ifdef SKEY
71 	options->skey_authentication = -1;
72 #endif
73 	options->permit_empty_passwd = -1;
74 	options->use_login = -1;
75 	options->num_allow_users = 0;
76 	options->num_deny_users = 0;
77 	options->num_allow_groups = 0;
78 	options->num_deny_groups = 0;
79 	options->ciphers = NULL;
80 	options->protocol = SSH_PROTO_UNKNOWN;
81 	options->gateway_ports = -1;
82 	options->connections_per_period = 0;
83 	options->connections_period = 0;
84 }
85 
86 void
87 fill_default_server_options(ServerOptions *options)
88 {
89 	if (options->num_ports == 0)
90 		options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
91 	if (options->listen_addrs == NULL)
92 		add_listen_addr(options, NULL);
93 	if (options->host_key_file == NULL)
94 		options->host_key_file = HOST_KEY_FILE;
95 	if (options->host_dsa_key_file == NULL)
96 		options->host_dsa_key_file = HOST_DSA_KEY_FILE;
97 	if (options->pid_file == NULL)
98 		options->pid_file = SSH_DAEMON_PID_FILE;
99 	if (options->server_key_bits == -1)
100 		options->server_key_bits = 768;
101 	if (options->login_grace_time == -1)
102 		options->login_grace_time = 60;
103 	if (options->key_regeneration_time == -1)
104 		options->key_regeneration_time = 3600;
105 	if (options->permit_root_login == -1)
106 		options->permit_root_login = 0;			/* no */
107 	if (options->ignore_rhosts == -1)
108 		options->ignore_rhosts = 1;
109 	if (options->ignore_user_known_hosts == -1)
110 		options->ignore_user_known_hosts = 0;
111 	if (options->check_mail == -1)
112 		options->check_mail = 1;
113 	if (options->print_motd == -1)
114 		options->print_motd = 1;
115 	if (options->x11_forwarding == -1)
116 		options->x11_forwarding = 0;
117 	if (options->x11_display_offset == -1)
118 		options->x11_display_offset = 10;
119 	if (options->strict_modes == -1)
120 		options->strict_modes = 1;
121 	if (options->keepalives == -1)
122 		options->keepalives = 1;
123 	if (options->log_facility == (SyslogFacility) (-1))
124 		options->log_facility = SYSLOG_FACILITY_AUTH;
125 	if (options->log_level == (LogLevel) (-1))
126 		options->log_level = SYSLOG_LEVEL_INFO;
127 	if (options->rhosts_authentication == -1)
128 		options->rhosts_authentication = 0;
129 	if (options->rhosts_rsa_authentication == -1)
130 		options->rhosts_rsa_authentication = 0;
131 	if (options->rsa_authentication == -1)
132 		options->rsa_authentication = 1;
133 	if (options->dsa_authentication == -1)
134 		options->dsa_authentication = 1;
135 #ifdef KRB4
136 	if (options->krb4_authentication == -1)
137 		options->krb4_authentication = (access(KEYFILE, R_OK) == 0);
138 	if (options->krb4_or_local_passwd == -1)
139 		options->krb4_or_local_passwd = 1;
140 	if (options->krb4_ticket_cleanup == -1)
141 		options->krb4_ticket_cleanup = 1;
142 #endif /* KRB4 */
143 #ifdef KRB5
144 	if (options->krb5_authentication == -1)
145 	  	options->krb5_authentication = 1;
146 	if (options->krb5_tgt_passing == -1)
147 	  	options->krb5_tgt_passing = 1;
148 #endif /* KRB5 */
149 #ifdef AFS
150 	if (options->krb4_tgt_passing == -1)
151 		options->krb4_tgt_passing = 0;
152 	if (options->afs_token_passing == -1)
153 		options->afs_token_passing = k_hasafs();
154 #endif /* AFS */
155 	if (options->password_authentication == -1)
156 		options->password_authentication = 1;
157 #ifdef SKEY
158 	if (options->skey_authentication == -1)
159 		options->skey_authentication = 1;
160 #endif
161 	if (options->permit_empty_passwd == -1)
162 		options->permit_empty_passwd = 0;
163 	if (options->use_login == -1)
164 		options->use_login = 0;
165 	if (options->protocol == SSH_PROTO_UNKNOWN)
166 		options->protocol = SSH_PROTO_1|SSH_PROTO_2;
167 	if (options->gateway_ports == -1)
168 		options->gateway_ports = 0;
169 }
170 
171 #define WHITESPACE " \t\r\n"
172 
173 /* Keyword tokens. */
174 typedef enum {
175 	sBadOption,		/* == unknown option */
176 	sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime,
177 	sPermitRootLogin, sLogFacility, sLogLevel,
178 	sRhostsAuthentication, sRhostsRSAAuthentication, sRSAAuthentication,
179 #ifdef KRB4
180 	sKrb4Authentication, sKrb4OrLocalPasswd, sKrb4TicketCleanup,
181 #endif
182 #ifdef KRB5
183 	sKrb5Authentication, sKrb5TgtPassing,
184 #endif /* KRB5 */
185 #ifdef AFS
186 	sKrb4TgtPassing, sAFSTokenPassing,
187 #endif
188 #ifdef SKEY
189 	sSkeyAuthentication,
190 #endif
191 	sPasswordAuthentication, sListenAddress,
192 	sPrintMotd, sIgnoreRhosts, sX11Forwarding, sX11DisplayOffset,
193 	sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail,
194 	sUseLogin, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
195 	sIgnoreUserKnownHosts, sHostDSAKeyFile, sCiphers, sProtocol, sPidFile,
196 	sGatewayPorts, sDSAAuthentication, sConnectionsPerPeriod
197 } ServerOpCodes;
198 
199 /* Textual representation of the tokens. */
200 static struct {
201 	const char *name;
202 	ServerOpCodes opcode;
203 } keywords[] = {
204 	{ "port", sPort },
205 	{ "hostkey", sHostKeyFile },
206 	{ "hostdsakey", sHostDSAKeyFile },
207  	{ "pidfile", sPidFile },
208 	{ "serverkeybits", sServerKeyBits },
209 	{ "logingracetime", sLoginGraceTime },
210 	{ "keyregenerationinterval", sKeyRegenerationTime },
211 	{ "permitrootlogin", sPermitRootLogin },
212 	{ "syslogfacility", sLogFacility },
213 	{ "loglevel", sLogLevel },
214 	{ "rhostsauthentication", sRhostsAuthentication },
215 	{ "rhostsrsaauthentication", sRhostsRSAAuthentication },
216 	{ "rsaauthentication", sRSAAuthentication },
217 	{ "dsaauthentication", sDSAAuthentication },
218 #ifdef KRB4
219 	{ "kerberos4authentication", sKrb4Authentication },
220 	{ "kerberos4orlocalpasswd", sKrb4OrLocalPasswd },
221 	{ "kerberos4ticketcleanup", sKrb4TicketCleanup },
222 #endif
223 #ifdef KRB5
224 	{ "kerberos5authentication", sKrb5Authentication },
225 	{ "kerberos5tgtpassing", sKrb5TgtPassing },
226 #endif /* KRB5 */
227 #ifdef AFS
228 	{ "kerberos4tgtpassing", sKrb4TgtPassing },
229 	{ "afstokenpassing", sAFSTokenPassing },
230 #endif
231 	{ "passwordauthentication", sPasswordAuthentication },
232 #ifdef SKEY
233 	{ "skeyauthentication", sSkeyAuthentication },
234 #endif
235 	{ "checkmail", sCheckMail },
236 	{ "listenaddress", sListenAddress },
237 	{ "printmotd", sPrintMotd },
238 	{ "ignorerhosts", sIgnoreRhosts },
239 	{ "ignoreuserknownhosts", sIgnoreUserKnownHosts },
240 	{ "x11forwarding", sX11Forwarding },
241 	{ "x11displayoffset", sX11DisplayOffset },
242 	{ "strictmodes", sStrictModes },
243 	{ "permitemptypasswords", sEmptyPasswd },
244 	{ "uselogin", sUseLogin },
245 	{ "randomseed", sRandomSeedFile },
246 	{ "keepalive", sKeepAlives },
247 	{ "allowusers", sAllowUsers },
248 	{ "denyusers", sDenyUsers },
249 	{ "allowgroups", sAllowGroups },
250 	{ "denygroups", sDenyGroups },
251 	{ "ciphers", sCiphers },
252 	{ "protocol", sProtocol },
253 	{ "gatewayports", sGatewayPorts },
254 	{ "connectionsperperiod", sConnectionsPerPeriod },
255 	{ NULL, 0 }
256 };
257 
258 /*
259  * Returns the number of the token pointed to by cp of length len. Never
260  * returns if the token is not known.
261  */
262 
263 static ServerOpCodes
264 parse_token(const char *cp, const char *filename,
265 	    int linenum)
266 {
267 	unsigned int i;
268 
269 	for (i = 0; keywords[i].name; i++)
270 		if (strcasecmp(cp, keywords[i].name) == 0)
271 			return keywords[i].opcode;
272 
273 	fprintf(stderr, "%s: line %d: Bad configuration option: %s\n",
274 		filename, linenum, cp);
275 	return sBadOption;
276 }
277 
278 /*
279  * add listen address
280  */
281 void
282 add_listen_addr(ServerOptions *options, char *addr)
283 {
284 	extern int IPv4or6;
285 	struct addrinfo hints, *ai, *aitop;
286 	char strport[NI_MAXSERV];
287 	int gaierr;
288 	int i;
289 
290 	if (options->num_ports == 0)
291 		options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
292 	for (i = 0; i < options->num_ports; i++) {
293 		memset(&hints, 0, sizeof(hints));
294 		hints.ai_family = IPv4or6;
295 		hints.ai_socktype = SOCK_STREAM;
296 		hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0;
297 		snprintf(strport, sizeof strport, "%d", options->ports[i]);
298 		if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0)
299 			fatal("bad addr or host: %s (%s)\n",
300 			    addr ? addr : "<NULL>",
301 			    gai_strerror(gaierr));
302 		for (ai = aitop; ai->ai_next; ai = ai->ai_next)
303 			;
304 		ai->ai_next = options->listen_addrs;
305 		options->listen_addrs = aitop;
306 	}
307 }
308 
309 /* Reads the server configuration file. */
310 
311 void
312 read_server_config(ServerOptions *options, const char *filename)
313 {
314 	FILE *f;
315 	char line[1024];
316 	char *cp, **charptr;
317 	int linenum, *intptr, value;
318 	int bad_options = 0;
319 	ServerOpCodes opcode;
320 
321 	f = fopen(filename, "r");
322 	if (!f) {
323 		perror(filename);
324 		exit(1);
325 	}
326 	linenum = 0;
327 	while (fgets(line, sizeof(line), f)) {
328 		linenum++;
329 		cp = line + strspn(line, WHITESPACE);
330 		if (!*cp || *cp == '#')
331 			continue;
332 		cp = strtok(cp, WHITESPACE);
333 		opcode = parse_token(cp, filename, linenum);
334 		switch (opcode) {
335 		case sBadOption:
336 			bad_options++;
337 			continue;
338 		case sPort:
339 			/* ignore ports from configfile if cmdline specifies ports */
340 			if (options->ports_from_cmdline)
341 				continue;
342 			if (options->listen_addrs != NULL)
343 				fatal("%s line %d: ports must be specified before "
344 				    "ListenAdress.\n", filename, linenum);
345 			if (options->num_ports >= MAX_PORTS)
346 				fatal("%s line %d: too many ports.\n",
347 				    filename, linenum);
348 			cp = strtok(NULL, WHITESPACE);
349 			if (!cp)
350 				fatal("%s line %d: missing port number.\n",
351 				    filename, linenum);
352 			options->ports[options->num_ports++] = atoi(cp);
353 			break;
354 
355 		case sServerKeyBits:
356 			intptr = &options->server_key_bits;
357 parse_int:
358 			cp = strtok(NULL, WHITESPACE);
359 			if (!cp) {
360 				fprintf(stderr, "%s line %d: missing integer value.\n",
361 					filename, linenum);
362 				exit(1);
363 			}
364 			if (sscanf(cp, " %d ", &value) != 1) {
365 				fprintf(stderr, "%s line %d: invalid integer value.\n",
366 					filename, linenum);
367 				exit(1);
368 			}
369 			if (*intptr == -1)
370 				*intptr = value;
371 			break;
372 
373 		case sLoginGraceTime:
374 			intptr = &options->login_grace_time;
375 			goto parse_int;
376 
377 		case sKeyRegenerationTime:
378 			intptr = &options->key_regeneration_time;
379 			goto parse_int;
380 
381 		case sListenAddress:
382 			cp = strtok(NULL, WHITESPACE);
383 			if (!cp)
384 				fatal("%s line %d: missing inet addr.\n",
385 				    filename, linenum);
386 			add_listen_addr(options, cp);
387 			break;
388 
389 		case sHostKeyFile:
390 		case sHostDSAKeyFile:
391 			charptr = (opcode == sHostKeyFile ) ?
392 			    &options->host_key_file : &options->host_dsa_key_file;
393 			cp = strtok(NULL, WHITESPACE);
394 			if (!cp) {
395 				fprintf(stderr, "%s line %d: missing file name.\n",
396 				    filename, linenum);
397 				exit(1);
398 			}
399 			if (*charptr == NULL)
400 				*charptr = tilde_expand_filename(cp, getuid());
401 			break;
402 
403 		case sPidFile:
404 			charptr = &options->pid_file;
405 			cp = strtok(NULL, WHITESPACE);
406 			if (!cp) {
407 				fprintf(stderr, "%s line %d: missing file name.\n",
408 				    filename, linenum);
409 				exit(1);
410 			}
411 			if (*charptr == NULL)
412 				*charptr = tilde_expand_filename(cp, getuid());
413 			break;
414 
415 		case sRandomSeedFile:
416 			fprintf(stderr, "%s line %d: \"randomseed\" option is obsolete.\n",
417 				filename, linenum);
418 			cp = strtok(NULL, WHITESPACE);
419 			break;
420 
421 		case sPermitRootLogin:
422 			intptr = &options->permit_root_login;
423 			cp = strtok(NULL, WHITESPACE);
424 			if (!cp) {
425 				fprintf(stderr, "%s line %d: missing yes/without-password/no argument.\n",
426 					filename, linenum);
427 				exit(1);
428 			}
429 			if (strcmp(cp, "without-password") == 0)
430 				value = 2;
431 			else if (strcmp(cp, "yes") == 0)
432 				value = 1;
433 			else if (strcmp(cp, "no") == 0)
434 				value = 0;
435 			else {
436 				fprintf(stderr, "%s line %d: Bad yes/without-password/no argument: %s\n",
437 					filename, linenum, cp);
438 				exit(1);
439 			}
440 			if (*intptr == -1)
441 				*intptr = value;
442 			break;
443 
444 		case sIgnoreRhosts:
445 			intptr = &options->ignore_rhosts;
446 parse_flag:
447 			cp = strtok(NULL, WHITESPACE);
448 			if (!cp) {
449 				fprintf(stderr, "%s line %d: missing yes/no argument.\n",
450 					filename, linenum);
451 				exit(1);
452 			}
453 			if (strcmp(cp, "yes") == 0)
454 				value = 1;
455 			else if (strcmp(cp, "no") == 0)
456 				value = 0;
457 			else {
458 				fprintf(stderr, "%s line %d: Bad yes/no argument: %s\n",
459 					filename, linenum, cp);
460 				exit(1);
461 			}
462 			if (*intptr == -1)
463 				*intptr = value;
464 			break;
465 
466 		case sIgnoreUserKnownHosts:
467 			intptr = &options->ignore_user_known_hosts;
468 			goto parse_flag;
469 
470 		case sRhostsAuthentication:
471 			intptr = &options->rhosts_authentication;
472 			goto parse_flag;
473 
474 		case sRhostsRSAAuthentication:
475 			intptr = &options->rhosts_rsa_authentication;
476 			goto parse_flag;
477 
478 		case sRSAAuthentication:
479 			intptr = &options->rsa_authentication;
480 			goto parse_flag;
481 
482 		case sDSAAuthentication:
483 			intptr = &options->dsa_authentication;
484 			goto parse_flag;
485 
486 #ifdef KRB4
487 		case sKrb4Authentication:
488 			intptr = &options->krb4_authentication;
489 			goto parse_flag;
490 
491 		case sKrb4OrLocalPasswd:
492 			intptr = &options->krb4_or_local_passwd;
493 			goto parse_flag;
494 
495 		case sKrb4TicketCleanup:
496 			intptr = &options->krb4_ticket_cleanup;
497 			goto parse_flag;
498 #endif
499 
500 #ifdef KRB5
501 		case sKrb5Authentication:
502 			intptr = &options->krb5_authentication;
503 			goto parse_flag;
504 
505 		case sKrb5TgtPassing:
506 			intptr = &options->krb5_tgt_passing;
507 			goto parse_flag;
508 #endif /* KRB5 */
509 
510 #ifdef AFS
511 		case sKrb4TgtPassing:
512 			intptr = &options->krb4_tgt_passing;
513 			goto parse_flag;
514 
515 		case sAFSTokenPassing:
516 			intptr = &options->afs_token_passing;
517 			goto parse_flag;
518 #endif
519 
520 		case sPasswordAuthentication:
521 			intptr = &options->password_authentication;
522 			goto parse_flag;
523 
524 		case sCheckMail:
525 			intptr = &options->check_mail;
526 			goto parse_flag;
527 
528 #ifdef SKEY
529 		case sSkeyAuthentication:
530 			intptr = &options->skey_authentication;
531 			goto parse_flag;
532 #endif
533 
534 		case sPrintMotd:
535 			intptr = &options->print_motd;
536 			goto parse_flag;
537 
538 		case sX11Forwarding:
539 			intptr = &options->x11_forwarding;
540 			goto parse_flag;
541 
542 		case sX11DisplayOffset:
543 			intptr = &options->x11_display_offset;
544 			goto parse_int;
545 
546 		case sStrictModes:
547 			intptr = &options->strict_modes;
548 			goto parse_flag;
549 
550 		case sKeepAlives:
551 			intptr = &options->keepalives;
552 			goto parse_flag;
553 
554 		case sEmptyPasswd:
555 			intptr = &options->permit_empty_passwd;
556 			goto parse_flag;
557 
558 		case sUseLogin:
559 			intptr = &options->use_login;
560 			goto parse_flag;
561 
562 		case sGatewayPorts:
563 			intptr = &options->gateway_ports;
564 			goto parse_flag;
565 
566 		case sLogFacility:
567 			intptr = (int *) &options->log_facility;
568 			cp = strtok(NULL, WHITESPACE);
569 			value = log_facility_number(cp);
570 			if (value == (SyslogFacility) - 1)
571 				fatal("%.200s line %d: unsupported log facility '%s'\n",
572 				    filename, linenum, cp ? cp : "<NONE>");
573 			if (*intptr == -1)
574 				*intptr = (SyslogFacility) value;
575 			break;
576 
577 		case sLogLevel:
578 			intptr = (int *) &options->log_level;
579 			cp = strtok(NULL, WHITESPACE);
580 			value = log_level_number(cp);
581 			if (value == (LogLevel) - 1)
582 				fatal("%.200s line %d: unsupported log level '%s'\n",
583 				    filename, linenum, cp ? cp : "<NONE>");
584 			if (*intptr == -1)
585 				*intptr = (LogLevel) value;
586 			break;
587 
588 		case sAllowUsers:
589 			while ((cp = strtok(NULL, WHITESPACE))) {
590 				if (options->num_allow_users >= MAX_ALLOW_USERS)
591 					fatal("%.200s line %d: too many allow users.\n",
592 					    filename, linenum);
593 				options->allow_users[options->num_allow_users++] = xstrdup(cp);
594 			}
595 			break;
596 
597 		case sDenyUsers:
598 			while ((cp = strtok(NULL, WHITESPACE))) {
599 				if (options->num_deny_users >= MAX_DENY_USERS)
600 					fatal("%.200s line %d: too many deny users.\n",
601 					    filename, linenum);
602 				options->deny_users[options->num_deny_users++] = xstrdup(cp);
603 			}
604 			break;
605 
606 		case sAllowGroups:
607 			while ((cp = strtok(NULL, WHITESPACE))) {
608 				if (options->num_allow_groups >= MAX_ALLOW_GROUPS)
609 					fatal("%.200s line %d: too many allow groups.\n",
610 					    filename, linenum);
611 				options->allow_groups[options->num_allow_groups++] = xstrdup(cp);
612 			}
613 			break;
614 
615 		case sDenyGroups:
616 			while ((cp = strtok(NULL, WHITESPACE))) {
617 				if (options->num_deny_groups >= MAX_DENY_GROUPS)
618 					fatal("%.200s line %d: too many deny groups.\n",
619 					    filename, linenum);
620 				options->deny_groups[options->num_deny_groups++] = xstrdup(cp);
621 			}
622 			break;
623 
624 		case sCiphers:
625 			cp = strtok(NULL, WHITESPACE);
626 			if (!cp)
627 				fatal("%s line %d: Missing argument.", filename, linenum);
628 			if (!ciphers_valid(cp))
629 				fatal("%s line %d: Bad SSH2 cipher spec '%s'.",
630 				    filename, linenum, cp ? cp : "<NONE>");
631 			if (options->ciphers == NULL)
632 				options->ciphers = xstrdup(cp);
633 			break;
634 
635 		case sProtocol:
636 			intptr = &options->protocol;
637 			cp = strtok(NULL, WHITESPACE);
638 			if (!cp)
639 				fatal("%s line %d: Missing argument.", filename, linenum);
640 			value = proto_spec(cp);
641 			if (value == SSH_PROTO_UNKNOWN)
642 				fatal("%s line %d: Bad protocol spec '%s'.",
643 				      filename, linenum, cp ? cp : "<NONE>");
644 			if (*intptr == SSH_PROTO_UNKNOWN)
645 				*intptr = value;
646 			break;
647 
648 		case sConnectionsPerPeriod:
649 			cp = strtok(NULL, WHITESPACE);
650 			if (cp == NULL)
651 				fatal("%.200s line %d: missing (>= 0) number argument.\n",
652 					filename, linenum);
653 			if (sscanf(cp, " %u/%u ", &options->connections_per_period,
654 			    &options->connections_period) != 2)
655 				fatal("%.200s line %d: invalid numerical argument(s).\n",
656 				    filename, linenum);
657 			if (options->connections_per_period != 0 &&
658 			    options->connections_period == 0)
659 				fatal("%.200s line %d: invalid connections period.\n",
660 				    filename, linenum);
661 			break;
662 
663 		default:
664 			fatal("%.200s line %d: Missing handler for opcode %s (%d)\n",
665 				filename, linenum, cp, opcode);
666 		}
667 		if (strtok(NULL, WHITESPACE) != NULL) {
668 			fatal("%.200s line %d: garbage at end of line.\n",
669 				filename, linenum);
670 		}
671 	}
672 	fclose(f);
673 	if (bad_options > 0) {
674 		fatal("%.200s: terminating, %d bad configuration options\n",
675 			filename, bad_options);
676 	}
677 }
678