mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-27 11:43:34 +08:00
14e9dd679a
1998-02-24 15:12 Ulrich Drepper <drepper@cygnus.com> * Makeconfig: Filter out frame-pointer effecting options when compiling profiling or debugging code. * config.h.in (internal_function): Don't define here if PROF is defined. * gmon/gmon.c (__moncontrol): Don't change state if already in error state. (__monstartup): If calloc fails set error state and mark array as not allocated. (_mcleanup): Don't call write_gmon if in error state. Don't try to free array if not successfully allocated. * elf/dl-load.c (STRING): Define to __STRING to enble expansion. Include elf.h to get macro definitions. Use __ELF?NATIVE?CLASS in message, not __ELF_WORDSIZE. 1998-02-24 09:40 Ulrich Drepper <drepper@cygnus.com> * elf/ldd.sh.in: Add compatibility for broken old shells. * elf/ldd.bash.in: Likewise. 1998-02-24 08:11 H.J. Lu <hjl@gnu.org> * sunrpc/rpc_main.c (open_input): Check pipe return error. * time/clocktest.c (main): Check signal return error. 1998-02-24 Andreas Jaeger <aj@arthur.rhein-neckar.de> * iconv/Makefile ($(inst_bindir)/iconv): Correct typo, add "/" and use do-install-program. Reported by Mark M. Kettenis. (subdir_install): Likewise. 1998-02-22 Thorsten Kukuk <kukuk@vt.uni-paderborn.de> * sunrpc/rpc_sample.c: Fix typo. * nscd/connections.c: Use locale. * nscd/grpcache.c: Add debug messages, gidtbl should get the calloc result. * nscd/nscd.c: Check if init functions fails. * nscd/nscd_conf.c: Allow disabling of group cache. * nscd/nscd_getgr_r.c: Fix return code if group not found. * nscd/pwdcache.c: Fix debug messages. 1998-02-22 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * libc.map: Add __monstartup and _mcleanup for profiling support. 1998-02-20 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * libc.map: Export __getpagesize, for binary compatibility with 2.0. 1998-02-21 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * posix/globtest.sh: Use --library-path instead of LD_LIBRARY_PATH. * localedata/sort-test.sh: Likewise. * localedata/tst-fmon.sh: Likewise. Avoid useless use of cat. 1998-02-22 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * sysdeps/unix/sysv/linux/sigaction.c: Translate between struct sigaction and struct kernel_sigaction for __syscall_rt_sigaction. * sysdeps/unix/sysv/linux/i386/sigaction.c: Likewise. * sysdeps/unix/sysv/linux/kernel_sigaction.h (struct kernel_sigaction): Define. * sysdeps/unix/sysv/linux/alpha/kernel_sigaction.h (struct kernel_sigaction): Define. 1998-02-23 Andreas Jaeger <aj@arthur.rhein-neckar.de> * math/libm-test.c: Change epsilons for libm-ieee754. 1998-02-23 12:33 Ulrich Drepper <drepper@cygnus.com> * sysdeps/i386/__longjmp.S: Fix race condition. Reported by Bruno Haible <haible@ilog.fr>.
530 lines
13 KiB
C
530 lines
13 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/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. */
|
|
static int sock[MAX_NUM_CONNECTIONS];
|
|
static int socks_active;
|
|
static fd_set read_set;
|
|
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"), strerror (errno));
|
|
|
|
sock[i] = 0;
|
|
--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;
|
|
--socks_active;
|
|
|
|
pthread_mutex_unlock (&sock_lock);
|
|
}
|
|
|
|
/* Local rountine, 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;
|
|
FD_SET (sock[i], &read_set);
|
|
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 simultainious 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 a selectset. */
|
|
static int
|
|
handle_new_request (fd_set read_selects, int **connp, request_header **reqp,
|
|
char **key)
|
|
{
|
|
ssize_t nbytes;
|
|
int i;
|
|
|
|
if (debug_flag)
|
|
dbg_log ("handle_new_request");
|
|
|
|
/* Find the descriptor. */
|
|
for (i = 1; i < MAX_NUM_CONNECTIONS; ++i)
|
|
if (FD_ISSET(sock[i], &read_selects))
|
|
break;
|
|
|
|
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);
|
|
FD_CLR (sock[i], &read_set);
|
|
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);
|
|
FD_CLR (sock[i], &read_set);
|
|
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 i, nr, done = 0;
|
|
fd_set read_selects;
|
|
|
|
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)
|
|
{
|
|
/* Set up the socket descriptor mask for the select.
|
|
copy read_set into the local copy. */
|
|
|
|
FD_ZERO (&read_selects);
|
|
pthread_mutex_lock (&sock_lock);
|
|
for (i = 0; i < MAX_NUM_CONNECTIONS; ++i)
|
|
{
|
|
if (FD_ISSET (sock[i], &read_set))
|
|
FD_SET (sock[i], &read_selects);
|
|
}
|
|
pthread_mutex_unlock (&sock_lock);
|
|
/* Poll active connections using select(). */
|
|
nr = select (FD_SETSIZE, &read_selects, NULL, NULL, NULL);
|
|
if (nr <= 0)
|
|
{
|
|
perror (_("Select new reads"));
|
|
exit (1);
|
|
}
|
|
if (FD_ISSET (sock[0], &read_selects))
|
|
/* 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 (read_selects, &conn, &req, key) == 0)
|
|
{
|
|
FD_CLR (sock[*conn], &read_set);
|
|
done = 1;
|
|
}
|
|
}
|
|
} /* While not_done. */
|
|
}
|
|
|
|
void
|
|
init_sockets (void)
|
|
{
|
|
struct sockaddr_un sock_addr;
|
|
|
|
/* Initialize the connections db. */
|
|
socks_active = 0;
|
|
FD_ZERO (&read_set);
|
|
|
|
/* 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. */
|
|
FD_SET (sock[0], &read_set);
|
|
++socks_active;
|
|
}
|
|
|
|
void
|
|
pw_send_answer (int conn, struct passwd *pwd)
|
|
{
|
|
pw_response_header resp;
|
|
|
|
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;
|
|
}
|
|
|
|
/* 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));
|
|
return;
|
|
}
|
|
|
|
if (resp.found)
|
|
{
|
|
struct iovec vec[5];
|
|
|
|
/* Send pw_name. */
|
|
vec[0].iov_base = pwd->pw_name;
|
|
vec[0].iov_len = resp.pw_name_len;
|
|
/* Send pw_passwd. */
|
|
vec[1].iov_base = pwd->pw_passwd;
|
|
vec[1].iov_len = resp.pw_passwd_len;
|
|
/* Send pw_gecos. */
|
|
vec[2].iov_base = pwd->pw_gecos;
|
|
vec[2].iov_len = resp.pw_gecos_len;
|
|
/* Send pw_dir. */
|
|
vec[3].iov_base = pwd->pw_dir;
|
|
vec[3].iov_len = resp.pw_dir_len;
|
|
/* Send pw_shell. */
|
|
vec[4].iov_base = pwd->pw_shell;
|
|
vec[4].iov_len = resp.pw_shell_len;
|
|
|
|
if (writev (sock[conn], vec, 5) != (resp.pw_name_len + resp.pw_passwd_len
|
|
+ resp.pw_gecos_len + resp.pw_dir_len
|
|
+ resp.pw_shell_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)
|
|
{
|
|
gr_response_header resp;
|
|
|
|
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;
|
|
}
|
|
|
|
/* Send response header. */
|
|
if (write (sock[conn], &resp, sizeof (gr_response_header))
|
|
!= sizeof (gr_response_header))
|
|
{
|
|
dbg_log (_("write incomplete on send response: %s"), strerror (errno));
|
|
return;
|
|
}
|
|
|
|
if (resp.found)
|
|
{
|
|
unsigned int l = 0;
|
|
|
|
/* Send gr_name. */
|
|
if (write (sock[conn], grp->gr_name, resp.gr_name_len)
|
|
!= resp.gr_name_len)
|
|
{
|
|
dbg_log (_("write incomplete on send response: %s"),
|
|
strerror (errno));
|
|
return;
|
|
}
|
|
/* Send gr_passwd. */
|
|
if (write (sock[conn], grp->gr_passwd, resp.gr_passwd_len)
|
|
!= resp.gr_passwd_len)
|
|
{
|
|
dbg_log (_("write incomplete on send response: %s"),
|
|
strerror (errno));
|
|
return;
|
|
}
|
|
|
|
while (grp->gr_mem[l])
|
|
{
|
|
size_t len = strlen (grp->gr_mem[l]);
|
|
|
|
if (write (sock[conn], &len, sizeof (len)) != sizeof (len))
|
|
{
|
|
dbg_log (_("write incomplete on send response: %s"),
|
|
strerror (errno));
|
|
return;
|
|
}
|
|
if (write (sock[conn], grp->gr_mem[l], len) != len)
|
|
{
|
|
dbg_log (_("write incomplete on send response: %s"),
|
|
strerror (errno));
|
|
return;
|
|
}
|
|
++l;
|
|
}
|
|
}
|
|
}
|
|
|
|
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));
|
|
}
|