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