glibc/nscd/connections.c
Ulrich Drepper e852e88944 Update.
1998-07-28  Ulrich Drepper  <drepper@cygnus.com>

	* math/libm-test.c (tgamma_test): Remove redundant tests.

1998-07-28 16:20  Ulrich Drepper  <drepper@cygnus.com>

	* sysdeps/generic/glob.c: Correct problems with */foo and GLOB_NOCHECK
	where foo does not exist in any of the subdirectories.
	Reported by Paul D. Smith <psmith@BayNetworks.COM>.

	* posix/globtest.sh: Add test for this bug.

1998-07-28  Mark Kettenis  <kettenis@phys.uva.nl>

	* io/sys/statfs.h: Fix typos.
	* io/sys/statvfs.h: Fix typos.

1998-07-28  Ulrich Drepper  <drepper@cygnus.com>

	* version.h (VERSION): Bump to 2.0.95.

	* math/Makefile (libm-calls): Remove w_gamma, add w_tgamma.
	* math/Versions [GLIBC_2.1]: Add tgamma, tgammaf, and tgammal.
	* math/libm-test.c: Split old gamma_test and move half of it in new
	function tgamma_test.
	* math/bits/mathcalls.h: Add declaration of tgamma.
	* sysdeps/libm-ieee754/k_standard.c: Change gamma errors into
	tgamma errors.
	* sysdeps/libm-ieee754/w_gamma.c: Remove lgamma compatibility code
	and rename to ...
	* sysdeps/libm-ieee754/w_tgamma.c: ... this.  New file.
	* sysdeps/libm-ieee754/w_gammaf.c: Remove lgammaf compatibility code
	and rename to ...
	* sysdeps/libm-ieee754/w_tgammaf.c: ... this.  New file.
	* sysdeps/libm-ieee754/w_gammal.c: Remove lgammal compatibility code
	and rename to ...
	* sysdeps/libm-ieee754/w_tgammal.c: ... this.  New file.
	* sysdeps/libm-ieee754/w_lgamma.c: Add gamma as weak alias.
	* sysdeps/libm-ieee754/w_lgammaf.c: Likewise.
	* sysdeps/libm-ieee754/w_lgammal.c: Likewise.

	* stgdio-common/printf-parse.h: Implement handling of j, t, and z
	modifiers.
	* stdio-common/vfprintf.c: Likewise.
	* stdio-common/vfscanf.c: Likewise.
	* manual/stdio.texi: Document new printf/scanf modifiers.

	* sysdeps/unix/sysv/linux/recvmsg.c: Remove alias __recvmsg.
	* sysdeps/unix/sysv/linux/sendmsg.c: Remove alias __sendmsg.

1998-07-28  Thorsten Kukuk  <kukuk@vt.uni-paderborn.de>

	* sunrpc/Makefile (routines): Add clnt_unix and svc_unix.
	* sunrpc/Versions: Add new *unix_create functions.
	* sunrpc/clnt_gen.c: Add support for RPC over AF_UNIX.
	* sunrpc/clnt_unix.c: New, client side of RPC over AF_UNIX.
	* sunrpc/key_call.c: Use RPC over AF_UNIX for communication
	with keyserv daemon.
	* sunrpc/rpc/clnt.h: Add AF_UNIX based RPC function prototypes.
	* sunrpc/rpc/svc.h: Likewise.
	* sunrpc/svc_authux.c: Copy internal auth flavor if none is given.
	* sunrpc/svc_tcp.c: Fix typos.
	* sunrpc/svc_unix.c: New, server side of AF_UNIX based RPC.

	* nis/Makefile: Remove currently not working cache functions.
	* nis/Versions: Add __nisbind_* functions for rpc.nisd.
	* nis/nis_call.c: Rewrite binding to a NIS+ server to reuse
	CLIENT handles.
	* nis/nis_file.c: Fix memory leaks.
	* nis/nis_intern.h: Move internal structs from here ...
	* nis/rpcsvc/nislib.h: ... to here for NIS+ server and tools.
	* nis/nis_lookup.c: Try at first if last client handle works.
	* nis/nis_table.c: Likewise.
	* nis/nis_checkpoint.c: Adjust __do_niscall2 parameters.
	* nis/nis_mkdir.c: Likewise.
	* nis/nis_ping.c: Likewise.
	* nis/nis_rmdir.c: Likewise.
	* nis/nis_server.c: Likewise.
	* nis/nis_util.c: Likewise.
	* nis/nis_findserv.c (__nis_findfastest): Little optimization.

