From d67281a7eac124e2f1b498c377dde3432f711039 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Sat, 31 Jan 1998 08:39:55 +0000 Subject: Update. 1998-01-31 Phil Blundell * configure.in: Add --without-cvs option to suppress automatic checkin of regenerated files. * config.make: Likewise. * Makefile: Respect with-cvs setting. * Makerules: Likewise. * configure.in: Allow the standalone ARM port to be configured. 1998-01-31 Thorsten Kukuk * grp/getgrgid_r.c: Define USE_NSCD. * grp/getgrnam_r.c: Likewise. * pwd/getpwuid_r.c: Likewise. * pwd/getpwnam_r.c: Likewise. * sysdeps/unix/inet/Subdirs: Add nscd subdir. * nss/getXXbyYY_r.c: Try at first nscd. * nscd/Makefile: New, for the Name Switch Cache Daemon (nscd). * nscd/connections.c: New file. * nscd/dbg_log.c: New file. * nscd/dbg_log.h: New file. * nscd/grpcache.c: New file. * nscd/nscd.c: New file. * nscd/nscd.h: New file. * nscd/nscd_conf.c: New file. * nscd/nscd_stat.c: New file. * nscd/pwdcache.c: New file. * nscd/nscd_getgr_r.c: New, client code, linked into libc. * nscd/nscd_getpw_r.c: Likewise. * nscd/nscd_proto.h: New, prototypes for client functions. * nscd/nscd.conf: New, example for a configuration file. * nscd/nscd.init: New, example for a startup script. * nscd/getgrgid_r.c: Old grp/getgrgid_r version, used from nscd to avoid deadlocks. * nscd/getgrnam_r.c: Likewise. * nscd/getpwnam_r.c: Likewise. * nscd/getpwuid_r.c: Likewise. * nis/nis_cache.c: New file. * nis/nis_cache2.h: New file. * nis/nis_cache2_xdr.c: New file. --- nscd/Makefile | 46 ++++ nscd/TODO | 7 + nscd/connections.c | 529 ++++++++++++++++++++++++++++++++++++++++++++++ nscd/dbg_log.c | 64 ++++++ nscd/dbg_log.h | 27 +++ nscd/getgrgid_r.c | 30 +++ nscd/getgrnam_r.c | 29 +++ nscd/getpwnam_r.c | 30 +++ nscd/getpwuid_r.c | 30 +++ nscd/grpcache.c | 589 ++++++++++++++++++++++++++++++++++++++++++++++++++++ nscd/nscd.c | 423 +++++++++++++++++++++++++++++++++++++ nscd/nscd.conf | 30 +++ nscd/nscd.h | 149 +++++++++++++ nscd/nscd.init | 50 +++++ nscd/nscd_conf.c | 148 +++++++++++++ nscd/nscd_getgr_r.c | 211 +++++++++++++++++++ nscd/nscd_getpw_r.c | 198 ++++++++++++++++++ nscd/nscd_proto.h | 35 ++++ nscd/nscd_stat.c | 87 ++++++++ nscd/pwdcache.c | 581 +++++++++++++++++++++++++++++++++++++++++++++++++++ 20 files changed, 3293 insertions(+) create mode 100644 nscd/Makefile create mode 100644 nscd/TODO create mode 100644 nscd/connections.c create mode 100644 nscd/dbg_log.c create mode 100644 nscd/dbg_log.h create mode 100644 nscd/getgrgid_r.c create mode 100644 nscd/getgrnam_r.c create mode 100644 nscd/getpwnam_r.c create mode 100644 nscd/getpwuid_r.c create mode 100644 nscd/grpcache.c create mode 100644 nscd/nscd.c create mode 100644 nscd/nscd.conf create mode 100644 nscd/nscd.h create mode 100644 nscd/nscd.init create mode 100644 nscd/nscd_conf.c create mode 100644 nscd/nscd_getgr_r.c create mode 100644 nscd/nscd_getpw_r.c create mode 100644 nscd/nscd_proto.h create mode 100644 nscd/nscd_stat.c create mode 100644 nscd/pwdcache.c (limited to 'nscd') diff --git a/nscd/Makefile b/nscd/Makefile new file mode 100644 index 0000000000..4510c4d452 --- /dev/null +++ b/nscd/Makefile @@ -0,0 +1,46 @@ +# Copyright (C) 1998 Free Software Foundation, Inc. +# This file is part of the GNU C Library. + +# 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. + +# +# Sub-makefile for nscd portion of the library. +# +subdir := nscd + +routines := nscd_getpw_r nscd_getgr_r + +# We can later add the names of other thread packages here. +ifeq (,$(findstring linuxthreads,$(add-ons))) + +others := nscd +install-sbin := nscd + +endif + +nscd-routines := nscd connections pwdcache getpwnam_r getpwuid_r grpcache\ + getgrnam_r getgrgid_r dbg_log nscd_conf nscd_stat +extra-objs := $(nscd-routines:=.o) + +distribute := nscd.h dbg_log.h + +include ../Rules + +ifeq ($(build-shared),yes) +$(objpfx)nscd: $(nscd-routines:%=$(objpfx)%.o) $(objpfx)../linuxthreads/libpthread.so$(libpthread.so-version) $(objpfx)../nis/libnsl.so$(libnsl.so-version) +else +$(objpfx)nscd: $(nscd-routines:%=$(objpfx)%.o) $(objpfx)../linuxthreads/libpthread.a $(objpfx)../nis/libnsl.a +endif diff --git a/nscd/TODO b/nscd/TODO new file mode 100644 index 0000000000..16c2835468 --- /dev/null +++ b/nscd/TODO @@ -0,0 +1,7 @@ + +* We should use readv/writev for group entries, too + +* If we have reached the max. # of process, close accept socket. + ! THIS COULD CAUSE THE KERNEL TO HANG ! BE CAREFUL ! + +* Implement cache for hosts diff --git a/nscd/connections.c b/nscd/connections.c new file mode 100644 index 0000000000..abde747a8a --- /dev/null +++ b/nscd/connections.c @@ -0,0 +1,529 @@ +/* Copyright (c) 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk , 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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)); +} diff --git a/nscd/dbg_log.c b/nscd/dbg_log.c new file mode 100644 index 0000000000..37065e446e --- /dev/null +++ b/nscd/dbg_log.c @@ -0,0 +1,64 @@ +/* Copyright (c) 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk , 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 +#include +#include +#include +#include "dbg_log.h" +#include "nscd.h" + +/* if in debug mode and we have a debug file, we write the messages to it, + if in debug mode and no debug file, we write the messages to stderr, + else to syslog. */ + +FILE *dbgout = NULL; +int debug_flag = 0; + +int +set_logfile (const char *logfile) +{ + dbgout = fopen (logfile, "a"); + return dbgout == NULL ? 0 : 1; +} + +void +dbg_log (const char *fmt,...) +{ + va_list ap; + char msg[512], msg2[512]; + + va_start (ap, fmt); + vsnprintf (msg2, sizeof (msg), fmt, ap); + + if (debug_flag) + { + snprintf (msg, sizeof (msg), "%d: %s\n", getpid (), msg2); + if (dbgout) + fputs (msg, dbgout); + else + fputs (msg, stderr); + } + else + { + snprintf (msg, sizeof (msg), "%d: %s", getpid (), msg2); + syslog (LOG_NOTICE, msg); + } + va_end (ap); +} diff --git a/nscd/dbg_log.h b/nscd/dbg_log.h new file mode 100644 index 0000000000..c3d1dc4559 --- /dev/null +++ b/nscd/dbg_log.h @@ -0,0 +1,27 @@ +/* Copyright (c) 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk , 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. */ + +#ifndef _DBG_LOG_H +#define _DBG_LOG_H 1 + +extern int debug_flag; + +extern void dbg_log (const char *, ...); + +#endif diff --git a/nscd/getgrgid_r.c b/nscd/getgrgid_r.c new file mode 100644 index 0000000000..3011602671 --- /dev/null +++ b/nscd/getgrgid_r.c @@ -0,0 +1,30 @@ +/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1996. + + 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 + + +#define LOOKUP_TYPE struct group +#define FUNCTION_NAME getgrgid +#define DATABASE_NAME group +#define ADD_PARAMS gid_t gid +#define ADD_VARIABLES gid +#define BUFLEN NSS_BUFLEN_GROUP + +#include diff --git a/nscd/getgrnam_r.c b/nscd/getgrnam_r.c new file mode 100644 index 0000000000..3575e74b1f --- /dev/null +++ b/nscd/getgrnam_r.c @@ -0,0 +1,29 @@ +/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1996. + + 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 + + +#define LOOKUP_TYPE struct group +#define FUNCTION_NAME getgrnam +#define DATABASE_NAME group +#define ADD_PARAMS const char *name +#define ADD_VARIABLES name + +#include diff --git a/nscd/getpwnam_r.c b/nscd/getpwnam_r.c new file mode 100644 index 0000000000..328c3055f8 --- /dev/null +++ b/nscd/getpwnam_r.c @@ -0,0 +1,30 @@ +/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1996. + + 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 + + +#define LOOKUP_TYPE struct passwd +#define FUNCTION_NAME getpwnam +#define DATABASE_NAME passwd +#define ADD_PARAMS const char *name +#define ADD_VARIABLES name +#define BUFLEN NSS_BUFLEN_PASSWD + +#include diff --git a/nscd/getpwuid_r.c b/nscd/getpwuid_r.c new file mode 100644 index 0000000000..91bd802d61 --- /dev/null +++ b/nscd/getpwuid_r.c @@ -0,0 +1,30 @@ +/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1996. + + 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 + + +#define LOOKUP_TYPE struct passwd +#define FUNCTION_NAME getpwuid +#define DATABASE_NAME passwd +#define ADD_PARAMS uid_t uid +#define ADD_VARIABLES uid +#define BUFLEN NSS_BUFLEN_PASSWD + +#include diff --git a/nscd/grpcache.c b/nscd/grpcache.c new file mode 100644 index 0000000000..9f6c767fd7 --- /dev/null +++ b/nscd/grpcache.c @@ -0,0 +1,589 @@ +/* Copyright (c) 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk , 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 +#include +#include +#include +#include +#include +#include + +#include "dbg_log.h" +#include "nscd.h" + +static unsigned long modulo = 211; +static unsigned long postimeout = 3600; +static unsigned long negtimeout = 60; + +static unsigned long poshit = 0; +static unsigned long posmiss = 0; +static unsigned long neghit = 0; +static unsigned long negmiss = 0; + +struct grphash +{ + time_t create; + struct grphash *next; + struct group *grp; +}; +typedef struct grphash grphash; + +struct gidhash +{ + struct gidhash *next; + struct grphash *grptr; +}; +typedef struct gidhash gidhash; + +struct neghash +{ + time_t create; + struct neghash *next; + char *key; +}; +typedef struct neghash neghash; + +static grphash *grptbl; +static gidhash *gidtbl; +static neghash *negtbl; + +static pthread_rwlock_t grplock = PTHREAD_RWLOCK_INITIALIZER; +static pthread_rwlock_t neglock = PTHREAD_RWLOCK_INITIALIZER; + +static void *grptable_update (void *); +static void *negtable_update (void *); + +void +get_gr_stat (stat_response_header *stat) +{ + stat->gr_poshit = poshit; + stat->gr_posmiss = posmiss; + stat->gr_neghit = neghit; + stat->gr_negmiss = negmiss; + stat->gr_size = modulo; + stat->gr_posttl = postimeout; + stat->gr_negttl = negtimeout; +} + +void +set_grp_modulo (unsigned long mod) +{ + modulo = mod; +} + +void +set_pos_grp_ttl (unsigned long ttl) +{ + postimeout = ttl; +} + +void +set_neg_grp_ttl (unsigned long ttl) +{ + negtimeout = ttl; +} + +int +cache_grpinit () +{ + pthread_attr_t attr; + pthread_t thread; + + grptbl = calloc (1, modulo * sizeof (grphash)); + if (grptbl == NULL) + return -1; + calloc (1, modulo * sizeof (grphash)); + if (gidtbl == NULL) + return -1; + negtbl = calloc (1, modulo * sizeof (neghash)); + if (negtbl == NULL) + return -1; + + pthread_attr_init (&attr); + pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); + + pthread_create (&thread, NULL, grptable_update, &attr); + pthread_create (&thread, NULL, negtable_update, &attr); + + pthread_attr_destroy (&attr); + + return 0; +} + +static struct group * +save_grp (struct group *src) +{ + struct group *dest; + unsigned long int l; + + dest = calloc (1, sizeof (struct group)); + dest->gr_name = strdup (src->gr_name); + dest->gr_passwd = strdup (src->gr_passwd); + dest->gr_gid = src->gr_gid; + + /* How many members does this group have? */ + l = 0; + while (src->gr_mem[l]) + ++l; + + dest->gr_mem = calloc (1, sizeof (char *) * (l+1)); + l = 0; + while (src->gr_mem[l]) + { + dest->gr_mem[l] = strdup (src->gr_mem[l]); + ++l; + } + + return dest; +} + +static void +free_grp (struct group *src) +{ + unsigned long int l; + + free (src->gr_name); + free (src->gr_passwd); + + l = 0; + while (src->gr_mem[l]) + { + free (src->gr_mem[l]); + ++l; + } + free (src->gr_mem); + free (src); +} + +static int +add_cache (struct group *grp) +{ + grphash *work; + unsigned long int hash = __nis_hash (grp->gr_name, + strlen (grp->gr_name)) % modulo; + + work = &grptbl[hash]; + + if (grptbl[hash].grp == NULL) + grptbl[hash].grp = save_grp (grp); + else + { + while (work->next != NULL) + work = work->next; + + work->next = calloc (1, sizeof (grphash)); + work->next->grp = save_grp (grp); + work = work->next; + } + + time (&work->create); + gidtbl[grp->gr_gid % modulo].grptr = work; + + return 0; +} + +static struct group * +cache_search_name (const char *name) +{ + grphash *work; + unsigned long int hash = __nis_hash (name, strlen(name)) % modulo; + + work = &grptbl[hash]; + + while (work->grp != NULL) + { + if (strcmp (work->grp->gr_name, name) == 0) + return work->grp; + if (work->next != NULL) + work = work->next; + else + return NULL; + } + return NULL; +} + +static struct group * +cache_search_gid (gid_t gid) +{ + gidhash *work; + + work = &gidtbl[gid % modulo]; + + while (work->grptr != NULL) + { + if (work->grptr->grp->gr_gid == gid) + return work->grptr->grp; + if (work->next != NULL) + work = work->next; + else + return NULL; + } + return NULL; +} + +static int +add_negcache (char *key) +{ + neghash *work; + unsigned long int hash = __nis_hash (key, strlen (key)) % modulo; + + work = &negtbl[hash]; + + if (negtbl[hash].key == NULL) + negtbl[hash].key = strdup (key); + else + { + while (work->next != NULL) + work = work->next; + + work->next = calloc (1, sizeof (neghash)); + work->next->key = strdup (key); + work = work->next; + } + + time (&work->create); + return 0; +} + +static int +cache_search_neg (const char *key) +{ + neghash *work; + unsigned long int hash = __nis_hash (key, strlen (key)) % modulo; + + work = &negtbl[hash]; + + while (work->key != NULL) + { + if (strcmp (work->key, key) == 0) + return 1; + if (work->next != NULL) + work = work->next; + else + return 0; + } + return 0; +} + +void * +cache_getgrnam (void *v_param) +{ + param_t *param = (param_t *)v_param; + struct group *grp, resultbuf; + + pthread_rwlock_rdlock (&grplock); + grp = cache_search_name (param->key); + + /* I don't like it to hold the read only lock longer, but it is + necessary to avoid to much malloc/free/strcpy. */ + + if (grp) + { + if (debug_flag) + dbg_log (_("Found \"%s\" in cache !"), param->key); + + ++poshit; + gr_send_answer (param->conn, grp); + close_socket (param->conn); + + pthread_rwlock_unlock (&grplock); + } + else + { + int buflen = 1024; + char *buffer = calloc (1, buflen); + int status; + + if (debug_flag) + dbg_log (_("Doesn't found \"%s\" in cache !"), param->key); + + pthread_rwlock_unlock (&grplock); + + pthread_rwlock_rdlock (&neglock); + status = cache_search_neg (param->key); + pthread_rwlock_unlock (&neglock); + + if (status == 0) + { + while (buffer != NULL + && (getgrnam_r (param->key, &resultbuf, buffer, buflen, &grp) + != 0) + && errno == ERANGE) + { + errno = 0; + buflen += 1024; + buffer = realloc (buffer, buflen); + } + + if (buffer != NULL && grp != NULL) + { + struct group *tmp; + + ++poshit; + pthread_rwlock_wrlock (&grplock); + /* While we are waiting on the lock, somebody else could + add this entry. */ + tmp = cache_search_name (param->key); + if (tmp == NULL) + add_cache (grp); + pthread_rwlock_unlock (&grplock); + } + else + { + pthread_rwlock_wrlock (&neglock); + add_negcache (param->key); + ++negmiss; + pthread_rwlock_unlock (&neglock); + } + } + else + ++neghit; + + gr_send_answer (param->conn, grp); + close_socket (param->conn); + if (buffer != NULL) + free (buffer); + } + free (param->key); + free (param); + return NULL; +} + +void * +cache_gr_disabled (void *v_param) +{ + param_t *param = (param_t *)v_param; + + gr_send_disabled (param->conn); + return NULL; +} + +void * +cache_getgrgid (void *v_param) +{ + param_t *param = (param_t *)v_param; + struct group *grp, resultbuf; + gid_t gid = strtol (param->key, NULL, 10); + + pthread_rwlock_rdlock (&grplock); + grp = cache_search_gid (gid); + + /* I don't like it to hold the read only lock longer, but it is + necessary to avoid to much malloc/free/strcpy. */ + + if (grp != NULL) + { + if (debug_flag) + dbg_log (_("Found \"%d\" in cache !\n"), gid); + + ++poshit; + gr_send_answer (param->conn, grp); + close_socket (param->conn); + + pthread_rwlock_unlock (&grplock); + } + else + { + int buflen = 1024; + char *buffer = malloc (buflen); + int status; + + if (debug_flag) + dbg_log (_("Doesn't found \"%d\" in cache !\n"), gid); + + pthread_rwlock_unlock (&grplock); + + pthread_rwlock_rdlock (&neglock); + status = cache_search_neg (param->key); + pthread_rwlock_unlock (&neglock); + + if (status == 0) + { + while (buffer != NULL + && (getgrgid_r (gid, &resultbuf, buffer, buflen, &grp) != 0) + && errno == ERANGE) + { + errno = 0; + buflen += 1024; + buffer = realloc (buffer, buflen); + } + + if (buffer != NULL && grp != NULL) + { + struct group *tmp; + + ++posmiss; + pthread_rwlock_wrlock (&grplock); + /* While we are waiting on the lock, somebody else could + add this entry. */ + tmp = cache_search_gid (gid); + if (tmp == NULL) + add_cache (grp); + pthread_rwlock_unlock (&grplock); + } + else + { + ++negmiss; + pthread_rwlock_wrlock (&neglock); + add_negcache (param->key); + pthread_rwlock_unlock (&neglock); + } + } + else + ++neghit; + + gr_send_answer (param->conn, grp); + close_socket (param->conn); + if (buffer != NULL) + free (buffer); + } + free (param->key); + free (param); + return NULL; +} + +void * +grptable_update (void *v) +{ + time_t now; + int i; + + sleep (20); + + while (!do_shutdown) + { + if (debug_flag > 2) + dbg_log (_("(grptable_update) Wait for write lock!")); + + pthread_rwlock_wrlock (&grplock); + + if (debug_flag > 2) + dbg_log (_("(grptable_update) Have write lock")); + + time (&now); + for (i = 0; i < modulo; ++i) + { + grphash *work = &grptbl[i]; + + while (work && work->grp) + { + if ((now - work->create) >= postimeout) + { + gidhash *uh = &gidtbl[work->grp->gr_gid % modulo]; + + if (debug_flag) + dbg_log (_("Give \"%s\" free"), work->grp->gr_name); + + while (uh && uh->grptr) + { + if (uh->grptr->grp->gr_gid == work->grp->gr_gid) + { + if (debug_flag > 3) + dbg_log (_("Give gid for \"%s\" free"), + work->grp->gr_name); + if (uh->next != NULL) + { + gidhash *tmp = uh->next; + uh->grptr = tmp->grptr; + uh->next = tmp->next; + free (tmp); + } + else + uh->grptr = NULL; + } + uh = uh->next; + } + + free_grp (work->grp); + if (work->next != NULL) + { + grphash *tmp = work->next; + work->create = tmp->create; + work->next = tmp->next; + work->grp = tmp->grp; + free (tmp); + } + else + work->grp = NULL; + } + work = work->next; + } + } + if (debug_flag > 2) + dbg_log (_("(pwdtable_update) Release wait lock\n")); + pthread_rwlock_unlock (&grplock); + sleep (20); + } + return NULL; +} + +void * +negtable_update (void *v) +{ + time_t now; + int i; + + sleep (30); + + while (!do_shutdown) + { + if (debug_flag > 2) + dbg_log (_("(negtable_update) Wait for write lock!")); + + pthread_rwlock_wrlock (&neglock); + + if (debug_flag > 2) + dbg_log (_("(negtable_update) Have write lock")); + + time (&now); + for (i = 0; i < modulo; ++i) + { + neghash *work = &negtbl[i]; + + while (work && work->key) + { + if ((now - work->create) >= negtimeout) + { + if (debug_flag) + dbg_log (_("Give \"%s\" free"), work->key); + + free (work->key); + + if (work->next != NULL) + { + neghash *tmp = work->next; + work->create = tmp->create; + work->next = tmp->next; + work->key = tmp->key; + free (tmp); + } + else + work->key = NULL; + } + work = work->next; + } + } + if (debug_flag > 2) + dbg_log (_("(negtable_update) Release wait lock")); + pthread_rwlock_unlock (&neglock); + sleep (10); + } + return NULL; +} diff --git a/nscd/nscd.c b/nscd/nscd.c new file mode 100644 index 0000000000..59d4a60e02 --- /dev/null +++ b/nscd/nscd.c @@ -0,0 +1,423 @@ +/* Copyright (c) 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk , 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. */ + +/* nscd - Name Service Cache Daemon. Caches passwd and group. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dbg_log.h" +#include "nscd.h" + +/* Get libc version number. */ +#include + +#define PACKAGE _libc_intl_domainname + +/* Structure used by main() thread to keep track of the number of + active threads. Used to limit how many threads it will create + and under a shutdown condition to wait till all in-progress + requests have finished before "turning off the lights". */ + +typedef struct +{ + int num_active; + pthread_cond_t thread_exit_cv; + pthread_mutex_t mutex; +} thread_info_t; + +thread_info_t thread_info; + +int do_shutdown = 0; +int disabled_passwd = 0; +int disabled_group = 0; + +static void termination_handler (int signum); +static int check_pid (const char *file); +static int write_pid (const char *file); +static void usage (int status) __attribute__ ((noreturn)); +static void handle_requests (void); + +int +main (int argc, char **argv) +{ + int go_background = 1; + const char *conffile = _PATH_NSCDCONF; + + /* Set locale via LC_ALL. */ + setlocale (LC_ALL, ""); + /* Set the text message domain. */ + textdomain (PACKAGE); + + while (1) + { + int c; + int option_index = 0; + static struct option long_options[] = { + { "debug", no_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + { "shutdown", no_argument, NULL, 'K' }, + {NULL, 0, NULL, '\0'} + }; + + c = getopt_long (argc, argv, "df:ghKV", long_options, &option_index); + if (c == (-1)) + break; + switch (c) + { + case 'd': + debug_flag = 1; + go_background = 0; + break; + case 'f': + conffile = optarg; + break; + case 'h': + usage (EXIT_SUCCESS); + break; + case 'K': + if (getuid () != 0) + { + printf (_("Only root is allowed to use this option!\n\n")); + usage (EXIT_FAILURE); + } + { + int sock = __nscd_open_socket (); + request_header req; + ssize_t nbytes; + + if (sock == -1) + exit (EXIT_FAILURE); + + req.version = NSCD_VERSION; + req.type = SHUTDOWN; + req.key_len = 0; + nbytes = write (sock, &req, sizeof (request_header)); + close (sock); + if (nbytes != req.key_len) + exit (EXIT_FAILURE); + else + exit (EXIT_SUCCESS); + } + case 'g': + print_stat (); + exit (EXIT_SUCCESS); + case 'V': + printf ("nscd (GNU %s) %s\n", PACKAGE, VERSION); + printf (_("\ +Copyright (C) %s Free Software Foundation, Inc.\n\ +This is free software; see the source for copying conditions. There is NO\n\ +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ +"), "1998"); + printf (_("Written by %s.\n"), "Thorsten Kukuk"); + exit (EXIT_SUCCESS); + default: + usage (EXIT_FAILURE); + } + } + + signal (SIGINT, termination_handler); + signal (SIGQUIT, termination_handler); + signal (SIGTERM, termination_handler); + + /* Check if we are already running. */ + if (check_pid (_PATH_NSCDPID)) + { + fputs (_("already running"), stderr); + exit (EXIT_FAILURE); + } + + /* Behave like a daemon. */ + if (go_background) + { + openlog ("nscd", LOG_CONS | LOG_ODELAY, LOG_DAEMON); + + if (daemon (0, 0) < 0) + { + fprintf (stderr, _("connot auto-background: %s\n"), + strerror (errno)); + exit (EXIT_FAILURE); + } + if (write_pid (_PATH_NSCDPID) < 0) + dbg_log ("%s: %s", _PATH_NSCDPID, strerror (errno)); + + /* Ignore job control signals */ + signal (SIGTTOU, SIG_IGN); + signal (SIGTTIN, SIG_IGN); + signal (SIGTSTP, SIG_IGN); + } + /* Cleanup files created by a previous `bind' */ + unlink (_PATH_NSCDSOCKET); + + nscd_parse_file (conffile); + + /* Create first sockets */ + init_sockets (); + /* Init databases */ + cache_pwdinit (); + cache_grpinit (); + /* Handle incoming requests */ + handle_requests (); + + return 0; +} + +/* Create a socket connected to a name. */ +int +__nscd_open_socket (void) +{ + struct sockaddr_un addr; + int sock; + + sock = socket (PF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + return -1; + + addr.sun_family = AF_UNIX; + strcpy (addr.sun_path, _PATH_NSCDSOCKET); + if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0) + { + close (sock); + return -1; + } + + return sock; +} + +/* Cleanup. */ +static void +termination_handler (int signum) +{ + close_sockets (); + + /* Clean up the files created by `bind'. */ + unlink (_PATH_NSCDSOCKET); + + /* Clean up pid file. */ + unlink (_PATH_NSCDPID); + + exit (EXIT_SUCCESS); +} + +/* Display usage information and exit. */ +static void +usage (int status) +{ + if (status != EXIT_SUCCESS) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_invocation_name); + else + { + printf (_("\ +Usage: %s [OPTION]...\n\ + -d, --debug do not fork and display messages on the current tty\n\ + -h, --help display this help and exit\n\ + -V, --version output version information and exit\n\ + -f configuration-file read configuration data from the specified file.\n\ + -K, --shutdown shut the server down.\n\ + -g Prints configuration and statistics to stdout.\n"), + program_invocation_name); + fputs (_("\ +Report bugs using the `glibcbug' script to .\n"), + stdout); + } + exit (status); +} + +/* Returns 1 if the process in pid file FILE is running, 0 if not. */ +static int +check_pid (const char *file) +{ + FILE *fp; + + fp = fopen (file, "r"); + if (fp) + { + pid_t pid; + + fscanf (fp, "%d", &pid); + fclose (fp); + + if (kill (pid, 0) == 0) + return 1; + } + + return 0; +} + +/* Write the current process id to the file FILE. + Returns 0 if successful, -1 if not. */ +static int +write_pid (const char *file) +{ + FILE *fp; + + fp = fopen (file, "w"); + if (fp == NULL) + return -1; + + fprintf (fp, "%d\n", getpid ()); + if (ferror (fp)) + return -1; + + fclose (fp); + + return 0; +} + +/* Type of the lookup function for netname2user. */ +typedef int (*pwbyname_function) (const char *name, struct passwd *pw, + char *buffer, size_t buflen); + +/* Hanlde incoming requests. */ +static +void handle_requests (void) +{ + request_header req; + int conn; /* Handle on which connection (client) the request came from. */ + int done = 0; + char *key; + + while (!done) + { + key = NULL; + get_request (&conn, &req, &key); + if (debug_flag) + dbg_log (_("handle_requests: request received (Version = %d)"), + req.version); + switch (req.type) + { + case GETPWBYNAME: + { + param_t *param = malloc (sizeof (param_t)); + pthread_t thread; + + if (debug_flag) + dbg_log ("\tGETPWBYNAME (%s)", key); + param->key = key; + param->conn = conn; + if (disabled_passwd) + pthread_create (&thread, NULL, cache_pw_disabled, (void *)param); + else + pthread_create (&thread, NULL, cache_getpwnam, (void *)param); + pthread_detach (thread); + } + break; + case GETPWBYUID: + { + param_t *param = malloc (sizeof (param_t)); + pthread_t thread; + + if (debug_flag) + dbg_log ("\tGETPWBYUID (%s)", key); + param->key = key; + param->conn = conn; + if (disabled_passwd) + pthread_create (&thread, NULL, cache_pw_disabled, (void *)param); + else + pthread_create (&thread, NULL, cache_getpwuid, (void *)param); + pthread_detach (thread); + } + break; + case GETGRBYNAME: + { + param_t *param = malloc (sizeof (param_t)); + pthread_t thread; + + if (debug_flag) + dbg_log ("\tGETGRBYNAME (%s)", key); + param->key = key; + param->conn = conn; + if (disabled_group) + pthread_create (&thread, NULL, cache_gr_disabled, (void *)param); + else + pthread_create (&thread, NULL, cache_getgrnam, (void *)param); + pthread_detach (thread); + } + break; + case GETGRBYGID: + { + param_t *param = malloc (sizeof (param_t)); + pthread_t thread; + + if (debug_flag) + dbg_log ("\tGETGRBYGID (%s)", key); + param->key = key; + param->conn = conn; + if (disabled_group) + pthread_create (&thread, NULL, cache_gr_disabled, (void *)param); + else + pthread_create (&thread, NULL, cache_getgrgid, (void *)param); + pthread_detach (thread); + } + break; + case GETHOSTBYNAME: + /* Not yetimplemented. */ + close_socket (conn); + break; + case GETHOSTBYADDR: + /* Not yet implemented. */ + close_socket (conn); + break; + case SHUTDOWN: + do_shutdown = 1; + close_socket (0); + close_socket (conn); + /* Clean up the files created by `bind'. */ + unlink (_PATH_NSCDSOCKET); + /* Clean up pid file. */ + unlink (_PATH_NSCDPID); + done = 1; + break; + case GETSTAT: + { + stat_response_header resp; + + if (debug_flag) + dbg_log ("\tGETSTAT"); + + get_pw_stat (&resp); + get_gr_stat (&resp); + resp.debug_level = debug_flag; + resp.pw_enabled = !disabled_passwd; + resp.gr_enabled = !disabled_group; + + stat_send (conn, &resp); + + close_socket (conn); + } + break; + default: + dbg_log (_("Unknown request (%d)"), req.type); + break; + } + } +} diff --git a/nscd/nscd.conf b/nscd/nscd.conf new file mode 100644 index 0000000000..5d8c7f31ac --- /dev/null +++ b/nscd/nscd.conf @@ -0,0 +1,30 @@ +# +# /etc/nscd.conf +# +# An example Name Service Cache config file. This file is needed by nscd. +# +# Legal entries are: +# +# logfile +# enable-cache +# debug-level +# positive-time-to-live