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. */
31 #include <sys/socket.h>
33 #include <sys/types.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
;
56 dbg_log (_("close_sockets called"));
58 pthread_mutex_lock (&sock_lock
);
61 for (i
= 0; i
< MAX_NUM_CONNECTIONS
; ++i
)
65 dbg_log (_("socket [%d|%d] close: %s"), i
, sock
[i
], strerror (errno
));
68 read_polls
[i
].fd
= -1;
72 pthread_mutex_unlock (&sock_lock
);
76 close_socket (int conn
)
79 dbg_log (_("close socket (%d|%d)"), conn
, sock
[conn
]);
81 pthread_mutex_lock (&sock_lock
);
85 read_polls
[conn
].fd
= -1;
88 pthread_mutex_unlock (&sock_lock
);
91 /* Local routine, assigns a socket to a new connection request. */
93 handle_new_connection (void)
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
)
108 if ((sock
[i
] = accept (sock
[0], NULL
, NULL
)) < 0)
110 dbg_log (_("socket accept: %s"), strerror (errno
));
114 read_polls
[i
].fd
= sock
[i
];
115 read_polls
[i
].events
= POLLRDNORM
;
117 dbg_log (_("handle_new_connection used socket %d|%d"), i
,
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. */
137 handle_new_request (int **connp
, request_header
**reqp
, char **key
)
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
))
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;
163 dbg_log (_("No sockets with data found !"));
168 dbg_log (_("handle_new_request uses socket %d"), i
);
171 nbytes
= read (sock
[i
], *reqp
, sizeof (request_header
));
172 if (nbytes
!= sizeof (request_header
))
174 /* Handle non-data read cases. */
177 /* Close socket down. */
179 dbg_log (_("Real close socket %d|%d"), i
, sock
[i
]);
181 pthread_mutex_lock (&sock_lock
);
182 read_polls
[i
].fd
= -1;
186 pthread_mutex_unlock (&sock_lock
);
191 dbg_log (_("Read(%d|%d) error on get request: %s"),
192 i
, sock
[i
], strerror (errno
));
196 dbg_log (_("Read, data < request buf size, ignoring data"));
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. */
210 /* Close socket down. */
212 dbg_log (_("Real close socket %d|%d"), i
, sock
[i
]);
214 pthread_mutex_lock (&sock_lock
);
215 read_polls
[i
].fd
= -1;
219 pthread_mutex_unlock (&sock_lock
);
224 perror (_("Read() error on get request"));
228 fputs (_("Read, data < request buf size, ignoring data"),
236 /* Ok, have a live one, A real data req buf has been obtained. */
237 (*key
)[(*reqp
)->key_len
] = '\0';
245 get_request (int *conn
, request_header
*req
, char **key
)
251 dbg_log ("get_request");
253 /* loop, processing new connection requests until a client buffer
254 is read in on an existing connection. */
257 /* Poll active connections. */
258 nr
= poll (read_polls
, MAX_NUM_CONNECTIONS
, -1);
261 perror (_("Poll new reads"));
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 ();
269 /* Read data from client specific descriptor. */
270 if (handle_new_request (&conn
, &req
, key
) == 0)
273 } /* While not_done. */
279 struct sockaddr_un sock_addr
;
282 /* Initialize the connections db. */
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);
293 perror (_("cannot create socket"));
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
));
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"));
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
;
321 pw_send_answer (int conn
, struct passwd
*pwd
)
324 pw_response_header resp
;
328 resp
.version
= NSCD_VERSION
;
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
);
343 resp
.pw_name_len
= 0;
344 resp
.pw_passwd_len
= 0;
347 resp
.pw_gecos_len
= 0;
349 resp
.pw_shell_len
= 0;
353 dbg_log (_("bad connection id on send response [%d|%d]"),
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
);
367 vec
[1].iov_base
= pwd
->pw_name
;
368 vec
[1].iov_len
= resp
.pw_name_len
;
369 total_len
+= resp
.pw_name_len
;
371 vec
[2].iov_base
= pwd
->pw_passwd
;
372 vec
[2].iov_len
= resp
.pw_passwd_len
;
373 total_len
+= resp
.pw_passwd_len
;
375 vec
[3].iov_base
= pwd
->pw_gecos
;
376 vec
[3].iov_len
= resp
.pw_gecos_len
;
377 total_len
+= resp
.pw_gecos_len
;
379 vec
[4].iov_base
= pwd
->pw_dir
;
380 vec
[4].iov_len
= resp
.pw_dir_len
;
381 total_len
+= resp
.pw_dir_len
;
383 vec
[5].iov_base
= pwd
->pw_shell
;
384 vec
[5].iov_len
= resp
.pw_shell_len
;
385 total_len
+= resp
.pw_shell_len
;
390 /* Send all the data. */
391 if (writev (sock
[conn
], vec
, nblocks
) != total_len
)
392 dbg_log (_("write incomplete on send passwd answer: %s"),
397 pw_send_disabled (int conn
)
399 pw_response_header resp
;
401 resp
.version
= NSCD_VERSION
;
403 resp
.pw_name_len
= 0;
404 resp
.pw_passwd_len
= 0;
407 resp
.pw_gecos_len
= 0;
409 resp
.pw_shell_len
= 0;
413 dbg_log (_("bad connection id on send response [%d|%d]"),
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
));
425 gr_send_answer (int conn
, struct group
*grp
)
429 gr_response_header resp
;
430 size_t total_len
, sum
;
434 resp
.version
= NSCD_VERSION
;
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
;
442 while (grp
->gr_mem
[resp
.gr_mem_len
])
448 resp
.gr_name_len
= 0;
449 resp
.gr_passwd_len
= 0;
455 dbg_log (_("bad connection id on send response [%d|%d]"),
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
);
475 vec
[1].iov_base
= grp
->gr_name
;
476 vec
[1].iov_len
= resp
.gr_name_len
;
477 total_len
+= resp
.gr_name_len
;
479 vec
[2].iov_base
= grp
->gr_passwd
;
480 vec
[2].iov_len
= resp
.gr_passwd_len
;
481 total_len
+= resp
.gr_passwd_len
;
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);
493 len
[l
] = strlen (grp
->gr_mem
[l
]);
495 vec
[nblocks
].iov_base
= grp
->gr_mem
[l
];
496 vec
[nblocks
].iov_len
= len
[l
];
501 while (grp
->gr_mem
[++l
]);
508 maxiov
= sysconf (_SC_UIO_MAXIOV
);
511 /* Send all the data. */
513 while (nblocks
> maxiov
)
515 sum
+= writev (sock
[conn
], vec
, maxiov
);
519 if (sum
+ writev (sock
[conn
], vec
, nblocks
) != total_len
)
520 dbg_log (_("write incomplete on send group answer: %s"),
525 gr_send_disabled (int conn
)
527 gr_response_header resp
;
529 resp
.version
= NSCD_VERSION
;
531 resp
.gr_name_len
= 0;
532 resp
.gr_passwd_len
= 0;
538 dbg_log (_("bad connection id on send gr_disabled response [%d|%d]"),
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"),
551 stat_send (int conn
, stat_response_header
*resp
)
555 dbg_log (_("bad connection id on send stat response [%d|%d]"),
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"),