Add nsswitch support.
[dragonfly.git] / usr.sbin / nscd / nscd.c
1 /*-
2  * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in thereg
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD: src/usr.sbin/nscd/nscd.c,v 1.7 2008/10/23 00:27:35 delphij Exp $
27  */
28
29 #include <sys/types.h>
30 #include <sys/event.h>
31 #include <sys/socket.h>
32 #include <sys/time.h>
33 #include <sys/param.h>
34 #include <sys/un.h>
35 #include <assert.h>
36 #include <err.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <libutil.h>
40 #include <pthread.h>
41 #include <signal.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46
47 #include "agents/passwd.h"
48 #include "agents/group.h"
49 #include "agents/services.h"
50 #include "cachelib.h"
51 #include "config.h"
52 #include "debug.h"
53 #include "log.h"
54 #include "nscdcli.h"
55 #include "parser.h"
56 #include "query.h"
57 #include "singletons.h"
58
59 #ifndef CONFIG_PATH
60 #define CONFIG_PATH "/etc/nscd.conf"
61 #endif
62 #define DEFAULT_CONFIG_PATH     "nscd.conf"
63
64 #define MAX_SOCKET_IO_SIZE      4096
65
66 struct processing_thread_args {
67         cache   the_cache;
68         struct configuration    *the_configuration;
69         struct runtime_env              *the_runtime_env;
70 };
71
72 static void accept_connection(struct kevent *, struct runtime_env *,
73         struct configuration *);
74 static void destroy_cache_(cache);
75 static void destroy_runtime_env(struct runtime_env *);
76 static cache init_cache_(struct configuration *);
77 static struct runtime_env *init_runtime_env(struct configuration *);
78 static void processing_loop(cache, struct runtime_env *,
79         struct configuration *);
80 static void process_socket_event(struct kevent *, struct runtime_env *,
81         struct configuration *);
82 static void process_timer_event(struct kevent *, struct runtime_env *,
83         struct configuration *);
84 static void *processing_thread(void *);
85 static void usage(void);
86
87 void get_time_func(struct timeval *);
88
89 static void
90 usage(void)
91 {
92         fprintf(stderr,
93             "usage: nscd [-dnst] [-i cachename] [-I cachename]\n");
94         exit(1);
95 }
96
97 static cache
98 init_cache_(struct configuration *config)
99 {
100         struct cache_params params;
101         cache retval;
102
103         struct configuration_entry *config_entry;
104         size_t  size, i;
105         int res;
106
107         TRACE_IN(init_cache_);
108
109         memset(&params, 0, sizeof(struct cache_params));
110         params.get_time_func = get_time_func;
111         retval = init_cache(&params);
112
113         size = configuration_get_entries_size(config);
114         for (i = 0; i < size; ++i) {
115                 config_entry = configuration_get_entry(config, i);
116                 /*
117                  * We should register common entries now - multipart entries
118                  * would be registered automatically during the queries.
119                  */
120                 res = register_cache_entry(retval, (struct cache_entry_params *)
121                         &config_entry->positive_cache_params);
122                 config_entry->positive_cache_entry = find_cache_entry(retval,
123                         config_entry->positive_cache_params.entry_name);
124                 assert(config_entry->positive_cache_entry !=
125                         INVALID_CACHE_ENTRY);
126
127                 res = register_cache_entry(retval, (struct cache_entry_params *)
128                         &config_entry->negative_cache_params);
129                 config_entry->negative_cache_entry = find_cache_entry(retval,
130                         config_entry->negative_cache_params.entry_name);
131                 assert(config_entry->negative_cache_entry !=
132                         INVALID_CACHE_ENTRY);
133         }
134
135         LOG_MSG_2("cache", "cache was successfully initialized");
136         TRACE_OUT(init_cache_);
137         return (retval);
138 }
139
140 static void
141 destroy_cache_(cache the_cache)
142 {
143         TRACE_IN(destroy_cache_);
144         destroy_cache(the_cache);
145         TRACE_OUT(destroy_cache_);
146 }
147
148 /*
149  * Socket and kqueues are prepared here. We have one global queue for both
150  * socket and timers events.
151  */
152 static struct runtime_env *
153 init_runtime_env(struct configuration *config)
154 {
155         int serv_addr_len;
156         struct sockaddr_un serv_addr;
157
158         struct kevent eventlist;
159         struct timespec timeout;
160
161         struct runtime_env *retval;
162
163         TRACE_IN(init_runtime_env);
164         retval = (struct runtime_env *)calloc(1, sizeof(struct runtime_env));
165         assert(retval != NULL);
166
167         retval->sockfd = socket(PF_LOCAL, SOCK_STREAM, 0);
168
169         if (config->force_unlink == 1)
170                 unlink(config->socket_path);
171
172         memset(&serv_addr, 0, sizeof(struct sockaddr_un));
173         serv_addr.sun_family = PF_LOCAL;
174         strlcpy(serv_addr.sun_path, config->socket_path,
175                 sizeof(serv_addr.sun_path));
176         serv_addr_len = sizeof(serv_addr.sun_family) +
177                 strlen(serv_addr.sun_path) + 1;
178
179         if (bind(retval->sockfd, (struct sockaddr *)&serv_addr,
180                 serv_addr_len) == -1) {
181                 close(retval->sockfd);
182                 free(retval);
183
184                 LOG_ERR_2("runtime environment", "can't bind socket to path: "
185                         "%s", config->socket_path);
186                 TRACE_OUT(init_runtime_env);
187                 return (NULL);
188         }
189         LOG_MSG_2("runtime environment", "using socket %s",
190                 config->socket_path);
191
192         /*
193          * Here we're marking socket as non-blocking and setting its backlog
194          * to the maximum value
195          */
196         chmod(config->socket_path, config->socket_mode);
197         listen(retval->sockfd, -1);
198         fcntl(retval->sockfd, F_SETFL, O_NONBLOCK);
199
200         retval->queue = kqueue();
201         assert(retval->queue != -1);
202
203         EV_SET(&eventlist, retval->sockfd, EVFILT_READ, EV_ADD | EV_ONESHOT,
204                 0, 0, 0);
205         memset(&timeout, 0, sizeof(struct timespec));
206         kevent(retval->queue, &eventlist, 1, NULL, 0, &timeout);
207
208         LOG_MSG_2("runtime environment", "successfully initialized");
209         TRACE_OUT(init_runtime_env);
210         return (retval);
211 }
212
213 static void
214 destroy_runtime_env(struct runtime_env *env)
215 {
216         TRACE_IN(destroy_runtime_env);
217         close(env->queue);
218         close(env->sockfd);
219         free(env);
220         TRACE_OUT(destroy_runtime_env);
221 }
222
223 static void
224 accept_connection(struct kevent *event_data, struct runtime_env *env,
225         struct configuration *config)
226 {
227         struct kevent   eventlist[2];
228         struct timespec timeout;
229         struct query_state      *qstate;
230
231         int     fd;
232         int     res;
233
234         uid_t   euid;
235         gid_t   egid;
236
237         TRACE_IN(accept_connection);
238         fd = accept(event_data->ident, NULL, NULL);
239         if (fd == -1) {
240                 LOG_ERR_2("accept_connection", "error %d during accept()",
241                     errno);
242                 TRACE_OUT(accept_connection);
243                 return;
244         }
245
246         if (getpeereid(fd, &euid, &egid) != 0) {
247                 LOG_ERR_2("accept_connection", "error %d during getpeereid()",
248                         errno);
249                 TRACE_OUT(accept_connection);
250                 return;
251         }
252
253         qstate = init_query_state(fd, sizeof(int), euid, egid);
254         if (qstate == NULL) {
255                 LOG_ERR_2("accept_connection", "can't init query_state");
256                 TRACE_OUT(accept_connection);
257                 return;
258         }
259
260         memset(&timeout, 0, sizeof(struct timespec));
261         EV_SET(&eventlist[0], fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
262                 0, qstate->timeout.tv_sec * 1000, qstate);
263         EV_SET(&eventlist[1], fd, EVFILT_READ, EV_ADD | EV_ONESHOT,
264                 NOTE_LOWAT, qstate->kevent_watermark, qstate);
265         res = kevent(env->queue, eventlist, 2, NULL, 0, &timeout);
266         if (res < 0)
267                 LOG_ERR_2("accept_connection", "kevent error");
268
269         TRACE_OUT(accept_connection);
270 }
271
272 static void
273 process_socket_event(struct kevent *event_data, struct runtime_env *env,
274         struct configuration *config)
275 {
276         struct kevent   eventlist[2];
277         struct timeval  query_timeout;
278         struct timespec kevent_timeout;
279         int     nevents;
280         int     eof_res, res;
281         ssize_t io_res;
282         struct query_state *qstate;
283
284         TRACE_IN(process_socket_event);
285         eof_res = event_data->flags & EV_EOF ? 1 : 0;
286         res = 0;
287
288         memset(&kevent_timeout, 0, sizeof(struct timespec));
289         EV_SET(&eventlist[0], event_data->ident, EVFILT_TIMER, EV_DELETE,
290                 0, 0, NULL);
291         nevents = kevent(env->queue, eventlist, 1, NULL, 0, &kevent_timeout);
292         if (nevents == -1) {
293                 if (errno == ENOENT) {
294                         /* the timer is already handling this event */
295                         TRACE_OUT(process_socket_event);
296                         return;
297                 } else {
298                         /* some other error happened */
299                         LOG_ERR_2("process_socket_event", "kevent error, errno"
300                                 " is %d", errno);
301                         TRACE_OUT(process_socket_event);
302                         return;
303                 }
304         }
305         qstate = (struct query_state *)event_data->udata;
306
307         /*
308          * If the buffer that is to be send/received is too large,
309          * we send it implicitly, by using query_io_buffer_read and
310          * query_io_buffer_write functions in the query_state. These functions
311          * use the temporary buffer, which is later send/received in parts.
312          * The code below implements buffer splitting/mergind for send/receive
313          * operations. It also does the actual socket IO operations.
314          */
315         if (((qstate->use_alternate_io == 0) &&
316                 (qstate->kevent_watermark <= event_data->data)) ||
317                 ((qstate->use_alternate_io != 0) &&
318                 (qstate->io_buffer_watermark <= event_data->data))) {
319                 if (qstate->use_alternate_io != 0) {
320                         switch (qstate->io_buffer_filter) {
321                         case EVFILT_READ:
322                                 io_res = query_socket_read(qstate,
323                                         qstate->io_buffer_p,
324                                         qstate->io_buffer_watermark);
325                                 if (io_res < 0) {
326                                         qstate->use_alternate_io = 0;
327                                         qstate->process_func = NULL;
328                                 } else {
329                                         qstate->io_buffer_p += io_res;
330                                         if (qstate->io_buffer_p ==
331                                                 qstate->io_buffer +
332                                                 qstate->io_buffer_size) {
333                                                 qstate->io_buffer_p =
334                                                     qstate->io_buffer;
335                                                 qstate->use_alternate_io = 0;
336                                         }
337                                 }
338                         break;
339                         default:
340                         break;
341                         }
342                 }
343
344                 if (qstate->use_alternate_io == 0) {
345                         do {
346                                 res = qstate->process_func(qstate);
347                         } while ((qstate->kevent_watermark == 0) &&
348                                         (qstate->process_func != NULL) &&
349                                         (res == 0));
350
351                         if (res != 0)
352                                 qstate->process_func = NULL;
353                 }
354
355                 if ((qstate->use_alternate_io != 0) &&
356                         (qstate->io_buffer_filter == EVFILT_WRITE)) {
357                         io_res = query_socket_write(qstate, qstate->io_buffer_p,
358                                 qstate->io_buffer_watermark);
359                         if (io_res < 0) {
360                                 qstate->use_alternate_io = 0;
361                                 qstate->process_func = NULL;
362                         } else
363                                 qstate->io_buffer_p += io_res;
364                 }
365         } else {
366                 /* assuming that socket was closed */
367                 qstate->process_func = NULL;
368                 qstate->use_alternate_io = 0;
369         }
370
371         if (((qstate->process_func == NULL) &&
372                 (qstate->use_alternate_io == 0)) ||
373                 (eof_res != 0) || (res != 0)) {
374                 destroy_query_state(qstate);
375                 close(event_data->ident);
376                 TRACE_OUT(process_socket_event);
377                 return;
378         }
379
380         /* updating the query_state lifetime variable */
381         get_time_func(&query_timeout);
382         query_timeout.tv_usec = 0;
383         query_timeout.tv_sec -= qstate->creation_time.tv_sec;
384         if (query_timeout.tv_sec > qstate->timeout.tv_sec)
385                 query_timeout.tv_sec = 0;
386         else
387                 query_timeout.tv_sec = qstate->timeout.tv_sec -
388                         query_timeout.tv_sec;
389
390         if ((qstate->use_alternate_io != 0) && (qstate->io_buffer_p ==
391                 qstate->io_buffer + qstate->io_buffer_size))
392                 qstate->use_alternate_io = 0;
393
394         if (qstate->use_alternate_io == 0) {
395                 /*
396                  * If we must send/receive the large block of data,
397                  * we should prepare the query_state's io_XXX fields.
398                  * We should also substitute its write_func and read_func
399                  * with the query_io_buffer_write and query_io_buffer_read,
400                  * which will allow us to implicitly send/receive this large
401                  * buffer later (in the subsequent calls to the
402                  * process_socket_event).
403                  */
404                 if (qstate->kevent_watermark > MAX_SOCKET_IO_SIZE) {
405                         if (qstate->io_buffer != NULL)
406                                 free(qstate->io_buffer);
407
408                         qstate->io_buffer = (char *)calloc(1,
409                                 qstate->kevent_watermark);
410                         assert(qstate->io_buffer != NULL);
411
412                         qstate->io_buffer_p = qstate->io_buffer;
413                         qstate->io_buffer_size = qstate->kevent_watermark;
414                         qstate->io_buffer_filter = qstate->kevent_filter;
415
416                         qstate->write_func = query_io_buffer_write;
417                         qstate->read_func = query_io_buffer_read;
418
419                         if (qstate->kevent_filter == EVFILT_READ)
420                                 qstate->use_alternate_io = 1;
421
422                         qstate->io_buffer_watermark = MAX_SOCKET_IO_SIZE;
423                         EV_SET(&eventlist[1], event_data->ident,
424                                 qstate->kevent_filter, EV_ADD | EV_ONESHOT,
425                                 NOTE_LOWAT, MAX_SOCKET_IO_SIZE, qstate);
426                 } else {
427                         EV_SET(&eventlist[1], event_data->ident,
428                                 qstate->kevent_filter, EV_ADD | EV_ONESHOT,
429                                 NOTE_LOWAT, qstate->kevent_watermark, qstate);
430                 }
431         } else {
432                 if (qstate->io_buffer + qstate->io_buffer_size -
433                         qstate->io_buffer_p <
434                         MAX_SOCKET_IO_SIZE) {
435                         qstate->io_buffer_watermark = qstate->io_buffer +
436                                 qstate->io_buffer_size - qstate->io_buffer_p;
437                         EV_SET(&eventlist[1], event_data->ident,
438                                 qstate->io_buffer_filter,
439                                 EV_ADD | EV_ONESHOT, NOTE_LOWAT,
440                                 qstate->io_buffer_watermark,
441                                 qstate);
442                 } else {
443                         qstate->io_buffer_watermark = MAX_SOCKET_IO_SIZE;
444                         EV_SET(&eventlist[1], event_data->ident,
445                                 qstate->io_buffer_filter, EV_ADD | EV_ONESHOT,
446                                 NOTE_LOWAT, MAX_SOCKET_IO_SIZE, qstate);
447                 }
448         }
449         EV_SET(&eventlist[0], event_data->ident, EVFILT_TIMER,
450                 EV_ADD | EV_ONESHOT, 0, query_timeout.tv_sec * 1000, qstate);
451         kevent(env->queue, eventlist, 2, NULL, 0, &kevent_timeout);
452
453         TRACE_OUT(process_socket_event);
454 }
455
456 /*
457  * This routine is called if timer event has been signaled in the kqueue. It
458  * just closes the socket and destroys the query_state.
459  */
460 static void
461 process_timer_event(struct kevent *event_data, struct runtime_env *env,
462         struct configuration *config)
463 {
464         struct query_state      *qstate;
465
466         TRACE_IN(process_timer_event);
467         qstate = (struct query_state *)event_data->udata;
468         destroy_query_state(qstate);
469         close(event_data->ident);
470         TRACE_OUT(process_timer_event);
471 }
472
473 /*
474  * Processing loop is the basic processing routine, that forms a body of each
475  * procssing thread
476  */
477 static void
478 processing_loop(cache the_cache, struct runtime_env *env,
479         struct configuration *config)
480 {
481         struct timespec timeout;
482         const int eventlist_size = 1;
483         struct kevent eventlist[eventlist_size];
484         int nevents, i;
485
486         TRACE_MSG("=> processing_loop");
487         memset(&timeout, 0, sizeof(struct timespec));
488         memset(&eventlist, 0, sizeof(struct kevent) * eventlist_size);
489
490         for (;;) {
491                 nevents = kevent(env->queue, NULL, 0, eventlist,
492                         eventlist_size, NULL);
493                 /*
494                  * we can only receive 1 event on success
495                  */
496                 if (nevents == 1) {
497                         struct kevent *event_data;
498                         event_data = &eventlist[0];
499
500                         if (event_data->ident == env->sockfd) {
501                                 for (i = 0; i < event_data->data; ++i)
502                                     accept_connection(event_data, env, config);
503
504                                 EV_SET(eventlist, s_runtime_env->sockfd,
505                                     EVFILT_READ, EV_ADD | EV_ONESHOT,
506                                     0, 0, 0);
507                                 memset(&timeout, 0,
508                                     sizeof(struct timespec));
509                                 kevent(s_runtime_env->queue, eventlist,
510                                     1, NULL, 0, &timeout);
511
512                         } else {
513                                 switch (event_data->filter) {
514                                 case EVFILT_READ:
515                                 case EVFILT_WRITE:
516                                         process_socket_event(event_data,
517                                                 env, config);
518                                         break;
519                                 case EVFILT_TIMER:
520                                         process_timer_event(event_data,
521                                                 env, config);
522                                         break;
523                                 default:
524                                         break;
525                                 }
526                         }
527                 } else {
528                         /* this branch shouldn't be currently executed */
529                 }
530         }
531
532         TRACE_MSG("<= processing_loop");
533 }
534
535 /*
536  * Wrapper above the processing loop function. It sets the thread signal mask
537  * to avoid SIGPIPE signals (which can happen if the client works incorrectly).
538  */
539 static void *
540 processing_thread(void *data)
541 {
542         struct processing_thread_args   *args;
543         sigset_t new;
544
545         TRACE_MSG("=> processing_thread");
546         args = (struct processing_thread_args *)data;
547
548         sigemptyset(&new);
549         sigaddset(&new, SIGPIPE);
550         if (pthread_sigmask(SIG_BLOCK, &new, NULL) != 0)
551                 LOG_ERR_1("processing thread",
552                         "thread can't block the SIGPIPE signal");
553
554         processing_loop(args->the_cache, args->the_runtime_env,
555                 args->the_configuration);
556         free(args);
557         TRACE_MSG("<= processing_thread");
558
559         return (NULL);
560 }
561
562 void
563 get_time_func(struct timeval *time)
564 {
565         struct timespec res;
566         memset(&res, 0, sizeof(struct timespec));
567         clock_gettime(CLOCK_MONOTONIC, &res);
568
569         time->tv_sec = res.tv_sec;
570         time->tv_usec = 0;
571 }
572
573 /*
574  * The idea of _nss_cache_cycle_prevention_function is that nsdispatch will
575  * search for this symbol in the executable. This symbol is the attribute of
576  * the caching daemon. So, if it exists, nsdispatch won't try to connect to
577  * the caching daemon and will just ignore the 'cache' source in the
578  * nsswitch.conf. This method helps to avoid cycles and organize
579  * self-performing requests.
580  */
581 void
582 _nss_cache_cycle_prevention_function(void)
583 {
584 }
585
586 int
587 main(int argc, char *argv[])
588 {
589         struct processing_thread_args *thread_args;
590         pthread_t *threads;
591
592         struct pidfh *pidfile;
593         pid_t pid;
594
595         char const *config_file;
596         char const *error_str;
597         int error_line;
598         int i, res;
599
600         int trace_mode_enabled;
601         int force_single_threaded;
602         int do_not_daemonize;
603         int clear_user_cache_entries, clear_all_cache_entries;
604         char *user_config_entry_name, *global_config_entry_name;
605         int show_statistics;
606         int daemon_mode, interactive_mode;
607
608
609         /* by default all debug messages are omitted */
610         TRACE_OFF();
611
612         /* parsing command line arguments */
613         trace_mode_enabled = 0;
614         force_single_threaded = 0;
615         do_not_daemonize = 0;
616         clear_user_cache_entries = 0;
617         clear_all_cache_entries = 0;
618         show_statistics = 0;
619         user_config_entry_name = NULL;
620         global_config_entry_name = NULL;
621         while ((res = getopt(argc, argv, "nstdi:I:")) != -1) {
622                 switch (res) {
623                 case 'n':
624                         do_not_daemonize = 1;
625                         break;
626                 case 's':
627                         force_single_threaded = 1;
628                         break;
629                 case 't':
630                         trace_mode_enabled = 1;
631                         break;
632                 case 'i':
633                         clear_user_cache_entries = 1;
634                         if (optarg != NULL)
635                                 if (strcmp(optarg, "all") != 0)
636                                         user_config_entry_name = strdup(optarg);
637                         break;
638                 case 'I':
639                         clear_all_cache_entries = 1;
640                         if (optarg != NULL)
641                                 if (strcmp(optarg, "all") != 0)
642                                         global_config_entry_name =
643                                                 strdup(optarg);
644                         break;
645                 case 'd':
646                         show_statistics = 1;
647                         break;
648                 case '?':
649                 default:
650                         usage();
651                         /* NOT REACHED */
652                 }
653         }
654
655         daemon_mode = do_not_daemonize | force_single_threaded |
656                 trace_mode_enabled;
657         interactive_mode = clear_user_cache_entries | clear_all_cache_entries |
658                 show_statistics;
659
660         if ((daemon_mode != 0) && (interactive_mode != 0)) {
661                 LOG_ERR_1("main", "daemon mode and interactive_mode arguments "
662                         "can't be used together");
663                 usage();
664         }
665
666         if (interactive_mode != 0) {
667                 FILE *pidfin = fopen(DEFAULT_PIDFILE_PATH, "r");
668                 char pidbuf[256];
669
670                 struct nscd_connection_params connection_params;
671                 nscd_connection connection;
672
673                 int result;
674
675                 if (pidfin == NULL)
676                         errx(EXIT_FAILURE, "There is no daemon running.");
677
678                 memset(pidbuf, 0, sizeof(pidbuf));
679                 fread(pidbuf, sizeof(pidbuf) - 1, 1, pidfin);
680                 fclose(pidfin);
681
682                 if (ferror(pidfin) != 0)
683                         errx(EXIT_FAILURE, "Can't read from pidfile.");
684
685                 if (sscanf(pidbuf, "%d", &pid) != 1)
686                         errx(EXIT_FAILURE, "Invalid pidfile.");
687                 LOG_MSG_1("main", "daemon PID is %d", pid);
688
689
690                 memset(&connection_params, 0,
691                         sizeof(struct nscd_connection_params));
692                 connection_params.socket_path = DEFAULT_SOCKET_PATH;
693                 connection = open_nscd_connection__(&connection_params);
694                 if (connection == INVALID_NSCD_CONNECTION)
695                         errx(EXIT_FAILURE, "Can't connect to the daemon.");
696
697                 if (clear_user_cache_entries != 0) {
698                         result = nscd_transform__(connection,
699                                 user_config_entry_name, TT_USER);
700                         if (result != 0)
701                                 LOG_MSG_1("main",
702                                         "user cache transformation failed");
703                         else
704                                 LOG_MSG_1("main",
705                                         "user cache_transformation "
706                                         "succeeded");
707                 }
708
709                 if (clear_all_cache_entries != 0) {
710                         if (geteuid() != 0)
711                                 errx(EXIT_FAILURE, "Only root can initiate "
712                                         "global cache transformation.");
713
714                         result = nscd_transform__(connection,
715                                 global_config_entry_name, TT_ALL);
716                         if (result != 0)
717                                 LOG_MSG_1("main",
718                                         "global cache transformation "
719                                         "failed");
720                         else
721                                 LOG_MSG_1("main",
722                                         "global cache transformation "
723                                         "succeeded");
724                 }
725
726                 close_nscd_connection__(connection);
727
728                 free(user_config_entry_name);
729                 free(global_config_entry_name);
730                 return (EXIT_SUCCESS);
731         }
732
733         pidfile = pidfile_open(DEFAULT_PIDFILE_PATH, 0644, &pid);
734         if (pidfile == NULL) {
735                 if (errno == EEXIST)
736                         errx(EXIT_FAILURE, "Daemon already running, pid: %d.",
737                                 pid);
738                 warn("Cannot open or create pidfile");
739         }
740
741         if (trace_mode_enabled == 1)
742                 TRACE_ON();
743
744         /* blocking the main thread from receiving SIGPIPE signal */
745         sigblock(sigmask(SIGPIPE));
746
747         /* daemonization */
748         if (do_not_daemonize == 0) {
749                 res = daemon(0, trace_mode_enabled == 0 ? 0 : 1);
750                 if (res != 0) {
751                         LOG_ERR_1("main", "can't daemonize myself: %s",
752                                 strerror(errno));
753                         pidfile_remove(pidfile);
754                         goto fin;
755                 } else
756                         LOG_MSG_1("main", "successfully daemonized");
757         }
758
759         pidfile_write(pidfile);
760
761         s_agent_table = init_agent_table();
762         register_agent(s_agent_table, init_passwd_agent());
763         register_agent(s_agent_table, init_passwd_mp_agent());
764         register_agent(s_agent_table, init_group_agent());
765         register_agent(s_agent_table, init_group_mp_agent());
766         register_agent(s_agent_table, init_services_agent());
767         register_agent(s_agent_table, init_services_mp_agent());
768         LOG_MSG_1("main", "request agents registered successfully");
769
770         /*
771          * Hosts agent can't work properly until we have access to the
772          * appropriate dtab structures, which are used in nsdispatch
773          * calls
774          *
775          register_agent(s_agent_table, init_hosts_agent());
776         */
777
778         /* configuration initialization */
779         s_configuration = init_configuration();
780         fill_configuration_defaults(s_configuration);
781
782         error_str = NULL;
783         error_line = 0;
784         config_file = CONFIG_PATH;
785
786         res = parse_config_file(s_configuration, config_file, &error_str,
787                 &error_line);
788         if ((res != 0) && (error_str == NULL)) {
789                 config_file = DEFAULT_CONFIG_PATH;
790                 res = parse_config_file(s_configuration, config_file,
791                         &error_str, &error_line);
792         }
793
794         if (res != 0) {
795                 if (error_str != NULL) {
796                 LOG_ERR_1("main", "error in configuration file(%s, %d): %s\n",
797                         config_file, error_line, error_str);
798                 } else {
799                 LOG_ERR_1("main", "no configuration file found "
800                         "- was looking for %s and %s",
801                         CONFIG_PATH, DEFAULT_CONFIG_PATH);
802                 }
803                 destroy_configuration(s_configuration);
804                 return (-1);
805         }
806
807         if (force_single_threaded == 1)
808                 s_configuration->threads_num = 1;
809
810         /* cache initialization */
811         s_cache = init_cache_(s_configuration);
812         if (s_cache == NULL) {
813                 LOG_ERR_1("main", "can't initialize the cache");
814                 destroy_configuration(s_configuration);
815                 return (-1);
816         }
817
818         /* runtime environment initialization */
819         s_runtime_env = init_runtime_env(s_configuration);
820         if (s_runtime_env == NULL) {
821                 LOG_ERR_1("main", "can't initialize the runtime environment");
822                 destroy_configuration(s_configuration);
823                 destroy_cache_(s_cache);
824                 return (-1);
825         }
826
827         if (s_configuration->threads_num > 1) {
828                 threads = (pthread_t *)calloc(1, sizeof(pthread_t) *
829                         s_configuration->threads_num);
830                 for (i = 0; i < s_configuration->threads_num; ++i) {
831                         thread_args = (struct processing_thread_args *)malloc(
832                                 sizeof(struct processing_thread_args));
833                         thread_args->the_cache = s_cache;
834                         thread_args->the_runtime_env = s_runtime_env;
835                         thread_args->the_configuration = s_configuration;
836
837                         LOG_MSG_1("main", "thread #%d was successfully created",
838                                 i);
839                         pthread_create(&threads[i], NULL, processing_thread,
840                                 thread_args);
841
842                         thread_args = NULL;
843                 }
844
845                 for (i = 0; i < s_configuration->threads_num; ++i)
846                         pthread_join(threads[i], NULL);
847         } else {
848                 LOG_MSG_1("main", "working in single-threaded mode");
849                 processing_loop(s_cache, s_runtime_env, s_configuration);
850         }
851
852 fin:
853         /* runtime environment destruction */
854         destroy_runtime_env(s_runtime_env);
855
856         /* cache destruction */
857         destroy_cache_(s_cache);
858
859         /* configuration destruction */
860         destroy_configuration(s_configuration);
861
862         /* agents table destruction */
863         destroy_agent_table(s_agent_table);
864
865         pidfile_remove(pidfile);
866         return (EXIT_SUCCESS);
867 }