config.c 8.69 KB
Newer Older
Roger Dingledine's avatar
Roger Dingledine committed
1
2
3
4
5
6
7
8
9
10
/**
 * config.c 
 * Routines for loading the configuration file.
 *
 * Matej Pfajfar <mp292@cam.ac.uk>
 */

/*
 * Changes :
 * $Log$
11
12
13
 * Revision 1.10  2002/07/15 16:42:27  montrose
 * corrected some string literals
 *
14
15
16
 * Revision 1.9  2002/07/11 19:03:44  montrose
 * finishing touches. think its ready for integration now.
 *
17
18
19
 * Revision 1.8  2002/07/11 18:38:15  montrose
 * added new option GlobalRole to getoptions()
 *
20
21
22
 * Revision 1.7  2002/07/11 14:50:26  montrose
 * cleaned up some, added validation to getoptions()
 *
Bruce Montrose's avatar
Bruce Montrose committed
23
24
25
 * Revision 1.6  2002/07/10 12:37:49  montrose
 * Added usage display on error.
 *
26
27
28
 * Revision 1.5  2002/07/09 19:51:41  montrose
 * Miscellaneous bug fixes / activated "make check" for src/or
 *
29
30
31
 * Revision 1.4  2002/07/03 19:58:18  montrose
 * minor bug fix in error checking
 *
32
33
34
 * Revision 1.3  2002/07/03 16:53:34  montrose
 * added error checking into getoptions()
 *
35
36
37
38
39
 * Revision 1.2  2002/07/03 16:31:22  montrose
 * Added getoptions() and made minor adjustment to poptReadDefaultOptions()
 *
 * Revision 1.1.1.1  2002/06/26 22:45:50  arma
 * initial commit: current code
Roger Dingledine's avatar
Roger Dingledine committed
40
41
42
43
44
45
46
47
48
49
50
51
52
 *
 * Revision 1.3  2002/04/02 14:28:24  badbytes
 * Final finishes.
 *
 * Revision 1.2  2002/01/27 00:42:50  mp292
 * Reviewed according to Secure-Programs-HOWTO.
 *
 * Revision 1.1  2002/01/03 10:24:05  badbytes
 * COde based on that in op. Needs to be modified.
 *
 */

#include "or.h"
53
#include <libgen.h>
Roger Dingledine's avatar
Roger Dingledine committed
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

/* loads the configuration file */
int getconfig(char *conf_filename, config_opt_t *options)
{
  FILE *cf = NULL;
  int retval = 0;
  
  if ((!conf_filename) || (!options))
    return -1;
  
  /* load config file */
  cf = open_config(conf_filename);
  if (!cf)
  {
    log(LOG_ERR,"Could not open configuration file %s.",conf_filename);
    return -1;
  }
  retval = parse_config(cf,options);
  if (retval)
    return -1;

  return 0;
}

