28ed51c80686d87ec8db00591ad986808b12386f
[rxpd] / src / rxpd_base.c
1 /*
2     rxpd_base.c - regex policy daemon
3
4   Copyright (C)
5     2007,               Christian Thaeter <ct@pipapo.org>
6
7   This program is free software; you can redistribute it and/or
8   modify it under the terms of the GNU General Public License as
9   published by the Free Software Foundation; either version 2 of the
10   License, or (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "rxpd.h"
23
24 static struct rxpd_base global_base;
25
26 struct rxpd_base*
27 rxpd_init (void)
28 {
29   if (global_base.basedir)
30     return NULL;
31
32   global_base.basedir = NULL;
33
34   global_base.verbosity = LOG_WARNING;
35   global_base.daemonize = 0;
36   global_base.regflags = 0;
37   global_base.locale = NULL;
38   global_base.user = NULL;
39   global_base.policy = NULL;
40   global_base.main = pth_self ();
41   pth_mutex_init (&global_base.nest_lock);
42
43   psplay_init_root (&global_base.files, rxpd_file_cmp, (psplay_delete_t)rxpd_file_delete);
44   llist_init (&global_base.sockets);
45
46   rxpd_log (&global_base, LOG_DEBUG, PACKAGE_NAME" initialized\n");
47   return &global_base;
48 }
49
50
51 void
52 rxpd_destroy (void)
53 {
54   if (global_base.basedir)
55     {
56       free (global_base.basedir);
57       psplay_destroy_root (&global_base.files);
58       LLIST_WHILE_HEAD (&global_base.sockets, n)
59         {
60           struct rxpd_socket* socket = (struct rxpd_socket*)n;
61           rxpd_socket_delete (socket);
62         }
63     }
64 }
65
66 void
67 rxpd_log (struct rxpd_base* self, int level, const char* fmt, ...)
68 {
69   va_list ap;
70   va_start (ap, fmt);
71   if (level <= (self?self->verbosity:LOG_DEBUG))
72     {
73       if (!self || self->daemonize)
74         {
75           va_list as;
76           va_copy (as, ap);
77           vsyslog (level, fmt, as);
78           va_end (as);
79         }
80       vfprintf (stderr, fmt, ap);
81     }
82   va_end (ap);
83 }
84
85 void
86 rxpd_fail (struct rxpd_base* self, const char* fmt, ...)
87 {
88   va_list ap;
89   va_start (ap, fmt);
90   if (!self || self->daemonize)
91     {
92       va_list as;
93       va_copy (as, ap);
94       vsyslog (LOG_ALERT, fmt, as);
95       va_end (as);
96     }
97   vfprintf (stderr, fmt, ap);
98   va_end (ap);
99   exit (EXIT_FAILURE);
100 }
101
102 void
103 rxpd_die (const char* fmt, ...)
104 {
105   va_list ap, as;
106   va_start(ap, fmt);
107   va_copy (as, ap);
108   vsyslog (LOG_EMERG, fmt, ap);
109   vfprintf (stderr, fmt, ap);
110   va_end (as);
111   va_end (ap);
112   abort ();
113 }
114
115 void*
116 rxpd_malloc (size_t size)
117 {
118   void* r;
119   r = malloc (size);
120   if (!r)
121     rxpd_die ("Out of Memeory\n");
122   return r;
123 }
124
125 char*
126 rxpd_strdup (const char* str)
127 {
128   char* r;
129   r = strdup (str);
130   if (!r)
131     rxpd_die ("Out of Memeory\n");
132   return r;
133 }
134
135 void
136 rxpd_enter_personality (struct rxpd_base* self)
137 {
138   umask (0022);
139
140   if (chdir (self->basedir))
141     rxpd_fail (self, "couldn't change to basedir '%s'\n", self->basedir);
142
143   if (getuid() == 0  ||  geteuid() == 0)
144     {
145       struct passwd *pw;
146
147       if (!self->user)
148         self->user = rxpd_strdup ("nobody");
149
150       pw = getpwnam (self->user);
151       if (!pw)
152         rxpd_fail (self, "couldn't find user '%s'\n", self->user);
153
154       if (setgid (pw->pw_gid))
155         rxpd_fail (self, "setgid failed\n");
156
157       if (setgroups (1, &pw->pw_gid))
158         rxpd_fail (self, "setgroups failed\n");
159
160       if (setuid (pw->pw_uid))
161         rxpd_fail (self, "setuid failed\n");
162     }
163
164   if (self->daemonize)
165     {
166       int n = open("/dev/null",O_RDWR);
167       if (n < 0)
168         rxpd_fail (self, "Couldn't open /dev/null\n");
169       dup2(n, 0);
170       dup2(n, 1);
171       dup2(n, 2);
172       close (n);
173
174       pid_t pid = fork();
175       if (pid < 0)
176         rxpd_fail (self, "Couldn't daemonize\n");
177       if (pid > 0)
178         exit (0);
179
180       setsid();
181     }
182 }
183
184 static psplay_delete_t
185 loadsave_files (PSplay node, const enum psplay_order_e which, int level, void* data)
186 {
187   (void) level;
188   struct rxpd_file* file = (struct rxpd_file*) node;
189
190   if (which == PSPLAY_INORDER)
191     {
192       if (data)
193         rxpd_file_load (file);
194       else
195         rxpd_file_save (file, 0);
196     }
197
198   return PSPLAY_CONT;
199 }
200
201
202 void
203 rxpd_signalloop (struct rxpd_base* base)
204 {
205   sigset_t sigs;
206   sigemptyset (&sigs);
207   sigaddset (&sigs, SIGHUP);
208   sigaddset (&sigs, SIGTERM);
209   sigaddset (&sigs, SIGINT);
210   sigaddset (&sigs, SIGALRM);
211
212   int signal;
213
214   while (!pth_sigwait (&sigs, &signal))
215     {
216       switch (signal)
217         {
218         case SIGHUP:
219           /* reload files from disk */
220           rxpd_log (base, LOG_NOTICE, "reloading all files\n");
221           if (!psplay_isempty_root (&base->files))
222             psplay_walk (&base->files, NULL, loadsave_files, 0, base /*just some non-NULL value*/);
223           break;
224         case SIGTERM:
225           /* save files and exit */
226           rxpd_log (base, LOG_NOTICE, "saving all files, terminating\n");
227           if (!psplay_isempty_root (&base->files))
228             psplay_walk (&base->files, NULL, loadsave_files, 0, NULL);
229
230           /* fallthrough */
231         case SIGINT:
232           /* exit without saving */
233           rxpd_log (base, LOG_NOTICE, "terminating\n");
234           LLIST_FOREACH (&base->sockets, n)
235             {
236               struct rxpd_socket* socket = (struct rxpd_socket*)n;
237               rxpd_socket_cancel (socket);
238             }
239           return;
240         case SIGALRM:
241           /* ALRM: save files */
242           rxpd_log (base, LOG_NOTICE, "saving all files\n");
243           if (!psplay_isempty_root (&base->files))
244             psplay_walk (&base->files, NULL, loadsave_files, 0, NULL);
245
246           break;
247         }
248     }
249 }