]> andersk Git - openssh.git/blob - readconf.c
9e4bd5f980dd29189dc4bb027b38be5794dbb8ff
[openssh.git] / readconf.c
1 /*
2
3 readconf.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: Sat Apr 22 00:03:10 1995 ylo
11
12 Functions for reading the configuration files.
13
14 */
15
16 #include "includes.h"
17 RCSID("$Id$");
18
19 #include "ssh.h"
20 #include "cipher.h"
21 #include "readconf.h"
22 #include "xmalloc.h"
23
24 /* Format of the configuration file:
25
26    # Configuration data is parsed as follows:
27    #  1. command line options
28    #  2. user-specific file
29    #  3. system-wide file
30    # Any configuration value is only changed the first time it is set.
31    # Thus, host-specific definitions should be at the beginning of the
32    # configuration file, and defaults at the end.
33
34    # Host-specific declarations.  These may override anything above.  A single
35    # host may match multiple declarations; these are processed in the order
36    # that they are given in.
37
38    Host *.ngs.fi ngs.fi
39      FallBackToRsh no
40
41    Host fake.com
42      HostName another.host.name.real.org
43      User blaah
44      Port 34289
45      ForwardX11 no
46      ForwardAgent no
47
48    Host books.com
49      RemoteForward 9999 shadows.cs.hut.fi:9999
50      Cipher 3des
51
52    Host fascist.blob.com
53      Port 23123
54      User tylonen
55      RhostsAuthentication no
56      PasswordAuthentication no
57
58    Host puukko.hut.fi
59      User t35124p
60      ProxyCommand ssh-proxy %h %p
61
62    Host *.fr
63      UseRsh yes
64
65    Host *.su
66      Cipher none
67      PasswordAuthentication no
68
69    # Defaults for various options
70    Host *
71      ForwardAgent no
72      ForwardX11 yes
73      RhostsAuthentication yes
74      PasswordAuthentication yes
75      RSAAuthentication yes
76      RhostsRSAAuthentication yes
77      FallBackToRsh no
78      UseRsh no
79      StrictHostKeyChecking yes
80      KeepAlives no
81      IdentityFile ~/.ssh/identity
82      Port 22
83      EscapeChar ~
84
85 */
86
87 /* Keyword tokens. */
88
89 typedef enum
90 {
91   oBadOption,
92   oForwardAgent, oForwardX11, oGatewayPorts, oRhostsAuthentication,
93   oPasswordAuthentication, oRSAAuthentication, oFallBackToRsh, oUseRsh,
94 #ifdef KRB4
95   oKerberosAuthentication,
96 #endif /* KRB4 */
97 #ifdef AFS
98   oKerberosTgtPassing, oAFSTokenPassing,
99 #endif
100   oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward, 
101   oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
102   oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
103   oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
104   oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, oTISAuthentication,
105   oUsePrivilegedPort, oLogLevel
106 } OpCodes;
107
108 /* Textual representations of the tokens. */
109
110 static struct
111 {
112   const char *name;
113   OpCodes opcode;
114 } keywords[] =
115 {
116   { "forwardagent", oForwardAgent },
117   { "forwardx11", oForwardX11 },
118   { "gatewayports", oGatewayPorts },
119   { "useprivilegedport", oUsePrivilegedPort },
120   { "rhostsauthentication", oRhostsAuthentication },
121   { "passwordauthentication", oPasswordAuthentication },
122   { "rsaauthentication", oRSAAuthentication },
123 #ifdef KRB4
124   { "kerberosauthentication", oKerberosAuthentication },
125 #endif /* KRB4 */
126 #ifdef AFS
127   { "kerberostgtpassing", oKerberosTgtPassing },
128   { "afstokenpassing", oAFSTokenPassing },
129 #endif
130   { "fallbacktorsh", oFallBackToRsh },
131   { "usersh", oUseRsh },
132   { "identityfile", oIdentityFile },
133   { "hostname", oHostName },
134   { "proxycommand", oProxyCommand },
135   { "port", oPort },
136   { "cipher", oCipher },
137   { "remoteforward", oRemoteForward },
138   { "localforward", oLocalForward },
139   { "user", oUser },
140   { "host", oHost },
141   { "escapechar", oEscapeChar },
142   { "rhostsrsaauthentication", oRhostsRSAAuthentication },
143   { "globalknownhostsfile", oGlobalKnownHostsFile },
144   { "userknownhostsfile", oUserKnownHostsFile },
145   { "connectionattempts", oConnectionAttempts },
146   { "batchmode", oBatchMode },
147   { "checkhostip", oCheckHostIP },
148   { "stricthostkeychecking", oStrictHostKeyChecking },
149   { "compression", oCompression },
150   { "compressionlevel", oCompressionLevel },
151   { "keepalive", oKeepAlives },
152   { "numberofpasswordprompts", oNumberOfPasswordPrompts },
153   { "tisauthentication", oTISAuthentication },
154   { "loglevel", oLogLevel },
155   { NULL, 0 }
156 };
157
158 /* Characters considered whitespace in strtok calls. */
159 #define WHITESPACE " \t\r\n"
160
161
162 /* Adds a local TCP/IP port forward to options.  Never returns if there
163    is an error. */
164
165 void add_local_forward(Options *options, int port, const char *host,
166                        int host_port)
167 {
168   Forward *fwd;
169   extern uid_t original_real_uid;
170   if ((port & 0xffff) != port)
171     fatal("Requested forwarding of nonexistent port %d.", port);
172   if (port < IPPORT_RESERVED && original_real_uid != 0)
173     fatal("Privileged ports can only be forwarded by root.\n");
174   if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
175     fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
176   fwd = &options->local_forwards[options->num_local_forwards++];
177   fwd->port = port;
178   fwd->host = xstrdup(host);
179   fwd->host_port = host_port;
180 }
181
182 /* Adds a remote TCP/IP port forward to options.  Never returns if there
183    is an error. */
184
185 void add_remote_forward(Options *options, int port, const char *host,
186                        int host_port)
187 {
188   Forward *fwd;
189   if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
190     fatal("Too many remote forwards (max %d).", 
191           SSH_MAX_FORWARDS_PER_DIRECTION);
192   fwd = &options->remote_forwards[options->num_remote_forwards++];
193   fwd->port = port;
194   fwd->host = xstrdup(host);
195   fwd->host_port = host_port;
196 }
197
198 /* Returns the number of the token pointed to by cp of length len.
199    Never returns if the token is not known. */
200
201 static OpCodes parse_token(const char *cp, const char *filename, int linenum)
202 {
203   unsigned int i;
204
205   for (i = 0; keywords[i].name; i++)
206     if (strcmp(cp, keywords[i].name) == 0)
207       return keywords[i].opcode;
208
209   fprintf(stderr, "%s: line %d: Bad configuration option: %s\n", 
210           filename, linenum, cp);
211   return oBadOption;
212 }
213
214 /* Processes a single option line as used in the configuration files.
215    This only sets those values that have not already been set. */
216
217 int
218 process_config_line(Options *options, const char *host,
219                          char *line, const char *filename, int linenum,
220                          int *activep)
221 {
222   char buf[256], *cp, *string, **charptr;
223   int opcode, *intptr, value, fwd_port, fwd_host_port;
224
225   /* Skip leading whitespace. */
226   cp = line + strspn(line, WHITESPACE);
227   if (!*cp || *cp == '\n' || *cp == '#')
228     return 0;
229
230   /* Get the keyword. (Each line is supposed to begin with a keyword). */
231   cp = strtok(cp, WHITESPACE);
232   {
233     char *t = cp;
234     for (; *t != 0; t++)
235       if ('A' <= *t && *t <= 'Z')
236         *t = *t - 'A' + 'a';    /* tolower */
237       
238   }
239   opcode = parse_token(cp, filename, linenum);
240
241   switch (opcode)
242     {
243     case oBadOption:
244       return -1;                /* don't panic, but count bad options */
245       /*NOTREACHED*/
246     case oForwardAgent:
247       intptr = &options->forward_agent;
248     parse_flag:
249       cp = strtok(NULL, WHITESPACE);
250       if (!cp)
251         fatal("%.200s line %d: Missing yes/no argument.", filename, linenum);
252       value = 0; /* To avoid compiler warning... */
253       if (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0)
254         value = 1;
255       else if (strcmp(cp, "no") == 0 || strcmp(cp, "false") == 0)
256         value = 0;
257       else
258         fatal("%.200s line %d: Bad yes/no argument.", filename, linenum);
259       if (*activep && *intptr == -1)
260         *intptr = value;
261       break;
262       
263     case oForwardX11:
264       intptr = &options->forward_x11;
265       goto parse_flag;
266
267     case oGatewayPorts:
268       intptr = &options->gateway_ports;
269       goto parse_flag;
270       
271     case oUsePrivilegedPort:
272       intptr = &options->use_privileged_port;
273       goto parse_flag;
274       
275     case oRhostsAuthentication:
276       intptr = &options->rhosts_authentication;
277       goto parse_flag;
278       
279     case oPasswordAuthentication:
280       intptr = &options->password_authentication;
281       goto parse_flag;
282       
283     case oRSAAuthentication:
284       intptr = &options->rsa_authentication;
285       goto parse_flag;
286       
287     case oRhostsRSAAuthentication:
288       intptr = &options->rhosts_rsa_authentication;
289       goto parse_flag;
290
291 #ifdef KRB4
292     case oKerberosAuthentication:
293       intptr = &options->kerberos_authentication;
294       goto parse_flag;
295 #endif /* KRB4 */
296
297 #ifdef AFS
298     case oKerberosTgtPassing:
299       intptr = &options->kerberos_tgt_passing;
300       goto parse_flag;
301
302     case oAFSTokenPassing:
303       intptr = &options->afs_token_passing;
304       goto parse_flag;
305 #endif
306       
307     case oFallBackToRsh:
308       intptr = &options->fallback_to_rsh;
309       goto parse_flag;
310       
311     case oUseRsh:
312       intptr = &options->use_rsh;
313       goto parse_flag;
314
315     case oBatchMode:
316       intptr = &options->batch_mode;
317       goto parse_flag;
318
319     case oCheckHostIP:
320       intptr = &options->check_host_ip;
321       goto parse_flag;
322
323     case oStrictHostKeyChecking:
324       intptr = &options->strict_host_key_checking;
325       cp = strtok(NULL, WHITESPACE);
326       if (!cp)
327         fatal("%.200s line %d: Missing yes/no argument.",
328               filename, linenum);
329       value = 0; /* To avoid compiler warning... */
330       if (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0)
331         value = 1;
332       else if (strcmp(cp, "no") == 0 || strcmp(cp, "false") == 0)
333         value = 0;
334       else if (strcmp(cp, "ask") == 0)
335         value = 2;
336       else
337         fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum);
338       if (*activep && *intptr == -1)
339         *intptr = value;
340       break;
341       
342     case oCompression:
343       intptr = &options->compression;
344       goto parse_flag;
345
346     case oKeepAlives:
347       intptr = &options->keepalives;
348       goto parse_flag;
349
350     case oNumberOfPasswordPrompts:
351       intptr = &options->number_of_password_prompts;
352       goto parse_int;
353       
354     case oTISAuthentication:
355       cp = strtok(NULL, WHITESPACE);
356       if (cp != 0 && (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0))
357         fprintf(stderr,
358                 "%.99s line %d: Warning, TIS is not supported.\n",
359                 filename,
360                 linenum);
361       break;
362
363     case oCompressionLevel:
364       intptr = &options->compression_level;
365       goto parse_int;
366
367     case oIdentityFile:
368       cp = strtok(NULL, WHITESPACE);
369       if (!cp)
370         fatal("%.200s line %d: Missing argument.", filename, linenum);
371       if (*activep)
372         {
373           if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
374             fatal("%.200s line %d: Too many identity files specified (max %d).",
375                   filename, linenum, SSH_MAX_IDENTITY_FILES);
376           options->identity_files[options->num_identity_files++] = xstrdup(cp);
377         }
378       break;
379       
380     case oUser:
381       charptr = &options->user;
382     parse_string:
383       cp = strtok(NULL, WHITESPACE);
384       if (!cp)
385         fatal("%.200s line %d: Missing argument.", filename, linenum);
386       if (*activep && *charptr == NULL)
387         *charptr = xstrdup(cp);
388       break;
389       
390     case oGlobalKnownHostsFile:
391       charptr = &options->system_hostfile;
392       goto parse_string;
393       
394     case oUserKnownHostsFile:
395       charptr = &options->user_hostfile;
396       goto parse_string;
397
398     case oHostName:
399       charptr = &options->hostname;
400       goto parse_string;
401       
402     case oProxyCommand:
403       charptr = &options->proxy_command;
404       string = xstrdup("");
405       while ((cp = strtok(NULL, WHITESPACE)) != NULL)
406         {
407           string = xrealloc(string, strlen(string) + strlen(cp) + 2);
408           strcat(string, " ");
409           strcat(string, cp);
410         }
411       if (*activep && *charptr == NULL)
412         *charptr = string;
413       else
414         xfree(string);
415       return 0;
416
417     case oPort:
418       intptr = &options->port;
419     parse_int:
420       cp = strtok(NULL, WHITESPACE);
421       if (!cp)
422         fatal("%.200s line %d: Missing argument.", filename, linenum);
423       if (cp[0] < '0' || cp[0] > '9')
424         fatal("%.200s line %d: Bad number.", filename, linenum);
425 #if 0
426       value = atoi(cp);
427 #else
428       {
429         char *ptr;
430         value = strtol(cp, &ptr, 0); /* Octal, decimal, or hex format? */
431         if (cp == ptr)
432           fatal("%.200s line %d: Bad number.", filename, linenum);          
433       }
434 #endif
435       if (*activep && *intptr == -1)
436         *intptr = value;
437       break;
438       
439     case oConnectionAttempts:
440       intptr = &options->connection_attempts;
441       goto parse_int;
442
443     case oCipher:
444       intptr = &options->cipher;
445       cp = strtok(NULL, WHITESPACE);
446       value = cipher_number(cp);
447       if (value == -1)
448         fatal("%.200s line %d: Bad cipher '%s'.",
449               filename, linenum, cp ? cp : "<NONE>");
450       if (*activep && *intptr == -1)
451         *intptr = value;
452       break;
453
454     case oLogLevel:
455       intptr = (int *)&options->log_level;
456       cp = strtok(NULL, WHITESPACE);
457       value = log_level_number(cp);
458       if (value == (LogLevel)-1)
459         fatal("%.200s line %d: unsupported log level '%s'\n",
460               filename, linenum, cp ? cp : "<NONE>");
461       if (*activep && (LogLevel)*intptr == -1)
462         *intptr = (LogLevel)value;
463       break;
464       
465     case oRemoteForward:
466       cp = strtok(NULL, WHITESPACE);
467       if (!cp)
468         fatal("%.200s line %d: Missing argument.", filename, linenum);
469       if (cp[0] < '0' || cp[0] > '9')
470         fatal("%.200s line %d: Badly formatted port number.", 
471               filename, linenum);
472       fwd_port = atoi(cp);
473       cp = strtok(NULL, WHITESPACE);
474       if (!cp)
475         fatal("%.200s line %d: Missing second argument.", 
476               filename, linenum);
477       if (sscanf(cp, "%255[^:]:%d", buf, &fwd_host_port) != 2)
478         fatal("%.200s line %d: Badly formatted host:port.", 
479               filename, linenum);
480       if (*activep)
481         add_remote_forward(options, fwd_port, buf, fwd_host_port);
482       break;
483       
484     case oLocalForward:
485       cp = strtok(NULL, WHITESPACE);
486       if (!cp)
487         fatal("%.200s line %d: Missing argument.", filename, linenum);
488       if (cp[0] < '0' || cp[0] > '9')
489         fatal("%.200s line %d: Badly formatted port number.", 
490               filename, linenum);
491       fwd_port = atoi(cp);
492       cp = strtok(NULL, WHITESPACE);
493       if (!cp)
494         fatal("%.200s line %d: Missing second argument.", 
495               filename, linenum);
496       if (sscanf(cp, "%255[^:]:%d", buf, &fwd_host_port) != 2)
497         fatal("%.200s line %d: Badly formatted host:port.", 
498               filename, linenum);
499       if (*activep)
500         add_local_forward(options, fwd_port, buf, fwd_host_port);
501       break;
502       
503     case oHost:
504       *activep = 0;
505       while ((cp = strtok(NULL, WHITESPACE)) != NULL)
506         if (match_pattern(host, cp))
507           {
508             debug("Applying options for %.100s", cp);
509             *activep = 1;
510             break;
511           }
512       /* Avoid garbage check below, as strtok already returned NULL. */
513       return 0;
514
515     case oEscapeChar:
516       intptr = &options->escape_char;
517       cp = strtok(NULL, WHITESPACE);
518       if (!cp)
519         fatal("%.200s line %d: Missing argument.", filename, linenum);
520       if (cp[0] == '^' && cp[2] == 0 && 
521           (unsigned char)cp[1] >= 64 && (unsigned char)cp[1] < 128)
522         value = (unsigned char)cp[1] & 31;
523       else
524         if (strlen(cp) == 1)
525           value = (unsigned char)cp[0];
526         else
527           if (strcmp(cp, "none") == 0)
528             value = -2;
529           else
530             {
531               fatal("%.200s line %d: Bad escape character.", 
532                     filename, linenum);
533               /*NOTREACHED*/
534               value = 0; /* Avoid compiler warning. */
535             }
536       if (*activep && *intptr == -1)
537         *intptr = value;
538       break;
539       
540     default:
541       fatal("process_config_line: Unimplemented opcode %d", opcode);
542     }
543   
544   /* Check that there is no garbage at end of line. */
545   if (strtok(NULL, WHITESPACE) != NULL)
546     fatal("%.200s line %d: garbage at end of line.",
547           filename, linenum);
548   return 0;
549 }
550
551
552 /* Reads the config file and modifies the options accordingly.  Options should
553    already be initialized before this call.  This never returns if there
554    is an error.  If the file does not exist, this returns immediately. */
555
556 void read_config_file(const char *filename, const char *host, Options *options)
557 {
558   FILE *f;
559   char line[1024];
560   int active, linenum;
561   int bad_options = 0;
562
563   /* Open the file. */
564   f = fopen(filename, "r");
565   if (!f)
566     return;
567
568   debug("Reading configuration data %.200s", filename);
569
570   /* Mark that we are now processing the options.  This flag is turned on/off
571      by Host specifications. */
572   active = 1;
573   linenum = 0;
574   while (fgets(line, sizeof(line), f))
575     {
576       /* Update line number counter. */
577       linenum++;
578       if (process_config_line(options, host, line, filename, linenum, &active) != 0)
579         bad_options++;
580     }
581   fclose(f);
582   if (bad_options > 0)
583     fatal("%s: terminating, %d bad configuration options\n", 
584           filename, bad_options);
585 }
586
587 /* Initializes options to special values that indicate that they have not
588    yet been set.  Read_config_file will only set options with this value.
589    Options are processed in the following order: command line, user config
590    file, system config file.  Last, fill_default_options is called. */
591
592 void initialize_options(Options *options)
593 {
594   memset(options, 'X', sizeof(*options));
595   options->forward_agent = -1;
596   options->forward_x11 = -1;
597   options->gateway_ports = -1;
598   options->use_privileged_port = -1;
599   options->rhosts_authentication = -1;
600   options->rsa_authentication = -1;
601 #ifdef KRB4
602   options->kerberos_authentication = -1;
603 #endif
604 #ifdef AFS
605   options->kerberos_tgt_passing = -1;
606   options->afs_token_passing = -1;
607 #endif
608   options->password_authentication = -1;
609   options->rhosts_rsa_authentication = -1;
610   options->fallback_to_rsh = -1;
611   options->use_rsh = -1;
612   options->batch_mode = -1;
613   options->check_host_ip = -1;
614   options->strict_host_key_checking = -1;
615   options->compression = -1;
616   options->keepalives = -1;
617   options->compression_level = -1;
618   options->port = -1;
619   options->connection_attempts = -1;
620   options->number_of_password_prompts = -1;
621   options->cipher = -1;
622   options->num_identity_files = 0;
623   options->hostname = NULL;
624   options->proxy_command = NULL;
625   options->user = NULL;
626   options->escape_char = -1;
627   options->system_hostfile = NULL;
628   options->user_hostfile = NULL;
629   options->num_local_forwards = 0;
630   options->num_remote_forwards = 0;
631   options->log_level = (LogLevel)-1;
632 }
633
634 /* Called after processing other sources of option data, this fills those
635    options for which no value has been specified with their default values. */
636
637 void fill_default_options(Options *options)
638 {
639   if (options->forward_agent == -1)
640     options->forward_agent = 1;
641   if (options->forward_x11 == -1)
642     options->forward_x11 = 1;
643   if (options->gateway_ports == -1)
644     options->gateway_ports = 0;
645   if (options->use_privileged_port == -1)
646     options->use_privileged_port = 1;
647   if (options->rhosts_authentication == -1)
648     options->rhosts_authentication = 1;
649   if (options->rsa_authentication == -1)
650     options->rsa_authentication = 1;
651 #ifdef KRB4
652   if (options->kerberos_authentication == -1)
653     options->kerberos_authentication = 1;
654 #endif /* KRB4 */
655 #ifdef AFS
656   if (options->kerberos_tgt_passing == -1)
657     options->kerberos_tgt_passing = 1;
658   if (options->afs_token_passing == -1)
659     options->afs_token_passing = 1;
660 #endif /* AFS */
661   if (options->password_authentication == -1)
662     options->password_authentication = 1;
663   if (options->rhosts_rsa_authentication == -1)
664     options->rhosts_rsa_authentication = 1;
665   if (options->fallback_to_rsh == -1)
666     options->fallback_to_rsh = 1;
667   if (options->use_rsh == -1)
668     options->use_rsh = 0;
669   if (options->batch_mode == -1)
670     options->batch_mode = 0;
671   if (options->check_host_ip == -1)
672     options->check_host_ip = 1;
673   if (options->strict_host_key_checking == -1)
674     options->strict_host_key_checking = 2; /* 2 is default */
675   if (options->compression == -1)
676     options->compression = 0;
677   if (options->keepalives == -1)
678     options->keepalives = 1;
679   if (options->compression_level == -1)
680     options->compression_level = 6;
681   if (options->port == -1)
682     options->port = 0; /* Filled in ssh_connect. */
683   if (options->connection_attempts == -1)
684     options->connection_attempts = 4;
685   if (options->number_of_password_prompts == -1)
686     options->number_of_password_prompts = 3;
687   if (options->cipher == -1)
688     options->cipher = SSH_CIPHER_NOT_SET; /* Selected in ssh_login(). */
689   if (options->num_identity_files == 0)
690     {
691       options->identity_files[0] = 
692         xmalloc(2 + strlen(SSH_CLIENT_IDENTITY) + 1);
693       sprintf(options->identity_files[0], "~/%.100s", SSH_CLIENT_IDENTITY);
694       options->num_identity_files = 1;
695     }
696   if (options->escape_char == -1)
697     options->escape_char = '~';
698   if (options->system_hostfile == NULL)
699     options->system_hostfile = SSH_SYSTEM_HOSTFILE;
700   if (options->user_hostfile == NULL)
701     options->user_hostfile = SSH_USER_HOSTFILE;
702   if (options->log_level == (LogLevel)-1)
703     options->log_level = SYSLOG_LEVEL_INFO;
704   /* options->proxy_command should not be set by default */
705   /* options->user will be set in the main program if appropriate */
706   /* options->hostname will be set in the main program if appropriate */
707 }
708
This page took 0.081015 seconds and 3 git commands to generate.