]> git.ipfire.org Git - thirdparty/glibc.git/blame - nscd/connections.c
Update.
[thirdparty/glibc.git] / nscd / connections.c
CommitLineData
d67281a7
UD
1/* Copyright (c) 1998 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1998.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
19
20#include <errno.h>
21#include <error.h>
22#include <fcntl.h>
23#include <libintl.h>
24#include <locale.h>
25#include <pthread.h>
26#include <pwd.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <unistd.h>
30#include <sys/socket.h>
31#include <sys/stat.h>
32#include <sys/types.h>
33#include <sys/uio.h>
34#include <sys/un.h>
35
36#include "nscd.h"
37#include "dbg_log.h"
38
39/* Socket 0 in the array is named and exported into the file namespace
40 as a connection point for clients. */
41static int sock[MAX_NUM_CONNECTIONS];
42static int socks_active;
43static fd_set read_set;
44static pthread_mutex_t sock_lock = PTHREAD_MUTEX_INITIALIZER;
45
46
47/* Cleanup. */
48void
49close_sockets (void)
50{
51 int i;
52
53 if (debug_flag)
54 dbg_log (_("close_sockets called"));
55
56 pthread_mutex_lock (&sock_lock);
57
58 /* Close sockets. */
59 for (i = 0; i < MAX_NUM_CONNECTIONS; ++i)
60 if (sock[i] != 0)
61 {
62 if (close (sock[i]))
63 dbg_log (_("socket [%d|%d] close: %s"), strerror (errno));
64
65 sock[i] = 0;
66 --socks_active;
67 }
68
69 pthread_mutex_unlock (&sock_lock);
70}
71
72void
73close_socket (int conn)
74{
75 if (debug_flag > 2)
76 dbg_log (_("close socket (%d|%d)"), conn, sock[conn]);
77
78 pthread_mutex_lock (&sock_lock);
79
80 close (sock[conn]);
81 sock[conn] = 0;
82 --socks_active;
83
84 pthread_mutex_unlock (&sock_lock);
85}
86
87/* Local rountine, assigns a socket to a new connection request. */
88static void
89handle_new_connection (void)
90{
91 int i;
92
93 if (debug_flag > 2)
94 dbg_log (_("handle_new_connection"));
95
96 pthread_mutex_lock (&sock_lock);
97
98 if (socks_active < MAX_NUM_CONNECTIONS)
99 /* Find a free socket entry to use. */
100 for (i = 1; i < MAX_NUM_CONNECTIONS; ++i)
101 {
102 if (sock[i] == 0)
103 {
104 if ((sock[i] = accept (sock[0], NULL, NULL)) < 0)
105 {
106 dbg_log (_("socket accept: %s"), strerror (errno));
107 return;
108 }
109 ++socks_active;
110 FD_SET (sock[i], &read_set);
111 if (debug_flag > 2)
112 dbg_log (_("handle_new_connection used socket %d|%d"), i,
113 sock[i]);
114 break;
115 }
116 }
117 else
118 {
119 int black_widow_sock;
120 dbg_log (_("Supported number of simultainious connections exceeded"));
121 dbg_log (_("Ignoring client connect request"));
122 /* There has to be a better way to ignore a connection request,..
123 when I get my hands on a sockets wiz I'll modify this. */
124 black_widow_sock = accept (sock[0], NULL, NULL);
125 close (black_widow_sock);
126 }
127 pthread_mutex_unlock (&sock_lock);
128}
129
130/* Local routine, reads a request off a socket indicated by a selectset. */
131static int
132handle_new_request (fd_set read_selects, int **connp, request_header **reqp,
133 char **key)
134{
135 ssize_t nbytes;
136 int i;
137
138 if (debug_flag)
139 dbg_log ("handle_new_request");
140
141 /* Find the descriptor. */
142 for (i = 1; i < MAX_NUM_CONNECTIONS; ++i)
143 if (FD_ISSET(sock[i], &read_selects))
144 break;
145
146 if (debug_flag > 2)
147 dbg_log (_("handle_new_request uses socket %d"), i);
148
149 /* Read from it. */
150 nbytes = read (sock[i], *reqp, sizeof (request_header));
151 if (nbytes != sizeof (request_header))
152 {
153 /* Handle non-data read cases. */
154 if (nbytes == 0)
155 {
156 /* Close socket down. */
157 if (debug_flag > 2)
158 dbg_log (_("Real close socket %d|%d"), i, sock[i]);
159
160 pthread_mutex_lock (&sock_lock);
161 FD_CLR (sock[i], &read_set);
162 close (sock[i]);
163 sock[i] = 0;
164 --socks_active;
165 pthread_mutex_unlock (&sock_lock);
166 }
167 else
168 if (nbytes < 0)
169 {
170 dbg_log (_("Read(%d|%d) error on get request: %s"),
171 i, sock[i], strerror (errno));
172 exit (1);
173 }
174 else
175 dbg_log (_("Read, data < request buf size, ignoring data"));
176
177 return -1;
178 }
179 else
180 {
181 *key = malloc ((*reqp)->key_len + 1);
182 /* Read the key from it */
183 nbytes = read (sock[i], *key, (*reqp)->key_len);
184 if (nbytes != (*reqp)->key_len)
185 {
186 /* Handle non-data read cases. */
187 if (nbytes == 0)
188 {
189 /* Close socket down. */
190 if (debug_flag > 2)
191 dbg_log (_("Real close socket %d|%d"), i, sock[i]);
192
193 pthread_mutex_lock (&sock_lock);
194 FD_CLR (sock[i], &read_set);
195 close (sock[i]);
196 sock[i] = 0;
197 --socks_active;
198 pthread_mutex_unlock (&sock_lock);
199 }
200 else
201 if (nbytes < 0)
202 {
203 perror (_("Read() error on get request"));
204 return 0;
205 }
206 else
207 fputs (_("Read, data < request buf size, ignoring data"),
208 stderr);
209
210 free (*key);
211 return -1;
212 }
213 else
214 {
215 /* Ok, have a live one, A real data req buf has been obtained. */
216 (*key)[(*reqp)->key_len] = '\0';
217 **connp = i;
218 return 0;
219 }
220 }
221}
222
223void
224get_request (int *conn, request_header *req, char **key)
225{
226 int i, nr, done = 0;
227 fd_set read_selects;
228
229 if (debug_flag)
230 dbg_log ("get_request");
231
232 /* loop, processing new connection requests until a client buffer
233 is read in on an existing connection. */
234 while (!done)
235 {
236 /* Set up the socket descriptor mask for the select.
237 copy read_set into the local copy. */
238
239 FD_ZERO (&read_selects);
240 pthread_mutex_lock (&sock_lock);
241 for (i = 0; i < MAX_NUM_CONNECTIONS; ++i)
242 {
243 if (FD_ISSET (sock[i], &read_set))
244 FD_SET (sock[i], &read_selects);
245 }
246 pthread_mutex_unlock (&sock_lock);
247 /* Poll active connections using select(). */
248 nr = select (FD_SETSIZE, &read_selects, NULL, NULL, NULL);
249 if (nr <= 0)
250 {
251 perror (_("Select new reads"));
252 exit (1);
253 }
254 if (FD_ISSET (sock[0], &read_selects))
255 /* Handle the case of a new connection request on the named socket. */
256 handle_new_connection ();
257 else
258 {
259 /* Read data from client specific descriptor. */
260 if (handle_new_request (read_selects, &conn, &req, key) == 0)
261 {
262 FD_CLR (sock[*conn], &read_set);
263 done = 1;
264 }
265 }
266 } /* While not_done. */
267}
268
269void
270init_sockets (void)
271{
272 struct sockaddr_un sock_addr;
273
274 /* Initialize the connections db. */
275 socks_active = 0;
276 FD_ZERO (&read_set);
277
278 /* Create the socket. */
279 sock[0] = socket (AF_UNIX, SOCK_STREAM, 0);
280 if (sock[0] < 0)
281 {
282 perror (_("cannot create socket"));
283 exit (1);
284 }
285 /* Bind a name to the socket. */
286 sock_addr.sun_family = AF_UNIX;
287 strcpy (sock_addr.sun_path, _PATH_NSCDSOCKET);
288 if (bind (sock[0], (struct sockaddr *) &sock_addr, sizeof (sock_addr)) < 0)
289 {
290 dbg_log ("%s: %s", _PATH_NSCDSOCKET, strerror (errno));
291 exit (1);
292 }
293 /* Set permissions for the socket. */
294 chmod (_PATH_NSCDSOCKET, 0666);
295
296 /* Set the socket up to accept connections. */
297 if (listen (sock[0], MAX_NUM_CONNECTIONS) < 0)
298 {
299 perror (_("cannot enable socket to accept connections"));
300 exit (1);
301 }
302
303 /* Add the socket to the server's set of active sockets. */
304 FD_SET (sock[0], &read_set);
305 ++socks_active;
306}
307
308void
309pw_send_answer (int conn, struct passwd *pwd)
310{
311 pw_response_header resp;
312
313 resp.version = NSCD_VERSION;
314 if (pwd != NULL)
315 {
316 resp.found = 1;
317 resp.pw_name_len = strlen (pwd->pw_name);
318 resp.pw_passwd_len = strlen (pwd->pw_passwd);
319 resp.pw_uid = pwd->pw_uid;
320 resp.pw_gid = pwd->pw_gid;
321 resp.pw_gecos_len = strlen (pwd->pw_gecos);
322 resp.pw_dir_len = strlen (pwd->pw_dir);
323 resp.pw_shell_len = strlen (pwd->pw_shell);
324 }
325 else
326 {
327 resp.found = 0;
328 resp.pw_name_len = 0;
329 resp.pw_passwd_len = 0;
330 resp.pw_uid = -1;
331 resp.pw_gid = -1;
332 resp.pw_gecos_len = 0;
333 resp.pw_dir_len = 0;
334 resp.pw_shell_len = 0;
335 }
336 if (sock[conn] == 0)
337 {
338 dbg_log (_("bad connection id on send response [%d|%d]"),
339 conn, sock[conn]);
340 return;
341 }
342
343 /* Send response header. */
344 if (write (sock[conn], &resp, sizeof (pw_response_header)) !=
345 sizeof (pw_response_header))
346 {
347 dbg_log (_("write incomplete on send response: %s"), strerror (errno));
348 return;
349 }
350
351 if (resp.found)
352 {
353 struct iovec vec[5];
354
355 /* Send pw_name. */
356 vec[0].iov_base = pwd->pw_name;
357 vec[0].iov_len = resp.pw_name_len;
358 /* Send pw_passwd. */
359 vec[1].iov_base = pwd->pw_passwd;
360 vec[1].iov_len = resp.pw_passwd_len;
361 /* Send pw_gecos. */
362 vec[2].iov_base = pwd->pw_gecos;
363 vec[2].iov_len = resp.pw_gecos_len;
364 /* Send pw_dir. */
365 vec[3].iov_base = pwd->pw_dir;
366 vec[3].iov_len = resp.pw_dir_len;
367 /* Send pw_shell. */
368 vec[4].iov_base = pwd->pw_shell;
369 vec[4].iov_len = resp.pw_shell_len;
370
371 if (writev (sock[conn], vec, 5) != (resp.pw_name_len + resp.pw_passwd_len
372 + resp.pw_gecos_len + resp.pw_dir_len
373 + resp.pw_shell_len))
374 dbg_log (_("write incomplete on send passwd answer: %s"),
375 strerror (errno));
376 }
377}
378
379void
380pw_send_disabled (int conn)
381{
382 pw_response_header resp;
383
384 resp.version = NSCD_VERSION;
385 resp.found = -1;
386 resp.pw_name_len = 0;
387 resp.pw_passwd_len = 0;
388 resp.pw_uid = -1;
389 resp.pw_gid = -1;
390 resp.pw_gecos_len = 0;
391 resp.pw_dir_len = 0;
392 resp.pw_shell_len = 0;
393
394 if (sock[conn] == 0)
395 {
396 dbg_log ("bad connection id on send response [%d|%d]",
397 conn, sock[conn]);
398 return;
399 }
400
401 /* Send response header. */
402 if (write (sock[conn], &resp, sizeof (pw_response_header))
403 != sizeof (pw_response_header))
404 dbg_log (_("write incomplete on send response: %s"), strerror (errno));
405}
406
407void
408gr_send_answer (int conn, struct group *grp)
409{
410 gr_response_header resp;
411
412 resp.version = NSCD_VERSION;
413 if (grp != NULL)
414 {
415 resp.found = 1;
416 resp.gr_name_len = strlen (grp->gr_name);
417 resp.gr_passwd_len = strlen (grp->gr_passwd);
418 resp.gr_gid = grp->gr_gid;
419 resp.gr_mem_len = 0;
420 while (grp->gr_mem[resp.gr_mem_len])
421 ++resp.gr_mem_len;
422 }
423 else
424 {
425 resp.found = 0;
426 resp.gr_name_len = 0;
427 resp.gr_passwd_len = 0;
428 resp.gr_gid = -1;
429 resp.gr_mem_len = 0;
430 }
431 if (sock[conn] == 0)
432 {
433 dbg_log (_("bad connection id on send response [%d|%d]"),
434 conn, sock[conn]);
435 return;
436 }
437
438 /* Send response header. */
439 if (write (sock[conn], &resp, sizeof (gr_response_header))
440 != sizeof (gr_response_header))
441 {
442 dbg_log (_("write incomplete on send response: %s"), strerror (errno));
443 return;
444 }
445
446 if (resp.found)
447 {
448 unsigned int l = 0;
449
450 /* Send gr_name. */
451 if (write (sock[conn], grp->gr_name, resp.gr_name_len)
452 != resp.gr_name_len)
453 {
454 dbg_log (_("write incomplete on send response: %s"),
455 strerror (errno));
456 return;
457 }
458 /* Send gr_passwd. */
459 if (write (sock[conn], grp->gr_passwd, resp.gr_passwd_len)
460 != resp.gr_passwd_len)
461 {
462 dbg_log (_("write incomplete on send response: %s"),
463 strerror (errno));
464 return;
465 }
466
467 while (grp->gr_mem[l])
468 {
469 size_t len = strlen (grp->gr_mem[l]);
470
471 if (write (sock[conn], &len, sizeof (len)) != sizeof (len))
472 {
473 dbg_log (_("write incomplete on send response: %s"),
474 strerror (errno));
475 return;
476 }
477 if (write (sock[conn], grp->gr_mem[l], len) != len)
478 {
479 dbg_log (_("write incomplete on send response: %s"),
480 strerror (errno));
481 return;
482 }
483 ++l;
484 }
485 }
486}
487
488void
489gr_send_disabled (int conn)
490{
491 gr_response_header resp;
492
493 resp.version = NSCD_VERSION;
494 resp.found = -1;
495 resp.gr_name_len = 0;
496 resp.gr_passwd_len = 0;
497 resp.gr_gid = -1;
498 resp.gr_mem_len = 0;
499
500 if (sock[conn] == 0)
501 {
502 dbg_log (_("bad connection id on send gr_disabled response [%d|%d]"),
503 conn, sock[conn]);
504 return;
505 }
506
507 /* Send response header. */
508 if (write (sock[conn], &resp, sizeof (gr_response_header))
509 != sizeof (gr_response_header))
510 dbg_log (_("write incomplete on send gr_disabled response: %s"),
511 strerror (errno));
512}
513
514void
515stat_send (int conn, stat_response_header *resp)
516{
517 if (sock[conn] == 0)
518 {
519 dbg_log (_("bad connection id on send stat response [%d|%d]"),
520 conn, sock[conn]);
521 return;
522 }
523
524 /* send response header. */
525 if (write (sock[conn], resp, sizeof (stat_response_header))
526 != sizeof (stat_response_header))
527 dbg_log (_("write incomplete on send stat response: %s"),
528 strerror (errno));
529}