new daemonizing code which chdir's and switches user etc
[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
41   psplay_init_root (&global_base.files, rxpd_file_cmp, (psplay_delete_t)rxpd_file_delete);
42   llist_init (&global_base.sockets);
43
44   rxpd_log (&global_base, LOG_DEBUG, PACKAGE_NAME" initialized\n");
45   return &global_base;
46 }
47
48
49 void
50 rxpd_destroy (void)
51 {
52   if (global_base.basedir)
53     {
54       free (global_base.basedir);
55       psplay_destroy_root (&global_base.files);
56       LLIST_WHILE_HEAD (&global_base.sockets, n)
57         {
58           struct rxpd_socket* socket = (struct rxpd_socket*)n;
59           rxpd_socket_delete (socket);
60         }
61     }
62 }
63
64 void
65 rxpd_log (struct rxpd_base* self, int level, const char* fmt, ...)
66 {
67   va_list ap;
68   va_start (ap, fmt);
69   if (level <= (self?self->verbosity:LOG_DEBUG))
70     {
71       if (!self || self->daemonize)
72         vsyslog (level, fmt, ap);
73       vfprintf (stderr, fmt, ap);
74     }
75   va_end (ap);
76 }
77
78 void
79 rxpd_fail (struct rxpd_base* self, const char* fmt, ...)
80 {
81   va_list ap;
82   va_start (ap, fmt);
83   if (!self || self->daemonize)
84     vsyslog (LOG_ALERT, fmt, ap);
85   vfprintf (stderr, fmt, ap);
86   va_end (ap);
87   exit (EXIT_FAILURE);
88 }
89
90 void
91 rxpd_die (const char* fmt, ...)
92 {
93   va_list ap;
94   va_start(ap, fmt);
95   vsyslog (LOG_EMERG, fmt, ap);
96   vfprintf (stderr, fmt, ap);
97   va_end (ap);
98   abort ();
99 }
100
101 void*
102 rxpd_malloc (size_t size)
103 {
104   void* r;
105   r = malloc (size);
106   if (!r)
107     rxpd_die ("Out of Memeory\n");
108   return r;
109 }
110
111 char*
112 rxpd_strdup (const char* str)
113 {
114   char* r;
115   r = strdup (str);
116   if (!r)
117     rxpd_die ("Out of Memeory\n");
118   return r;
119 }
120
121 void
122 rxpd_enter_personality (struct rxpd_base* self)
123 {
124   umask (0022);
125
126   if (chdir (self->basedir))
127     rxpd_fail (self, "couldn't change to basedir '%s'\n", self->basedir);
128
129   if (getuid() == 0  ||  geteuid() == 0)
130     {
131       struct passwd *pw;
132
133       if (!self->user)
134         self->user = rxpd_strdup ("nobody");
135
136       pw = getpwnam (self->user);
137       if (!pw)
138         rxpd_fail (self, "couldn't find user '%s'\n", self->user);
139
140       if (setgid (pw->pw_gid))
141         rxpd_fail (self, "setgid failed\n");
142
143       if (setgroups (1, &pw->pw_gid))
144         rxpd_fail (self, "setgroups failed\n");
145
146       if (setuid (pw->pw_uid))
147         rxpd_fail (self, "setuid failed\n");
148     }
149
150   if (self->daemonize)
151     {
152       struct rlimit lim;
153
154       if (getrlimit (RLIMIT_NOFILE, &lim))
155         rxpd_die ("rlimit error\n");
156
157       for (rlim_t i = 0; i < lim.rlim_max; ++i)
158         close (i);
159
160       int n = open("/dev/null",O_RDWR);
161       if (n < 0)
162         rxpd_fail (self, "Couldn't open /dev/null\n");
163       dup(n);
164       dup(n);
165
166       pid_t pid = fork();
167       if (pid < 0)
168         rxpd_fail (self, "Couldn't daemonize\n");
169       if (pid > 0)
170         exit (0);
171
172       setsid();
173     }
174 }