~ubuntu-branches/ubuntu/karmic/pdnsd/karmic

« back to all changes in this revision

Viewing changes to src/conff.c

  • Committer: Bazaar Package Importer
  • Author(s): Michael Ablassmeier
  • Date: 2006-10-12 08:18:52 UTC
  • mfrom: (3.1.3 edgy)
  • Revision ID: james.westby@ubuntu.com-20061012081852-k70ha1vynt2vu7mg
Tags: 1.2.4par-0.2
* Non-maintainer upload.
* Check for bind named pidfile in initscript and do not
  try to startup, otherwise pdnsd installation bails
  out if named is running on the same host (Closes: #389609)
* add --no-create-home to adduser call.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* conff.c - Maintain configuration information
 
2
 
2
3
   Copyright (C) 2000, 2001 Thomas Moestl
3
 
 
4
 
   With modifications by Paul Rombouts, 2002, 2003, 2004.
 
4
   Copyright (C) 2002, 2003, 2004, 2005 Paul A. Rombouts
5
5
 
6
6
This file is part of the pdnsd package.
7
7
 
27
27
#include <string.h>
28
28
#include <sys/stat.h>
29
29
#include <unistd.h>
 
30
#include <pwd.h>
30
31
#include "ipvers.h"
31
32
#include "conff.h"
32
33
#include "consts.h"
33
34
#include "helpers.h"
34
 
#include "dns_query.h"
35
35
#include "conf-parser.h"
36
36
#include "servers.h"
 
37
#include "icmp.h"
37
38
 
38
39
#if !defined(lint) && !defined(NO_RCSIDS)
39
40
static char rcsid[]="$Id: conff.c,v 1.26 2001/07/02 18:55:27 tmm Exp $";
42
43
globparm_t global={
43
44
  perm_cache:        2048,
44
45
  cache_dir:         NULL,
 
46
  pidfile:           NULL,
45
47
  port:              53,
46
48
#ifdef ENABLE_IPV4
47
49
  a:                 {{INADDR_ANY}},
48
50
#else
49
51
  a:                 {IN6ADDR_ANY_INIT},
50
52
#endif
 
53
#ifdef ENABLE_IPV6
 
54
  ipv4_6_prefix:     IN6ADDR_ANY_INIT,
 
55
#endif
51
56
  max_ttl:           604800,
52
57
  min_ttl:           120,
53
58
  neg_ttl:           900,
54
59
  neg_rrs_pol:       C_AUTH,
55
60
  neg_domain_pol:    C_AUTH,
 
61
  verbosity:         VERBOSITY,
56
62
  run_as:            "",
 
63
  daemon:            0,
 
64
  debug:             0,
 
65
  stat_pipe:         0,
 
66
  notcp:             0,
57
67
  strict_suid:       1,
58
68
  paranoid:          0,
59
69
  lndown_kluge:      0,
61
71
  rnd_recs:          1,
62
72
  ctl_perms:         0600,
63
73
  scheme_file:       NULL,
64
 
  proc_limit:        20,
65
 
  procq_limit:       30,
 
74
  proc_limit:        40,
 
75
  procq_limit:       60,
66
76
  tcp_qtimeout:      TCP_TIMEOUT,
67
77
  timeout:           0,
68
78
  par_queries:       PAR_QUERIES,
 
79
  query_method:      M_PRESET,
69
80
  query_port_start:  0,
70
81
  query_port_end:    65535,
71
82
  deleg_only_zones:  NULL
87
98
  nocache:       0,
88
99
  lean_query:    1,
89
100
  is_proxy:      0,
 
101
  rootserver:    0,
90
102
  preset:        1,
91
103
  policy:        C_INCLUDED,
92
104
  alist:         NULL,
100
112
 
101
113
servparm_array servers=NULL;
102
114
 
103
 
void lex_set_io(FILE *in, FILE *out); /* defined in conf.l */
104
 
int  yyparse (void);                  /* from yacc/bison output */
 
115
static void free_zones(zone_array za);
 
116
static void free_server_data(servparm_array sa);
105
117
static int report_server_stat(int f,int i);
106
118
 
107
119
 
108
120
/*
109
 
 * Read a configuration file and save the result. This uses the parser generated by yacc/bison
110
 
 * from conf.y, which in turn uses the lexer generated lex/flex from conf.l
 
121
 * Read a configuration file and save the result.
 
122
 * Return 1 on success, 0 on failure.
 
123
 * In case of failure, **errstr will refer to a newly allocated string containing an error message.
 
124
 * If we are multi-threaded, call with locks applied.
111
125
 */
112
 
void read_config_file(char *nm)
 
126
int read_config_file(const char *nm, globparm_t *global, servparm_array *servers, char **errstr)
113
127
{
 
128
        int retval=0,fd;
114
129
        FILE *in;
115
130
        struct stat sb;
116
 
        if (nm==NULL) {
117
 
                nm=CONFDIR"/pdnsd.conf";
118
 
        } 
119
 
        if (stat(nm,&sb)!=0) {
120
 
                fprintf(stderr,"Error: Could not stat conf file %s: %s\n",nm,strerror(errno));
121
 
                exit(3);
122
 
        }
123
 
        if (sb.st_uid!=getuid()) {
124
 
                fprintf(stderr,"Error: You must own the config file.\n");
125
 
                exit(3);
126
 
        }
127
 
        if ((sb.st_mode&(S_IWGRP|S_IWOTH))) {
128
 
                fprintf(stderr,"Error: Bad config file permissions: the file must be only writeable by the user.\n");
129
 
                exit(3);
130
 
        }
 
131
 
 
132
        if (nm==NULL)
 
133
                nm=conf_file;
 
134
 
131
135
        if (!(in=fopen(nm,"r"))) {
132
 
                fprintf(stderr,"Error: Could not open conf file %s: %s\n",nm,strerror(errno));
133
 
                exit(3);
134
 
        }
135
 
 
136
 
        if (!confparse(in))
137
 
                exit(3);
138
 
        fclose(in);
 
136
                if(asprintf(errstr,"Error: Could not open config file %s: %s",nm,strerror(errno))<0)
 
137
                        *errstr=NULL;
 
138
                return 0;
 
139
        }
 
140
        fd=fileno(in);
 
141
        /* Note by Paul Rombouts: I am using fstat() instead of stat() here to
 
142
           prevent a possible exploitable race condition */
 
143
        if (fd==-1 || fstat(fd,&sb)!=0) {
 
144
                if(asprintf(errstr, "Error: Could not stat config file %s: %s",nm,strerror(errno))<0)
 
145
                        *errstr=NULL;
 
146
        }
 
147
        else if (sb.st_uid!=init_uid) {
 
148
                /* Note by Paul Rombouts:
 
149
                   Perhaps we should use getpwuid_r() instead of getpwuid(), which is not necessarily thread safe.
 
150
                   As long as getpwuid() is only used by only one thread, it should be OK,
 
151
                   but it is something to keep in mind.
 
152
                */                 
 
153
                struct passwd *pws;
 
154
                char owner[24],user[24];
 
155
                if((pws=getpwuid(sb.st_uid)))
 
156
                        strncp(owner,pws->pw_name,sizeof(owner));
 
157
                else
 
158
                        sprintf(owner,"%i",sb.st_uid);
 
159
                if((pws=getpwuid(init_uid)))
 
160
                        strncp(user,pws->pw_name,sizeof(user));
 
161
                else
 
162
                        sprintf(user,"%i",init_uid);
 
163
                if(asprintf(errstr,
 
164
                            "Error: Config file %s is owned by '%s', but pdnsd was started as user '%s'.",
 
165
                            nm,owner,user)<0)
 
166
                        *errstr=NULL;
 
167
        }
 
168
        else if ((sb.st_mode&(S_IWGRP|S_IWOTH))) {
 
169
                if(asprintf(errstr,
 
170
                            "Error: Bad config file permissions: file %s must be only writeable by the user.",nm)<0)
 
171
                        *errstr=NULL;
 
172
        }
 
173
        else
 
174
                retval=confparse(in,global,servers,errstr);
 
175
 
 
176
        if(fclose(in) && retval) {
 
177
                if(asprintf(errstr,"Error: Could not close config file %s: %s",nm,strerror(errno))<0)
 
178
                        *errstr=NULL;
 
179
                return 0;
 
180
        }
 
181
        return retval;
 
182
}
 
183
 
 
184
/*
 
185
 * Re-Read the configuration file.
 
186
 * Return 1 on success, 0 on failure.
 
187
 * In case of failure, the old configuration will be unchanged (although the cache may not) and
 
188
 * **errstr will refer to a newly allocated string containing an error message.
 
189
 */
 
190
int reload_config_file(const char *nm, char **errstr)
 
191
{
 
192
        globparm_t global_new;
 
193
        servparm_array servers_new;
 
194
 
 
195
        global_new=global;
 
196
        global_new.cache_dir=NULL;
 
197
        global_new.pidfile=NULL;
 
198
        global_new.scheme_file=NULL;
 
199
        global_new.deleg_only_zones=NULL;
 
200
        global_new.onquery=0;
 
201
        servers_new=NULL;
 
202
        if(read_config_file(nm,&global_new,&servers_new,errstr)) {
 
203
                if(global_new.cache_dir && strcmp(global_new.cache_dir,global.cache_dir)) {
 
204
                        *errstr=strdup("Cannot reload config file: the specified cache_dir directory has changed.\n"
 
205
                                       "Try restarting pdnsd instead.");
 
206
                        goto cleanup_return;
 
207
                }
 
208
                if(global_new.pidfile && (!global.pidfile || strcmp(global_new.pidfile,global.pidfile))) {
 
209
                        *errstr=strdup("Cannot reload config file: the specified pid_file has changed.\n"
 
210
                                       "Try restarting pdnsd instead.");
 
211
                        goto cleanup_return;
 
212
                }
 
213
                if(global_new.scheme_file && strcmp(global_new.scheme_file,global.scheme_file)) {
 
214
                        *errstr=strdup("Cannot reload config file: the specified scheme_file has changed.\n"
 
215
                                       "Try restarting pdnsd instead.");
 
216
                        goto cleanup_return;
 
217
                }
 
218
                if(global_new.port!=global.port) {
 
219
                        *errstr=strdup("Cannot reload config file: the specified server_port has changed.\n"
 
220
                                       "Try restarting pdnsd instead.");
 
221
                        goto cleanup_return;
 
222
                }
 
223
                if(!ADDR_EQUIV(&global_new.a,&global.a)) {
 
224
                        *errstr=strdup("Cannot reload config file: the specified interface address (server_ip) has changed.\n"
 
225
                                       "Try restarting pdnsd instead.");
 
226
                        goto cleanup_return;
 
227
                }
 
228
#ifdef ENABLE_IPV6
 
229
                if(!IN6_ARE_ADDR_EQUAL(&global_new.ipv4_6_prefix,&global.ipv4_6_prefix)) {
 
230
                        *errstr=strdup("Cannot reload config file: the specified ipv4_6_prefix has changed.\n"
 
231
                                       "Try restarting pdnsd instead.");
 
232
                        goto cleanup_return;
 
233
                }
 
234
#endif
 
235
                if(strcmp(global_new.run_as,global.run_as)) {
 
236
                        *errstr=strdup("Cannot reload config file: the specified run_as id has changed.\n"
 
237
                                       "Try restarting pdnsd instead.");
 
238
                        goto cleanup_return;
 
239
                }
 
240
                if(global_new.daemon!=global.daemon) {
 
241
                        *errstr=strdup("Cannot reload config file: the daemon option has changed.\n"
 
242
                                       "Try restarting pdnsd instead.");
 
243
                        goto cleanup_return;
 
244
                }
 
245
                if(global_new.debug!=global.debug) {
 
246
                        *errstr=strdup("Cannot reload config file: the debug option has changed.\n"
 
247
                                       "Try restarting pdnsd instead.");
 
248
                        goto cleanup_return;
 
249
                }
 
250
                if(global_new.stat_pipe!=global.stat_pipe) {
 
251
                        *errstr=strdup("Cannot reload config file: the status_ctl option has changed.\n"
 
252
                                       "Try restarting pdnsd instead.");
 
253
                        goto cleanup_return;
 
254
                }
 
255
                if(global_new.notcp!=global.notcp) {
 
256
                        *errstr=strdup("Cannot reload config file: the tcp_server option has changed.\n"
 
257
                                       "Try restarting pdnsd instead.");
 
258
                        goto cleanup_return;
 
259
                }
 
260
                if(global_new.strict_suid!=global.strict_suid) {
 
261
                        *errstr=strdup("Cannot reload config file: the strict_setuid option has changed.\n"
 
262
                                       "Try restarting pdnsd instead.");
 
263
                        goto cleanup_return;
 
264
                }
 
265
                if(global_new.ctl_perms!=global.ctl_perms) {
 
266
                        *errstr=strdup("Cannot reload config file: the specified ctl_perms has changed.\n"
 
267
                                       "Try restarting pdnsd instead.");
 
268
                        goto cleanup_return;
 
269
                }
 
270
                if(ping_isocket==-1
 
271
#ifdef ENABLE_IPV6
 
272
                   && ping6_isocket==-1
 
273
#endif
 
274
                  ) {
 
275
                        int i,n=DA_NEL(servers_new);
 
276
                        for (i=0;i<n;++i) {
 
277
                                if (DA_INDEX(servers_new,i).uptest==C_PING) {
 
278
                                        if(asprintf(errstr,"Cannot reload config file: the ping socket is not initialized"
 
279
                                                    " and the new config contains uptest=ping in server section %i.\n"
 
280
                                                    "Try restarting pdnsd instead.",i)<0)
 
281
                                                *errstr=NULL;
 
282
                                        goto cleanup_return;
 
283
                                }
 
284
                        }
 
285
                }
 
286
 
 
287
                /* we need exclusive access to the server data to make the changes */
 
288
                /* Wait at most 60 seconds to obtain a lock. */
 
289
                if(!exclusive_lock_server_data(60)) {
 
290
                        *errstr=strdup("Cannot reload config file: Timed out while waiting for access to config data.");
 
291
                        goto cleanup_return;
 
292
                }
 
293
                free(global_new.cache_dir); global_new.cache_dir=global.cache_dir;
 
294
                free(global_new.pidfile); global_new.pidfile=global.pidfile;
 
295
                free(global_new.scheme_file); global_new.scheme_file=global.scheme_file;
 
296
                free_zones(global.deleg_only_zones);
 
297
                global=global_new;
 
298
 
 
299
                free_server_data(servers);
 
300
                servers=servers_new;
 
301
                /* schedule a retest to check which servers are up,
 
302
                   and free the lock. */
 
303
                exclusive_unlock_server_data(1);
 
304
 
 
305
                return 1;
 
306
        }
 
307
 
 
308
 cleanup_return:
 
309
        free(global_new.cache_dir);
 
310
        free(global_new.pidfile);
 
311
        free(global_new.scheme_file);
 
312
        free_zones(global_new.deleg_only_zones);
 
313
        free_server_data(servers_new);
 
314
        return 0;
 
315
}
 
316
 
 
317
void free_zone(void *ptr)
 
318
{
 
319
  free(*((unsigned char **)ptr));
 
320
}
 
321
 
 
322
static void free_zones(zone_array za)
 
323
{
 
324
        int i,n=DA_NEL(za);
 
325
        for(i=0;i<n;++i)
 
326
                free(DA_INDEX(za,i));
 
327
 
 
328
        da_free(za);
 
329
}
 
330
 
 
331
void free_slist_domain(void *ptr)
 
332
{
 
333
        free(((slist_t *)ptr)->domain);
 
334
}
 
335
 
 
336
void free_slist_array(slist_array sla)
 
337
{
 
338
        int j,m=DA_NEL(sla);
 
339
        for(j=0;j<m;++j)
 
340
                free(DA_INDEX(sla,j).domain);
 
341
        da_free(sla);
 
342
 
 
343
}
 
344
 
 
345
void free_servparm(servparm_t *serv)
 
346
{
 
347
        free(serv->uptest_cmd);
 
348
        free(serv->label);
 
349
        da_free(serv->atup_a);
 
350
        free_slist_array(serv->alist);
 
351
}
 
352
 
 
353
static void free_server_data(servparm_array sa)
 
354
{
 
355
        int i,n=DA_NEL(sa);
 
356
        for(i=0;i<n;++i)
 
357
                free_servparm(&DA_INDEX(sa,i));
 
358
        da_free(sa);
139
359
}
140
360
 
141
361
/* Report the current configuration to the file descriptor f (for the status fifo, see status.c) */
155
375
#ifdef ENABLE_IPV6
156
376
        if(!run_ipv4) {
157
377
          char buf[ADDRSTR_MAXLEN];
158
 
          fsprintf_or_return(f,"\tIPv4 to IPv6 prefix: %s\n",inet_ntop(AF_INET6,&ipv4_6_prefix,buf,ADDRSTR_MAXLEN)?:"?.?.?.?");
 
378
          fsprintf_or_return(f,"\tIPv4 to IPv6 prefix: %s\n",inet_ntop(AF_INET6,&global.ipv4_6_prefix,buf,ADDRSTR_MAXLEN)?:"?.?.?.?");
159
379
        }
160
380
#endif
161
381
        fsprintf_or_return(f,"\tIgnore cache when link is down: %s\n",global.lndown_kluge?"on":"off");
173
393
        fsprintf_or_return(f,"\tGlobal timeout setting: %li\n",(long)global.timeout);
174
394
        fsprintf_or_return(f,"\tParallel queries increment: %i\n",global.par_queries);
175
395
        fsprintf_or_return(f,"\tRandomize records in answer: %s\n",global.rnd_recs?"on":"off");
176
 
        fsprintf_or_return(f,"\tQuery method: %s\n",const_name(query_method));
 
396
        fsprintf_or_return(f,"\tQuery method: %s\n",const_name(global.query_method));
177
397
        fsprintf_or_return(f,"\tQuery port start: %i\n",global.query_port_start);
178
398
        fsprintf_or_return(f,"\tQuery port end: %i\n",global.query_port_end);
179
399
#ifndef NO_TCP_SERVER
180
 
        fsprintf_or_return(f,"\tTCP server thread: %s\n",notcp?"off":"on");
181
 
        if(!notcp)
 
400
        fsprintf_or_return(f,"\tTCP server thread: %s\n",global.notcp?"off":"on");
 
401
        if(!global.notcp)
182
402
          {fsprintf_or_return(f,"\tTCP query timeout: %li\n",(long)global.tcp_qtimeout);}
183
403
#endif
184
 
        fsprintf_or_return(f,"\tDelegation-only zones: ");
 
404
 
 
405
        lock_server_data();
 
406
        {
 
407
                int rv=fsprintf(f,"\tDelegation-only zones: ");
 
408
                if(rv<0) {retval=rv; goto unlock_return;}
 
409
        }
185
410
        if(global.deleg_only_zones==NULL) {
186
 
                fsprintf_or_return(f,"(none)\n");
 
411
                int rv=fsprintf(f,"(none)\n");
 
412
                if(rv<0) {retval=rv; goto unlock_return;}
187
413
        }
188
414
        else {
 
415
                int rv;
189
416
                for(i=0;i<DA_NEL(global.deleg_only_zones);++i) {
190
 
                        unsigned char zstr[256];
191
 
                        rhn2str(DA_INDEX(global.deleg_only_zones,i),zstr);
192
 
                        fsprintf_or_return(f,i==0?"%s":", %s",zstr);
 
417
                        unsigned char buf[256];
 
418
                        rv=fsprintf(f,i==0?"%s":", %s",
 
419
                                        rhn2str(DA_INDEX(global.deleg_only_zones,i),buf,sizeof(buf)));
 
420
                        if(rv<0) {retval=rv; goto unlock_return;}
193
421
                }
194
 
                fsprintf_or_return(f,"\n");
 
422
                rv=fsprintf(f,"\n");
 
423
                if(rv<0) {retval=rv; goto unlock_return;}
195
424
        }
196
425
 
197
 
        lock_server_data();
198
426
        for(i=0;i<DA_NEL(servers);i++) {
199
427
                int rv=report_server_stat(f,i);
200
 
                if(rv<0) {
201
 
                        retval=rv;
202
 
                        break;
203
 
                }
 
428
                if(rv<0) {retval=rv; goto unlock_return;}
204
429
        }
 
430
 unlock_return:
205
431
        unlock_server_data();
206
432
 
207
433
        return retval;
229
455
        if(st->interval>0) {
230
456
                fsprintf_or_return(f,"\tuptest interval: %li\n",(long)st->interval);
231
457
        } else {
232
 
                fsprintf_or_return(f,"\tuptest interval: %s\n",st->interval?"onquery":"(never retest)");
 
458
                fsprintf_or_return(f,"\tuptest interval: %s\n",
 
459
                                   st->interval==-1?"onquery":
 
460
                                   st->interval==-2?"ontimeout":
 
461
                                                    "(never retest)");
233
462
        }
234
463
        fsprintf_or_return(f,"\tping timeout: %li\n",(long)st->ping_timeout);
235
464
        {char buf[ADDRSTR_MAXLEN];
245
474
        fsprintf_or_return(f,"\tserver is cached: %s\n",st->nocache?"off":"on");
246
475
        fsprintf_or_return(f,"\tlean query: %s\n",st->lean_query?"on":"off");
247
476
        fsprintf_or_return(f,"\tUse only proxy?: %s\n",st->is_proxy?"on":"off");
 
477
        fsprintf_or_return(f,"\tAssumed root server: %s\n",st->rootserver?"yes":"no");
248
478
        fsprintf_or_return(f,"\tDefault policy: %s\n",const_name(st->policy));
249
479
        fsprintf_or_return(f,"\tPolicies:\n");
250
480
        if (st->alist==NULL) {
252
482
        } else {
253
483
                for (j=0;j<DA_NEL(st->alist);j++) {
254
484
                        slist_t *sl=&DA_INDEX(st->alist,j);
255
 
                        fsprintf_or_return(f,"\t\t%s: %s\n",sl->rule==C_INCLUDED?"include":"exclude",sl->domain);
 
485
                        unsigned char buf[256];
 
486
                        fsprintf_or_return(f,"\t\t%s: %s%s\n",
 
487
                                           sl->rule==C_INCLUDED?"include":"exclude",
 
488
                                           sl->exact?"":".",
 
489
                                           rhn2str(sl->domain,buf,sizeof(buf)));
256
490
                }
257
491
        }
258
492
        return 0;