63deac598e74d555a3f75173191033130dedc5f7
[kopensolaris-gnu/glibc.git] / nscd / connections.c
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/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>
36
37 #include "nscd.h"
38 #include "dbg_log.h"
39
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;
47
48
49 /* Cleanup.  */
50 void
51 close_sockets (void)
52 {
53   int i;
54
55   if (debug_flag)
56     dbg_log (_("close_sockets called"));
57
58   pthread_mutex_lock (&sock_lock);
59
60   /* Close sockets.  */
61   for (i = 0; i < MAX_NUM_CONNECTIONS; ++i)
62     if (sock[i] != 0)
63       {
64         if (close (sock[i]))
65           dbg_log (_("socket [%d|%d] close: %s"), strerror (errno));
66
67         sock[i] = 0;
68         read_polls[i].fd = -1;
69         --socks_active;
70       }
71
72   pthread_mutex_unlock (&sock_lock);
73 }
74
75 void
76 close_socket (int conn)
77 {
78   if (debug_flag > 2)
79     dbg_log (_("close socket (%d|%d)"), conn, sock[conn]);
80
81   pthread_mutex_lock (&sock_lock);
82
83   close (sock[conn]);
84   sock[conn] = 0;
85   read_polls[conn].fd = -1;
86   --socks_active;
87
88   pthread_mutex_unlock (&sock_lock);
89 }
90
91 /* Local routine, assigns a socket to a new connection request.  */
92 static void
93 handle_new_connection (void)
94 {
95   int i;
96
97   if (debug_flag > 2)
98     dbg_log (_("handle_new_connection"));
99
100   pthread_mutex_lock (&sock_lock);
101
102   if (socks_active < MAX_NUM_CONNECTIONS)
103     /* Find a free socket entry to use.  */
104     for (i = 1; i < MAX_NUM_CONNECTIONS; ++i)
105       {
106         if (sock[i] == 0)
107           {
108             if ((sock[i] = accept (sock[0], NULL, NULL)) < 0)
109               {
110                 dbg_log (_("socket accept: %s"), strerror (errno));
111                 return;
112               }
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;
120           }
121       }
122   else
123     {
124       int black_widow_sock;
125       dbg_log (_("Supported number of simultainious 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);
131     }
132   pthread_mutex_unlock (&sock_lock);
133 }
134
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)
138 {
139   ssize_t nbytes;
140   int i;
141
142   if (debug_flag)
143     dbg_log ("handle_new_request");
144
145   /* Find the descriptor.  */
146   for (i = 1; i < MAX_NUM_CONNECTIONS; ++i)
147     if (read_polls[i].revents & (POLLRDNORM|POLLERR))
148       break;
149
150   if (debug_flag > 2)
151     dbg_log (_("handle_new_request uses socket %d"), i);
152
153   /* Read from it.  */
154   nbytes = read (sock[i], *reqp, sizeof (request_header));
155   if (nbytes != sizeof (request_header))
156     {
157       /* Handle non-data read cases.  */
158       if (nbytes == 0)
159         {
160           /* Close socket down.  */
161           if (debug_flag > 2)
162             dbg_log (_("Real close socket %d|%d"), i, sock[i]);
163
164           pthread_mutex_lock (&sock_lock);
165           read_polls[i].fd = -1;
166           close (sock[i]);
167           sock[i] = 0;
168           --socks_active;
169           pthread_mutex_unlock (&sock_lock);
170         }
171       else
172         if (nbytes < 0)
173           {
174             dbg_log (_("Read(%d|%d) error on get request: %s"),
175                      i, sock[i], strerror (errno));
176             exit (1);
177           }
178         else
179           dbg_log (_("Read, data < request buf size, ignoring data"));
180
181       return -1;
182     }
183   else
184     {
185       *key = malloc ((*reqp)->key_len + 1);
186       /* Read the key from it */
187       nbytes = read (sock[i], *key, (*reqp)->key_len);
188       if (nbytes != (*reqp)->key_len)
189         {
190           /* Handle non-data read cases.  */
191           if (nbytes == 0)
192             {
193               /* Close socket down.  */
194               if (debug_flag > 2)
195                 dbg_log (_("Real close socket %d|%d"), i, sock[i]);
196
197               pthread_mutex_lock (&sock_lock);
198               read_polls[i].fd = -1;
199               close (sock[i]);
200               sock[i] = 0;
201               --socks_active;
202               pthread_mutex_unlock (&sock_lock);
203             }
204           else
205             if (nbytes < 0)
206               {
207                 perror (_("Read() error on get request"));
208                 return 0;
209               }
210             else
211               fputs (_("Read, data < request buf size, ignoring data"),
212                      stderr);
213
214           free (*key);
215           return -1;
216         }
217       else
218         {
219           /* Ok, have a live one, A real data req buf has been obtained.  */
220           (*key)[(*reqp)->key_len] = '\0';
221           **connp = i;
222           return 0;
223         }
224     }
225 }
226
227 void
228 get_request (int *conn, request_header *req, char **key)
229 {
230   int done = 0;
231   int nr;
232
233   if (debug_flag)
234     dbg_log ("get_request");
235
236   /* loop, processing new connection requests until a client buffer
237      is read in on an existing connection.  */
238   while (!done)
239     {
240       /* Poll active connections.  */
241       nr = poll (read_polls, MAX_NUM_CONNECTIONS, -1);
242       if (nr <= 0)
243         {
244           perror (_("Poll new reads"));
245           exit (1);
246         }
247       if (read_polls[0].revents & (POLLRDNORM|POLLERR))
248         /* Handle the case of a new connection request on the named socket.  */
249         handle_new_connection ();
250       else
251         {
252           /* Read data from client specific descriptor.  */
253           if (handle_new_request (&conn, &req, key) == 0)
254             done = 1;
255         }
256     } /* While not_done.  */
257 }
258
259 void
260 init_sockets (void)
261 {
262   struct sockaddr_un sock_addr;
263   int i;
264
265   /* Initialize the connections db.  */
266   socks_active = 0;
267
268   /* Initialize the poll array. */
269   for (i = 0; i < MAX_NUM_CONNECTIONS; i++)
270     read_polls[i].fd = -1;
271
272   /* Create the socket.  */
273   sock[0] = socket (AF_UNIX, SOCK_STREAM, 0);
274   if (sock[0] < 0)
275     {
276       perror (_("cannot create socket"));
277       exit (1);
278     }
279   /* Bind a name to the socket.  */
280   sock_addr.sun_family = AF_UNIX;
281   strcpy (sock_addr.sun_path, _PATH_NSCDSOCKET);
282   if (bind (sock[0], (struct sockaddr *) &sock_addr, sizeof (sock_addr)) < 0)
283     {
284       dbg_log ("%s: %s", _PATH_NSCDSOCKET, strerror (errno));
285       exit (1);
286     }
287   /* Set permissions for the socket.  */
288   chmod (_PATH_NSCDSOCKET, 0666);
289
290   /* Set the socket up to accept connections.  */
291   if (listen (sock[0], MAX_NUM_CONNECTIONS) < 0)
292     {
293       perror (_("cannot enable socket to accept connections"));
294       exit (1);
295     }
296
297   /* Add the socket to the server's set of active sockets.  */
298   read_polls[0].fd = sock[0];
299   read_polls[0].events = POLLRDNORM;
300   ++socks_active;
301 }
302
303 void
304 pw_send_answer (int conn, struct passwd *pwd)
305 {
306   pw_response_header resp;
307
308   resp.version = NSCD_VERSION;
309   if (pwd != NULL)
310     {
311       resp.found = 1;
312       resp.pw_name_len = strlen (pwd->pw_name);
313       resp.pw_passwd_len = strlen (pwd->pw_passwd);
314       resp.pw_uid = pwd->pw_uid;
315       resp.pw_gid = pwd->pw_gid;
316       resp.pw_gecos_len = strlen (pwd->pw_gecos);
317       resp.pw_dir_len = strlen (pwd->pw_dir);
318       resp.pw_shell_len = strlen (pwd->pw_shell);
319     }
320   else
321     {
322       resp.found = 0;
323       resp.pw_name_len = 0;
324       resp.pw_passwd_len = 0;
325       resp.pw_uid = -1;
326       resp.pw_gid = -1;
327       resp.pw_gecos_len = 0;
328       resp.pw_dir_len = 0;
329       resp.pw_shell_len = 0;
330     }
331   if (sock[conn] == 0)
332     {
333       dbg_log (_("bad connection id on send response [%d|%d]"),
334                conn, sock[conn]);
335       return;
336     }
337
338   /* Send response header.  */
339   if (write (sock[conn], &resp, sizeof (pw_response_header)) !=
340       sizeof (pw_response_header))
341     {
342       dbg_log (_("write incomplete on send response: %s"), strerror (errno));
343       return;
344     }
345
346   if (resp.found)
347     {
348       struct iovec vec[5];
349
350       /* Send pw_name.  */
351       vec[0].iov_base = pwd->pw_name;
352       vec[0].iov_len = resp.pw_name_len;
353       /* Send pw_passwd.  */
354       vec[1].iov_base = pwd->pw_passwd;
355       vec[1].iov_len = resp.pw_passwd_len;
356       /* Send pw_gecos.  */
357       vec[2].iov_base = pwd->pw_gecos;
358       vec[2].iov_len = resp.pw_gecos_len;
359       /* Send pw_dir.  */
360       vec[3].iov_base = pwd->pw_dir;
361       vec[3].iov_len = resp.pw_dir_len;
362       /* Send pw_shell.  */
363       vec[4].iov_base = pwd->pw_shell;
364       vec[4].iov_len = resp.pw_shell_len;
365
366       if (writev (sock[conn], vec, 5) != (resp.pw_name_len + resp.pw_passwd_len
367                                           + resp.pw_gecos_len + resp.pw_dir_len
368                                           + resp.pw_shell_len))
369         dbg_log (_("write incomplete on send passwd answer: %s"),
370                  strerror (errno));
371     }
372 }
373
374 void
375 pw_send_disabled (int conn)
376 {
377   pw_response_header resp;
378
379   resp.version = NSCD_VERSION;
380   resp.found = -1;
381   resp.pw_name_len = 0;
382   resp.pw_passwd_len = 0;
383   resp.pw_uid = -1;
384   resp.pw_gid = -1;
385   resp.pw_gecos_len = 0;
386   resp.pw_dir_len = 0;
387   resp.pw_shell_len = 0;
388
389   if (sock[conn] == 0)
390     {
391       dbg_log (_("bad connection id on send response [%d|%d]"),
392                conn, sock[conn]);
393       return;
394     }
395
396   /* Send response header.  */
397   if (write (sock[conn], &resp, sizeof (pw_response_header))
398       != sizeof (pw_response_header))
399     dbg_log (_("write incomplete on send response: %s"), strerror (errno));
400 }
401
402 void
403 gr_send_answer (int conn, struct group *grp)
404 {
405   gr_response_header resp;
406
407   resp.version = NSCD_VERSION;
408   if (grp != NULL)
409     {
410       resp.found = 1;
411       resp.gr_name_len = strlen (grp->gr_name);
412       resp.gr_passwd_len = strlen (grp->gr_passwd);
413       resp.gr_gid = grp->gr_gid;
414       resp.gr_mem_len = 0;
415       while (grp->gr_mem[resp.gr_mem_len])
416         ++resp.gr_mem_len;
417     }
418   else
419     {
420       resp.found = 0;
421       resp.gr_name_len = 0;
422       resp.gr_passwd_len = 0;
423       resp.gr_gid = -1;
424       resp.gr_mem_len = 0;
425     }
426   if (sock[conn] == 0)
427     {
428       dbg_log (_("bad connection id on send response [%d|%d]"),
429                conn, sock[conn]);
430       return;
431     }
432
433   /* Send response header.  */
434   if (write (sock[conn], &resp, sizeof (gr_response_header))
435       != sizeof (gr_response_header))
436     {
437       dbg_log (_("write incomplete on send response: %s"), strerror (errno));
438       return;
439     }
440
441   if (resp.found)
442     {
443       unsigned int l = 0;
444
445       /* Send gr_name.  */
446       if (write (sock[conn], grp->gr_name, resp.gr_name_len)
447           != resp.gr_name_len)
448         {
449           dbg_log (_("write incomplete on send response: %s"),
450                    strerror (errno));
451           return;
452         }
453       /* Send gr_passwd.  */
454       if (write (sock[conn], grp->gr_passwd, resp.gr_passwd_len)
455           != resp.gr_passwd_len)
456         {
457           dbg_log (_("write incomplete on send response: %s"),
458                    strerror (errno));
459           return;
460         }
461
462       while (grp->gr_mem[l])
463         {
464           size_t len = strlen (grp->gr_mem[l]);
465
466           if (write (sock[conn], &len, sizeof (len)) != sizeof (len))
467             {
468               dbg_log (_("write incomplete on send response: %s"),
469                        strerror (errno));
470               return;
471             }
472           if (write (sock[conn], grp->gr_mem[l], len) != len)
473             {
474               dbg_log (_("write incomplete on send response: %s"),
475                        strerror (errno));
476               return;
477             }
478           ++l;
479         }
480     }
481 }
482
483 void
484 gr_send_disabled (int conn)
485 {
486   gr_response_header resp;
487
488   resp.version = NSCD_VERSION;
489   resp.found = -1;
490   resp.gr_name_len = 0;
491   resp.gr_passwd_len = 0;
492   resp.gr_gid = -1;
493   resp.gr_mem_len = 0;
494
495   if (sock[conn] == 0)
496     {
497       dbg_log (_("bad connection id on send gr_disabled response [%d|%d]"),
498                conn, sock[conn]);
499       return;
500     }
501
502   /* Send response header.  */
503   if (write (sock[conn], &resp, sizeof (gr_response_header))
504       != sizeof (gr_response_header))
505     dbg_log (_("write incomplete on send gr_disabled response: %s"),
506              strerror (errno));
507 }
508
509 void
510 stat_send (int conn, stat_response_header *resp)
511 {
512   if (sock[conn] == 0)
513     {
514       dbg_log (_("bad connection id on send stat response [%d|%d]"),
515                conn, sock[conn]);
516       return;
517     }
518
519   /* send response header.  */
520   if (write (sock[conn], resp, sizeof (stat_response_header))
521       != sizeof (stat_response_header))
522     dbg_log (_("write incomplete on send stat response: %s"),
523              strerror (errno));
524 }