servconf.c revision 65022
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: head/crypto/openssh/servconf.c 65022 2000-08-23 09:47:25Z kris $
13 */
14
15#include "includes.h"
16RCSID("$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 */
24void add_listen_addr(ServerOptions *options, char *addr);
25
26/* Initializes the server options to their default values. */
27
28void
29initialize_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
86void
87fill_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 = 120;
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. */
174typedef 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. */
200static 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
263static ServerOpCodes
264parse_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 */
281void
282add_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
311void
312read_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;
357parse_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;
446parse_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