Fix typo.
[glibc/history.git] / nscd / connections.c
blob4cf397d2011af17c87a65f41ebfa3e055ca7a2d9
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.
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.
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.
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. */
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/poll.h>
31 #include <sys/socket.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
34 #include <sys/uio.h>
35 #include <sys/un.h>
37 #include "nscd.h"
38 #include "dbg_log.h"
40 /* Socket 0 in the array is named and exported into the file namespace
41 as a connection point for clients. There's a one to one
42 correspondence between sock[i] and read_polls[i]. */
43 static int sock[MAX_NUM_CONNECTIONS];
44 static int socks_active;
45 static struct pollfd read_polls[MAX_NUM_CONNECTIONS];
46 static pthread_mutex_t sock_lock = PTHREAD_MUTEX_INITIALIZER;
49 /* Cleanup. */
50 void
51 close_sockets (void)
53 int i;
55 if (debug_flag)
56 dbg_log (_("close_sockets called"));
58 pthread_mutex_lock (&sock_lock);
60 /* Close sockets. */
61 for (i = 0; i < MAX_NUM_CONNECTIONS; ++i)
62 if (sock[i] != 0)
64 if (close (sock[i]))
65 dbg_log (_("socket [%d|%d] close: %s"), i, sock[i], strerror (errno));
67 sock[i] = 0;
68 read_polls[i].fd = -1;
69 --socks_active;
72 pthread_mutex_unlock (&sock_lock);
75 void
76 close_socket (int conn)
78 if (debug_flag > 2)
79 dbg_log (_("close socket (%d|%d)"), conn, sock[conn]);
81 pthread_mutex_lock (&sock_lock);
83 close (sock[conn]);
84 sock[conn] = 0;
85 read_polls[conn].fd = -1;
86 --socks_active;
88 pthread_mutex_unlock (&sock_lock);
91 /* Local routine, assigns a socket to a new connection request. */
92 static void
93 handle_new_connection (void)
95 int i;
97 if (debug_flag > 2)
98 dbg_log (_("handle_new_connection"));
100 pthread_mutex_lock (&sock_lock);
102 if (socks_active < MAX_NUM_CONNECTIONS)
103 /* Find a free socket entry to use. */
104 for (i = 1; i < MAX_NUM_CONNECTIONS; ++i)
106 if (sock[i] == 0)
108 if ((sock[i] = accept (sock[0], NULL, NULL)) < 0)
110 dbg_log (_("socket accept: %s"), strerror (errno));
111 return;
113 ++socks_active;
114 read_polls[i].fd = sock[i];
115 read_polls[i].events = POLLRDNORM;
116 if (debug_flag > 2)
117 dbg_log (_("handle_new_connection used socket %d|%d"), i,
118 sock[i]);
119 break;
122 else
124 int black_widow_sock;
125 dbg_log (_("Supported number of simultaneous connections exceeded"));
126 dbg_log (_("Ignoring client connect request"));
127 /* There has to be a better way to ignore a connection request,..
128 when I get my hands on a sockets wiz I'll modify this. */
129 black_widow_sock = accept (sock[0], NULL, NULL);
130 close (black_widow_sock);
132 pthread_mutex_unlock (&sock_lock);
135 /* Local routine, reads a request off a socket indicated by read_polls. */
136 static int
137 handle_new_request (int **connp, request_header **reqp, char **key)
139 ssize_t nbytes;
140 int i, found = 0;
142 if (debug_flag)
143 dbg_log ("handle_new_request");
145 /* Find the descriptor. */
146 for (i = 1; i < MAX_NUM_CONNECTIONS; ++i) {
147 if (read_polls[i].fd >= 0
148 && read_polls[i].revents & (POLLRDNORM|POLLERR|POLLNVAL))
150 found = i;
151 break;
153 if (read_polls[i].fd >= 0 && (read_polls[i].revents & POLLHUP))
155 /* Don't close the socket, we still need to send data. Just
156 stop polling for more data now. */
157 read_polls[i].fd = -1;
161 if (found == 0)
163 dbg_log (_("No sockets with data found !"));
164 return -1;
167 if (debug_flag > 2)
168 dbg_log (_("handle_new_request uses socket %d"), i);
170 /* Read from it. */
171 nbytes = read (sock[i], *reqp, sizeof (request_header));
172 if (nbytes != sizeof (request_header))
174 /* Handle non-data read cases. */
175 if (nbytes == 0)
177 /* Close socket down. */
178 if (debug_flag > 2)
179 dbg_log (_("Real close socket %d|%d"), i, sock[i]);
181 pthread_mutex_lock (&sock_lock);
182 read_polls[i].fd = -1;
183 close (sock[i]);
184 sock[i] = 0;
185 --socks_active;
186 pthread_mutex_unlock (&sock_lock);
188 else
189 if (nbytes < 0)
191 dbg_log (_("Read(%d|%d) error on get request: %s"),
192 i, sock[i], strerror (errno));
193 exit (1);
195 else
196 dbg_log (_("Read, data < request buf size, ignoring data"));
198 return -1;
200 else
202 *key = malloc ((*reqp)->key_len + 1);
203 /* Read the key from it */
204 nbytes = read (sock[i], *key, (*reqp)->key_len);
205 if (nbytes != (*reqp)->key_len)
207 /* Handle non-data read cases. */
208 if (nbytes == 0)
210 /* Close socket down. */
211 if (debug_flag > 2)
212 dbg_log (_("Real close socket %d|%d"), i, sock[i]);
214 pthread_mutex_lock (&sock_lock);
215 read_polls[i].fd = -1;
216 close (sock[i]);
217 sock[i] = 0;
218 --socks_active;
219 pthread_mutex_unlock (&sock_lock);
221 else
222 if (nbytes < 0)
224 perror (_("Read() error on get request"));
225 return 0;
227 else
228 fputs (_("Read, data < request buf size, ignoring data"),
229 stderr);
231 free (*key);
232 return -1;
234 else
236 /* Ok, have a live one, A real data req buf has been obtained. */
237 (*key)[(*reqp)->key_len] = '\0';
238 **connp = i;
239 return 0;
244 void
245 get_request (int *conn, request_header *req, char **key)
247 int done = 0;
248 int nr;
250 if (debug_flag)
251 dbg_log ("get_request");
253 /* loop, processing new connection requests until a client buffer
254 is read in on an existing connection. */
255 while (!done)
257 /* Poll active connections. */
258 nr = poll (read_polls, MAX_NUM_CONNECTIONS, -1);
259 if (nr <= 0)
261 perror (_("Poll new reads"));
262 exit (1);
264 if (read_polls[0].revents & (POLLRDNORM|POLLERR|POLLHUP|POLLNVAL))
265 /* Handle the case of a new connection request on the named socket. */
266 handle_new_connection ();
267 else
269 /* Read data from client specific descriptor. */
270 if (handle_new_request (&conn, &req, key) == 0)
271 done = 1;
273 } /* While not_done. */
276 void
277 init_sockets (void)
279 struct sockaddr_un sock_addr;
280 int i;
282 /* Initialize the connections db. */
283 socks_active = 0;
285 /* Initialize the poll array. */
286 for (i = 0; i < MAX_NUM_CONNECTIONS; i++)
287 read_polls[i].fd = -1;
289 /* Create the socket. */
290 sock[0] = socket (AF_UNIX, SOCK_STREAM, 0);
291 if (sock[0] < 0)
293 perror (_("cannot create socket"));
294 exit (1);
296 /* Bind a name to the socket. */
297 sock_addr.sun_family = AF_UNIX;
298 strcpy (sock_addr.sun_path, _PATH_NSCDSOCKET);
299 if (bind (sock[0], (struct sockaddr *) &sock_addr, sizeof (sock_addr)) < 0)
301 dbg_log ("%s: %s", _PATH_NSCDSOCKET, strerror (errno));
302 exit (1);
304 /* Set permissions for the socket. */
305 chmod (_PATH_NSCDSOCKET, 0666);
307 /* Set the socket up to accept connections. */
308 if (listen (sock[0], MAX_NUM_CONNECTIONS) < 0)
310 perror (_("cannot enable socket to accept connections"));
311 exit (1);
314 /* Add the socket to the server's set of active sockets. */
315 read_polls[0].fd = sock[0];
316 read_polls[0].events = POLLRDNORM;
317 ++socks_active;
320 void
321 pw_send_answer (int conn, struct passwd *pwd)
323 struct iovec vec[6];
324 pw_response_header resp;
325 size_t total_len;
326 int nblocks;
328 resp.version = NSCD_VERSION;
329 if (pwd != NULL)
331 resp.found = 1;
332 resp.pw_name_len = strlen (pwd->pw_name);
333 resp.pw_passwd_len = strlen (pwd->pw_passwd);
334 resp.pw_uid = pwd->pw_uid;
335 resp.pw_gid = pwd->pw_gid;
336 resp.pw_gecos_len = strlen (pwd->pw_gecos);
337 resp.pw_dir_len = strlen (pwd->pw_dir);
338 resp.pw_shell_len = strlen (pwd->pw_shell);
340 else
342 resp.found = 0;
343 resp.pw_name_len = 0;
344 resp.pw_passwd_len = 0;
345 resp.pw_uid = -1;
346 resp.pw_gid = -1;
347 resp.pw_gecos_len = 0;
348 resp.pw_dir_len = 0;
349 resp.pw_shell_len = 0;
351 if (sock[conn] == 0)
353 dbg_log (_("bad connection id on send response [%d|%d]"),
354 conn, sock[conn]);
355 return;
358 /* Add response header. */
359 vec[0].iov_base = &resp;
360 vec[0].iov_len = sizeof (pw_response_header);
361 total_len = sizeof (pw_response_header);
362 nblocks = 1;
364 if (resp.found)
366 /* Add pw_name. */
367 vec[1].iov_base = pwd->pw_name;
368 vec[1].iov_len = resp.pw_name_len;
369 total_len += resp.pw_name_len;
370 /* Add pw_passwd. */
371 vec[2].iov_base = pwd->pw_passwd;
372 vec[2].iov_len = resp.pw_passwd_len;
373 total_len += resp.pw_passwd_len;
374 /* Add pw_gecos. */
375 vec[3].iov_base = pwd->pw_gecos;
376 vec[3].iov_len = resp.pw_gecos_len;
377 total_len += resp.pw_gecos_len;
378 /* Add pw_dir. */
379 vec[4].iov_base = pwd->pw_dir;
380 vec[4].iov_len = resp.pw_dir_len;
381 total_len += resp.pw_dir_len;
382 /* Add pw_shell. */
383 vec[5].iov_base = pwd->pw_shell;
384 vec[5].iov_len = resp.pw_shell_len;
385 total_len += resp.pw_shell_len;
387 nblocks = 6;
390 /* Send all the data. */
391 if (writev (sock[conn], vec, nblocks) != total_len)
392 dbg_log (_("write incomplete on send passwd answer: %s"),
393 strerror (errno));
396 void
397 pw_send_disabled (int conn)
399 pw_response_header resp;
401 resp.version = NSCD_VERSION;
402 resp.found = -1;
403 resp.pw_name_len = 0;
404 resp.pw_passwd_len = 0;
405 resp.pw_uid = -1;
406 resp.pw_gid = -1;
407 resp.pw_gecos_len = 0;
408 resp.pw_dir_len = 0;
409 resp.pw_shell_len = 0;
411 if (sock[conn] == 0)
413 dbg_log (_("bad connection id on send response [%d|%d]"),
414 conn, sock[conn]);
415 return;
418 /* Send response header. */
419 if (write (sock[conn], &resp, sizeof (pw_response_header))
420 != sizeof (pw_response_header))
421 dbg_log (_("write incomplete on send response: %s"), strerror (errno));
424 void
425 gr_send_answer (int conn, struct group *grp)
427 struct iovec *vec;
428 size_t *len;
429 gr_response_header resp;
430 size_t total_len, sum;
431 int nblocks;
432 size_t maxiov;
434 resp.version = NSCD_VERSION;
435 if (grp != NULL)
437 resp.found = 1;
438 resp.gr_name_len = strlen (grp->gr_name);
439 resp.gr_passwd_len = strlen (grp->gr_passwd);
440 resp.gr_gid = grp->gr_gid;
441 resp.gr_mem_len = 0;
442 while (grp->gr_mem[resp.gr_mem_len])
443 ++resp.gr_mem_len;
445 else
447 resp.found = 0;
448 resp.gr_name_len = 0;
449 resp.gr_passwd_len = 0;
450 resp.gr_gid = -1;
451 resp.gr_mem_len = 0;
453 if (sock[conn] == 0)
455 dbg_log (_("bad connection id on send response [%d|%d]"),
456 conn, sock[conn]);
457 return;
460 /* We have no fixed number of records so allocate the IOV here. */
461 vec = alloca ((3 + 1 + resp.gr_mem_len) * sizeof (struct iovec));
462 len = alloca (resp.gr_mem_len * sizeof (size_t));
464 /* Add response header. */
465 vec[0].iov_base = &resp;
466 vec[0].iov_len = sizeof (gr_response_header);
467 total_len = sizeof (gr_response_header);
468 nblocks = 1;
470 if (resp.found)
472 unsigned int l = 0;
474 /* Add gr_name. */
475 vec[1].iov_base = grp->gr_name;
476 vec[1].iov_len = resp.gr_name_len;
477 total_len += resp.gr_name_len;
478 /* Add gr_passwd. */
479 vec[2].iov_base = grp->gr_passwd;
480 vec[2].iov_len = resp.gr_passwd_len;
481 total_len += resp.gr_passwd_len;
482 nblocks = 3;
484 if (grp->gr_mem[l])
486 vec[3].iov_base = len;
487 vec[3].iov_len = resp.gr_mem_len * sizeof (size_t);
488 total_len += resp.gr_mem_len * sizeof (size_t);
489 nblocks = 4;
493 len[l] = strlen (grp->gr_mem[l]);
495 vec[nblocks].iov_base = grp->gr_mem[l];
496 vec[nblocks].iov_len = len[l];
497 total_len += len[l];
499 ++nblocks;
501 while (grp->gr_mem[++l]);
505 #ifdef UIO_MAXIOV
506 maxiov = UIO_MAXIOV;
507 #else
508 maxiov = sysconf (_SC_UIO_MAXIOV);
509 #endif
511 /* Send all the data. */
512 sum = 0;
513 while (nblocks > maxiov)
515 sum += writev (sock[conn], vec, maxiov);
516 vec += maxiov;
517 nblocks -= maxiov;
519 if (sum + writev (sock[conn], vec, nblocks) != total_len)
520 dbg_log (_("write incomplete on send group answer: %s"),
521 strerror (errno));
524 void
525 gr_send_disabled (int conn)
527 gr_response_header resp;
529 resp.version = NSCD_VERSION;
530 resp.found = -1;
531 resp.gr_name_len = 0;
532 resp.gr_passwd_len = 0;
533 resp.gr_gid = -1;
534 resp.gr_mem_len = 0;
536 if (sock[conn] == 0)
538 dbg_log (_("bad connection id on send gr_disabled response [%d|%d]"),
539 conn, sock[conn]);
540 return;
543 /* Send response header. */
544 if (write (sock[conn], &resp, sizeof (gr_response_header))
545 != sizeof (gr_response_header))
546 dbg_log (_("write incomplete on send gr_disabled response: %s"),
547 strerror (errno));
550 void
551 stat_send (int conn, stat_response_header *resp)
553 if (sock[conn] == 0)
555 dbg_log (_("bad connection id on send stat response [%d|%d]"),
556 conn, sock[conn]);
557 return;
560 /* send response header. */
561 if (write (sock[conn], resp, sizeof (stat_response_header))
562 != sizeof (stat_response_header))
563 dbg_log (_("write incomplete on send stat response: %s"),
564 strerror (errno));