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