]> andersk Git - gssapi-openssh.git/blob - openssh/servconf.c
merged OpenSSH 5.1p1 to trunk
[gssapi-openssh.git] / openssh / servconf.c
1 /* $OpenBSD: servconf.c,v 1.186 2008/07/04 03:44:59 djm Exp $ */
2 /*
3  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4  *                    All rights reserved
5  *
6  * As far as I am concerned, the code I have written for this software
7  * can be used freely for any purpose.  Any derived versions of this
8  * software must be clearly marked as such, and if the derived work is
9  * incompatible with the protocol description in the RFC file, it must be
10  * called by a name other than "ssh" or "Secure Shell".
11  */
12
13 #include "includes.h"
14
15 #include <sys/types.h>
16 #include <sys/socket.h>
17
18 #include <netdb.h>
19 #include <pwd.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <signal.h>
24 #include <unistd.h>
25 #include <stdarg.h>
26 #include <errno.h>
27
28 #include "openbsd-compat/sys-queue.h"
29 #include "xmalloc.h"
30 #include "ssh.h"
31 #include "log.h"
32 #include "buffer.h"
33 #include "servconf.h"
34 #include "compat.h"
35 #include "pathnames.h"
36 #include "misc.h"
37 #include "cipher.h"
38 #include "key.h"
39 #include "kex.h"
40 #include "mac.h"
41 #include "match.h"
42 #include "channels.h"
43 #include "groupaccess.h"
44
45 static void add_listen_addr(ServerOptions *, char *, u_short);
46 static void add_one_listen_addr(ServerOptions *, char *, u_short);
47
48 /* Use of privilege separation or not */
49 extern int use_privsep;
50 extern Buffer cfg;
51
52 /* Initializes the server options to their default values. */
53
54 void
55 initialize_server_options(ServerOptions *options)
56 {
57         memset(options, 0, sizeof(*options));
58
59         /* Portable-specific options */
60         options->use_pam = -1;
61
62         /* Standard Options */
63         options->num_ports = 0;
64         options->ports_from_cmdline = 0;
65         options->listen_addrs = NULL;
66         options->address_family = -1;
67         options->num_host_key_files = 0;
68         options->pid_file = NULL;
69         options->server_key_bits = -1;
70         options->login_grace_time = -1;
71         options->key_regeneration_time = -1;
72         options->permit_root_login = PERMIT_NOT_SET;
73         options->ignore_rhosts = -1;
74         options->ignore_user_known_hosts = -1;
75         options->print_motd = -1;
76         options->print_lastlog = -1;
77         options->x11_forwarding = -1;
78         options->x11_display_offset = -1;
79         options->x11_use_localhost = -1;
80         options->xauth_location = NULL;
81         options->strict_modes = -1;
82         options->tcp_keep_alive = -1;
83         options->log_facility = SYSLOG_FACILITY_NOT_SET;
84         options->log_level = SYSLOG_LEVEL_NOT_SET;
85         options->rhosts_rsa_authentication = -1;
86         options->hostbased_authentication = -1;
87         options->hostbased_uses_name_from_packet_only = -1;
88         options->rsa_authentication = -1;
89         options->pubkey_authentication = -1;
90         options->kerberos_authentication = -1;
91         options->kerberos_or_local_passwd = -1;
92         options->kerberos_ticket_cleanup = -1;
93 #ifdef  SESSION_HOOKS
94         options->session_hooks_allow = -1;
95         options->session_hooks_startup_cmd = NULL;
96         options->session_hooks_shutdown_cmd = NULL;
97 #endif
98         options->kerberos_get_afs_token = -1;
99         options->gss_authentication = -1;
100         options->gss_deleg_creds = -1;
101         options->gss_keyex = -1;
102         options->gss_cleanup_creds = -1;
103         options->gss_strict_acceptor = -1;
104         options->gsi_allow_limited_proxy = -1;
105         options->password_authentication = -1;
106         options->kbd_interactive_authentication = -1;
107         options->challenge_response_authentication = -1;
108         options->permit_empty_passwd = -1;
109         options->permit_user_env = -1;
110         options->use_login = -1;
111         options->compression = -1;
112         options->allow_tcp_forwarding = -1;
113         options->allow_agent_forwarding = -1;
114         options->num_allow_users = 0;
115         options->num_deny_users = 0;
116         options->num_allow_groups = 0;
117         options->num_deny_groups = 0;
118         options->ciphers = NULL;
119         options->macs = NULL;
120         options->protocol = SSH_PROTO_UNKNOWN;
121         options->gateway_ports = -1;
122         options->num_subsystems = 0;
123         options->max_startups_begin = -1;
124         options->max_startups_rate = -1;
125         options->max_startups = -1;
126         options->max_authtries = -1;
127         options->max_sessions = -1;
128         options->banner = NULL;
129         options->use_dns = -1;
130         options->client_alive_interval = -1;
131         options->client_alive_count_max = -1;
132         options->authorized_keys_file = NULL;
133         options->authorized_keys_file2 = NULL;
134         options->num_accept_env = 0;
135         options->permit_tun = -1;
136         options->num_permitted_opens = -1;
137         options->adm_forced_command = NULL;
138         options->chroot_directory = NULL;
139         options->none_enabled = -1;
140         options->tcp_rcv_buf_poll = -1;
141         options->hpn_disabled = -1;
142         options->hpn_buffer_size = -1;
143 }
144
145 void
146 fill_default_server_options(ServerOptions *options)
147 {
148         int sock;
149         int socksize;
150         int socksizelen = sizeof(int);
151
152         /* Portable-specific options */
153         if (options->use_pam == -1)
154                 options->use_pam = 0;
155
156         /* Standard Options */
157         if (options->protocol == SSH_PROTO_UNKNOWN)
158                 options->protocol = SSH_PROTO_1|SSH_PROTO_2;
159         if (options->num_host_key_files == 0) {
160                 /* fill default hostkeys for protocols */
161                 if (options->protocol & SSH_PROTO_1)
162                         options->host_key_files[options->num_host_key_files++] =
163                             _PATH_HOST_KEY_FILE;
164                 if (options->protocol & SSH_PROTO_2) {
165                         options->host_key_files[options->num_host_key_files++] =
166                             _PATH_HOST_RSA_KEY_FILE;
167                         options->host_key_files[options->num_host_key_files++] =
168                             _PATH_HOST_DSA_KEY_FILE;
169                 }
170         }
171         if (options->num_ports == 0)
172                 options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
173         if (options->listen_addrs == NULL)
174                 add_listen_addr(options, NULL, 0);
175         if (options->pid_file == NULL)
176                 options->pid_file = _PATH_SSH_DAEMON_PID_FILE;
177         if (options->server_key_bits == -1)
178                 options->server_key_bits = 1024;
179         if (options->login_grace_time == -1)
180                 options->login_grace_time = 120;
181         if (options->key_regeneration_time == -1)
182                 options->key_regeneration_time = 3600;
183         if (options->permit_root_login == PERMIT_NOT_SET)
184                 options->permit_root_login = PERMIT_YES;
185         if (options->ignore_rhosts == -1)
186                 options->ignore_rhosts = 1;
187         if (options->ignore_user_known_hosts == -1)
188                 options->ignore_user_known_hosts = 0;
189         if (options->print_motd == -1)
190                 options->print_motd = 1;
191         if (options->print_lastlog == -1)
192                 options->print_lastlog = 1;
193         if (options->x11_forwarding == -1)
194                 options->x11_forwarding = 0;
195         if (options->x11_display_offset == -1)
196                 options->x11_display_offset = 10;
197         if (options->x11_use_localhost == -1)
198                 options->x11_use_localhost = 1;
199         if (options->xauth_location == NULL)
200                 options->xauth_location = _PATH_XAUTH;
201         if (options->strict_modes == -1)
202                 options->strict_modes = 1;
203         if (options->tcp_keep_alive == -1)
204                 options->tcp_keep_alive = 1;
205         if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
206                 options->log_facility = SYSLOG_FACILITY_AUTH;
207         if (options->log_level == SYSLOG_LEVEL_NOT_SET)
208                 options->log_level = SYSLOG_LEVEL_INFO;
209         if (options->rhosts_rsa_authentication == -1)
210                 options->rhosts_rsa_authentication = 0;
211         if (options->hostbased_authentication == -1)
212                 options->hostbased_authentication = 0;
213         if (options->hostbased_uses_name_from_packet_only == -1)
214                 options->hostbased_uses_name_from_packet_only = 0;
215         if (options->rsa_authentication == -1)
216                 options->rsa_authentication = 1;
217         if (options->pubkey_authentication == -1)
218                 options->pubkey_authentication = 1;
219         if (options->kerberos_authentication == -1)
220                 options->kerberos_authentication = 0;
221         if (options->kerberos_or_local_passwd == -1)
222                 options->kerberos_or_local_passwd = 1;
223         if (options->kerberos_ticket_cleanup == -1)
224                 options->kerberos_ticket_cleanup = 1;
225         if (options->kerberos_get_afs_token == -1)
226                 options->kerberos_get_afs_token = 0;
227         if (options->gss_authentication == -1)
228                 options->gss_authentication = 1;
229         if (options->gss_deleg_creds == -1)
230                 options->gss_deleg_creds = 1;
231         if (options->gss_keyex == -1)
232                 options->gss_keyex = 1;
233         if (options->gss_cleanup_creds == -1)
234                 options->gss_cleanup_creds = 1;
235         if (options->gss_strict_acceptor == -1)
236                 options->gss_strict_acceptor = 1;
237         if (options->gsi_allow_limited_proxy == -1)
238                 options->gsi_allow_limited_proxy = 0;
239         if (options->password_authentication == -1)
240                 options->password_authentication = 1;
241         if (options->kbd_interactive_authentication == -1)
242                 options->kbd_interactive_authentication = 0;
243         if (options->challenge_response_authentication == -1)
244                 options->challenge_response_authentication = 1;
245         if (options->permit_empty_passwd == -1)
246                 options->permit_empty_passwd = 0;
247         if (options->permit_user_env == -1)
248                 options->permit_user_env = 0;
249         if (options->use_login == -1)
250                 options->use_login = 0;
251         if (options->compression == -1)
252                 options->compression = COMP_DELAYED;
253         if (options->allow_tcp_forwarding == -1)
254                 options->allow_tcp_forwarding = 1;
255         if (options->allow_agent_forwarding == -1)
256                 options->allow_agent_forwarding = 1;
257         if (options->gateway_ports == -1)
258                 options->gateway_ports = 0;
259         if (options->max_startups == -1)
260                 options->max_startups = 10;
261         if (options->max_startups_rate == -1)
262                 options->max_startups_rate = 100;               /* 100% */
263         if (options->max_startups_begin == -1)
264                 options->max_startups_begin = options->max_startups;
265         if (options->max_authtries == -1)
266                 options->max_authtries = DEFAULT_AUTH_FAIL_MAX;
267         if (options->max_sessions == -1)
268                 options->max_sessions = DEFAULT_SESSIONS_MAX;
269         if (options->use_dns == -1)
270                 options->use_dns = 1;
271         if (options->client_alive_interval == -1)
272                 options->client_alive_interval = 0;
273         if (options->client_alive_count_max == -1)
274                 options->client_alive_count_max = 3;
275         if (options->authorized_keys_file2 == NULL) {
276                 /* authorized_keys_file2 falls back to authorized_keys_file */
277                 if (options->authorized_keys_file != NULL)
278                         options->authorized_keys_file2 = options->authorized_keys_file;
279                 else
280                         options->authorized_keys_file2 = _PATH_SSH_USER_PERMITTED_KEYS2;
281         }
282         if (options->authorized_keys_file == NULL)
283                 options->authorized_keys_file = _PATH_SSH_USER_PERMITTED_KEYS;
284         if (options->permit_tun == -1)
285                 options->permit_tun = SSH_TUNMODE_NO;
286
287         if (options->hpn_disabled == -1) 
288                 options->hpn_disabled = 0;
289
290         if (options->hpn_buffer_size == -1) {
291                 /* option not explicitly set. Now we have to figure out */
292                 /* what value to use */
293                 if (options->hpn_disabled == 1) {
294                         options->hpn_buffer_size = CHAN_SES_WINDOW_DEFAULT;
295                 } else {
296                         /* get the current RCV size and set it to that */
297                         /*create a socket but don't connect it */
298                         /* we use that the get the rcv socket size */
299                         sock = socket(AF_INET, SOCK_STREAM, 0);
300                         getsockopt(sock, SOL_SOCKET, SO_RCVBUF, 
301                                    &socksize, &socksizelen);
302                         close(sock);
303                         options->hpn_buffer_size = socksize;
304                         debug ("HPN Buffer Size: %d", options->hpn_buffer_size);
305                         
306                 } 
307         } else {
308                 /* we have to do this incase the user sets both values in a contradictory */
309                 /* manner. hpn_disabled overrrides hpn_buffer_size*/
310                 if (options->hpn_disabled <= 0) {
311                         if (options->hpn_buffer_size == 0)
312                                 options->hpn_buffer_size = 1;
313                         /* limit the maximum buffer to 64MB */
314                         if (options->hpn_buffer_size > 64*1024) {
315                                 options->hpn_buffer_size = 64*1024*1024;
316                         } else {
317                                 options->hpn_buffer_size *= 1024;
318                         }
319                 } else
320                         options->hpn_buffer_size = CHAN_TCP_WINDOW_DEFAULT;
321         }
322
323         /* Turn privilege separation on by default */
324         if (use_privsep == -1)
325                 use_privsep = 1;
326
327 #ifndef HAVE_MMAP
328         if (use_privsep && options->compression == 1) {
329                 error("This platform does not support both privilege "
330                     "separation and compression");
331                 error("Compression disabled");
332                 options->compression = 0;
333         }
334 #endif
335
336 }
337
338 /* Keyword tokens. */
339 typedef enum {
340         sBadOption,             /* == unknown option */
341         /* Portable-specific options */
342         sUsePAM,
343         /* Standard Options */
344         sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime,
345         sPermitRootLogin, sLogFacility, sLogLevel,
346         sRhostsRSAAuthentication, sRSAAuthentication,
347         sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
348         sKerberosGetAFSToken,
349         sKerberosTgtPassing, sChallengeResponseAuthentication,
350 #ifdef SESSION_HOOKS
351         sAllowSessionHooks, sSessionHookStartupCmd, sSessionHookShutdownCmd,
352 #endif
353         sPasswordAuthentication, sKbdInteractiveAuthentication,
354         sListenAddress, sAddressFamily,
355         sPrintMotd, sPrintLastLog, sIgnoreRhosts,
356         sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
357         sStrictModes, sEmptyPasswd, sTCPKeepAlive,
358         sPermitUserEnvironment, sUseLogin, sAllowTcpForwarding, sCompression,
359         sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
360         sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
361         sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem,
362         sMaxStartups, sMaxAuthTries, sMaxSessions,
363         sBanner, sUseDNS, sHostbasedAuthentication,
364         sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
365         sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
366         sGssAuthentication, sGssCleanupCreds,
367     sGssDelegateCreds,
368     sGssStrictAcceptor,
369         sGssKeyEx, 
370     sGssCredsPath,
371         sGsiAllowLimitedProxy,
372     sAcceptEnv, sPermitTunnel,
373         sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
374         sNoneEnabled, sTcpRcvBufPoll, 
375         sHPNDisabled, sHPNBufferSize,
376         sUsePrivilegeSeparation, sAllowAgentForwarding,
377         sDeprecated, sUnsupported
378 } ServerOpCodes;
379
380 #define SSHCFG_GLOBAL   0x01    /* allowed in main section of sshd_config */
381 #define SSHCFG_MATCH    0x02    /* allowed inside a Match section */
382 #define SSHCFG_ALL      (SSHCFG_GLOBAL|SSHCFG_MATCH)
383
384 /* Textual representation of the tokens. */
385 static struct {
386         const char *name;
387         ServerOpCodes opcode;
388         u_int flags;
389 } keywords[] = {
390         /* Portable-specific options */
391 #ifdef USE_PAM
392         { "usepam", sUsePAM, SSHCFG_GLOBAL },
393 #else
394         { "usepam", sUnsupported, SSHCFG_GLOBAL },
395 #endif
396         { "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL },
397         /* Standard Options */
398         { "port", sPort, SSHCFG_GLOBAL },
399         { "hostkey", sHostKeyFile, SSHCFG_GLOBAL },
400         { "hostdsakey", sHostKeyFile, SSHCFG_GLOBAL },          /* alias */
401         { "pidfile", sPidFile, SSHCFG_GLOBAL },
402         { "serverkeybits", sServerKeyBits, SSHCFG_GLOBAL },
403         { "logingracetime", sLoginGraceTime, SSHCFG_GLOBAL },
404         { "keyregenerationinterval", sKeyRegenerationTime, SSHCFG_GLOBAL },
405         { "permitrootlogin", sPermitRootLogin, SSHCFG_ALL },
406         { "syslogfacility", sLogFacility, SSHCFG_GLOBAL },
407         { "loglevel", sLogLevel, SSHCFG_GLOBAL },
408         { "rhostsauthentication", sDeprecated, SSHCFG_GLOBAL },
409         { "rhostsrsaauthentication", sRhostsRSAAuthentication, SSHCFG_ALL },
410         { "hostbasedauthentication", sHostbasedAuthentication, SSHCFG_ALL },
411         { "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly, SSHCFG_GLOBAL },
412         { "rsaauthentication", sRSAAuthentication, SSHCFG_ALL },
413         { "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_ALL },
414         { "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL },  /* alias */
415 #ifdef KRB5
416         { "kerberosauthentication", sKerberosAuthentication, SSHCFG_ALL },
417         { "kerberosorlocalpasswd", sKerberosOrLocalPasswd, SSHCFG_GLOBAL },
418         { "kerberosticketcleanup", sKerberosTicketCleanup, SSHCFG_GLOBAL },
419 #ifdef USE_AFS
420         { "kerberosgetafstoken", sKerberosGetAFSToken, SSHCFG_GLOBAL },
421 #else
422         { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
423 #endif
424 #else
425         { "kerberosauthentication", sUnsupported, SSHCFG_ALL },
426         { "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL },
427         { "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL },
428         { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
429 #endif
430         { "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL },
431         { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
432 #ifdef GSSAPI
433         { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
434         { "gssapidelegatecredentials", sGssDelegateCreds, SSHCFG_ALL },
435         { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
436         { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
437         { "gssapicredentialspath", sGssCredsPath, SSHCFG_GLOBAL },
438         { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL },
439 #ifdef GSI
440         { "gsiallowlimitedproxy", sGsiAllowLimitedProxy, SSHCFG_GLOBAL },
441 #endif
442 #else
443         { "gssapiauthentication", sUnsupported, SSHCFG_ALL },
444         { "gssapidelegatecredentials", sUnsupported, SSHCFG_ALL },
445         { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
446         { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
447         { "gssapicredentialspath", sUnsupported, SSHCFG_GLOBAL },
448         { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL },
449 #ifdef GSI
450         { "gsiallowlimitedproxy", sUnsupported, SSHCFG_GLOBAL },
451 #endif
452 #endif
453 #ifdef SESSION_HOOKS
454     { "allowsessionhooks", sAllowSessionHooks, SSHCFG_GLOBAL },
455     { "sessionhookstartupcmd", sSessionHookStartupCmd, SSHCFG_GLOBAL },
456     { "sessionhookshutdowncmd", sSessionHookShutdownCmd, SSHCFG_GLOBAL },
457 #endif        
458         { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
459         { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
460         { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
461         { "skeyauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, /* alias */
462         { "checkmail", sDeprecated, SSHCFG_GLOBAL },
463         { "listenaddress", sListenAddress, SSHCFG_GLOBAL },
464         { "addressfamily", sAddressFamily, SSHCFG_GLOBAL },
465         { "printmotd", sPrintMotd, SSHCFG_GLOBAL },
466         { "printlastlog", sPrintLastLog, SSHCFG_GLOBAL },
467         { "ignorerhosts", sIgnoreRhosts, SSHCFG_GLOBAL },
468         { "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL },
469         { "x11forwarding", sX11Forwarding, SSHCFG_ALL },
470         { "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL },
471         { "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
472         { "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
473         { "strictmodes", sStrictModes, SSHCFG_GLOBAL },
474         { "permitemptypasswords", sEmptyPasswd, SSHCFG_GLOBAL },
475         { "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
476         { "uselogin", sUseLogin, SSHCFG_GLOBAL },
477         { "compression", sCompression, SSHCFG_GLOBAL },
478         { "tcpkeepalive", sTCPKeepAlive, SSHCFG_GLOBAL },
479         { "keepalive", sTCPKeepAlive, SSHCFG_GLOBAL },  /* obsolete alias */
480         { "allowtcpforwarding", sAllowTcpForwarding, SSHCFG_ALL },
481         { "allowagentforwarding", sAllowAgentForwarding, SSHCFG_ALL },
482         { "allowusers", sAllowUsers, SSHCFG_GLOBAL },
483         { "denyusers", sDenyUsers, SSHCFG_GLOBAL },
484         { "allowgroups", sAllowGroups, SSHCFG_GLOBAL },
485         { "denygroups", sDenyGroups, SSHCFG_GLOBAL },
486         { "ciphers", sCiphers, SSHCFG_GLOBAL },
487         { "macs", sMacs, SSHCFG_GLOBAL },
488         { "protocol", sProtocol, SSHCFG_GLOBAL },
489         { "gatewayports", sGatewayPorts, SSHCFG_ALL },
490         { "subsystem", sSubsystem, SSHCFG_GLOBAL },
491         { "maxstartups", sMaxStartups, SSHCFG_GLOBAL },
492         { "maxauthtries", sMaxAuthTries, SSHCFG_ALL },
493         { "maxsessions", sMaxSessions, SSHCFG_ALL },
494         { "banner", sBanner, SSHCFG_ALL },
495         { "usedns", sUseDNS, SSHCFG_GLOBAL },
496         { "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL },
497         { "reversemappingcheck", sDeprecated, SSHCFG_GLOBAL },
498         { "clientaliveinterval", sClientAliveInterval, SSHCFG_GLOBAL },
499         { "clientalivecountmax", sClientAliveCountMax, SSHCFG_GLOBAL },
500         { "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_GLOBAL },
501         { "authorizedkeysfile2", sAuthorizedKeysFile2, SSHCFG_GLOBAL },
502         { "useprivilegeseparation", sUsePrivilegeSeparation, SSHCFG_GLOBAL },
503         { "acceptenv", sAcceptEnv, SSHCFG_GLOBAL },
504         { "permittunnel", sPermitTunnel, SSHCFG_GLOBAL },
505         { "match", sMatch, SSHCFG_ALL },
506         { "permitopen", sPermitOpen, SSHCFG_ALL },
507         { "forcecommand", sForceCommand, SSHCFG_ALL },
508         { "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
509         { "noneenabled", sNoneEnabled },
510         { "hpndisabled", sHPNDisabled },
511         { "hpnbuffersize", sHPNBufferSize },
512         { "tcprcvbufpoll", sTcpRcvBufPoll },
513         { NULL, sBadOption, 0 }
514 };
515
516 static struct {
517         int val;
518         char *text;
519 } tunmode_desc[] = {
520         { SSH_TUNMODE_NO, "no" },
521         { SSH_TUNMODE_POINTOPOINT, "point-to-point" },
522         { SSH_TUNMODE_ETHERNET, "ethernet" },
523         { SSH_TUNMODE_YES, "yes" },
524         { -1, NULL }
525 };
526
527 /*
528  * Returns the number of the token pointed to by cp or sBadOption.
529  */
530
531 static ServerOpCodes
532 parse_token(const char *cp, const char *filename,
533             int linenum, u_int *flags)
534 {
535         u_int i;
536
537         for (i = 0; keywords[i].name; i++)
538                 if (strcasecmp(cp, keywords[i].name) == 0) {
539                         debug ("Config token is %s", keywords[i].name);
540                         *flags = keywords[i].flags;
541                         return keywords[i].opcode;
542                 }
543
544         error("%s: line %d: Bad configuration option: %s",
545             filename, linenum, cp);
546         return sBadOption;
547 }
548
549 static void
550 add_listen_addr(ServerOptions *options, char *addr, u_short port)
551 {
552         u_int i;
553
554         if (options->num_ports == 0)
555                 options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
556         if (options->address_family == -1)
557                 options->address_family = AF_UNSPEC;
558         if (port == 0)
559                 for (i = 0; i < options->num_ports; i++)
560                         add_one_listen_addr(options, addr, options->ports[i]);
561         else
562                 add_one_listen_addr(options, addr, port);
563 }
564
565 static void
566 add_one_listen_addr(ServerOptions *options, char *addr, u_short port)
567 {
568         struct addrinfo hints, *ai, *aitop;
569         char strport[NI_MAXSERV];
570         int gaierr;
571
572         memset(&hints, 0, sizeof(hints));
573         hints.ai_family = options->address_family;
574         hints.ai_socktype = SOCK_STREAM;
575         hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0;
576         snprintf(strport, sizeof strport, "%u", port);
577         if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0)
578                 fatal("bad addr or host: %s (%s)",
579                     addr ? addr : "<NULL>",
580                     ssh_gai_strerror(gaierr));
581         for (ai = aitop; ai->ai_next; ai = ai->ai_next)
582                 ;
583         ai->ai_next = options->listen_addrs;
584         options->listen_addrs = aitop;
585 }
586
587 /*
588  * The strategy for the Match blocks is that the config file is parsed twice.
589  *
590  * The first time is at startup.  activep is initialized to 1 and the
591  * directives in the global context are processed and acted on.  Hitting a
592  * Match directive unsets activep and the directives inside the block are
593  * checked for syntax only.
594  *
595  * The second time is after a connection has been established but before
596  * authentication.  activep is initialized to 2 and global config directives
597  * are ignored since they have already been processed.  If the criteria in a
598  * Match block is met, activep is set and the subsequent directives
599  * processed and actioned until EOF or another Match block unsets it.  Any
600  * options set are copied into the main server config.
601  *
602  * Potential additions/improvements:
603  *  - Add Match support for pre-kex directives, eg Protocol, Ciphers.
604  *
605  *  - Add a Tag directive (idea from David Leonard) ala pf, eg:
606  *      Match Address 192.168.0.*
607  *              Tag trusted
608  *      Match Group wheel
609  *              Tag trusted
610  *      Match Tag trusted
611  *              AllowTcpForwarding yes
612  *              GatewayPorts clientspecified
613  *              [...]
614  *
615  *  - Add a PermittedChannelRequests directive
616  *      Match Group shell
617  *              PermittedChannelRequests session,forwarded-tcpip
618  */
619
620 static int
621 match_cfg_line_group(const char *grps, int line, const char *user)
622 {
623         int result = 0;
624         struct passwd *pw;
625
626         if (user == NULL)
627                 goto out;
628
629         if ((pw = getpwnam(user)) == NULL) {
630                 debug("Can't match group at line %d because user %.100s does "
631                     "not exist", line, user);
632         } else if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
633                 debug("Can't Match group because user %.100s not in any group "
634                     "at line %d", user, line);
635         } else if (ga_match_pattern_list(grps) != 1) {
636                 debug("user %.100s does not match group list %.100s at line %d",
637                     user, grps, line);
638         } else {
639                 debug("user %.100s matched group list %.100s at line %d", user,
640                     grps, line);
641                 result = 1;
642         }
643 out:
644         ga_free();
645         return result;
646 }
647
648 static int
649 match_cfg_line(char **condition, int line, const char *user, const char *host,
650     const char *address)
651 {
652         int result = 1;
653         char *arg, *attrib, *cp = *condition;
654         size_t len;
655
656         if (user == NULL)
657                 debug3("checking syntax for 'Match %s'", cp);
658         else
659                 debug3("checking match for '%s' user %s host %s addr %s", cp,
660                     user ? user : "(null)", host ? host : "(null)",
661                     address ? address : "(null)");
662
663         while ((attrib = strdelim(&cp)) && *attrib != '\0') {
664                 if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
665                         error("Missing Match criteria for %s", attrib);
666                         return -1;
667                 }
668                 len = strlen(arg);
669                 if (strcasecmp(attrib, "user") == 0) {
670                         if (!user) {
671                                 result = 0;
672                                 continue;
673                         }
674                         if (match_pattern_list(user, arg, len, 0) != 1)
675                                 result = 0;
676                         else
677                                 debug("user %.100s matched 'User %.100s' at "
678                                     "line %d", user, arg, line);
679                 } else if (strcasecmp(attrib, "group") == 0) {
680                         switch (match_cfg_line_group(arg, line, user)) {
681                         case -1:
682                                 return -1;
683                         case 0:
684                                 result = 0;
685                         }
686                 } else if (strcasecmp(attrib, "host") == 0) {
687                         if (!host) {
688                                 result = 0;
689                                 continue;
690                         }
691                         if (match_hostname(host, arg, len) != 1)
692                                 result = 0;
693                         else
694                                 debug("connection from %.100s matched 'Host "
695                                     "%.100s' at line %d", host, arg, line);
696                 } else if (strcasecmp(attrib, "address") == 0) {
697                         switch (addr_match_list(address, arg)) {
698                         case 1:
699                                 debug("connection from %.100s matched 'Address "
700                                     "%.100s' at line %d", address, arg, line);
701                                 break;
702                         case 0:
703                         case -1:
704                                 result = 0;
705                                 break;
706                         case -2:
707                                 return -1;
708                         }
709                 } else {
710                         error("Unsupported Match attribute %s", attrib);
711                         return -1;
712                 }
713         }
714         if (user != NULL)
715                 debug3("match %sfound", result ? "" : "not ");
716         *condition = cp;
717         return result;
718 }
719
720 #define WHITESPACE " \t\r\n"
721
722 int
723 process_server_config_line(ServerOptions *options, char *line,
724     const char *filename, int linenum, int *activep, const char *user,
725     const char *host, const char *address)
726 {
727         char *cp, **charptr, *arg, *p;
728         int cmdline = 0, *intptr, value, n;
729         SyslogFacility *log_facility_ptr;
730         LogLevel *log_level_ptr;
731         ServerOpCodes opcode;
732         u_short port;
733         u_int i, flags = 0;
734         size_t len;
735
736         cp = line;
737         if ((arg = strdelim(&cp)) == NULL)
738                 return 0;
739         /* Ignore leading whitespace */
740         if (*arg == '\0')
741                 arg = strdelim(&cp);
742         if (!arg || !*arg || *arg == '#')
743                 return 0;
744         intptr = NULL;
745         charptr = NULL;
746         opcode = parse_token(arg, filename, linenum, &flags);
747
748         if (activep == NULL) { /* We are processing a command line directive */
749                 cmdline = 1;
750                 activep = &cmdline;
751         }
752         if (*activep && opcode != sMatch)
753                 debug3("%s:%d setting %s %s", filename, linenum, arg, cp);
754         if (*activep == 0 && !(flags & SSHCFG_MATCH)) {
755                 if (user == NULL) {
756                         fatal("%s line %d: Directive '%s' is not allowed "
757                             "within a Match block", filename, linenum, arg);
758                 } else { /* this is a directive we have already processed */
759                         while (arg)
760                                 arg = strdelim(&cp);
761                         return 0;
762                 }
763         }
764
765         switch (opcode) {
766         /* Portable-specific options */
767         case sUsePAM:
768                 intptr = &options->use_pam;
769                 goto parse_flag;
770
771         /* Standard Options */
772         case sBadOption:
773                 return -1;
774         case sPort:
775                 /* ignore ports from configfile if cmdline specifies ports */
776                 if (options->ports_from_cmdline)
777                         return 0;
778                 if (options->listen_addrs != NULL)
779                         fatal("%s line %d: ports must be specified before "
780                             "ListenAddress.", filename, linenum);
781                 if (options->num_ports >= MAX_PORTS)
782                         fatal("%s line %d: too many ports.",
783                             filename, linenum);
784                 arg = strdelim(&cp);
785                 if (!arg || *arg == '\0')
786                         fatal("%s line %d: missing port number.",
787                             filename, linenum);
788                 options->ports[options->num_ports++] = a2port(arg);
789                 if (options->ports[options->num_ports-1] == 0)
790                         fatal("%s line %d: Badly formatted port number.",
791                             filename, linenum);
792                 break;
793
794         case sServerKeyBits:
795                 intptr = &options->server_key_bits;
796  parse_int:
797                 arg = strdelim(&cp);
798                 if (!arg || *arg == '\0')
799                         fatal("%s line %d: missing integer value.",
800                             filename, linenum);
801                 value = atoi(arg);
802                 if (*activep && *intptr == -1)
803                         *intptr = value;
804                 break;
805
806         case sLoginGraceTime:
807                 intptr = &options->login_grace_time;
808  parse_time:
809                 arg = strdelim(&cp);
810                 if (!arg || *arg == '\0')
811                         fatal("%s line %d: missing time value.",
812                             filename, linenum);
813                 if ((value = convtime(arg)) == -1)
814                         fatal("%s line %d: invalid time value.",
815                             filename, linenum);
816                 if (*intptr == -1)
817                         *intptr = value;
818                 break;
819
820         case sKeyRegenerationTime:
821                 intptr = &options->key_regeneration_time;
822                 goto parse_time;
823
824         case sListenAddress:
825                 arg = strdelim(&cp);
826                 if (arg == NULL || *arg == '\0')
827                         fatal("%s line %d: missing address",
828                             filename, linenum);
829                 /* check for bare IPv6 address: no "[]" and 2 or more ":" */
830                 if (strchr(arg, '[') == NULL && (p = strchr(arg, ':')) != NULL
831                     && strchr(p+1, ':') != NULL) {
832                         add_listen_addr(options, arg, 0);
833                         break;
834                 }
835                 p = hpdelim(&arg);
836                 if (p == NULL)
837                         fatal("%s line %d: bad address:port usage",
838                             filename, linenum);
839                 p = cleanhostname(p);
840                 if (arg == NULL)
841                         port = 0;
842                 else if ((port = a2port(arg)) == 0)
843                         fatal("%s line %d: bad port number", filename, linenum);
844
845                 add_listen_addr(options, p, port);
846
847                 break;
848
849         case sAddressFamily:
850                 arg = strdelim(&cp);
851                 if (!arg || *arg == '\0')
852                         fatal("%s line %d: missing address family.",
853                             filename, linenum);
854                 intptr = &options->address_family;
855                 if (options->listen_addrs != NULL)
856                         fatal("%s line %d: address family must be specified before "
857                             "ListenAddress.", filename, linenum);
858                 if (strcasecmp(arg, "inet") == 0)
859                         value = AF_INET;
860                 else if (strcasecmp(arg, "inet6") == 0)
861                         value = AF_INET6;
862                 else if (strcasecmp(arg, "any") == 0)
863                         value = AF_UNSPEC;
864                 else
865                         fatal("%s line %d: unsupported address family \"%s\".",
866                             filename, linenum, arg);
867                 if (*intptr == -1)
868                         *intptr = value;
869                 break;
870
871         case sHostKeyFile:
872                 intptr = &options->num_host_key_files;
873                 if (*intptr >= MAX_HOSTKEYS)
874                         fatal("%s line %d: too many host keys specified (max %d).",
875                             filename, linenum, MAX_HOSTKEYS);
876                 charptr = &options->host_key_files[*intptr];
877  parse_filename:
878                 arg = strdelim(&cp);
879                 if (!arg || *arg == '\0')
880                         fatal("%s line %d: missing file name.",
881                             filename, linenum);
882                 if (*activep && *charptr == NULL) {
883                         *charptr = tilde_expand_filename(arg, getuid());
884                         /* increase optional counter */
885                         if (intptr != NULL)
886                                 *intptr = *intptr + 1;
887                 }
888                 break;
889
890         case sPidFile:
891                 charptr = &options->pid_file;
892                 goto parse_filename;
893
894         case sPermitRootLogin:
895                 intptr = &options->permit_root_login;
896                 arg = strdelim(&cp);
897                 if (!arg || *arg == '\0')
898                         fatal("%s line %d: missing yes/"
899                             "without-password/forced-commands-only/no "
900                             "argument.", filename, linenum);
901                 value = 0;      /* silence compiler */
902                 if (strcmp(arg, "without-password") == 0)
903                         value = PERMIT_NO_PASSWD;
904                 else if (strcmp(arg, "forced-commands-only") == 0)
905                         value = PERMIT_FORCED_ONLY;
906                 else if (strcmp(arg, "yes") == 0)
907                         value = PERMIT_YES;
908                 else if (strcmp(arg, "no") == 0)
909                         value = PERMIT_NO;
910                 else
911                         fatal("%s line %d: Bad yes/"
912                             "without-password/forced-commands-only/no "
913                             "argument: %s", filename, linenum, arg);
914                 if (*activep && *intptr == -1)
915                         *intptr = value;
916                 break;
917
918         case sIgnoreRhosts:
919                 intptr = &options->ignore_rhosts;
920  parse_flag:
921                 arg = strdelim(&cp);
922                 if (!arg || *arg == '\0')
923                         fatal("%s line %d: missing yes/no argument.",
924                             filename, linenum);
925                 value = 0;      /* silence compiler */
926                 if (strcmp(arg, "yes") == 0)
927                         value = 1;
928                 else if (strcmp(arg, "no") == 0)
929                         value = 0;
930                 else
931                         fatal("%s line %d: Bad yes/no argument: %s",
932                                 filename, linenum, arg);
933                 if (*activep && *intptr == -1)
934                         *intptr = value;
935                 break;
936
937         case sNoneEnabled:
938                 intptr = &options->none_enabled;
939                 goto parse_flag;
940
941         case sTcpRcvBufPoll:
942                 intptr = &options->tcp_rcv_buf_poll;
943                 goto parse_flag;
944
945         case sHPNDisabled:
946                 intptr = &options->hpn_disabled;
947                 goto parse_flag;
948
949         case sHPNBufferSize:
950                 intptr = &options->hpn_buffer_size;
951                 goto parse_int;
952
953         case sIgnoreUserKnownHosts:
954                 intptr = &options->ignore_user_known_hosts;
955                 goto parse_flag;
956
957         case sRhostsRSAAuthentication:
958                 intptr = &options->rhosts_rsa_authentication;
959                 goto parse_flag;
960
961         case sHostbasedAuthentication:
962                 intptr = &options->hostbased_authentication;
963                 goto parse_flag;
964
965         case sHostbasedUsesNameFromPacketOnly:
966                 intptr = &options->hostbased_uses_name_from_packet_only;
967                 goto parse_flag;
968
969         case sRSAAuthentication:
970                 intptr = &options->rsa_authentication;
971                 goto parse_flag;
972
973         case sPubkeyAuthentication:
974                 intptr = &options->pubkey_authentication;
975                 goto parse_flag;
976
977         case sKerberosAuthentication:
978                 intptr = &options->kerberos_authentication;
979                 goto parse_flag;
980
981         case sKerberosOrLocalPasswd:
982                 intptr = &options->kerberos_or_local_passwd;
983                 goto parse_flag;
984
985         case sKerberosTicketCleanup:
986                 intptr = &options->kerberos_ticket_cleanup;
987                 goto parse_flag;
988
989         case sKerberosGetAFSToken:
990                 intptr = &options->kerberos_get_afs_token;
991                 goto parse_flag;
992
993         case sGssAuthentication:
994                 intptr = &options->gss_authentication;
995                 goto parse_flag;
996
997         case sGssDelegateCreds:
998                 intptr = &options->gss_deleg_creds;
999                 goto parse_flag;
1000
1001         case sGssKeyEx:
1002                 intptr = &options->gss_keyex;
1003                 goto parse_flag;
1004
1005         case sGssCleanupCreds:
1006                 intptr = &options->gss_cleanup_creds;
1007                 goto parse_flag;
1008
1009         case sGssStrictAcceptor:
1010                 intptr = &options->gss_strict_acceptor;
1011                 goto parse_flag;
1012
1013         case sGssCredsPath:
1014                 charptr = &options->gss_creds_path;
1015                 goto parse_filename;
1016
1017         case sGsiAllowLimitedProxy:
1018                 intptr = &options->gsi_allow_limited_proxy;
1019                 goto parse_flag;
1020
1021 #ifdef SESSION_HOOKS
1022         case sAllowSessionHooks:
1023                 intptr = &options->session_hooks_allow;
1024                 goto parse_flag;
1025         case sSessionHookStartupCmd:
1026         case sSessionHookShutdownCmd:
1027                 arg = strdelim(&cp);
1028                 if (!arg || *arg == '\0')
1029                     fatal("%s line %d: empty session hook command",
1030                           filename, linenum);
1031                 if (opcode==sSessionHookStartupCmd)
1032                     options->session_hooks_startup_cmd = strdup(arg);
1033                 else
1034                     options->session_hooks_shutdown_cmd = strdup(arg);
1035                 break;
1036 #endif                  
1037
1038         case sPasswordAuthentication:
1039                 intptr = &options->password_authentication;
1040                 goto parse_flag;
1041
1042         case sKbdInteractiveAuthentication:
1043                 intptr = &options->kbd_interactive_authentication;
1044                 goto parse_flag;
1045
1046         case sChallengeResponseAuthentication:
1047                 intptr = &options->challenge_response_authentication;
1048                 goto parse_flag;
1049
1050         case sPrintMotd:
1051                 intptr = &options->print_motd;
1052                 goto parse_flag;
1053
1054         case sPrintLastLog:
1055                 intptr = &options->print_lastlog;
1056                 goto parse_flag;
1057
1058         case sX11Forwarding:
1059                 intptr = &options->x11_forwarding;
1060                 goto parse_flag;
1061
1062         case sX11DisplayOffset:
1063                 intptr = &options->x11_display_offset;
1064                 goto parse_int;
1065
1066         case sX11UseLocalhost:
1067                 intptr = &options->x11_use_localhost;
1068                 goto parse_flag;
1069
1070         case sXAuthLocation:
1071                 charptr = &options->xauth_location;
1072                 goto parse_filename;
1073
1074         case sStrictModes:
1075                 intptr = &options->strict_modes;
1076                 goto parse_flag;
1077
1078         case sTCPKeepAlive:
1079                 intptr = &options->tcp_keep_alive;
1080                 goto parse_flag;
1081
1082         case sEmptyPasswd:
1083                 intptr = &options->permit_empty_passwd;
1084                 goto parse_flag;
1085
1086         case sPermitUserEnvironment:
1087                 intptr = &options->permit_user_env;
1088                 goto parse_flag;
1089
1090         case sUseLogin:
1091                 intptr = &options->use_login;
1092                 goto parse_flag;
1093
1094         case sCompression:
1095                 intptr = &options->compression;
1096                 arg = strdelim(&cp);
1097                 if (!arg || *arg == '\0')
1098                         fatal("%s line %d: missing yes/no/delayed "
1099                             "argument.", filename, linenum);
1100                 value = 0;      /* silence compiler */
1101                 if (strcmp(arg, "delayed") == 0)
1102                         value = COMP_DELAYED;
1103                 else if (strcmp(arg, "yes") == 0)
1104                         value = COMP_ZLIB;
1105                 else if (strcmp(arg, "no") == 0)
1106                         value = COMP_NONE;
1107                 else
1108                         fatal("%s line %d: Bad yes/no/delayed "
1109                             "argument: %s", filename, linenum, arg);
1110                 if (*intptr == -1)
1111                         *intptr = value;
1112                 break;
1113
1114         case sGatewayPorts:
1115                 intptr = &options->gateway_ports;
1116                 arg = strdelim(&cp);
1117                 if (!arg || *arg == '\0')
1118                         fatal("%s line %d: missing yes/no/clientspecified "
1119                             "argument.", filename, linenum);
1120                 value = 0;      /* silence compiler */
1121                 if (strcmp(arg, "clientspecified") == 0)
1122                         value = 2;
1123                 else if (strcmp(arg, "yes") == 0)
1124                         value = 1;
1125                 else if (strcmp(arg, "no") == 0)
1126                         value = 0;
1127                 else
1128                         fatal("%s line %d: Bad yes/no/clientspecified "
1129                             "argument: %s", filename, linenum, arg);
1130                 if (*activep && *intptr == -1)
1131                         *intptr = value;
1132                 break;
1133
1134         case sUseDNS:
1135                 intptr = &options->use_dns;
1136                 goto parse_flag;
1137
1138         case sLogFacility:
1139                 log_facility_ptr = &options->log_facility;
1140                 arg = strdelim(&cp);
1141                 value = log_facility_number(arg);
1142                 if (value == SYSLOG_FACILITY_NOT_SET)
1143                         fatal("%.200s line %d: unsupported log facility '%s'",
1144                             filename, linenum, arg ? arg : "<NONE>");
1145                 if (*log_facility_ptr == -1)
1146                         *log_facility_ptr = (SyslogFacility) value;
1147                 break;
1148
1149         case sLogLevel:
1150                 log_level_ptr = &options->log_level;
1151                 arg = strdelim(&cp);
1152                 value = log_level_number(arg);
1153                 if (value == SYSLOG_LEVEL_NOT_SET)
1154                         fatal("%.200s line %d: unsupported log level '%s'",
1155                             filename, linenum, arg ? arg : "<NONE>");
1156                 if (*log_level_ptr == -1)
1157                         *log_level_ptr = (LogLevel) value;
1158                 break;
1159
1160         case sAllowTcpForwarding:
1161                 intptr = &options->allow_tcp_forwarding;
1162                 goto parse_flag;
1163
1164         case sAllowAgentForwarding:
1165                 intptr = &options->allow_agent_forwarding;
1166                 goto parse_flag;
1167
1168         case sUsePrivilegeSeparation:
1169                 intptr = &use_privsep;
1170                 goto parse_flag;
1171
1172         case sAllowUsers:
1173                 while ((arg = strdelim(&cp)) && *arg != '\0') {
1174                         if (options->num_allow_users >= MAX_ALLOW_USERS)
1175                                 fatal("%s line %d: too many allow users.",
1176                                     filename, linenum);
1177                         options->allow_users[options->num_allow_users++] =
1178                             xstrdup(arg);
1179                 }
1180                 break;
1181
1182         case sDenyUsers:
1183                 while ((arg = strdelim(&cp)) && *arg != '\0') {
1184                         if (options->num_deny_users >= MAX_DENY_USERS)
1185                                 fatal("%s line %d: too many deny users.",
1186                                     filename, linenum);
1187                         options->deny_users[options->num_deny_users++] =
1188                             xstrdup(arg);
1189                 }
1190                 break;
1191
1192         case sAllowGroups:
1193                 while ((arg = strdelim(&cp)) && *arg != '\0') {
1194                         if (options->num_allow_groups >= MAX_ALLOW_GROUPS)
1195                                 fatal("%s line %d: too many allow groups.",
1196                                     filename, linenum);
1197                         options->allow_groups[options->num_allow_groups++] =
1198                             xstrdup(arg);
1199                 }
1200                 break;
1201
1202         case sDenyGroups:
1203                 while ((arg = strdelim(&cp)) && *arg != '\0') {
1204                         if (options->num_deny_groups >= MAX_DENY_GROUPS)
1205                                 fatal("%s line %d: too many deny groups.",
1206                                     filename, linenum);
1207                         options->deny_groups[options->num_deny_groups++] = xstrdup(arg);
1208                 }
1209                 break;
1210
1211         case sCiphers:
1212                 arg = strdelim(&cp);
1213                 if (!arg || *arg == '\0')
1214                         fatal("%s line %d: Missing argument.", filename, linenum);
1215                 if (!ciphers_valid(arg))
1216                         fatal("%s line %d: Bad SSH2 cipher spec '%s'.",
1217                             filename, linenum, arg ? arg : "<NONE>");
1218                 if (options->ciphers == NULL)
1219                         options->ciphers = xstrdup(arg);
1220                 break;
1221
1222         case sMacs:
1223                 arg = strdelim(&cp);
1224                 if (!arg || *arg == '\0')
1225                         fatal("%s line %d: Missing argument.", filename, linenum);
1226                 if (!mac_valid(arg))
1227                         fatal("%s line %d: Bad SSH2 mac spec '%s'.",
1228                             filename, linenum, arg ? arg : "<NONE>");
1229                 if (options->macs == NULL)
1230                         options->macs = xstrdup(arg);
1231                 break;
1232
1233         case sProtocol:
1234                 intptr = &options->protocol;
1235                 arg = strdelim(&cp);
1236                 if (!arg || *arg == '\0')
1237                         fatal("%s line %d: Missing argument.", filename, linenum);
1238                 value = proto_spec(arg);
1239                 if (value == SSH_PROTO_UNKNOWN)
1240                         fatal("%s line %d: Bad protocol spec '%s'.",
1241                             filename, linenum, arg ? arg : "<NONE>");
1242                 if (*intptr == SSH_PROTO_UNKNOWN)
1243                         *intptr = value;
1244                 break;
1245
1246         case sSubsystem:
1247                 if (options->num_subsystems >= MAX_SUBSYSTEMS) {
1248                         fatal("%s line %d: too many subsystems defined.",
1249                             filename, linenum);
1250                 }
1251                 arg = strdelim(&cp);
1252                 if (!arg || *arg == '\0')
1253                         fatal("%s line %d: Missing subsystem name.",
1254                             filename, linenum);
1255                 if (!*activep) {
1256                         arg = strdelim(&cp);
1257                         break;
1258                 }
1259                 for (i = 0; i < options->num_subsystems; i++)
1260                         if (strcmp(arg, options->subsystem_name[i]) == 0)
1261                                 fatal("%s line %d: Subsystem '%s' already defined.",
1262                                     filename, linenum, arg);
1263                 options->subsystem_name[options->num_subsystems] = xstrdup(arg);
1264                 arg = strdelim(&cp);
1265                 if (!arg || *arg == '\0')
1266                         fatal("%s line %d: Missing subsystem command.",
1267                             filename, linenum);
1268                 options->subsystem_command[options->num_subsystems] = xstrdup(arg);
1269
1270                 /* Collect arguments (separate to executable) */
1271                 p = xstrdup(arg);
1272                 len = strlen(p) + 1;
1273                 while ((arg = strdelim(&cp)) != NULL && *arg != '\0') {
1274                         len += 1 + strlen(arg);
1275                         p = xrealloc(p, 1, len);
1276                         strlcat(p, " ", len);
1277                         strlcat(p, arg, len);
1278                 }
1279                 options->subsystem_args[options->num_subsystems] = p;
1280                 options->num_subsystems++;
1281                 break;
1282
1283         case sMaxStartups:
1284                 arg = strdelim(&cp);
1285                 if (!arg || *arg == '\0')
1286                         fatal("%s line %d: Missing MaxStartups spec.",
1287                             filename, linenum);
1288                 if ((n = sscanf(arg, "%d:%d:%d",
1289                     &options->max_startups_begin,
1290                     &options->max_startups_rate,
1291                     &options->max_startups)) == 3) {
1292                         if (options->max_startups_begin >
1293                             options->max_startups ||
1294                             options->max_startups_rate > 100 ||
1295                             options->max_startups_rate < 1)
1296                                 fatal("%s line %d: Illegal MaxStartups spec.",
1297                                     filename, linenum);
1298                 } else if (n != 1)
1299                         fatal("%s line %d: Illegal MaxStartups spec.",
1300                             filename, linenum);
1301                 else
1302                         options->max_startups = options->max_startups_begin;
1303                 break;
1304
1305         case sMaxAuthTries:
1306                 intptr = &options->max_authtries;
1307                 goto parse_int;
1308
1309         case sMaxSessions:
1310                 intptr = &options->max_sessions;
1311                 goto parse_int;
1312
1313         case sBanner:
1314                 charptr = &options->banner;
1315                 goto parse_filename;
1316
1317         /*
1318          * These options can contain %X options expanded at
1319          * connect time, so that you can specify paths like:
1320          *
1321          * AuthorizedKeysFile   /etc/ssh_keys/%u
1322          */
1323         case sAuthorizedKeysFile:
1324         case sAuthorizedKeysFile2:
1325                 charptr = (opcode == sAuthorizedKeysFile) ?
1326                     &options->authorized_keys_file :
1327                     &options->authorized_keys_file2;
1328                 goto parse_filename;
1329
1330         case sClientAliveInterval:
1331                 intptr = &options->client_alive_interval;
1332                 goto parse_time;
1333
1334         case sClientAliveCountMax:
1335                 intptr = &options->client_alive_count_max;
1336                 goto parse_int;
1337
1338         case sAcceptEnv:
1339                 while ((arg = strdelim(&cp)) && *arg != '\0') {
1340                         if (strchr(arg, '=') != NULL)
1341                                 fatal("%s line %d: Invalid environment name.",
1342                                     filename, linenum);
1343                         if (options->num_accept_env >= MAX_ACCEPT_ENV)
1344                                 fatal("%s line %d: too many allow env.",
1345                                     filename, linenum);
1346                         if (!*activep)
1347                                 break;
1348                         options->accept_env[options->num_accept_env++] =
1349                             xstrdup(arg);
1350                 }
1351                 break;
1352
1353         case sPermitTunnel:
1354                 intptr = &options->permit_tun;
1355                 arg = strdelim(&cp);
1356                 if (!arg || *arg == '\0')
1357                         fatal("%s line %d: Missing yes/point-to-point/"
1358                             "ethernet/no argument.", filename, linenum);
1359                 value = -1;
1360                 for (i = 0; tunmode_desc[i].val != -1; i++)
1361                         if (strcmp(tunmode_desc[i].text, arg) == 0) {
1362                                 value = tunmode_desc[i].val;
1363                                 break;
1364                         }
1365                 if (value == -1)
1366                         fatal("%s line %d: Bad yes/point-to-point/ethernet/"
1367                             "no argument: %s", filename, linenum, arg);
1368                 if (*intptr == -1)
1369                         *intptr = value;
1370                 break;
1371
1372         case sMatch:
1373                 if (cmdline)
1374                         fatal("Match directive not supported as a command-line "
1375                            "option");
1376                 value = match_cfg_line(&cp, linenum, user, host, address);
1377                 if (value < 0)
1378                         fatal("%s line %d: Bad Match condition", filename,
1379                             linenum);
1380                 *activep = value;
1381                 break;
1382
1383         case sPermitOpen:
1384                 arg = strdelim(&cp);
1385                 if (!arg || *arg == '\0')
1386                         fatal("%s line %d: missing PermitOpen specification",
1387                             filename, linenum);
1388                 n = options->num_permitted_opens;       /* modified later */
1389                 if (strcmp(arg, "any") == 0) {
1390                         if (*activep && n == -1) {
1391                                 channel_clear_adm_permitted_opens();
1392                                 options->num_permitted_opens = 0;
1393                         }
1394                         break;
1395                 }
1396                 if (*activep && n == -1)
1397                         channel_clear_adm_permitted_opens();
1398                 for (; arg != NULL && *arg != '\0'; arg = strdelim(&cp)) {
1399                         p = hpdelim(&arg);
1400                         if (p == NULL)
1401                                 fatal("%s line %d: missing host in PermitOpen",
1402                                     filename, linenum);
1403                         p = cleanhostname(p);
1404                         if (arg == NULL || (port = a2port(arg)) == 0)
1405                                 fatal("%s line %d: bad port number in "
1406                                     "PermitOpen", filename, linenum);
1407                         if (*activep && n == -1)
1408                                 options->num_permitted_opens =
1409                                     channel_add_adm_permitted_opens(p, port);
1410                 }
1411                 break;
1412
1413         case sForceCommand:
1414                 if (cp == NULL)
1415                         fatal("%.200s line %d: Missing argument.", filename,
1416                             linenum);
1417                 len = strspn(cp, WHITESPACE);
1418                 if (*activep && options->adm_forced_command == NULL)
1419                         options->adm_forced_command = xstrdup(cp + len);
1420                 return 0;
1421
1422         case sChrootDirectory:
1423                 charptr = &options->chroot_directory;
1424
1425                 arg = strdelim(&cp);
1426                 if (!arg || *arg == '\0')
1427                         fatal("%s line %d: missing file name.",
1428                             filename, linenum);
1429                 if (*activep && *charptr == NULL)
1430                         *charptr = xstrdup(arg);
1431                 break;
1432
1433         case sDeprecated:
1434                 logit("%s line %d: Deprecated option %s",
1435                     filename, linenum, arg);
1436                 while (arg)
1437                     arg = strdelim(&cp);
1438                 break;
1439
1440         case sUnsupported:
1441                 logit("%s line %d: Unsupported option %s",
1442                     filename, linenum, arg);
1443                 while (arg)
1444                     arg = strdelim(&cp);
1445                 break;
1446
1447         default:
1448                 fatal("%s line %d: Missing handler for opcode %s (%d)",
1449                     filename, linenum, arg, opcode);
1450         }
1451         if ((arg = strdelim(&cp)) != NULL && *arg != '\0')
1452                 fatal("%s line %d: garbage at end of line; \"%.200s\".",
1453                     filename, linenum, arg);
1454         return 0;
1455 }
1456
1457 /* Reads the server configuration file. */
1458
1459 void
1460 load_server_config(const char *filename, Buffer *conf)
1461 {
1462         char line[1024], *cp;
1463         FILE *f;
1464
1465         debug2("%s: filename %s", __func__, filename);
1466         if ((f = fopen(filename, "r")) == NULL) {
1467                 perror(filename);
1468                 exit(1);
1469         }
1470         buffer_clear(conf);
1471         while (fgets(line, sizeof(line), f)) {
1472                 /*
1473                  * Trim out comments and strip whitespace
1474                  * NB - preserve newlines, they are needed to reproduce
1475                  * line numbers later for error messages
1476                  */
1477                 if ((cp = strchr(line, '#')) != NULL)
1478                         memcpy(cp, "\n", 2);
1479                 cp = line + strspn(line, " \t\r");
1480
1481                 buffer_append(conf, cp, strlen(cp));
1482         }
1483         buffer_append(conf, "\0", 1);
1484         fclose(f);
1485         debug2("%s: done config len = %d", __func__, buffer_len(conf));
1486 }
1487
1488 void
1489 parse_server_match_config(ServerOptions *options, const char *user,
1490     const char *host, const char *address)
1491 {
1492         ServerOptions mo;
1493
1494         initialize_server_options(&mo);
1495         parse_server_config(&mo, "reprocess config", &cfg, user, host, address);
1496         copy_set_server_options(options, &mo, 0);
1497 }
1498
1499 /* Helper macros */
1500 #define M_CP_INTOPT(n) do {\
1501         if (src->n != -1) \
1502                 dst->n = src->n; \
1503 } while (0)
1504 #define M_CP_STROPT(n) do {\
1505         if (src->n != NULL) { \
1506                 if (dst->n != NULL) \
1507                         xfree(dst->n); \
1508                 dst->n = src->n; \
1509         } \
1510 } while(0)
1511
1512 /*
1513  * Copy any supported values that are set.
1514  *
1515  * If the preauth flag is set, we do not bother copying the the string or
1516  * array values that are not used pre-authentication, because any that we
1517  * do use must be explictly sent in mm_getpwnamallow().
1518  */
1519 void
1520 copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
1521 {
1522         M_CP_INTOPT(password_authentication);
1523         M_CP_INTOPT(gss_authentication);
1524         M_CP_INTOPT(gss_deleg_creds);
1525         M_CP_INTOPT(rsa_authentication);
1526         M_CP_INTOPT(pubkey_authentication);
1527         M_CP_INTOPT(kerberos_authentication);
1528         M_CP_INTOPT(hostbased_authentication);
1529         M_CP_INTOPT(kbd_interactive_authentication);
1530         M_CP_INTOPT(permit_root_login);
1531
1532         M_CP_INTOPT(allow_tcp_forwarding);
1533         M_CP_INTOPT(allow_agent_forwarding);
1534         M_CP_INTOPT(gateway_ports);
1535         M_CP_INTOPT(x11_display_offset);
1536         M_CP_INTOPT(x11_forwarding);
1537         M_CP_INTOPT(x11_use_localhost);
1538         M_CP_INTOPT(max_sessions);
1539         M_CP_INTOPT(max_authtries);
1540
1541         M_CP_STROPT(banner);
1542         if (preauth)
1543                 return;
1544         M_CP_STROPT(adm_forced_command);
1545         M_CP_STROPT(chroot_directory);
1546 }
1547
1548 #undef M_CP_INTOPT
1549 #undef M_CP_STROPT
1550
1551 void
1552 parse_server_config(ServerOptions *options, const char *filename, Buffer *conf,
1553     const char *user, const char *host, const char *address)
1554 {
1555         int active, linenum, bad_options = 0;
1556         char *cp, *obuf, *cbuf;
1557
1558         debug2("%s: config %s len %d", __func__, filename, buffer_len(conf));
1559
1560         obuf = cbuf = xstrdup(buffer_ptr(conf));
1561         active = user ? 0 : 1;
1562         linenum = 1;
1563         while ((cp = strsep(&cbuf, "\n")) != NULL) {
1564                 if (process_server_config_line(options, cp, filename,
1565                     linenum++, &active, user, host, address) != 0)
1566                         bad_options++;
1567         }
1568         xfree(obuf);
1569         if (bad_options > 0)
1570                 fatal("%s: terminating, %d bad configuration options",
1571                     filename, bad_options);
1572 }
1573
1574 static const char *
1575 fmt_intarg(ServerOpCodes code, int val)
1576 {
1577         if (code == sAddressFamily) {
1578                 switch (val) {
1579                 case AF_INET:
1580                         return "inet";
1581                 case AF_INET6:
1582                         return "inet6";
1583                 case AF_UNSPEC:
1584                         return "any";
1585                 default:
1586                         return "UNKNOWN";
1587                 }
1588         }
1589         if (code == sPermitRootLogin) {
1590                 switch (val) {
1591                 case PERMIT_NO_PASSWD:
1592                         return "without-passord";
1593                 case PERMIT_FORCED_ONLY:
1594                         return "forced-commands-only";
1595                 case PERMIT_YES:
1596                         return "yes";
1597                 }
1598         }
1599         if (code == sProtocol) {
1600                 switch (val) {
1601                 case SSH_PROTO_1:
1602                         return "1";
1603                 case SSH_PROTO_2:
1604                         return "2";
1605                 case (SSH_PROTO_1|SSH_PROTO_2):
1606                         return "2,1";
1607                 default:
1608                         return "UNKNOWN";
1609                 }
1610         }
1611         if (code == sGatewayPorts && val == 2)
1612                 return "clientspecified";
1613         if (code == sCompression && val == COMP_DELAYED)
1614                 return "delayed";
1615         switch (val) {
1616         case -1:
1617                 return "unset";
1618         case 0:
1619                 return "no";
1620         case 1:
1621                 return "yes";
1622         }
1623         return "UNKNOWN";
1624 }
1625
1626 static const char *
1627 lookup_opcode_name(ServerOpCodes code)
1628 {
1629         u_int i;
1630
1631         for (i = 0; keywords[i].name != NULL; i++)
1632                 if (keywords[i].opcode == code)
1633                         return(keywords[i].name);
1634         return "UNKNOWN";
1635 }
1636
1637 static void
1638 dump_cfg_int(ServerOpCodes code, int val)
1639 {
1640         printf("%s %d\n", lookup_opcode_name(code), val);
1641 }
1642
1643 static void
1644 dump_cfg_fmtint(ServerOpCodes code, int val)
1645 {
1646         printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
1647 }
1648
1649 static void
1650 dump_cfg_string(ServerOpCodes code, const char *val)
1651 {
1652         if (val == NULL)
1653                 return;
1654         printf("%s %s\n", lookup_opcode_name(code), val);
1655 }
1656
1657 static void
1658 dump_cfg_strarray(ServerOpCodes code, u_int count, char **vals)
1659 {
1660         u_int i;
1661
1662         for (i = 0; i < count; i++)
1663                 printf("%s %s\n", lookup_opcode_name(code),  vals[i]);
1664 }
1665
1666 void
1667 dump_config(ServerOptions *o)
1668 {
1669         u_int i;
1670         int ret;
1671         struct addrinfo *ai;
1672         char addr[NI_MAXHOST], port[NI_MAXSERV], *s = NULL;
1673
1674         /* these are usually at the top of the config */
1675         for (i = 0; i < o->num_ports; i++)
1676                 printf("port %d\n", o->ports[i]);
1677         dump_cfg_fmtint(sProtocol, o->protocol);
1678         dump_cfg_fmtint(sAddressFamily, o->address_family);
1679
1680         /* ListenAddress must be after Port */
1681         for (ai = o->listen_addrs; ai; ai = ai->ai_next) {
1682                 if ((ret = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr,
1683                     sizeof(addr), port, sizeof(port),
1684                     NI_NUMERICHOST|NI_NUMERICSERV)) != 0) {
1685                         error("getnameinfo failed: %.100s",
1686                             (ret != EAI_SYSTEM) ? gai_strerror(ret) :
1687                             strerror(errno));
1688                 } else {
1689                         if (ai->ai_family == AF_INET6)
1690                                 printf("listenaddress [%s]:%s\n", addr, port);
1691                         else
1692                                 printf("listenaddress %s:%s\n", addr, port);
1693                 }
1694         }
1695
1696         /* integer arguments */
1697         dump_cfg_int(sServerKeyBits, o->server_key_bits);
1698         dump_cfg_int(sLoginGraceTime, o->login_grace_time);
1699         dump_cfg_int(sKeyRegenerationTime, o->key_regeneration_time);
1700         dump_cfg_int(sX11DisplayOffset, o->x11_display_offset);
1701         dump_cfg_int(sMaxAuthTries, o->max_authtries);
1702         dump_cfg_int(sClientAliveInterval, o->client_alive_interval);
1703         dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max);
1704
1705         /* formatted integer arguments */
1706         dump_cfg_fmtint(sPermitRootLogin, o->permit_root_login);
1707         dump_cfg_fmtint(sIgnoreRhosts, o->ignore_rhosts);
1708         dump_cfg_fmtint(sIgnoreUserKnownHosts, o->ignore_user_known_hosts);
1709         dump_cfg_fmtint(sRhostsRSAAuthentication, o->rhosts_rsa_authentication);
1710         dump_cfg_fmtint(sHostbasedAuthentication, o->hostbased_authentication);
1711         dump_cfg_fmtint(sHostbasedUsesNameFromPacketOnly,
1712             o->hostbased_uses_name_from_packet_only);
1713         dump_cfg_fmtint(sRSAAuthentication, o->rsa_authentication);
1714         dump_cfg_fmtint(sPubkeyAuthentication, o->pubkey_authentication);
1715         dump_cfg_fmtint(sKerberosAuthentication, o->kerberos_authentication);
1716         dump_cfg_fmtint(sKerberosOrLocalPasswd, o->kerberos_or_local_passwd);
1717         dump_cfg_fmtint(sKerberosTicketCleanup, o->kerberos_ticket_cleanup);
1718         dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token);
1719         dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
1720         dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
1721         dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
1722         dump_cfg_fmtint(sKbdInteractiveAuthentication,
1723             o->kbd_interactive_authentication);
1724         dump_cfg_fmtint(sChallengeResponseAuthentication,
1725             o->challenge_response_authentication);
1726         dump_cfg_fmtint(sPrintMotd, o->print_motd);
1727         dump_cfg_fmtint(sPrintLastLog, o->print_lastlog);
1728         dump_cfg_fmtint(sX11Forwarding, o->x11_forwarding);
1729         dump_cfg_fmtint(sX11UseLocalhost, o->x11_use_localhost);
1730         dump_cfg_fmtint(sStrictModes, o->strict_modes);
1731         dump_cfg_fmtint(sTCPKeepAlive, o->tcp_keep_alive);
1732         dump_cfg_fmtint(sEmptyPasswd, o->permit_empty_passwd);
1733         dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env);
1734         dump_cfg_fmtint(sUseLogin, o->use_login);
1735         dump_cfg_fmtint(sCompression, o->compression);
1736         dump_cfg_fmtint(sGatewayPorts, o->gateway_ports);
1737         dump_cfg_fmtint(sUseDNS, o->use_dns);
1738         dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding);
1739         dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep);
1740
1741         /* string arguments */
1742         dump_cfg_string(sPidFile, o->pid_file);
1743         dump_cfg_string(sXAuthLocation, o->xauth_location);
1744         dump_cfg_string(sCiphers, o->ciphers);
1745         dump_cfg_string(sMacs, o->macs);
1746         dump_cfg_string(sBanner, o->banner);
1747         dump_cfg_string(sAuthorizedKeysFile, o->authorized_keys_file);
1748         dump_cfg_string(sAuthorizedKeysFile2, o->authorized_keys_file2);
1749         dump_cfg_string(sForceCommand, o->adm_forced_command);
1750
1751         /* string arguments requiring a lookup */
1752         dump_cfg_string(sLogLevel, log_level_name(o->log_level));
1753         dump_cfg_string(sLogFacility, log_facility_name(o->log_facility));
1754
1755         /* string array arguments */
1756         dump_cfg_strarray(sHostKeyFile, o->num_host_key_files,
1757              o->host_key_files);
1758         dump_cfg_strarray(sAllowUsers, o->num_allow_users, o->allow_users);
1759         dump_cfg_strarray(sDenyUsers, o->num_deny_users, o->deny_users);
1760         dump_cfg_strarray(sAllowGroups, o->num_allow_groups, o->allow_groups);
1761         dump_cfg_strarray(sDenyGroups, o->num_deny_groups, o->deny_groups);
1762         dump_cfg_strarray(sAcceptEnv, o->num_accept_env, o->accept_env);
1763
1764         /* other arguments */
1765         for (i = 0; i < o->num_subsystems; i++)
1766                 printf("subsystem %s %s\n", o->subsystem_name[i],
1767                     o->subsystem_args[i]);
1768
1769         printf("maxstartups %d:%d:%d\n", o->max_startups_begin,
1770             o->max_startups_rate, o->max_startups);
1771
1772         for (i = 0; tunmode_desc[i].val != -1; i++)
1773                 if (tunmode_desc[i].val == o->permit_tun) {
1774                         s = tunmode_desc[i].text;
1775                         break;
1776                 }
1777         dump_cfg_string(sPermitTunnel, s);
1778
1779         printf("permitopen");
1780         channel_print_adm_permitted_opens();
1781         printf("\n");
1782 }
This page took 0.182821 seconds and 5 git commands to generate.