78
79
int getoptions(int argc, char **argv, or_options_t *options)
/**
80

81
82
83
A replacement for getargs() and getconfig() which uses the <popt> library to parse
both command-line arguments and configuration files. A specific configuration file
may be specified using the --ConfigFile option. If one is not specified, then the
84
85
86
87
configuration files at /etc/<cmd>rc and ~/.<cmd>rc will be loaded in that order so
user preferences will override the ones specified in /etc.

The --ConfigFile (-f) option may only be used on the command-line. All other command-line
88
options may also be specified in configuration files. <popt> aliases are enabled
89
90
91
so a user can define their own options in the /etc/popt or ~/.popt files as outlined
in "man popt" pages.

92
93
94
95
96
97
98
99
100
101
RETURN VALUE: 0 on success, non-zero on error
**/
{
   char *ConfigFile;
   int Verbose;
   int code;
   poptContext optCon;
   char *cmd;
   struct poptOption opt_tab[] =
   {
102
      { "APPort",          'a',  POPT_ARG_INT,     &options->APPort,
103
         0, "application proxy port",                          "<port>" },
104
      { "CoinWeight",      'w',  POPT_ARG_FLOAT,   &options->CoinWeight,
105
         0, "coin weight used in determining routes",          "<weight>" },
106
      { "ConfigFile",      'f',  POPT_ARG_STRING,  &ConfigFile,
107
         0, "user specified configuration file",               "<file>" },
108
      { "LogLevel",        'l',  POPT_ARG_STRING,  &options->LogLevel,
109
         0, "emerg|alert|crit|err|warning|notice|info|debug",  "<level>" },
110
      { "MaxConn",         'm',  POPT_ARG_INT,     &options->MaxConn,
111
         0, "maximum number of incoming connections",          "<max>" },
112
      { "OPPort",          'o',  POPT_ARG_INT,     &options->OPPort,
113
         0, "onion proxy port",                                "<port>" },
114
      { "ORPort",          'p',  POPT_ARG_INT,     &options->ORPort,
115
         0, "onion router port",                               "<port>" },
116
      { "PrivateKeyFile",  'k',  POPT_ARG_STRING,  &options->PrivateKeyFile,
117
         0, "maximum number of incoming connections",          "<file>" },
118
      { "RouterFile",      'r',  POPT_ARG_STRING,  &options->RouterFile,
119
         0, "local port on which the onion proxy is running",  "<file>" },
120
      { "TrafficShaping",  't',  POPT_ARG_INT,     &options->TrafficShaping,
121
         0, "which traffic shaping policy to use",             "<policy>" },
122
123
124
      { "GlobalRole",      'g',  POPT_ARG_INT,     &options->GlobalRole,
         0, "4-bit global role id",                            "<role>" },
      { "Verbose",         'v',  POPT_ARG_NONE,    &Verbose,
125
         0, "display options selected before execution",       NULL },
126
127
128
129
130
131
132
133
      POPT_AUTOHELP  /* handles --usage and --help automatically */
      POPT_TABLEEND  /* marks end of table */
   };
   cmd = basename(argv[0]);
   optCon = poptGetContext(cmd,argc,(const char **)argv,opt_tab,0);

   poptReadDefaultConfig(optCon,0);       /* read <popt> alias definitions */

134
135
136
   /* assign default option values */

   bzero(options,sizeof(or_options_t));
137
   options->LogLevel = "debug";
138
139
140
   options->loglevel = LOG_DEBUG;
   options->CoinWeight = 0.8;
   options->GlobalRole = ROLE_OR_LISTEN | ROLE_OR_CONNECT_ALL | ROLE_OP_LISTEN | ROLE_AP_LISTEN;
141
142

   code = poptGetNextOpt(optCon);         /* first we handle command-line args */
143
   if ( code == -1 )
144
   {
145
      if ( ConfigFile )                   /* handle user-specified config file */
146
147
148
         code = poptReadOptions(optCon,ConfigFile);
      else                                /* load Default configuration files */
         code = poptReadDefaultOptions(cmd,optCon);
149
150
   }

151
   switch(code)                           /* error checking */
152
   {
153
   case INT_MIN:
154
      log(LOG_ERR, "%s: Unable to open configuration file.\n", ConfigFile);
155
      break;
156
157
   case -1:
      code = 0;
158
      break;
159
   default:
Bruce Montrose's avatar
Bruce Montrose committed
160
      poptPrintUsage(optCon, stderr, 0);
161
      log(LOG_ERR, "%s: %s\n", poptBadOption(optCon, POPT_BADOPTION_NOALIAS), poptStrerror(code));
162
      break;
163
164
165
166
   }

   poptFreeContext(optCon);

167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
   if ( code ) return code;      /* return here if we encountered any problems */

   /* Display options upon user request */

   if ( Verbose )                      
   {
      printf("LogLevel=%s, GlobalRole=%d\n",
             options->LogLevel,
             options->GlobalRole);
      printf("RouterFile=%s, PrivateKeyFile=%s\n",
             options->RouterFile,
             options->PrivateKeyFile);
      printf("ORPort=%d, OPPort=%d, APPort=%d\n",
             options->ORPort,options->OPPort,
             options->APPort);
      printf("CoinWeight=%6.4f, MaxConn=%d, TrafficShaping=%d\n",
             options->CoinWeight,
             options->MaxConn,
             options->TrafficShaping);
   }

188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
   /* Validate options */

   if ( options->LogLevel )
   {
      if (!strcmp(options->LogLevel,"emerg"))
         options->loglevel = LOG_EMERG;
      else if (!strcmp(options->LogLevel,"alert"))
         options->loglevel = LOG_ALERT;
      else if (!strcmp(options->LogLevel,"crit"))
         options->loglevel = LOG_CRIT;
      else if (!strcmp(options->LogLevel,"err"))
         options->loglevel = LOG_ERR;
      else if (!strcmp(options->LogLevel,"warning"))
         options->loglevel = LOG_WARNING;
      else if (!strcmp(options->LogLevel,"notice"))
         options->loglevel = LOG_NOTICE;
      else if (!strcmp(options->LogLevel,"info"))
         options->loglevel = LOG_INFO;
      else if (!strcmp(options->LogLevel,"debug"))
         options->loglevel = LOG_DEBUG;
      else
      {
         log(LOG_ERR,"LogLevel must be one of emerg|alert|crit|err|warning|notice|info|debug.");
         code = -1;
      }
   }

   if ( options->RouterFile == NULL )
   {
      log(LOG_ERR,"RouterFile option required, but not found.");
      code = -1;
   }

   if ( options->PrivateKeyFile == NULL )
   {
      log(LOG_ERR,"PrivateKeyFile option required, but not found.");
      code = -1;
   }

   if ( options->ORPort < 1 )
   {
      log(LOG_ERR,"ORPort option required and must be a positive integer value.");
      code = -1;
   }

   if ( options->OPPort < 1 )
   {
      log(LOG_ERR,"OPPort option required and must be a positive integer value.");
      code = -1;
   }

   if ( options->APPort < 1 )
   {
      log(LOG_ERR,"APPort option required and must be a positive integer value.");
      code = -1;
   }

   if ( options->CoinWeight < 0.0 || options->CoinWeight >= 1.0 )
   {
247
      log(LOG_ERR,"CoinWeight option must be a value from 0.0 upto 1.0, but not including 1.0.");
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
      code = -1;
   }

   if ( options->MaxConn <= 0 )
   {
      log(LOG_ERR,"MaxConn option must be a non-zero positive integer.");
      code = -1;
   }

   if ( options->TrafficShaping != 0 && options->TrafficShaping != 1 )
   {
      log(LOG_ERR,"TrafficShaping option must be either 0 or 1.");
      code = -1;
   }

263
264
265
266
267
268
   if ( options->GlobalRole < 0 || options->GlobalRole > 15 )
   {
      log(LOG_ERR,"GlobalRole option must be an integer between 0 and 15 (inclusive).");
      code = -1;
   }

269
   return code;
270
271
}