1a6debbc5ad566ec29b981a7a871a046dad7d7fb
[apps/pfixtools.git] / daemon.c
1 /******************************************************************************/
2 /*          pfixtools: a collection of postfix related tools                  */
3 /*          ~~~~~~~~~                                                         */
4 /*  ________________________________________________________________________  */
5 /*                                                                            */
6 /*  Redistribution and use in source and binary forms, with or without        */
7 /*  modification, are permitted provided that the following conditions        */
8 /*  are met:                                                                  */
9 /*                                                                            */
10 /*  1. Redistributions of source code must retain the above copyright         */
11 /*     notice, this list of conditions and the following disclaimer.          */
12 /*  2. Redistributions in binary form must reproduce the above copyright      */
13 /*     notice, this list of conditions and the following disclaimer in the    */
14 /*     documentation and/or other materials provided with the distribution.   */
15 /*  3. The names of its contributors may not be used to endorse or promote    */
16 /*     products derived from this software without specific prior written     */
17 /*     permission.                                                            */
18 /*                                                                            */
19 /*  THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND   */
20 /*  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE     */
21 /*  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR        */
22 /*  PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS    */
23 /*  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR    */
24 /*  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF      */
25 /*  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  */
26 /*  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN   */
27 /*  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)   */
28 /*  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF    */
29 /*  THE POSSIBILITY OF SUCH DAMAGE.                                           */
30 /******************************************************************************/
31
32 /*
33  * Copyright © 2007 Pierre Habouzit
34  */
35
36 #include <fcntl.h>
37 #include <grp.h>
38 #include <pwd.h>
39 #include <sys/un.h>
40
41 #include "common.h"
42
43 static int setnonblock(int sock)
44 {
45     int res = fcntl(sock, F_GETFL);
46
47     if (res < 0) {
48         UNIXERR("fcntl");
49         return -1;
50     }
51
52     if (fcntl(sock, F_SETFL, res | O_NONBLOCK) < 0) {
53         UNIXERR("fcntl");
54         return -1;
55     }
56
57     return 0;
58 }
59
60
61 int tcp_listen_nonblock(const struct sockaddr *addr, socklen_t len)
62 {
63     int sock;
64
65     switch (addr->sa_family) {
66       case AF_UNIX:
67         unlink(((struct sockaddr_un *)addr)->sun_path);
68         sock = socket(PF_UNIX, SOCK_STREAM, 0);
69         break;
70       case AF_INET:
71         sock = socket(PF_INET, SOCK_STREAM, 0);
72         break;
73       case AF_INET6:
74         sock = socket(PF_INET6, SOCK_STREAM, 0);
75         break;
76       default:
77         errno = EINVAL;
78         return -1;
79     }
80
81     if (sock < 0) {
82         UNIXERR("socket");
83         return -1;
84     }
85
86     if (addr->sa_family != AF_UNIX) {
87         int v = 1;
88         if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v)) < 0) {
89             UNIXERR("setsockopt(SO_REUSEADDR)");
90             close(sock);
91             return -1;
92         }
93     }
94
95     if (bind(sock, addr, len) < 0) {
96         UNIXERR("bind");
97         close(sock);
98         return -1;
99     }
100
101     if (setnonblock(sock)) {
102         close(sock);
103         return -1;
104     }
105
106     if (listen(sock, 0) < 0) {
107         UNIXERR("bind");
108         close(sock);
109         return -1;
110     }
111
112     return sock;
113 }
114
115 int accept_nonblock(int fd)
116 {
117     int sock = accept(fd, NULL, 0);
118
119     if (sock < 0) {
120         UNIXERR("accept");
121         return -1;
122     }
123
124     if (setnonblock(sock)) {
125         close(sock);
126         return -1;
127     }
128
129     return sock;
130 }
131
132 int daemon_detach(void)
133 {
134     pid_t pid;
135
136     close(STDIN_FILENO);
137     close(STDOUT_FILENO);
138     close(STDERR_FILENO);
139
140     open("/dev/null", O_RDWR);
141     open("/dev/null", O_RDWR);
142     open("/dev/null", O_RDWR);
143
144     pid = fork();
145     if (pid < 0)
146         return -1;
147     if (pid)
148         exit(0);
149
150     setsid();
151     return 0;
152 }
153
154 int drop_privileges(const char *user, const char *group)
155 {
156     if (!geteuid()) {
157         struct passwd *pw;
158         struct group *gr;
159
160         if (group) {
161             gr = getgrnam(group);
162             if (!gr)
163                 return -1;
164             setgid(gr->gr_gid);
165         }
166
167         pw = getpwnam(user);
168         if (!pw)
169             return -1;
170         if (!group) {
171             setgid(pw->pw_gid);
172         }
173         setuid(pw->pw_uid);
174     }
175
176     return 0;
177 }