"Fossies" - the Fresh Open Source Software Archive 
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "daemon.c" see the
Fossies "Dox" file reference documentation.
1 /*
2 * Ident-2 - an Identity server for UNIX
3 * Copyright (C) 1998-2001 Michael Bacarella
4 * Copyright (C) 2003 Netgraft Corporation
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 *
20 * Please view the file README for program information.
21 *
22 * ---------------------
23 * This file provides the 'daemon' implementation of
24 * ident2.
25 *
26 * Daemon waits for connections
27 * forks, handles connections, cleans up,
28 * dies, etc.
29 *
30 * Module entry point is ``daemon_service''
31 * ---------------------
32 */
33
34 #include "ident2.h"
35
36
37 static int
38 _go_daemon (void)
39 {
40 switch (fork()) {
41 case 0:
42 setsid();
43 m_register_pid ();
44 m_reduce_rights ();
45 return 0;
46 case -1:
47 syslog (LOG_ERR, "d_core: error fork(): %s\n", strerror(errno));
48 return -1;
49 default:
50 exit (0);
51 }
52 }
53
54 /*
55 * remove dead children from the process vector
56 */
57 static void
58 _reap_proc (pid_t *pv, size_t Max_Connections)
59 {
60 pid_t *p;
61 int r, s;
62
63 for (p = pv; p < pv+Max_Connections; p++) {
64 if (*p == 0)
65 continue;
66
67 while ((r = waitpid (*p, &s, WNOHANG)) == -1)
68 if (errno != EINTR) {
69 syslog (LOG_NOTICE,
70 "warning: waitpid() error: %s",
71 strerror (errno));
72 break;
73 }
74 if (r == 0)
75 continue;
76 if (r > 0)
77 *p = 0;
78 }
79 }
80
81
82 static void
83 declient (int s)
84 {
85 struct sockaddr sin;
86 int ss = sizeof (sin);
87 close (accept (s, (struct sockaddr *)&sin, &ss));
88 }
89
90
91 static void _sig_ign (int s) { return; }
92
93
94 static int
95 _accept_connect (int sv, struct sockaddr_in *sin)
96 {
97 size_t sl = sizeof (struct sockaddr_in);
98 int cl;
99
100 while ((cl = accept(sv, (struct sockaddr *)sin, &sl)) == -1) {
101 if (errno == EINTR)
102 continue;
103 return -1;
104 }
105 return cl;
106 }
107
108 /*
109 * will wait for a connection on SV,
110 * find a space in the proc table and fork()
111 * child for it. the child will accept() it and
112 * process the waiting client.
113 * we rely on the delivery of EINTR to interrupt
114 * select(), which gives us a chance to test for
115 * deceased children.
116 */
117 static void
118 d_core (int sv)
119 {
120 struct sigaction sa;
121 struct sockaddr_in sin;
122 pid_t *pv;
123 /* become daemon */
124 if (_go_daemon () == -1) {
125 syslog (LOG_ERR, "d_core: error fork(): %s\n", strerror(errno));
126 return;
127 }
128
129 pv = xmalloc (Max_Connections * sizeof (pid_t));
130 memset (pv, 0, Max_Connections * sizeof(pid_t));
131
132 sa.sa_handler = _sig_ign;
133 sigemptyset (&sa.sa_mask);
134 sa.sa_flags = 0;
135
136 if (sigaction (SIGCHLD, &sa, NULL) == -1) {
137 syslog (LOG_ERR, "error: registering SIGCHLD handler: %s",
138 strerror (errno));
139 return;
140 }
141
142 while (1) {
143 pid_t *p;
144 int cl;
145 fd_set rfd;
146
147 FD_ZERO(&rfd);
148 FD_SET(sv, &rfd);
149
150 if (select (sv+1, &rfd, NULL, NULL, NULL) == -1) {
151 if (errno != EINTR)
152 break;
153 _reap_proc (pv, Max_Connections);
154 continue;
155 }
156 if (!FD_ISSET (sv, &rfd))
157 continue;
158
159 for (p = pv; p < pv+Max_Connections; p++)
160 if (*p == 0)
161 break;
162
163 if (p == pv+Max_Connections) {
164 syslog (LOG_INFO, "refusing %s: too many open "
165 "connections", inet_ntoa (sin.sin_addr));
166 declient (sv);
167 }
168
169 if ((cl = _accept_connect (sv, &sin)) == -1) {
170 syslog (LOG_NOTICE, "warning: inconsistency error: "
171 "select() and accept() disagree: %s",
172 strerror (errno));
173 continue;
174 }
175
176 if ((*p = fork()) == -1) {
177 syslog (LOG_ERR, "warning: couldn't fork(): %s",
178 strerror (errno));
179 *p = 0;
180 } else if (*p == 0) {
181 child_service (cl, cl);
182 close (cl);
183 exit (0);
184 }
185 close (cl); /* close now that it's mapped into the child */
186 }
187 }
188
189
190 void daemon_service (void)
191 {
192 int s;
193 struct sockaddr_in sin;
194
195 openlog ("ident2", LOG_PID, LOG_DAEMON);
196
197 if ((s = socket (PF_INET, SOCK_STREAM, 0)) == -1) {
198 syslog (LOG_ERR, "error: socket(): %s", strerror (errno));
199 return;
200 }
201
202 sin.sin_family = AF_INET;
203 sin.sin_port = htons (Ident_Port);
204 sin.sin_addr.s_addr = INADDR_ANY;
205
206 if (bind (s, (struct sockaddr *)&sin, sizeof (sin)) == -1) {
207 syslog (LOG_ERR, "error: binding to port %d: bind(): %s",
208 Ident_Port, strerror (errno));
209 fprintf (stderr, "error: binding to port %d: bind(): %s\n\n",
210 Ident_Port, strerror (errno));
211 return;
212 }
213
214 if (listen (s, 15) == -1) {
215 syslog (LOG_ERR, "error: listening to port %d: listen(): %s",
216 Ident_Port, strerror (errno));
217 fprintf (stderr, "error: listening to port %d: listen(): %s\n",
218 Ident_Port, strerror (errno));
219 return;
220 }
221
222 fclose (stdin);
223 fclose (stderr);
224 fclose (stdout);
225
226 syslog (LOG_NOTICE, "identity services started [%s]",
227 ID_VERSION);
228 d_core (s);
229
230 syslog (LOG_ERR, "error: identity services terminated on "
231 "internal error: See last (few) message(s)");
232
233 closelog ();
234 close (s);
235 return;
236 }