1998-07-28  Andreas Jaeger  <aj@arthur.rhein-neckar.de>

	* stdlib/strtol.c (STRTOL_LONG_MAX): Correct typo in last patch -
	define as LONG_MAX.

1998-07-28 09:31  Ulrich Drepper  <drepper@cygnus.com>

	* nscd/connections.c (gr_send_answer): Deal with missing UIO_MAXIOV.
	Correct test whether writev send all data.
	* nscd/nscd_getgr_r.c (__nscd_getgr_r): Correct test whether readv
	received all data.

1998-07-28  Mark Kettenis  <kettenis@phys.uva.nl>

	* nscd/nscd_getgr_r.c (__nscd_getgr_r): Deal with missing UIO_MAXIOV.

1998-07-28  Mark Kettenis  <kettenis@phys.uva.nl>

	* sysdeps/mach/hurd/dl-sysdep.c (open_file): Change assert call to
	allow mode to be 0.
	(__xstat): New function.
	(__fxstat): New function.
	(_dl_sysdep_read_whole_file): Removed.  The implementation in
	`elf/dl-misc.c' now also works for the Hurd.
1998-07-28 16:26:04 +00:00

566 lines
14 KiB
C

/* Copyright (c) 1998 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1998.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include <errno.h>
#include <error.h>
#include <fcntl.h>
#include <libintl.h>
#include <locale.h>
#include <pthread.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/un.h>
#include "nscd.h"
#include "dbg_log.h"
/* Socket 0 in the array is named and exported into the file namespace
as a connection point for clients. There's a one to one
correspondence between sock[i] and read_polls[i]. */
static int sock[MAX_NUM_CONNECTIONS];
static int socks_active;
static struct pollfd read_polls[MAX_NUM_CONNECTIONS];
static pthread_mutex_t sock_lock = PTHREAD_MUTEX_INITIALIZER;
/* Cleanup. */
void
close_sockets (void)
{
int i;
if (debug_flag)
dbg_log (_("close_sockets called"));
pthread_mutex_lock (&sock_lock);
/* Close sockets. */
for (i = 0; i < MAX_NUM_CONNECTIONS; ++i)
if (sock[i] != 0)
{
if (close (sock[i]))
dbg_log (_("socket [%d|%d] close: %s"), i, sock[i], strerror (errno));
sock[i] = 0;
read_polls[i].fd = -1;
--socks_active;
}
pthread_mutex_unlock (&sock_lock);
}
void
close_socket (int conn)
{
if (debug_flag > 2)
dbg_log (_("close socket (%d|%d)"), conn, sock[conn]);
pthread_mutex_lock (&sock_lock);
close (sock[conn]);
sock[conn] = 0;
read_polls[conn].fd = -1;
--socks_active;
pthread_mutex_unlock (&sock_lock);
}
/* Local routine, assigns a socket to a new connection request. */
static void
handle_new_connection (void)
{
int i;
if (debug_flag > 2)
dbg_log (_("handle_new_connection"));
pthread_mutex_lock (&sock_lock);
if (socks_active < MAX_NUM_CONNECTIONS)
/* Find a free socket entry to use. */
for (i = 1; i < MAX_NUM_CONNECTIONS; ++i)
{
if (sock[i] == 0)
{
if ((sock[i] = accept (sock[0], NULL, NULL)) < 0)
{
dbg_log (_("socket accept: %s"), strerror (errno));
return;
}
++socks_active;
read_polls[i].fd = sock[i];
read_polls[i].events = POLLRDNORM;
if (debug_flag > 2)
dbg_log (_("handle_new_connection used socket %d|%d"), i,
sock[i]);
break;
}
}
else
{
int black_widow_sock;
dbg_log (_("Supported number of simultaneous connections exceeded"));
dbg_log (_("Ignoring client connect request"));
/* There has to be a better way to ignore a connection request,..
when I get my hands on a sockets wiz I'll modify this. */
black_widow_sock = accept (sock[0], NULL, NULL);
close (black_widow_sock);
}
pthread_mutex_unlock (&sock_lock);
}
/* Local routine, reads a request off a socket indicated by read_polls. */
static int
handle_new_request (int **connp, request_header **reqp, char **key)
{
ssize_t nbytes;
int i, found = 0;
if (debug_flag)
dbg_log ("handle_new_request");
/* Find the descriptor. */
for (i = 1; i < MAX_NUM_CONNECTIONS; ++i) {
if (read_polls[i].fd >= 0
&& read_polls[i].revents & (POLLRDNORM|POLLERR|POLLNVAL))
{
found = i;
break;
}
if (read_polls[i].fd >= 0 && (read_polls[i].revents & POLLHUP))
{
/* Don't close the socket, we still need to send data. Just
stop polling for more data now. */
read_polls[i].fd = -1;
}
}
if (found == 0)
{
dbg_log (_("No sockets with data found !"));
return -1;
}
if (debug_flag > 2)
dbg_log (_("handle_new_request uses socket %d"), i);
/* Read from it. */
nbytes = read (sock[i], *reqp, sizeof (request_header));
if (nbytes != sizeof (request_header))
{
/* Handle non-data read cases. */
if (nbytes == 0)
{
/* Close socket down. */
if (debug_flag > 2)
dbg_log (_("Real close socket %d|%d"), i, sock[i]);
pthread_mutex_lock (&sock_lock);
read_polls[i].fd = -1;
close (sock[i]);
sock[i] = 0;
--socks_active;
pthread_mutex_unlock (&sock_lock);
}
else
if (nbytes < 0)
{
dbg_log (_("Read(%d|%d) error on get request: %s"),
i, sock[i], strerror (errno));
exit (1);
}
else
dbg_log (_("Read, data < request buf size, ignoring data"));
return -1;
}
else
{
*key = malloc ((*reqp)->key_len + 1);
/* Read the key from it */
nbytes = read (sock[i], *key, (*reqp)->key_len);
if (nbytes != (*reqp)->key_len)
{
/* Handle non-data read cases. */
if (nbytes == 0)
{
/* Close socket down. */
if (debug_flag > 2)
dbg_log (_("Real close socket %d|%d"), i, sock[i]);
pthread_mutex_lock (&sock_lock);
read_polls[i].fd = -1;
close (sock[i]);
sock[i] = 0;
--socks_active;
pthread_mutex_unlock (&sock_lock);
}
else
if (nbytes < 0)
{
perror (_("Read() error on get request"));
return 0;
}
else
fputs (_("Read, data < request buf size, ignoring data"),
stderr);
free (*key);
return -1;
}
else
{
/* Ok, have a live one, A real data req buf has been obtained. */
(*key)[(*reqp)->key_len] = '\0';
**connp = i;
return 0;
}
}
}
void
get_request (int *conn, request_header *req, char **key)
{
int done = 0;
int nr;
if (debug_flag)
dbg_log ("get_request");
/* loop, processing new connection requests until a client buffer
is read in on an existing connection. */
while (!done)
{
/* Poll active connections. */
nr = poll (read_polls, MAX_NUM_CONNECTIONS, -1);
if (nr <= 0)
{
perror (_("Poll new reads"));
exit (1);
}
if (read_polls[0].revents & (POLLRDNORM|POLLERR|POLLHUP|POLLNVAL))
/* Handle the case of a new connection request on the named socket. */
handle_new_connection ();
else
{
/* Read data from client specific descriptor. */
if (handle_new_request (&conn, &req, key) == 0)
done = 1;
}
} /* While not_done. */
}
void
init_sockets (void)
{
struct sockaddr_un sock_addr;
int i;
/* Initialize the connections db. */
socks_active = 0;
/* Initialize the poll array. */
for (i = 0; i < MAX_NUM_CONNECTIONS; i++)
read_polls[i].fd = -1;
/* Create the socket. */
sock[0] = socket (AF_UNIX, SOCK_STREAM, 0);
if (sock[0] < 0)
{
perror (_("cannot create socket"));
exit (1);
}
/* Bind a name to the socket. */
sock_addr.sun_family = AF_UNIX;
strcpy (sock_addr.sun_path, _PATH_NSCDSOCKET);
if (bind (sock[0], (struct sockaddr *) &sock_addr, sizeof (sock_addr)) < 0)
{
dbg_log ("%s: %s", _PATH_NSCDSOCKET, strerror (errno));
exit (1);
}
/* Set permissions for the socket. */
chmod (_PATH_NSCDSOCKET, 0666);
/* Set the socket up to accept connections. */
if (listen (sock[0], MAX_NUM_CONNECTIONS) < 0)
{
perror (_("cannot enable socket to accept connections"));
exit (1);
}
/* Add the socket to the server's set of active sockets. */
read_polls[0].fd = sock[0];
read_polls[0].events = POLLRDNORM;
++socks_active;
}
void
pw_send_answer (int conn, struct passwd *pwd)
{
struct iovec vec[6];
pw_response_header resp;
size_t total_len;
int nblocks;
resp.version = NSCD_VERSION;
if (pwd != NULL)
{
resp.found = 1;
resp.pw_name_len = strlen (pwd->pw_name);
resp.pw_passwd_len = strlen (pwd->pw_passwd);
resp.pw_uid = pwd->pw_uid;
resp.pw_gid = pwd->pw_gid;
resp.pw_gecos_len = strlen (pwd->pw_gecos);
resp.pw_dir_len = strlen (pwd->pw_dir);
resp.pw_shell_len = strlen (pwd->pw_shell);
}
else
{
resp.found = 0;
resp.pw_name_len = 0;
resp.pw_passwd_len = 0;
resp.pw_uid = -1;
resp.pw_gid = -1;
resp.pw_gecos_len = 0;
resp.pw_dir_len = 0;
resp.pw_shell_len = 0;
}
if (sock[conn] == 0)
{
dbg_log (_("bad connection id on send response [%d|%d]"),
conn, sock[conn]);
return;
}
/* Add response header. */
vec[0].iov_base = &resp;
vec[0].iov_len = sizeof (pw_response_header);
total_len = sizeof (pw_response_header);
nblocks = 1;
if (resp.found)
{
/* Add pw_name. */
vec[1].iov_base = pwd->pw_name;
vec[1].iov_len = resp.pw_name_len;
total_len += resp.pw_name_len;
/* Add pw_passwd. */
vec[2].iov_base = pwd->pw_passwd;
vec[2].iov_len = resp.pw_passwd_len;
total_len += resp.pw_passwd_len;
/* Add pw_gecos. */
vec[3].iov_base = pwd->pw_gecos;
vec[3].iov_len = resp.pw_gecos_len;
total_len += resp.pw_gecos_len;
/* Add pw_dir. */
vec[4].iov_base = pwd->pw_dir;
vec[4].iov_len = resp.pw_dir_len;
total_len += resp.pw_dir_len;
/* Add pw_shell. */
vec[5].iov_base = pwd->pw_shell;
vec[5].iov_len = resp.pw_shell_len;
total_len += resp.pw_shell_len;
nblocks = 6;
}
/* Send all the data. */
if (writev (sock[conn], vec, nblocks) != total_len)
dbg_log (_("write incomplete on send passwd answer: %s"),
strerror (errno));
}
void
pw_send_disabled (int conn)
{
pw_response_header resp;
resp.version = NSCD_VERSION;
resp.found = -1;
resp.pw_name_len = 0;
resp.pw_passwd_len = 0;
resp.pw_uid = -1;
resp.pw_gid = -1;
resp.pw_gecos_len = 0;
resp.pw_dir_len = 0;
resp.pw_shell_len = 0;
if (sock[conn] == 0)
{
dbg_log (_("bad connection id on send response [%d|%d]"),
conn, sock[conn]);
return;
}
/* Send response header. */
if (write (sock[conn], &resp, sizeof (pw_response_header))
!= sizeof (pw_response_header))
dbg_log (_("write incomplete on send response: %s"), strerror (errno));
}
void
gr_send_answer (int conn, struct group *grp)
{
struct iovec *vec;
size_t *len;
gr_response_header resp;
size_t total_len, sum;
int nblocks;
size_t maxiov;
resp.version = NSCD_VERSION;
if (grp != NULL)
{
resp.found = 1;
resp.gr_name_len = strlen (grp->gr_name);
resp.gr_passwd_len = strlen (grp->gr_passwd);
resp.gr_gid = grp->gr_gid;
resp.gr_mem_len = 0;
while (grp->gr_mem[resp.gr_mem_len])
++resp.gr_mem_len;
}
else
{
resp.found = 0;
resp.gr_name_len = 0;
resp.gr_passwd_len = 0;
resp.gr_gid = -1;
resp.gr_mem_len = 0;
}
if (sock[conn] == 0)
{
dbg_log (_("bad connection id on send response [%d|%d]"),
conn, sock[conn]);
return;
}
/* We have no fixed number of records so allocate the IOV here. */
vec = alloca ((3 + 1 + resp.gr_mem_len) * sizeof (struct iovec));
len = alloca (resp.gr_mem_len * sizeof (size_t));
/* Add response header. */
vec[0].iov_base = &resp;
vec[0].iov_len = sizeof (gr_response_header);
total_len = sizeof (gr_response_header);
nblocks = 1;
if (resp.found)
{
unsigned int l = 0;
/* Add gr_name. */
vec[1].iov_base = grp->gr_name;
vec[1].iov_len = resp.gr_name_len;
total_len += resp.gr_name_len;
/* Add gr_passwd. */
vec[2].iov_base = grp->gr_passwd;
vec[2].iov_len = resp.gr_passwd_len;
total_len += resp.gr_passwd_len;
nblocks = 3;
if (grp->gr_mem[l])
{
vec[3].iov_base = len;
vec[3].iov_len = resp.gr_mem_len * sizeof (size_t);
total_len += resp.gr_mem_len * sizeof (size_t);
nblocks = 4;
do
{
len[l] = strlen (grp->gr_mem[l]);
vec[nblocks].iov_base = grp->gr_mem[l];
vec[nblocks].iov_len = len[l];
total_len += len[l];
++nblocks;
}
while (grp->gr_mem[++l]);
}
}
#ifdef UIO_MAXIOV
maxiov = UIO_MAXIOV;
#else
maxiov = sysconf (_SC_UIO_MAXIOV);
#endif
/* Send all the data. */
sum = 0;
while (nblocks > maxiov)
{
sum += writev (sock[conn], vec, maxiov);
vec += maxiov;
nblocks -= maxiov;
}
if (sum + writev (sock[conn], vec, nblocks) != total_len)
dbg_log (_("write incomplete on send group answer: %s"),
strerror (errno));
}
void
gr_send_disabled (int conn)
{
gr_response_header resp;
resp.version = NSCD_VERSION;
resp.found = -1;
resp.gr_name_len = 0;
resp.gr_passwd_len = 0;
resp.gr_gid = -1;
resp.gr_mem_len = 0;
if (sock[conn] == 0)
{
dbg_log (_("bad connection id on send gr_disabled response [%d|%d]"),
conn, sock[conn]);
return;
}
/* Send response header. */
if (write (sock[conn], &resp, sizeof (gr_response_header))
!= sizeof (gr_response_header))
dbg_log (_("write incomplete on send gr_disabled response: %s"),
strerror (errno));
}
void
stat_send (int conn, stat_response_header *resp)
{
if (sock[conn] == 0)
{
dbg_log (_("bad connection id on send stat response [%d|%d]"),
conn, sock[conn]);
return;
}
/* send response header. */
if (write (sock[conn], resp, sizeof (stat_response_header))
!= sizeof (stat_response_header))
dbg_log (_("write incomplete on send stat response: %s"),
strerror (errno));
}