diff options
-rw-r--r-- | ChangeLog | 51 | ||||
-rwxr-xr-x | configure | 158 | ||||
-rw-r--r-- | grp/getgrgid_r.c | 5 | ||||
-rw-r--r-- | grp/getgrnam_r.c | 5 | ||||
-rw-r--r-- | nscd/Makefile | 46 | ||||
-rw-r--r-- | nscd/TODO | 7 | ||||
-rw-r--r-- | nscd/connections.c | 529 | ||||
-rw-r--r-- | nscd/dbg_log.c | 64 | ||||
-rw-r--r-- | nscd/dbg_log.h | 27 | ||||
-rw-r--r-- | nscd/getgrgid_r.c | 30 | ||||
-rw-r--r-- | nscd/getgrnam_r.c | 29 | ||||
-rw-r--r-- | nscd/getpwnam_r.c | 30 | ||||
-rw-r--r-- | nscd/getpwuid_r.c | 30 | ||||
-rw-r--r-- | nscd/grpcache.c | 589 | ||||
-rw-r--r-- | nscd/nscd.c | 423 | ||||
-rw-r--r-- | nscd/nscd.conf | 30 | ||||
-rw-r--r-- | nscd/nscd.h | 149 | ||||
-rw-r--r-- | nscd/nscd.init | 50 | ||||
-rw-r--r-- | nscd/nscd_conf.c | 148 | ||||
-rw-r--r-- | nscd/nscd_getgr_r.c | 211 | ||||
-rw-r--r-- | nscd/nscd_getpw_r.c | 198 | ||||
-rw-r--r-- | nscd/nscd_proto.h | 35 | ||||
-rw-r--r-- | nscd/nscd_stat.c | 87 | ||||
-rw-r--r-- | nscd/pwdcache.c | 581 | ||||
-rw-r--r-- | nss/getXXbyYY_r.c | 21 | ||||
-rw-r--r-- | pwd/getpwnam_r.c | 5 | ||||
-rw-r--r-- | pwd/getpwuid_r.c | 5 | ||||
-rw-r--r-- | sysdeps/unix/inet/Subdirs | 1 |
28 files changed, 3459 insertions, 85 deletions
@@ -1,3 +1,48 @@ +1998-01-31 Phil Blundell <philb@gnu.org> + + * 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 <kukuk@vt.uni-paderborn.de> + + * 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. + 1998-01-31 11:44 Ulrich Drepper <drepper@cygnus.com> * intl/Makefile: Use CVSOPTS in cvs invocation. @@ -520,9 +565,9 @@ * nis/Makefile: Distribute nis_cache2.h, add nis cache functions to routines. - * nis/nis_cache.c: New. - * nis/nis_cache2.h: New. - * nis/nis_cache2_xdr.c: New. + * nis/nis_cache.c: New file. + * nis/nis_cache2.h: New file. + * nis/nis_cache2_xdr.c: New file. * nis/nis_call.c: Changes for cache2_info parameter. * nis/nis_checkpoint.c: Likewise. * nis/nis_intern.h: Likewise. @@ -31,6 +31,8 @@ ac_help="$ac_help ac_help="$ac_help --with-elf if using the ELF object format" ac_help="$ac_help + --without-cvs if CVS should not be used" +ac_help="$ac_help --enable-libio build in GNU libio instead of GNU stdio" ac_help="$ac_help --disable-sanity-checks really do not use threads (should not be used @@ -618,6 +620,15 @@ else elf=no fi +# Check whether --with-cvs or --without-cvs was given. +if test "${with_cvs+set}" = set; then + withval="$with_cvs" + with_cvs=$withval +else + with_cvs=yes +fi + + # Check whether --enable-libio or --disable-libio was given. if test "${enable_libio+set}" = set; then @@ -762,7 +773,7 @@ else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } fi echo $ac_n "checking host system type""... $ac_c" 1>&6 -echo "configure:766: checking host system type" >&5 +echo "configure:777: checking host system type" >&5 host_alias=$host case "$host_alias" in @@ -805,8 +816,8 @@ esac ### platforms. ### if test -z "$enable_hacker_mode"; then - case "$host_os" in - linux* | gnu*) + case "$machine-$host_os" in + *-linux* | *-gnu* | arm*-none*) ;; *) echo "*** The GNU C library is currently not available for this platform." @@ -881,7 +892,7 @@ fi # This can take a while to compute. sysdep_dir=$srcdir/sysdeps echo $ac_n "checking sysdep dirs""... $ac_c" 1>&6 -echo "configure:885: checking sysdep dirs" >&5 +echo "configure:896: checking sysdep dirs" >&5 # Make sco3.2v4 become sco3.2.4 and sunos4.1.1_U1 become sunos4.1.1.U1. os="`echo $os | sed 's/\([0-9A-Z]\)[v_]\([0-9A-Z]\)/\1.\2/g'`" @@ -1082,7 +1093,7 @@ echo "$ac_t""sysdeps/generic" 1>&6 # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # ./install, which can be erroneously created by make from ./install.sh. echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 -echo "configure:1086: checking for a BSD compatible install" >&5 +echo "configure:1097: checking for a BSD compatible install" >&5 if test -z "$INSTALL"; then if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -1136,7 +1147,7 @@ if test "$INSTALL" = "${srcdir}/install-sh -c"; then INSTALL='\$(..)./install-sh -c' fi echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6 -echo "configure:1140: checking whether ln -s works" >&5 +echo "configure:1151: checking whether ln -s works" >&5 if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1161,7 +1172,7 @@ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1165: checking for $ac_word" >&5 +echo "configure:1176: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_MSGFMT'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1193,7 +1204,7 @@ test -n "$MSGFMT" || MSGFMT=":" # Extract the first word of "makeinfo", so it can be a program name with args. set dummy makeinfo; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1197: checking for $ac_word" >&5 +echo "configure:1208: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_MAKEINFO'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1233,7 +1244,7 @@ fi # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1237: checking for $ac_word" >&5 +echo "configure:1248: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1262,7 +1273,7 @@ if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1266: checking for $ac_word" >&5 +echo "configure:1277: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1310,7 +1321,7 @@ fi fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 -echo "configure:1314: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 +echo "configure:1325: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. @@ -1320,11 +1331,11 @@ ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS cross_compiling=$ac_cv_prog_cc_cross cat > conftest.$ac_ext <<EOF -#line 1324 "configure" +#line 1335 "configure" #include "confdefs.h" main(){return(0);} EOF -if { (eval echo configure:1328: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:1339: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then ac_cv_prog_cc_works=yes # If we can't run a trivial program, we are probably using a cross compiler. if (./conftest; exit) 2>/dev/null; then @@ -1347,13 +1358,13 @@ else cross_linkable=yes fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 -echo "configure:1351: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "configure:1362: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 cross_compiling=$ac_cv_prog_cc_cross echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 -echo "configure:1357: checking whether we are using GNU C" >&5 +echo "configure:1368: checking whether we are using GNU C" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1362,7 +1373,7 @@ else yes; #endif EOF -if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1366: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then +if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1377: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then ac_cv_prog_gcc=yes else ac_cv_prog_gcc=no @@ -1379,7 +1390,7 @@ if test $ac_cv_prog_gcc = yes; then yes; #endif EOF - if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1383: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1394: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then if test -z "$CFLAGS"; then CFLAGS="-g -O2" fi @@ -1391,7 +1402,7 @@ else fi echo $ac_n "checking build system type""... $ac_c" 1>&6 -echo "configure:1395: checking build system type" >&5 +echo "configure:1406: checking build system type" >&5 build_alias=$build case "$build_alias" in @@ -1414,7 +1425,7 @@ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1418: checking for $ac_word" >&5 +echo "configure:1429: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_BUILD_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1445,7 +1456,7 @@ done fi echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 -echo "configure:1449: checking how to run the C preprocessor" >&5 +echo "configure:1460: checking how to run the C preprocessor" >&5 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= @@ -1460,13 +1471,13 @@ else # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. cat > conftest.$ac_ext <<EOF -#line 1464 "configure" +#line 1475 "configure" #include "confdefs.h" #include <assert.h> Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1470: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:1481: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then : @@ -1477,13 +1488,13 @@ else rm -rf conftest* CPP="${CC-cc} -E -traditional-cpp" cat > conftest.$ac_ext <<EOF -#line 1481 "configure" +#line 1492 "configure" #include "confdefs.h" #include <assert.h> Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1487: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:1498: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then : @@ -1516,7 +1527,7 @@ LD=`$CC -print-file-name=ld` # Determine whether we are using GNU binutils. echo $ac_n "checking whether $AS is GNU as""... $ac_c" 1>&6 -echo "configure:1520: checking whether $AS is GNU as" >&5 +echo "configure:1531: checking whether $AS is GNU as" >&5 if eval "test \"`echo '$''{'libc_cv_prog_as_gnu'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1534,7 +1545,7 @@ rm -f a.out gnu_as=$libc_cv_prog_as_gnu echo $ac_n "checking whether $LD is GNU ld""... $ac_c" 1>&6 -echo "configure:1538: checking whether $LD is GNU ld" >&5 +echo "configure:1549: checking whether $LD is GNU ld" >&5 if eval "test \"`echo '$''{'libc_cv_prog_ld_gnu'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1558,7 +1569,7 @@ fi # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. set dummy ${ac_tool_prefix}ar; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1562: checking for $ac_word" >&5 +echo "configure:1573: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1589,7 +1600,7 @@ fi # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1593: checking for $ac_word" >&5 +echo "configure:1604: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1620,7 +1631,7 @@ if test -n "$ac_tool_prefix"; then # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1624: checking for $ac_word" >&5 +echo "configure:1635: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1655,7 +1666,7 @@ fi # Extract the first word of "bash", so it can be a program name with args. set dummy bash; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1659: checking for $ac_word" >&5 +echo "configure:1670: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_BASH'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1697,7 +1708,7 @@ if test "$BASH" = no; then # Extract the first word of "ksh", so it can be a program name with args. set dummy ksh; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1701: checking for $ac_word" >&5 +echo "configure:1712: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_KSH'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1743,7 +1754,7 @@ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1747: checking for $ac_word" >&5 +echo "configure:1758: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_PERL'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1778,7 +1789,7 @@ test -n "$PERL" || PERL="no" echo $ac_n "checking for signed size_t type""... $ac_c" 1>&6 -echo "configure:1782: checking for signed size_t type" >&5 +echo "configure:1793: checking for signed size_t type" >&5 if eval "test \"`echo '$''{'libc_cv_signed_size_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1802,12 +1813,12 @@ EOF fi echo $ac_n "checking for libc-friendly stddef.h""... $ac_c" 1>&6 -echo "configure:1806: checking for libc-friendly stddef.h" >&5 +echo "configure:1817: checking for libc-friendly stddef.h" >&5 if eval "test \"`echo '$''{'libc_cv_friendly_stddef'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 1811 "configure" +#line 1822 "configure" #include "confdefs.h" #define __need_size_t #define __need_wchar_t @@ -1822,7 +1833,7 @@ size_t size; wchar_t wchar; if (&size == NULL || &wchar == NULL) abort (); ; return 0; } EOF -if { (eval echo configure:1826: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:1837: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* libc_cv_friendly_stddef=yes else @@ -1841,7 +1852,7 @@ override stddef.h = # The installed <stddef.h> seems to be libc-friendly." fi echo $ac_n "checking whether we need to use -P to assemble .S files""... $ac_c" 1>&6 -echo "configure:1845: checking whether we need to use -P to assemble .S files" >&5 +echo "configure:1856: checking whether we need to use -P to assemble .S files" >&5 if eval "test \"`echo '$''{'libc_cv_need_minus_P'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1872,7 +1883,7 @@ if test $ac_cv_prog_gcc = yes; then # We must check this even if -pipe is not given here, because the user # might do `make CFLAGS=-pipe'. echo $ac_n "checking for gcc 2.7.x -pipe bug""... $ac_c" 1>&6 -echo "configure:1876: checking for gcc 2.7.x -pipe bug" >&5 +echo "configure:1887: checking for gcc 2.7.x -pipe bug" >&5 if eval "test \"`echo '$''{'libc_cv_gcc_pipe_bug'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1901,7 +1912,7 @@ else fi echo $ac_n "checking for assembler global-symbol directive""... $ac_c" 1>&6 -echo "configure:1905: checking for assembler global-symbol directive" >&5 +echo "configure:1916: checking for assembler global-symbol directive" >&5 if eval "test \"`echo '$''{'libc_cv_asm_global_directive'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1931,7 +1942,7 @@ EOF fi echo $ac_n "checking for .set assembler directive""... $ac_c" 1>&6 -echo "configure:1935: checking for .set assembler directive" >&5 +echo "configure:1946: checking for .set assembler directive" >&5 if eval "test \"`echo '$''{'libc_cv_asm_set_directive'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1965,7 +1976,7 @@ EOF fi echo $ac_n "checking for .symver assembler directive""... $ac_c" 1>&6 -echo "configure:1969: checking for .symver assembler directive" >&5 +echo "configure:1980: checking for .symver assembler directive" >&5 if eval "test \"`echo '$''{'libc_cv_asm_symver_directive'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1984,7 +1995,7 @@ fi echo "$ac_t""$libc_cv_asm_symver_directive" 1>&6 echo $ac_n "checking for ld --version-script""... $ac_c" 1>&6 -echo "configure:1988: checking for ld --version-script" >&5 +echo "configure:1999: checking for ld --version-script" >&5 if eval "test \"`echo '$''{'libc_cv_ld_version_script_option'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2007,7 +2018,7 @@ EOF if { ac_try='${CC-cc} $CFLAGS -shared -o conftest.so conftest.o -nostartfiles -nostdlib -Wl,--version-script,conftest.map - 1>&5'; { (eval echo configure:2011: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; + 1>&5'; { (eval echo configure:2022: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then libc_cv_ld_version_script_option=yes else @@ -2045,7 +2056,7 @@ if test $VERSIONING = no; then fi if test $elf = yes; then echo $ac_n "checking for .previous assembler directive""... $ac_c" 1>&6 -echo "configure:2049: checking for .previous assembler directive" >&5 +echo "configure:2060: checking for .previous assembler directive" >&5 if eval "test \"`echo '$''{'libc_cv_asm_previous_directive'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2053,7 +2064,7 @@ else .section foo_section .previous EOF - if { ac_try='${CC-cc} -c $CFLAGS conftest.s 1>&5'; { (eval echo configure:2057: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then + if { ac_try='${CC-cc} -c $CFLAGS conftest.s 1>&5'; { (eval echo configure:2068: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then libc_cv_asm_previous_directive=yes else libc_cv_asm_previous_directive=no @@ -2069,7 +2080,7 @@ EOF else echo $ac_n "checking for .popsection assembler directive""... $ac_c" 1>&6 -echo "configure:2073: checking for .popsection assembler directive" >&5 +echo "configure:2084: checking for .popsection assembler directive" >&5 if eval "test \"`echo '$''{'libc_cv_asm_popsection_directive'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2077,7 +2088,7 @@ else .pushsection foo_section .popsection EOF - if { ac_try='${CC-cc} -c $CFLAGS conftest.s 1>&5'; { (eval echo configure:2081: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then + if { ac_try='${CC-cc} -c $CFLAGS conftest.s 1>&5'; { (eval echo configure:2092: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then libc_cv_asm_popsection_directive=yes else libc_cv_asm_popsection_directive=no @@ -2097,12 +2108,12 @@ fi if test $elf != yes; then echo $ac_n "checking for .init and .fini sections""... $ac_c" 1>&6 -echo "configure:2101: checking for .init and .fini sections" >&5 +echo "configure:2112: checking for .init and .fini sections" >&5 if eval "test \"`echo '$''{'libc_cv_have_initfini'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2106 "configure" +#line 2117 "configure" #include "confdefs.h" int main() { @@ -2111,7 +2122,7 @@ asm (".section .init"); asm (".text"); ; return 0; } EOF -if { (eval echo configure:2115: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:2126: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* libc_cv_have_initfini=yes else @@ -2139,19 +2150,19 @@ if test $elf = yes; then else if test $ac_cv_prog_cc_works = yes; then echo $ac_n "checking for _ prefix on C symbol names""... $ac_c" 1>&6 -echo "configure:2143: checking for _ prefix on C symbol names" >&5 +echo "configure:2154: checking for _ prefix on C symbol names" >&5 if eval "test \"`echo '$''{'libc_cv_asm_underscores'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2148 "configure" +#line 2159 "configure" #include "confdefs.h" asm ("_glibc_foobar:"); int main() { glibc_foobar (); ; return 0; } EOF -if { (eval echo configure:2155: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:2166: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* libc_cv_asm_underscores=yes else @@ -2166,17 +2177,17 @@ fi echo "$ac_t""$libc_cv_asm_underscores" 1>&6 else echo $ac_n "checking for _ prefix on C symbol names""... $ac_c" 1>&6 -echo "configure:2170: checking for _ prefix on C symbol names" >&5 +echo "configure:2181: checking for _ prefix on C symbol names" >&5 if eval "test \"`echo '$''{'libc_cv_asm_underscores'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2175 "configure" +#line 2186 "configure" #include "confdefs.h" void underscore_test(void) { return; } EOF -if { (eval echo configure:2180: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:2191: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then if grep _underscore_test conftest* >/dev/null; then rm -f conftest* libc_cv_asm_underscores=yes @@ -2209,7 +2220,7 @@ if test $elf = yes; then libc_cv_asm_weakext_directive=no else echo $ac_n "checking for assembler .weak directive""... $ac_c" 1>&6 -echo "configure:2213: checking for assembler .weak directive" >&5 +echo "configure:2224: checking for assembler .weak directive" >&5 if eval "test \"`echo '$''{'libc_cv_asm_weak_directive'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2232,7 +2243,7 @@ echo "$ac_t""$libc_cv_asm_weak_directive" 1>&6 if test $libc_cv_asm_weak_directive = no; then echo $ac_n "checking for assembler .weakext directive""... $ac_c" 1>&6 -echo "configure:2236: checking for assembler .weakext directive" >&5 +echo "configure:2247: checking for assembler .weakext directive" >&5 if eval "test \"`echo '$''{'libc_cv_asm_weakext_directive'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2269,7 +2280,7 @@ EOF fi echo $ac_n "checking for ld --no-whole-archive""... $ac_c" 1>&6 -echo "configure:2273: checking for ld --no-whole-archive" >&5 +echo "configure:2284: checking for ld --no-whole-archive" >&5 if eval "test \"`echo '$''{'libc_cv_ld_no_whole_archive'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2280,7 +2291,7 @@ __throw () {} EOF if { ac_try='${CC-cc} $CFLAGS -nostdlib -nostartfiles -Wl,--no-whole-archive - -o conftest conftest.c 1>&5'; { (eval echo configure:2284: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then + -o conftest conftest.c 1>&5'; { (eval echo configure:2295: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then libc_cv_ld_no_whole_archive=yes else libc_cv_ld_no_whole_archive=no @@ -2291,7 +2302,7 @@ fi echo "$ac_t""$libc_cv_ld_no_whole_archive" 1>&6 echo $ac_n "checking for gcc -fno-exceptions""... $ac_c" 1>&6 -echo "configure:2295: checking for gcc -fno-exceptions" >&5 +echo "configure:2306: checking for gcc -fno-exceptions" >&5 if eval "test \"`echo '$''{'libc_cv_gcc_no_exceptions'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2302,7 +2313,7 @@ __throw () {} EOF if { ac_try='${CC-cc} $CFLAGS -nostdlib -nostartfiles -fno-exceptions - -o conftest conftest.c 1>&5'; { (eval echo configure:2306: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then + -o conftest conftest.c 1>&5'; { (eval echo configure:2317: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then libc_cv_gcc_no_exceptions=yes else libc_cv_gcc_no_exceptions=no @@ -2314,14 +2325,14 @@ echo "$ac_t""$libc_cv_gcc_no_exceptions" 1>&6 if test "$base_machine" = alpha ; then echo $ac_n "checking for function ..ng prefix""... $ac_c" 1>&6 -echo "configure:2318: checking for function ..ng prefix" >&5 +echo "configure:2329: checking for function ..ng prefix" >&5 if eval "test \"`echo '$''{'libc_cv_gcc_alpha_ng_prefix'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.c <<\EOF foo () { } EOF -if { ac_try='${CC-cc} -S conftest.c -o - | fgrep "\$foo..ng" > /dev/null'; { (eval echo configure:2325: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; +if { ac_try='${CC-cc} -S conftest.c -o - | fgrep "\$foo..ng" > /dev/null'; { (eval echo configure:2336: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then libc_cv_gcc_alpha_ng_prefix=yes else @@ -2345,12 +2356,12 @@ fi fi echo $ac_n "checking for DWARF2 unwind info support""... $ac_c" 1>&6 -echo "configure:2349: checking for DWARF2 unwind info support" >&5 +echo "configure:2360: checking for DWARF2 unwind info support" >&5 if eval "test \"`echo '$''{'libc_cv_gcc_dwarf2_unwind_info'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.c <<EOF -#line 2354 "configure" +#line 2365 "configure" static char __EH_FRAME_BEGIN__; _start () { @@ -2377,7 +2388,7 @@ __bzero () {} EOF if { ac_try='${CC-cc} $CFLAGS -DCHECK__register_frame_info -nostdlib -nostartfiles - -o conftest conftest.c -lgcc >&5'; { (eval echo configure:2381: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then + -o conftest conftest.c -lgcc >&5'; { (eval echo configure:2392: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then libc_cv_gcc_dwarf2_unwind_info=static else libc_cv_gcc_dwarf2_unwind_info=no @@ -2385,7 +2396,7 @@ fi if test $libc_cv_gcc_dwarf2_unwind_info = no; then if { ac_try='${CC-cc} $CFLAGS -DCHECK__register_frame -nostdlib -nostartfiles - -o conftest conftest.c -lgcc >&5'; { (eval echo configure:2389: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then + -o conftest conftest.c -lgcc >&5'; { (eval echo configure:2400: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then libc_cv_gcc_dwarf2_unwind_info=yes else libc_cv_gcc_dwarf2_unwind_info=no @@ -2456,7 +2467,7 @@ if test "$uname" = "sysdeps/generic"; then fi echo $ac_n "checking OS release for uname""... $ac_c" 1>&6 -echo "configure:2460: checking OS release for uname" >&5 +echo "configure:2471: checking OS release for uname" >&5 if eval "test \"`echo '$''{'libc_cv_uname_release'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2478,7 +2489,7 @@ echo "$ac_t""$libc_cv_uname_release" 1>&6 uname_release="$libc_cv_uname_release" echo $ac_n "checking OS version for uname""... $ac_c" 1>&6 -echo "configure:2482: checking OS version for uname" >&5 +echo "configure:2493: checking OS version for uname" >&5 if eval "test \"`echo '$''{'libc_cv_uname_version'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2500,7 +2511,7 @@ else fi echo $ac_n "checking stdio selection""... $ac_c" 1>&6 -echo "configure:2504: checking stdio selection" >&5 +echo "configure:2515: checking stdio selection" >&5 case $stdio in libio) cat >> confdefs.h <<\EOF @@ -2512,7 +2523,7 @@ esac echo "$ac_t""$stdio" 1>&6 echo $ac_n "checking ldap selection""... $ac_c" 1>&6 -echo "configure:2516: checking ldap selection" >&5 +echo "configure:2527: checking ldap selection" >&5 case $add_ons in *ldap*) @@ -2574,7 +2585,7 @@ if test $static = no && test $shared = yes; then fi echo $ac_n "checking whether -fPIC is default""... $ac_c" 1>&6 -echo "configure:2578: checking whether -fPIC is default" >&5 +echo "configure:2589: checking whether -fPIC is default" >&5 if eval "test \"`echo '$''{'pic_default'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2756,6 +2767,7 @@ s%@includedir@%$includedir%g s%@oldincludedir@%$oldincludedir%g s%@infodir@%$infodir%g s%@mandir@%$mandir%g +s%@with_cvs@%$with_cvs%g s%@subdirs@%$subdirs%g s%@host@%$host%g s%@host_alias@%$host_alias%g diff --git a/grp/getgrgid_r.c b/grp/getgrgid_r.c index 8f05ae5060..8d5122a2cd 100644 --- a/grp/getgrgid_r.c +++ b/grp/getgrgid_r.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1996, 1997 Free Software Foundation, Inc. +/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996. @@ -26,5 +26,6 @@ #define ADD_PARAMS gid_t gid #define ADD_VARIABLES gid #define BUFLEN NSS_BUFLEN_GROUP +#define USE_NSCD 1 -#include "../nss/getXXbyYY_r.c" +#include <nss/getXXbyYY_r.c> diff --git a/grp/getgrnam_r.c b/grp/getgrnam_r.c index eb34c1f777..ee84cfe5ec 100644 --- a/grp/getgrnam_r.c +++ b/grp/getgrnam_r.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1996, 1997 Free Software Foundation, Inc. +/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996. @@ -25,5 +25,6 @@ #define DATABASE_NAME group #define ADD_PARAMS const char *name #define ADD_VARIABLES name +#define USE_NSCD 1 -#include "../nss/getXXbyYY_r.c" +#include <nss/getXXbyYY_r.c> 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 <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)); +} 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 <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 <stdarg.h> +#include <stdio.h> +#include <syslog.h> +#include <unistd.h> +#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 <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. */ + +#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 <drepper@cygnus.com>, 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 <grp.h> + + +#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 <nss/getXXbyYY_r.c> 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 <drepper@cygnus.com>, 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 <grp.h> + + +#define LOOKUP_TYPE struct group +#define FUNCTION_NAME getgrnam +#define DATABASE_NAME group +#define ADD_PARAMS const char *name +#define ADD_VARIABLES name + +#include <nss/getXXbyYY_r.c> 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 <drepper@cygnus.com>, 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 <pwd.h> + + +#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 <nss/getXXbyYY_r.c> 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 <drepper@cygnus.com>, 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 <pwd.h> + + +#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 <nss/getXXbyYY_r.c> 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 <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 <grp.h> +#include <malloc.h> +#include <pthread.h> +#include <string.h> +#include <rpcsvc/nis.h> +#include <sys/types.h> + +#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 <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. */ + +/* nscd - Name Service Cache Daemon. Caches passwd and group. */ + +#include <errno.h> +#include <getopt.h> +#include <libintl.h> +#include <locale.h> +#include <pthread.h> +#include <pwd.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include "dbg_log.h" +#include "nscd.h" + +/* Get libc version number. */ +#include <version.h> + +#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 <bugs@gnu.org>.\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 <file> +# enable-cache <service> <yes|no> +# debug-level <level> +# positive-time-to-live <service> <time in seconds> +# negative-time-to-live <service> <time in seconds> +# suggested-size <service> <prime number> +# +# Currently supported cache names (services): passwd, group +# + + +# logfile /var/adm/nscd.log +# enable-cache hosts no + + debug-level 0 + + positive-time-to-live passwd 600 + negative-time-to-live passwd 20 + suggested-size passwd 211 + + positive-time-to-live group 3600 + negative-time-to-live group 60 + suggested-size group 211 diff --git a/nscd/nscd.h b/nscd/nscd.h new file mode 100644 index 0000000000..4835542619 --- /dev/null +++ b/nscd/nscd.h @@ -0,0 +1,149 @@ +/* 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. */ + +#ifndef _NSCD_H +#define _NSCD_H 1 + +#include <grp.h> +#include <pwd.h> + +/* Version number of the daemon interface */ +#define NSCD_VERSION 1 + +/* How many threads do we spawn maximal ? */ +#define MAX_NUM_CONNECTIONS 16 + +/* Services provided */ +typedef enum +{ + GETPWBYNAME, + GETPWBYUID, + GETGRBYNAME, + GETGRBYGID, + GETHOSTBYNAME, + GETHOSTBYADDR, + SHUTDOWN, /* Shut the server down */ + GETSTAT /* Get the server statistic */ +} request_type; + +/* Header common to all requests */ +typedef struct +{ + /* Version number of the daemon interface */ + int version; + /* Service requested */ + request_type type; + /* key len */ + ssize_t key_len; +} request_header; + +typedef struct +{ + int version; + int found; + ssize_t pw_name_len; + ssize_t pw_passwd_len; + uid_t pw_uid; + gid_t pw_gid; + ssize_t pw_gecos_len; + ssize_t pw_dir_len; + ssize_t pw_shell_len; +} pw_response_header; + +typedef struct +{ + int version; + int found; + ssize_t gr_name_len; + ssize_t gr_passwd_len; + gid_t gr_gid; + ssize_t gr_mem_len; +} gr_response_header; + +typedef struct +{ + int debug_level; + int pw_enabled; + unsigned long pw_poshit; + unsigned long pw_posmiss; + unsigned long pw_neghit; + unsigned long pw_negmiss; + unsigned long pw_size; + unsigned long pw_posttl; + unsigned long pw_negttl; + int gr_enabled; + unsigned long gr_poshit; + unsigned long gr_posmiss; + unsigned long gr_neghit; + unsigned long gr_negmiss; + unsigned long gr_size; + unsigned long gr_posttl; + unsigned long gr_negttl; +} stat_response_header; + +#define _PATH_NSCDPID "/var/run/nscd.pid" +#define _PATH_NSCDSOCKET "/var/run/.nscd_socket" +#define _PATH_NSCDCONF "/etc/nscd.conf" + +typedef struct +{ + char *key; + int conn; +} param_t; + +extern int do_shutdown; /* 1 if we should quit the programm. */ +extern int disabled_passwd; +extern int disabled_group; + +extern int nscd_parse_file __P ((const char *fname)); +extern int set_logfile __P ((const char *logfile)); +extern void set_pos_pwd_ttl __P ((unsigned long)); +extern void set_neg_pwd_ttl __P ((unsigned long)); +extern void set_pos_grp_ttl __P ((unsigned long)); +extern void set_neg_grp_ttl __P ((unsigned long)); +extern void set_pwd_modulo __P ((unsigned long)); +extern void set_grp_modulo __P ((unsigned long)); + +extern void init_sockets __P ((void)); +extern void close_socket __P ((int conn)); +extern void close_sockets __P ((void)); +extern void get_request __P ((int *conn, request_header *req, char **key)); +extern void pw_send_answer __P ((int conn, struct passwd *pwd)); +extern void pw_send_disabled __P ((int conn)); +extern void gr_send_answer __P ((int conn, struct group *grp)); +extern void gr_send_disabled __P ((int conn)); + +extern int cache_pwdinit __P ((void)); +extern void *cache_getpwnam __P ((void *param)); +extern void *cache_getpwuid __P ((void *param)); +extern void *cache_pw_disabled __P ((void *param)); + +extern int cache_grpinit __P ((void)); +extern void *cache_getgrnam __P ((void *param)); +extern void *cache_getgrgid __P ((void *param)); +extern void *cache_gr_disabled __P ((void *param)); + +extern int __nscd_open_socket __P ((void)); + +extern void get_pw_stat __P ((stat_response_header *resp)); +extern void get_gr_stat __P ((stat_response_header *resp)); +extern void print_stat __P ((void)); +extern void stat_send __P ((int conn, stat_response_header *resp)); + +#endif diff --git a/nscd/nscd.init b/nscd/nscd.init new file mode 100644 index 0000000000..097ce42c99 --- /dev/null +++ b/nscd/nscd.init @@ -0,0 +1,50 @@ +#!/bin/sh +# +# nscd: Starts the Name Switch Cache Daemon +# +# chkconfig: 345 52 25 +# description: This is a daemon which handles passwd and group lookups +# for running programs and cache the results for the next +# query. You should start this daemon only if you use +# slow Services like NIS or NIS+ + +# Source function library. +. /etc/rc.d/init.d/functions + +# See how we were called. +case "$1" in + start) + test -f /etc/nscd.conf -a -f /usr/sbin/nscd || exit 0 + secure="" +# for table in passwd group +# do +# if egrep '^'$table':.*nisplus' /etc/nsswitch.conf >/dev/null +# then +# /usr/lib/nscd_nischeck $table || +# secure="$secure -S $table,yes" +# fi +# done + echo -n "Starting Name Switch Cache Daemon: " + daemon nscd $secure + echo + touch /var/lock/subsys/nscd + ;; + stop) + test -f /usr/sbin/nscd || exit 0 + echo -n "Stopping Name Switch Cache Daemon: " + /usr/sbin/nscd -K + rm -f /var/lock/subsys/nscd + echo nscd + ;; + status) + status nscd + ;; + restart) + $0 stop + $0 start + ;; + *) + echo "Usage: /etc/rc.d/init.d/nscd.init {start|stop|status|restart}" + ;; +esac +exit 0 diff --git a/nscd/nscd_conf.c b/nscd/nscd_conf.c new file mode 100644 index 0000000000..59c225e566 --- /dev/null +++ b/nscd/nscd_conf.c @@ -0,0 +1,148 @@ +/* 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 <ctype.h> +#include <malloc.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include "dbg_log.h" +#include "nscd.h" + +int +nscd_parse_file (const char *fname) +{ + FILE *fp; + char *line, *cp, *entry, *arg1, *arg2; + size_t len; + + /* Open the configuration file. */ + fp = fopen (fname, "r"); + if (fp == NULL) + return -1; + + line = NULL; + len = 0; + + do + { + ssize_t n = getline (&line, &len, fp); + if (n < 0) + break; + if (line[n - 1] == '\n') + line[n - 1] = '\0'; + + /* Because the file format does not know any form of quoting we + can search forward for the next '#' character and if found + make it terminating the line. */ + cp = strchr (line, '#'); + if (cp != NULL) + *cp = '\0'; + + /* If the line is blank it is ignored. */ + if (line[0] == '\0') + continue; + + entry = line; + while (isspace (*entry) && *entry != '\0') + ++entry; + cp = entry; + while (!isspace (*cp) && *cp != '\0') + ++cp; + arg1 = cp; + ++arg1; + *cp = '\0'; + if (*cp = '\0' || strlen (entry) == 0) + dbg_log (_("Parse error: %s"), line); + while (isspace (*arg1) && *arg1 != '\0') + ++arg1; + cp = arg1; + while (!isspace (*cp) && *cp != '\0') + ++cp; + arg2 = cp; + ++arg2; + *cp = '\0'; + if (strlen (arg2) > 0) + { + while (isspace (*arg2) && *arg2 != '\0') + ++arg2; + cp = arg2; + while (!isspace (*cp) && *cp != '\0') + ++cp; + *cp = '\0'; + } + + if (strcmp (entry, "positive-time-to-live") == 0) + { + if (strcmp (arg1, "passwd") == 0) + set_pos_pwd_ttl (atol (arg2)); + else if (strcmp (arg1, "group") == 0) + set_pos_grp_ttl (atol (arg2)); + else + dbg_log ("server %s is not supported\n", arg1); + } + else if (strcmp (entry, "negative-time-to-live") == 0) + { + if (strcmp (arg1, "passwd") == 0) + set_neg_pwd_ttl (atol (arg2)); + else if (strcmp (arg1, "group") == 0) + set_neg_grp_ttl (atol (arg2)); + else + dbg_log (_("service %s is not supported"), arg1); + } + else if (strcmp (entry, "suggested-size") == 0) + { + if (strcmp (arg1, "passwd") == 0) + set_pwd_modulo (atol (arg2)); + else if (strcmp (arg1, "group") == 0) + set_grp_modulo (atol (arg2)); + else + dbg_log (_("service %s is not supported"), arg1); + } + else if (strcmp (entry, "enable-cache") ==0) + { + if (strcmp (arg1, "passwd") == 0 + && strcmp (arg2, "no") == 0) + disabled_passwd = 1; + } + else if (strcmp (entry, "logfile") == 0) + { + if (!set_logfile (arg1)) + dbg_log (_("Could not create log file \"%s\""), arg1); + } + else if (strcmp (entry, "debug-level") == 0) + { + int level = atoi (arg1); + if (level > 0) + debug_flag = level; + } + else + dbg_log (_("Unknown option: %s %s %s"), entry, arg1, arg2); + } + while (!feof (fp)); + + /* Free the buffer. */ + free (line); + /* Close configuration file. */ + fclose (fp); + + return 0; +} diff --git a/nscd/nscd_getgr_r.c b/nscd/nscd_getgr_r.c new file mode 100644 index 0000000000..6739657e48 --- /dev/null +++ b/nscd/nscd_getgr_r.c @@ -0,0 +1,211 @@ +/* Copyright (C) 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@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 <grp.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include "nscd.h" +#include "nscd_proto.h" + +static int __nscd_getgr_r (const char *key, request_type type, + struct group *resultbuf, char *buffer, + size_t buflen); + +int +__nscd_getgrnam_r (const char *name, struct group *resultbuf, char *buffer, + size_t buflen) +{ + if (name == NULL) + return 1; + + return __nscd_getgr_r (name, GETGRBYNAME, resultbuf, buffer, buflen); +} + +int +__nscd_getgrgid_r (gid_t gid, struct group *resultbuf, char *buffer, + size_t buflen) +{ + char *p = buffer; + char plen; + + plen = snprintf (buffer, buflen, "%d", gid); + if (plen == -1) + { + __set_errno (ERANGE); + return -1; + } + p = buffer + plen + 1; + + return __nscd_getgr_r (buffer, GETGRBYGID, resultbuf, p, buflen - plen -1); +} + +/* Create a socket connected to a name. */ +static 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; +} + +static int +__nscd_getgr_r (const char *key, request_type type, struct group *resultbuf, + char *buffer, size_t buflen) +{ + int sock = nscd_open_socket (); + request_header req; + gr_response_header gr_resp; + ssize_t nbytes; + + if (sock == -1) + return 1; + + req.version = NSCD_VERSION; + req.type = type; + req.key_len = strlen (key); + nbytes = write (sock, &req, sizeof (request_header)); + if (nbytes != sizeof (request_header)) + { + close (sock); + return 1; + } + + nbytes = write (sock, key, req.key_len); + if (nbytes != req.key_len) + { + close (sock); + return 1; + } + + nbytes = read (sock, &gr_resp, sizeof (gr_response_header)); + if (nbytes != sizeof (gr_response_header)) + { + close (sock); + return 1; + } + + if (gr_resp.found == -1) + { + close (sock); + return 1; + } + + if (gr_resp.found == 1) + { + size_t i; + char *p = buffer; + + if (buflen < gr_resp.gr_name_len + 1) + { + __set_errno (ERANGE); + close (sock); + return -1; + } + resultbuf->gr_name = p; + p += gr_resp.gr_name_len + 1; + buflen -= (gr_resp.gr_name_len + 1); + nbytes = read (sock, resultbuf->gr_name, gr_resp.gr_name_len); + if (nbytes != gr_resp.gr_name_len) + { + close (sock); + return 1; + } + resultbuf->gr_name[gr_resp.gr_name_len] = '\0'; + + if (buflen < gr_resp.gr_passwd_len + 1) + { + __set_errno (ERANGE); + close (sock); + return -1; + } + resultbuf->gr_passwd = p; + p += gr_resp.gr_passwd_len + 1; + buflen -= (gr_resp.gr_passwd_len + 1); + nbytes = read (sock, resultbuf->gr_passwd, gr_resp.gr_passwd_len); + if (nbytes != gr_resp.gr_passwd_len) + { + close (sock); + return 1; + } + resultbuf->gr_passwd[gr_resp.gr_passwd_len] = '\0'; + + resultbuf->gr_gid = gr_resp.gr_gid; + + if (buflen < ((gr_resp.gr_mem_len + 1) * sizeof (char *))) + { + __set_errno (ERANGE); + close (sock); + return -1; + } + resultbuf->gr_mem = (char **)p; + p += ((gr_resp.gr_mem_len + 1) * sizeof (char *)); + buflen -= ((gr_resp.gr_mem_len + 1) * sizeof (char *)); + + resultbuf->gr_mem[gr_resp.gr_mem_len] = NULL; + + for (i = 0; i < gr_resp.gr_mem_len; ++i) + { + size_t len; + nbytes = read (sock, &len, sizeof (len)); + if (nbytes != sizeof (len)) + { + close (sock); + return 1; + } + + if (buflen < (len + 1)) + { + __set_errno (ERANGE); + close (sock); + return -1; + } + resultbuf->gr_mem[i] = p; + p += len + 1; + buflen -= (len + 1); + nbytes = read (sock, resultbuf->gr_mem[i], len); + resultbuf->gr_mem[i][len] = '\0'; + if (nbytes != len) + { + close (sock); + return 1; + } + } + } + close (sock); + return 0; +} diff --git a/nscd/nscd_getpw_r.c b/nscd/nscd_getpw_r.c new file mode 100644 index 0000000000..c956abc3b4 --- /dev/null +++ b/nscd/nscd_getpw_r.c @@ -0,0 +1,198 @@ +/* Copyright (C) 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@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 <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <sys/un.h> + +#include "nscd.h" + +static int __nscd_getpw_r (const char *key, request_type type, + struct passwd *resultbuf, char *buffer, + size_t buflen); + +int +__nscd_getpwnam_r (const char *name, struct passwd *resultbuf, char *buffer, + size_t buflen) +{ + if (name == NULL) + return 1; + + return __nscd_getpw_r (name, GETPWBYNAME, resultbuf, buffer, buflen); +} + +int +__nscd_getpwuid_r (uid_t uid, struct passwd *resultbuf, char *buffer, + size_t buflen) +{ + char *p = buffer; + char plen; + + plen = snprintf (buffer, buflen, "%d", uid); + if (plen == -1) + { + __set_errno (ERANGE); + return -1; + } + p = buffer + plen + 1; + + return __nscd_getpw_r (buffer, GETPWBYUID, resultbuf, p, buflen - plen -1); +} + +/* Create a socket connected to a name. */ +static 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; +} + +static int +__nscd_getpw_r (const char *key, request_type type, struct passwd *resultbuf, + char *buffer, size_t buflen) +{ + int sock = nscd_open_socket (); + request_header req; + pw_response_header pw_resp; + ssize_t nbytes; + + if (sock == -1) + return 1; + + req.version = NSCD_VERSION; + req.type = type; + req.key_len = strlen (key); + nbytes = write (sock, &req, sizeof (request_header)); + if (nbytes != sizeof (request_header)) + { + close (sock); + return 1; + } + + nbytes = write (sock, key, req.key_len); + if (nbytes != req.key_len) + { + close (sock); + return 1; + } + + nbytes = read (sock, &pw_resp, sizeof (pw_response_header)); + if (nbytes != sizeof (pw_response_header)) + { + close (sock); + return 1; + } + + if (pw_resp.found == -1) + { + close (sock); + return 1; + } + + if (pw_resp.found == 1) + { + struct iovec vec[5]; + char *p = buffer; + + if (buflen < pw_resp.pw_name_len + 1 + pw_resp.pw_passwd_len + 1 + + pw_resp.pw_gecos_len + 1 + pw_resp.pw_dir_len + 1 + + pw_resp.pw_shell_len + 1) + { + __set_errno (ERANGE); + close (sock); + return -1; + } + + /* get pw_name */ + vec[0].iov_base = p; + vec[0].iov_len = pw_resp.pw_name_len; + p += pw_resp.pw_name_len + 1; + buflen -= (pw_resp.pw_name_len + 1); + /* get pw_passwd */ + vec[1].iov_base = p; + vec[1].iov_len = pw_resp.pw_passwd_len; + p += pw_resp.pw_passwd_len + 1; + buflen -= (pw_resp.pw_passwd_len + 1); + /* get pw_gecos */ + vec[2].iov_base = p; + vec[2].iov_len = pw_resp.pw_gecos_len; + p += pw_resp.pw_gecos_len + 1; + buflen -= (pw_resp.pw_gecos_len + 1); + /* get pw_dir */ + vec[3].iov_base = p; + vec[3].iov_len = pw_resp.pw_dir_len; + p += pw_resp.pw_dir_len + 1; + buflen -= (pw_resp.pw_dir_len + 1); + /* get pw_pshell */ + vec[4].iov_base = p; + vec[4].iov_len = pw_resp.pw_dir_len; + p += pw_resp.pw_dir_len + 1; + buflen -= (pw_resp.pw_dir_len + 1); + + nbytes = readv (sock, vec, 5); + if (nbytes != pw_resp.pw_name_len + 1 + pw_resp.pw_passwd_len + 1 + + pw_resp.pw_gecos_len + 1 + pw_resp.pw_dir_len + 1 + + pw_resp.pw_shell_len + 1) + { + close (sock); + return 1; + } + + resultbuf->pw_name = vec[0].iov_base; + resultbuf->pw_name[pw_resp.pw_name_len] = '\0'; + resultbuf->pw_passwd = vec[1].iov_base; + resultbuf->pw_passwd[pw_resp.pw_passwd_len] = '\0'; + resultbuf->pw_uid = pw_resp.pw_uid; + resultbuf->pw_gid = pw_resp.pw_gid; + resultbuf->pw_gecos = vec[2].iov_base; + resultbuf->pw_gecos[pw_resp.pw_gecos_len] = '\0'; + resultbuf->pw_dir = vec[3].iov_base; + resultbuf->pw_dir[pw_resp.pw_dir_len] = '\0'; + resultbuf->pw_shell = vec[4].iov_base; + resultbuf->pw_shell[pw_resp.pw_shell_len] = '\0'; + + close (sock); + return 0; + } + else + { + close (sock); + return -1; + } +} diff --git a/nscd/nscd_proto.h b/nscd/nscd_proto.h new file mode 100644 index 0000000000..6f7b30df88 --- /dev/null +++ b/nscd/nscd_proto.h @@ -0,0 +1,35 @@ +/* Copyright (C) 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@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. */ + +#ifndef _NSCD_PROTO_H +#define _NSCD_PROTO_H 1 + +#include <grp.h> +#include <pwd.h> + +extern int __nscd_getpwnam_r __P ((const char *name, struct passwd *resultbuf, + char *buffer, size_t buflen)); +extern int __nscd_getpwuid_r __P ((uid_t uid, struct passwd *resultbuf, + char *buffer, size_t buflen)); +extern int __nscd_getgrnam_r __P ((const char *name, struct group *resultbuf, + char *buffer, size_t buflen)); +extern int __nscd_getgrgid_r __P ((uid_t uid, struct group *resultbuf, + char *buffer, size_t buflen)); + +#endif /* _NSCD_PROTO_H */ diff --git a/nscd/nscd_stat.c b/nscd/nscd_stat.c new file mode 100644 index 0000000000..d8182885ac --- /dev/null +++ b/nscd/nscd_stat.c @@ -0,0 +1,87 @@ +/* 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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include "nscd.h" + +void +print_stat (void) +{ + int sock = __nscd_open_socket (); + request_header req; + stat_response_header resp; + ssize_t nbytes; + + if (sock == -1) + { + fputs (_("nscd not running!\n"), stdout); + exit (EXIT_FAILURE); + } + + req.version = NSCD_VERSION; + req.type = GETSTAT; + req.key_len = 0; + nbytes = write (sock, &req, sizeof (request_header)); + if (nbytes != sizeof (request_header)) + { + perror (_("write incomplete")); + close (sock); + exit (EXIT_FAILURE); + } + + nbytes = read (sock, &resp, sizeof (stat_response_header)); + if (nbytes != sizeof (stat_response_header)) + { + perror (_("read incomplete")); + close (sock); + exit (EXIT_FAILURE); + } + + close (sock); + + printf (_("nscd configuration:\n\n")); + printf (_("%12d server debug level\n\n"), resp.debug_level); + + printf (_("passwd cache:\n\n")); + printf (_("%12s cache is enabled\n"), resp.pw_enabled ? _("Yes") : _("No")); + printf (_("%12ld cache hits on positive entries\n"), resp.pw_poshit); + printf (_("%12ld cache hits on negative entries\n"), resp.pw_neghit); + printf (_("%12ld cache misses on positive entries\n"), resp.pw_posmiss); + printf (_("%12ld cache misses on negative entries\n"), resp.pw_negmiss); + printf (_("%12ld suggested size\n"), resp.pw_size); + printf (_("%12ld seconds time to live for positive entries\n"), + resp.pw_posttl); + printf (_("%12ld seconds time to live for negative entries\n\n"), + resp.pw_negttl); + + printf (_("group cache:\n\n")); + printf (_("%12s cache is enabled\n"), resp.gr_enabled ? _("Yes") : _("No")); + printf (_("%12ld cache hits on positive entries\n"), resp.gr_poshit); + printf (_("%12ld cache hits on negative entries\n"), resp.gr_neghit); + printf (_("%12ld cache misses on positive entries\n"), resp.gr_posmiss); + printf (_("%12ld cache misses on negative entries\n"), resp.gr_negmiss); + printf (_("%12ld suggested size\n"), resp.gr_size); + printf (_("%12ld seconds time to live for positive entries\n"), + resp.gr_posttl); + printf (_("%12ld seconds time to live for negative entries\n"), + resp.gr_negttl); +} diff --git a/nscd/pwdcache.c b/nscd/pwdcache.c new file mode 100644 index 0000000000..a3676666da --- /dev/null +++ b/nscd/pwdcache.c @@ -0,0 +1,581 @@ +/* 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 <malloc.h> +#include <pthread.h> +#include <pwd.h> +#include <string.h> +#include <rpcsvc/nis.h> +#include <sys/types.h> + +#include "dbg_log.h" +#include "nscd.h" + +static unsigned long int modulo = 211; +static unsigned long int postimeout = 600; +static unsigned long int negtimeout = 20; + +static unsigned long int poshit = 0; +static unsigned long int posmiss = 0; +static unsigned long int neghit = 0; +static unsigned long int negmiss = 0; + +struct pwdhash +{ + time_t create; + struct pwdhash *next; + struct passwd *pwd; +}; +typedef struct pwdhash pwdhash; + +struct uidhash +{ + struct uidhash *next; + struct pwdhash *pwptr; +}; +typedef struct uidhash uidhash; + +struct neghash +{ + time_t create; + struct neghash *next; + char *key; +}; +typedef struct neghash neghash; + +static pwdhash *pwdtbl; +static uidhash *uidtbl; +static neghash *negtbl; + +static pthread_rwlock_t pwdlock = PTHREAD_RWLOCK_INITIALIZER; +static pthread_rwlock_t neglock = PTHREAD_RWLOCK_INITIALIZER; + +static void *pwdtable_update (void *); +static void *negtable_update (void *); + +void +get_pw_stat (stat_response_header *stat) +{ + stat->pw_poshit = poshit; + stat->pw_posmiss = posmiss; + stat->pw_neghit = neghit; + stat->pw_negmiss = negmiss; + stat->pw_size = modulo; + stat->pw_posttl = postimeout; + stat->pw_negttl = negtimeout; +} + +void +set_pwd_modulo (unsigned long int mod) +{ + modulo = mod; +} + +void +set_pos_pwd_ttl (unsigned long int ttl) +{ + postimeout = ttl; +} + +void +set_neg_pwd_ttl (unsigned long int ttl) +{ + negtimeout = ttl; +} + +int +cache_pwdinit () +{ + pthread_t thread; + + pwdtbl = calloc (modulo, sizeof (pwdhash)); + if (pwdtbl == NULL) + return -1; + uidtbl = calloc (modulo, sizeof (pwdhash)); + if (uidtbl == NULL) + return -1; + negtbl = calloc (modulo, sizeof (neghash)); + if (negtbl == NULL) + return -1; + + pthread_create (&thread, NULL, pwdtable_update, (void *)NULL); + pthread_detach (thread); + pthread_create (&thread, NULL, negtable_update, (void *)NULL); + pthread_detach (thread); + return 0; +} + +static struct passwd * +save_pwd (struct passwd *src) +{ + struct passwd *dest; + + dest = calloc (1, sizeof (struct passwd)); + dest->pw_name = strdup (src->pw_name); + dest->pw_passwd = strdup (src->pw_passwd); + dest->pw_uid = src->pw_uid; + dest->pw_gid = src->pw_gid; + dest->pw_gecos = strdup (src->pw_gecos); + dest->pw_dir = strdup (src->pw_dir); + dest->pw_shell = strdup (src->pw_shell); + + return dest; +} + +static void +free_pwd (struct passwd *src) +{ + free (src->pw_name); + free (src->pw_passwd); + free (src->pw_gecos); + free (src->pw_dir); + free (src->pw_shell); + free (src); +} + +static int +add_cache (struct passwd *pwd) +{ + pwdhash *work; + unsigned long int hash = __nis_hash (pwd->pw_name, + strlen (pwd->pw_name)) % modulo; + + if (debug_flag) + dbg_log (_("add_cache (%s)"), pwd->pw_name); + + work = &pwdtbl[hash]; + + if (pwdtbl[hash].pwd == NULL) + pwdtbl[hash].pwd = save_pwd (pwd); + else + { + while (work->next != NULL) + work = work->next; + + work->next = calloc (1, sizeof (pwdhash)); + work->next->pwd = save_pwd (pwd); + work = work->next; + } + /* Set a pointer from the pwuid hash table to the pwname hash table */ + time (&work->create); + uidtbl[pwd->pw_uid % modulo].pwptr = work; + + return 0; +} + +static struct passwd * +cache_search_name (const char *name) +{ + pwdhash *work; + unsigned long int hash = __nis_hash (name, strlen (name)) % modulo; + + work = &pwdtbl[hash]; + + while (work->pwd != NULL) + { + if (strcmp (work->pwd->pw_name, name) == 0) + return work->pwd; + if (work->next != NULL) + work = work->next; + else + return NULL; + } + return NULL; +} + +static struct passwd * +cache_search_uid (uid_t uid) +{ + uidhash *work; + + work = &uidtbl[uid % modulo]; + + while (work->pwptr != NULL) + { + if (work->pwptr->pwd->pw_uid == uid) + return work->pwptr->pwd; + 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; + + if (debug_flag) + dbg_log (_("add_netgache (%s|%ld)"), key, hash); + + work = &negtbl[hash]; + + if (negtbl[hash].key == NULL) + { + negtbl[hash].key = strdup (key); + negtbl[hash].next = NULL; + } + else + { + while (work->next != NULL) + work = work->next; + + work->next = calloc (1, sizeof (neghash)); + work->next->key = strdup (key); + work = work->next; + } + /* Set a pointer from the pwuid hash table to the pwname hash table */ + 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]; + + if (debug_flag) + dbg_log (_("cache_search_neg (%s|%ld)"), key, 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_getpwnam (void *v_param) +{ + param_t *param = (param_t *)v_param; + struct passwd *pwd, resultbuf; + + pthread_rwlock_rdlock (&pwdlock); + pwd = 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 (pwd != NULL) + { + if (debug_flag) + dbg_log (_("Found \"%s\" in cache !"), param->key); + + ++poshit; + pw_send_answer (param->conn, pwd); + close_socket (param->conn); + + pthread_rwlock_unlock (&pwdlock); + pwd = &resultbuf; + } + else + { + int status; + int buflen = 1024; + char *buffer = malloc (buflen); + + if (debug_flag) + dbg_log (_("Doesn't found \"%s\" in cache !"), param->key); + + pthread_rwlock_unlock (&pwdlock); + + pthread_rwlock_rdlock (&neglock); + status = cache_search_neg (param->key); + pthread_rwlock_unlock (&neglock); + + if (status == 0) + { + while (buffer != NULL + && (getpwnam_r (param->key, &resultbuf, buffer, buflen, &pwd) + != 0) + && errno == ERANGE) + { + errno = 0; + buflen += 1024; + buffer = realloc (buffer, buflen); + } + + if (buffer != NULL && pwd != NULL) + { + struct passwd *tmp; + + ++posmiss; + pthread_rwlock_wrlock (&pwdlock); + /* While we are waiting on the lock, somebody else could + add this entry. */ + tmp = cache_search_name (param->key); + if (tmp == NULL) + add_cache (pwd); + pthread_rwlock_unlock (&pwdlock); + } + else + { + ++negmiss; + pthread_rwlock_wrlock (&neglock); + add_negcache (param->key); + pthread_rwlock_unlock (&neglock); + } + } + else + ++neghit; + pw_send_answer (param->conn, pwd); + close_socket (param->conn); + if (buffer != NULL) + free (buffer); + } + free (param->key); + free (param); + return NULL; +} + +void * +cache_pw_disabled (void *v_param) +{ + param_t *param = (param_t *)v_param; + + pw_send_disabled (param->conn); + return NULL; +} + +void * +cache_getpwuid (void *v_param) +{ + param_t *param = (param_t *)v_param; + struct passwd *pwd, resultbuf; + uid_t uid = strtol (param->key, NULL, 10); + + pthread_rwlock_rdlock (&pwdlock); + pwd = cache_search_uid (uid); + + /* I don't like it to hold the read only lock longer, but it is + necessary to avoid to much malloc/free/strcpy. */ + + if (pwd != NULL) + { + if (debug_flag) + dbg_log (_("Found \"%d\" in cache !"), uid); + + ++poshit; + pw_send_answer (param->conn, pwd); + close_socket (param->conn); + + pthread_rwlock_unlock (&pwdlock); + } + else + { + int buflen = 1024; + char *buffer = malloc (buflen); + int status; + + if (debug_flag) + dbg_log (_("Doesn't found \"%d\" in cache !"), uid); + + pthread_rwlock_unlock (&pwdlock); + + pthread_rwlock_rdlock (&neglock); + status = cache_search_neg (param->key); + pthread_rwlock_unlock (&neglock); + + if (status == 0) + { + while (buffer != NULL + && (getpwuid_r (uid, &resultbuf, buffer, buflen, &pwd) != 0) + && errno == ERANGE) + { + errno = 0; + buflen += 1024; + buffer = realloc (buffer, buflen); + } + + if (buffer != NULL && pwd != NULL) + { + struct passwd *tmp; + + ++posmiss; + pthread_rwlock_wrlock (&pwdlock); + /* While we are waiting on the lock, somebody else could + add this entry. */ + tmp = cache_search_uid (uid); + if (tmp == NULL) + add_cache (pwd); + pthread_rwlock_unlock (&pwdlock); + } + else + { + ++negmiss; + pthread_rwlock_wrlock (&neglock); + add_negcache (param->key); + pthread_rwlock_unlock (&neglock); + } + } + else + ++neghit; + + pw_send_answer (param->conn, pwd); + close_socket (param->conn); + if (buffer != NULL) + free (buffer); + } + free (param->key); + free (param); + return NULL; +} + +void * +pwdtable_update (void *v) +{ + time_t now; + int i; + + sleep (20); + + while (!do_shutdown) + { + if (debug_flag > 2) + dbg_log (_("(pwdtable_update) Wait for write lock!")); + + pthread_rwlock_wrlock (&pwdlock); + + if (debug_flag > 2) + dbg_log (_("(pwdtable_update) Have write lock")); + + time (&now); + for (i = 0; i < modulo; ++i) + { + pwdhash *work = &pwdtbl[i]; + + while (work && work->pwd) + { + if ((now - work->create) >= postimeout) + { + uidhash *uh = &uidtbl[work->pwd->pw_uid % modulo]; + + if (debug_flag) + dbg_log (_("Give \"%s\" free"), work->pwd->pw_name); + + while (uh != NULL && uh->pwptr) + { + if (uh->pwptr->pwd->pw_uid == work->pwd->pw_uid) + { + if (debug_flag) + dbg_log (_("Give uid for \"%s\" free"), + work->pwd->pw_name); + if (uh->next != NULL) + { + uidhash *tmp = uh->next; + uh->pwptr = tmp->pwptr; + uh->next = tmp->next; + free (tmp); + } + else + uh->pwptr = NULL; + } + uh = uh->next; + } + + free_pwd (work->pwd); + if (work->next != NULL) + { + pwdhash *tmp = work->next; + work->create = tmp->create; + work->next = tmp->next; + work->pwd = tmp->pwd; + free (tmp); + } + else + work->pwd = NULL; + } + work = work->next; + } + } + if (debug_flag > 2) + dbg_log (_("(pwdtable_update) Release wait lock")); + pthread_rwlock_unlock (&pwdlock); + 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) + 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) + dbg_log (_("(negtable_update) Release wait lock")); + + pthread_rwlock_unlock (&neglock); + sleep (10); + } + return NULL; +} diff --git a/nss/getXXbyYY_r.c b/nss/getXXbyYY_r.c index 47df01054e..d20fa34498 100644 --- a/nss/getXXbyYY_r.c +++ b/nss/getXXbyYY_r.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1996, 1997 Free Software Foundation, Inc. +/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996. @@ -19,6 +19,7 @@ #include <errno.h> #include "nsswitch.h" +#include <nscd/nscd_proto.h> /*******************************************************************\ |* Here we assume several symbols to be defined: *| @@ -51,6 +52,12 @@ #define INTERNAL(name) INTERNAL1 (name) #define INTERNAL1(name) __##name +#ifdef USE_NSCD +# define NSCD_NAME ADD_NSCD (REENTRANT_NAME) +# define ADD_NSCD(name) ADD_NSCD1 (name) +# define ADD_NSCD1(name) __nscd_##name +#endif + #define FUNCTION_NAME_STRING STRINGIZE (FUNCTION_NAME) #define REENTRANT_NAME_STRING STRINGIZE (REENTRANT_NAME) #define DATABASE_NAME_STRING STRINGIZE (DATABASE_NAME) @@ -93,6 +100,9 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer, lookup_function fct; int no_more; enum nss_status status = NSS_STATUS_UNAVAIL; +#ifdef USE_NSCD + int nscd_status; +#endif #ifdef HANDLE_DIGITS_DOTS # define resbuf (*resbuf) @@ -100,6 +110,15 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer, # undef resbuf #endif +#ifdef USE_NSCD + nscd_status = NSCD_NAME (ADD_VARIABLES, resbuf, buffer, buflen H_ERRNO_VAR); + if (nscd_status < 1) + { + *result = nscd_status == 0 ? resbuf : NULL; + return nscd_status; + } +#endif + if (startp == NULL) { no_more = DB_LOOKUP_FCT (&nip, REENTRANT_NAME_STRING, (void **) &fct); diff --git a/pwd/getpwnam_r.c b/pwd/getpwnam_r.c index 0dc1eacaed..429d3c47b0 100644 --- a/pwd/getpwnam_r.c +++ b/pwd/getpwnam_r.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1996, 1997 Free Software Foundation, Inc. +/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996. @@ -26,5 +26,6 @@ #define ADD_PARAMS const char *name #define ADD_VARIABLES name #define BUFLEN NSS_BUFLEN_PASSWD +#define USE_NSCD 1 -#include "../nss/getXXbyYY_r.c" +#include <nss/getXXbyYY_r.c> diff --git a/pwd/getpwuid_r.c b/pwd/getpwuid_r.c index 4db8bc0317..18b925b794 100644 --- a/pwd/getpwuid_r.c +++ b/pwd/getpwuid_r.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1996, 1997 Free Software Foundation, Inc. +/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996. @@ -26,5 +26,6 @@ #define ADD_PARAMS uid_t uid #define ADD_VARIABLES uid #define BUFLEN NSS_BUFLEN_PASSWD +#define USE_NSCD 1 -#include "../nss/getXXbyYY_r.c" +#include <nss/getXXbyYY_r.c> diff --git a/sysdeps/unix/inet/Subdirs b/sysdeps/unix/inet/Subdirs index 0dc102b03f..4a191e2993 100644 --- a/sysdeps/unix/inet/Subdirs +++ b/sysdeps/unix/inet/Subdirs @@ -3,4 +3,5 @@ resolv hesiod sunrpc nis +nscd streams |