diff options
author | Roland McGrath <roland@gnu.org> | 2004-09-22 21:21:10 +0000 |
---|---|---|
committer | Roland McGrath <roland@gnu.org> | 2004-09-22 21:21:10 +0000 |
commit | b5707b44d25d7af61b0338c2a2206c036eaf7337 (patch) | |
tree | d8b9e865cbc78d64835a63959370865a2a043223 /glibc-compat | |
parent | 4ff389feb39f2eb649530b843d478c80c27ab4cf (diff) | |
download | glibc-b5707b44d25d7af61b0338c2a2206c036eaf7337.tar glibc-b5707b44d25d7af61b0338c2a2206c036eaf7337.tar.gz glibc-b5707b44d25d7af61b0338c2a2206c036eaf7337.tar.bz2 glibc-b5707b44d25d7af61b0338c2a2206c036eaf7337.zip |
Changes and additions migrated from cvs.devel.redhat.com:/cvs/devel/glibc to fedora-branch
Diffstat (limited to 'glibc-compat')
62 files changed, 12462 insertions, 0 deletions
diff --git a/glibc-compat/.cvsignore b/glibc-compat/.cvsignore new file mode 100644 index 0000000000..6eaa1d38eb --- /dev/null +++ b/glibc-compat/.cvsignore @@ -0,0 +1 @@ +glibc-compat*.tar.gz diff --git a/glibc-compat/Banner b/glibc-compat/Banner new file mode 100644 index 0000000000..7d4bde6291 --- /dev/null +++ b/glibc-compat/Banner @@ -0,0 +1 @@ +Glibc-2.0 compatibility add-on by Cristian Gafton diff --git a/glibc-compat/ChangeLog b/glibc-compat/ChangeLog new file mode 100644 index 0000000000..e61c488926 --- /dev/null +++ b/glibc-compat/ChangeLog @@ -0,0 +1,37 @@ +2000-04-13 Jakub Jelinek <jakub@redhat.com> + + * Makefile (services): revert last change. + (libnss1_db-routines): Add db-open. + (libnss1_db.so): Remove libdb dependencies, add libdl. + * nss_db/db-open.c: New file. + * nss_db/dummy-db.h: New file. + * nss_db/nss_db.h: New file. + * nss_db/db-XXX.c: Update from glibc 2.1.90 nss_db/db-XXX.c, + remove errnop passing and EXTRA_ARGS. + * nss_db/db-alias.c: Likewise. + * nss_db/db-netgrp.c: Likewise. + +2000-01-04 Cristian Gafton <gafton@redhat.com> + + * Makefile (services): disable the compat NSS module for + Berkeley DB (nss_db). Berkeley BD is not part of the glibc anymore. + +1999-07-08 Cristian Gafton <gafton@redhat.com> + + * stubs.c (__setfpucw): New function + * Makefile: Use -include, not include + (archive): New target. + +1999-04-09 Andreas Jaeger <aj@arthur.rhein-neckar.de> + * glibc-compat/Makefile: Add rules to link libnss_*.so.1 to libnss1_*.so.2. + +1998-11-18 Cristian Gafton <gafton@redhat.com> + + * shlib-versions: added alpha versions + + * Makefile (services): Added libnss_dns + +1998-11-16 Cristian Gafton <gafton@redhat.com> + + * makedist (archive): remove old tar file just in case + diff --git a/glibc-compat/Depend b/glibc-compat/Depend new file mode 100644 index 0000000000..89d8e5bfec --- /dev/null +++ b/glibc-compat/Depend @@ -0,0 +1,3 @@ +resolv +nss +nis diff --git a/glibc-compat/Makefile b/glibc-compat/Makefile new file mode 100644 index 0000000000..8c60483524 --- /dev/null +++ b/glibc-compat/Makefile @@ -0,0 +1,150 @@ +# Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + +# This 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. + +# $Id$ + +subdir := glibc-compat + +distribute := nss-nis.h + +# This is the trivial part which goes into libc itself. +routines = + +# These are the databases that go through nss dispatch. +# Caution: if you add a database here, you must add its real name +# in databases.def, too. +databases = proto service hosts network grp pwd rpc ethers \ + spwd netgrp alias + +# Specify rules for the nss_* modules. We have some services. +services := files nis compat dns + +extra-libs := $(services:%=libnss1_%) libNoVersion +# These libraries will be built in the `others' pass rather than +# the `lib' pass, because they depend on libc.so being built already. +extra-libs-others = $(extra-libs) + +# The sources are found in the appropriate subdir. +subdir-dirs = $(services:%=nss_%) +vpath %.c $(subdir-dirs) + +libnss1_files-routines := $(addprefix files-,$(databases)) +libnss1_compat-routines := $(addprefix compat-,grp pwd spwd) +libnss1_nis-routines := $(addprefix nis-,$(databases)) +libnss1_dns-routines := $(addprefix dns-, host network) + +libcompat-routines := $(addprefix old, fileops iofdopen iopopen stdfiles \ + iofclose iofopen pclose tmpfile) +libNoVersion-routines := stubs + +libnss1_files-inhibit-o = $(filter-out .os,$(object-suffixes)) +libnss1_compat-inhibit-o = $(filter-out .os,$(object-suffixes)) +libnss1_nis-inhibit-o = $(filter-out .os,$(object-suffixes)) +libnss1_dns-inhibit-o = $(filter-out .os,$(object-suffixes)) + +-include ../Rules + +# Force the soname to be libnss_*.so.1 for compatibility. +LDFLAGS-nss1_files.so = -Wl,-soname=lib$(libprefix)nss_files.so$($(@F)-version) +LDFLAGS-nss1_nis.so = -Wl,-soname=lib$(libprefix)nss_nis.so$($(@F)-version) +LDFLAGS-nss1_compat.so = -Wl,-soname=lib$(libprefix)nss_compat.so$($(@F)-version) +LDFLAGS-nss1_dns.so = -Wl,-soname=lib$(libprefix)nss_dns.so$($(@F)-version) + +-include ../Makeconfig + +ifeq (yes,$(build-shared)) +install-others += $(inst_slibdir)/libnss_files.so$(libnss1_files.so-version) \ + $(inst_slibdir)/libnss_nis.so$(libnss1_nis.so-version) \ + $(inst_slibdir)/libnss_compat.so$(libnss1_compat.so-version) \ + $(inst_slibdir)/libnss_dns.so$(libnss1_dns.so-version) +endif + +$(inst_slibdir)/libnss_files.so$(libnss1_files.so-version): $(inst_slibdir)/libnss1_files-$(version).so $(+force) + rm -f $@ + $(LN_S) $(<F) $@ + +$(inst_slibdir)/libnss_nis.so$(libnss1_nis.so-version): $(inst_slibdir)/libnss1_nis-$(version).so $(+force) + rm -f $@ + $(LN_S) $(<F) $@ + +$(inst_slibdir)/libnss_compat.so$(libnss1_compat.so-version): $(inst_slibdir)/libnss1_compat-$(version).so $(+force) + rm -f $@ + $(LN_S) $(<F) $@ + +$(inst_slibdir)/libnss_dns.so$(libnss1_dns.so-version): $(inst_slibdir)/libnss1_dns-$(version).so $(+force) + rm -f $@ + $(LN_S) $(<F) $@ + + +$(objpfx)libnss1_compat.so: $(common-objpfx)nis/libnsl.so$(libnsl.so-version) \ + $(objpfx)libnss1_files.so +$(objpfx)libnss1_nis.so: $(common-objpfx)nis/libnsl.so$(libnsl.so-version) \ + $(objpfx)libnss1_files.so + +# The DNS NSS modules needs the resolver. +#$(objpfx)libnss1_dns.so: $(filter-out $(common-objpfx)resolv/stamp.os, \ +# $(wildcard $(common-objpfx)resolv/*.os)) \ +# $(common-objpfx)libc.so +$(objpfx)libnss1_dns.so: $(common-objpfx)resolv/libresolv.so $(common-objpfx)libc.so + +# Depend on libc.so so a DT_NEEDED is generated in the shared objects. +# This ensures they will load libc.so for needed symbols if loaded by +# a statically-linked program that hasn't already loaded it. +$(objpfx)libnss1_compat.so: $(common-objpfx)nis/libnsl.so$(libnsl.so-version) \ + $(objpfx)libnss1_files.so $(common-objpfx)libc.so +$(objpfx)libnss1_dns.so: $(common-objpfx)resolv/libresolv.so \ + $(common-objpfx)libc.so +$(objpfs)libnss1_files.so: $(common-objpfx)libc.so +$(objpfx)libnss1_nis.so: $(common-objpfx)nis/libnsl.so$(libnsl.so-version) \ + $(objpfx)libnss1_files.so $(common-objpfx)libc.so + +check-abi-libNoVersion: $(..)scripts/extract-abilist.awk + @: +update-abi-libNoVersion: $(..)scripts/merge-abilist.awk + @: +check-abi-libnss1_compat: $(..)scripts/extract-abilist.awk + @: +update-abi-libnss1_compat: $(..)scripts/merge-abilist.awk + @: +check-abi-libnss1_dns: $(..)scripts/extract-abilist.awk + @: +update-abi-libnss1_dns: $(..)scripts/merge-abilist.awk + @: +check-abi-libnss1_files: $(..)scripts/extract-abilist.awk + @: +update-abi-libnss1_files: $(..)scripts/merge-abilist.awk + @: +check-abi-libnss1_nis: $(..)scripts/extract-abilist.awk + @: +update-abi-libnss1_nis: $(..)scripts/merge-abilist.awk + @: + +# +# This is needed to build the separate tarball +# +pkgNAME = $(subdir) +pkgVERSION = 2.1.3 +pkgCVSTAG = $(pkgNAME)_$(subst .,-,$(pkgVERSION)) + +archive: + @rm -f *.tar.gz *~ + cvs tag -F $(pkgCVSTAG) . + @rm -rf /tmp/$(pkgNAME)-$(pkgVERSION) /tmp/$(pkgNAME) $(pkgNAME)-$(pkgVERSION).tar.gz + @cd /tmp; cvs export -r$(pkgCVSTAG) $(pkgNAME) + @pkgDIR=$$PWD; cd /tmp; tar cvzf $$pkgDIR/$(pkgNAME)-$(pkgVERSION).tar.gz $(pkgNAME) + @rm -rf /tmp/$(pkgNAME) + @echo "The archive is in $(pkgNAME)-$(pkgVERSION).tar.gz" diff --git a/glibc-compat/Versions b/glibc-compat/Versions new file mode 100644 index 0000000000..354d5b62a6 --- /dev/null +++ b/glibc-compat/Versions @@ -0,0 +1,106 @@ +libnss1_db { + GLIBC_2.0 { + _nss_db_endaliasent; _nss_db_endetherent; _nss_db_endgrent; + _nss_db_endnetgrent; _nss_db_endprotoent; _nss_db_endpwent; + _nss_db_endrpcent; _nss_db_endservent; _nss_db_endspent; + _nss_db_getaliasbyname_r; _nss_db_getaliasent_r; _nss_db_getetherent_r; + _nss_db_getgrent_r; _nss_db_getgrgid_r; _nss_db_getgrnam_r; + _nss_db_gethostton_r; _nss_db_getnetgrent_r; _nss_db_getntohost_r; + _nss_db_getprotobyname_r; _nss_db_getprotobynumber_r; + _nss_db_getprotoent_r; _nss_db_getpwent_r; _nss_db_getpwnam_r; + _nss_db_getpwuid_r; _nss_db_getrpcbyname_r; _nss_db_getrpcbynumber_r; + _nss_db_getrpcent_r; _nss_db_getservbyname_r; _nss_db_getservbyport_r; + _nss_db_getservent_r; _nss_db_getspent_r; _nss_db_getspnam_r; + _nss_db_setaliasent; _nss_db_setetherent; _nss_db_setgrent; + _nss_db_setnetgrent; _nss_db_setprotoent; _nss_db_setpwent; + _nss_db_setrpcent; _nss_db_setservent; _nss_db_setspent; + } +} + +libnss1_dns { + GLIBC_2.0 { + _nss_dns_gethostbyaddr_r; _nss_dns_gethostbyname2_r; + _nss_dns_gethostbyname_r; _nss_dns_getnetbyaddr_r; + _nss_dns_getnetbyname_r; + } +} + +libnss1_files { + GLIBC_2.0 { + _nss_files_setaliasent; _nss_files_endaliasent; + _nss_files_getaliasbyname_r; _nss_files_getaliasent_r; + + _nss_files_setetherent; _nss_files_endetherent; + _nss_files_getetherent_r; _nss_files_parse_etherent; + + _nss_files_setgrent; _nss_files_endgrent; + _nss_files_getgrent_r; _nss_files_getgrgid_r; _nss_files_getgrnam_r; + + _nss_files_sethostent; _nss_files_endhostent; + _nss_files_gethostbyaddr_r; _nss_files_gethostbyname2_r; _nss_files_gethostbyname_r; + _nss_files_gethostent_r; _nss_files_gethostton_r; + + _nss_files_setnetent; _nss_files_endnetent; + _nss_files_getnetbyaddr_r; _nss_files_getnetbyname_r; + _nss_files_getnetent_r; _nss_files_getntohost_r; + _nss_files_parse_netent; + + _nss_files_setnetgrent; _nss_files_endnetgrent; _nss_files_getnetgrent_r; + + _nss_files_setprotoent; _nss_files_endprotoent; + _nss_files_getprotobyname_r; _nss_files_getprotobynumber_r; + _nss_files_getprotoent_r; _nss_files_parse_protoent; + + _nss_files_setpwent; _nss_files_endpwent; + _nss_files_getpwent_r; _nss_files_getpwnam_r; _nss_files_getpwuid_r; + + _nss_files_setrpcent; _nss_files_endrpcent; + _nss_files_getrpcbyname_r; _nss_files_getrpcbynumber_r; + _nss_files_getrpcent_r; + _nss_files_parse_rpcent; + + _nss_files_setservent; _nss_files_endservent; + _nss_files_getservbyname_r; _nss_files_getservbyport_r; + _nss_files_getservent_r; + _nss_files_parse_servent; + + _nss_files_setspent; _nss_files_endspent; + _nss_files_getspent_r; _nss_files_getspnam_r; + + _nss_netgroup_parseline; + } +} + +libnss1_compat { + GLIBC_2.0 { + _nss_compat_endgrent; _nss_compat_endpwent; _nss_compat_endspent; + _nss_compat_getgrent_r; _nss_compat_getgrgid_r; _nss_compat_getgrnam_r; + _nss_compat_getpwent_r; _nss_compat_getpwnam_r; _nss_compat_getpwuid_r; + _nss_compat_getspent_r; _nss_compat_getspnam_r; _nss_compat_initgroups; + _nss_compat_setgrent; _nss_compat_setpwent; _nss_compat_setspent; + } +} + +libnss1_nis { + GLIBC_2.0 { + _nss_nis_endaliasent; _nss_nis_endetherent; _nss_nis_endgrent; + _nss_nis_endhostent; _nss_nis_endnetent; _nss_nis_endnetgrent; + _nss_nis_endprotoent; _nss_nis_endpwent; _nss_nis_endrpcent; + _nss_nis_endservent; _nss_nis_endspent; _nss_nis_getaliasbyname_r; + _nss_nis_getaliasent_r; _nss_nis_getetherent_r; _nss_nis_getgrent_r; + _nss_nis_getgrgid_r; _nss_nis_getgrnam_r; _nss_nis_gethostbyaddr_r; + _nss_nis_gethostbyname2_r; _nss_nis_gethostbyname_r; _nss_nis_gethostent_r; + _nss_nis_gethostton_r; _nss_nis_getnetbyaddr_r; _nss_nis_getnetbyname_r; + _nss_nis_getnetent_r; _nss_nis_getnetgrent_r; _nss_nis_getntohost_r; + _nss_nis_getprotobyname_r; _nss_nis_getprotobynumber_r; + _nss_nis_getprotoent_r; _nss_nis_getpublickey; _nss_nis_getpwent_r; + _nss_nis_getpwnam_r; _nss_nis_getpwuid_r; _nss_nis_getrpcbyname_r; + _nss_nis_getrpcbynumber_r; _nss_nis_getrpcent_r; _nss_nis_getsecretkey; + _nss_nis_getservbyname_r; _nss_nis_getservbyport_r; _nss_nis_getservent_r; + _nss_nis_getspent_r; _nss_nis_getspnam_r; _nss_nis_initgroups; + _nss_nis_netname2user; _nss_nis_setaliasent; _nss_nis_setetherent; + _nss_nis_setgrent; _nss_nis_sethostent; _nss_nis_setnetent; + _nss_nis_setnetgrent; _nss_nis_setprotoent; _nss_nis_setpwent; + _nss_nis_setrpcent; _nss_nis_setservent; _nss_nis_setspent; + } +} diff --git a/glibc-compat/Versions.def b/glibc-compat/Versions.def new file mode 100644 index 0000000000..742eda0f2c --- /dev/null +++ b/glibc-compat/Versions.def @@ -0,0 +1,15 @@ +libnss1_files { + GLIBC_2.0 +} +libnss1_db { + GLIBC_2.0 +} +libnss1_dns { + GLIBC_2.0 +} +libnss1_nis { + GLIBC_2.0 +} +libnss1_compat { + GLIBC_2.0 +} diff --git a/glibc-compat/configure b/glibc-compat/configure new file mode 100755 index 0000000000..53d0dcd67e --- /dev/null +++ b/glibc-compat/configure @@ -0,0 +1,3 @@ +# This is only to keep the GNU C library configure mechanism happy. +# This is a shell script fragment sourced by the main configure script. +# We have nothing we need to add here. diff --git a/glibc-compat/include/aliases.h b/glibc-compat/include/aliases.h new file mode 100644 index 0000000000..3932e52097 --- /dev/null +++ b/glibc-compat/include/aliases.h @@ -0,0 +1,20 @@ +#ifndef _ALIASES_H +#include <inet/aliases.h> + +extern int __getaliasent_r (struct aliasent *__restrict __result_buf, + char *__restrict __buffer, size_t __buflen, + struct aliasent **__restrict __result); +extern int __old_getaliasent_r (struct aliasent *__restrict __result_buf, + char *__restrict __buffer, size_t __buflen, + struct aliasent **__restrict __result); + +extern int __getaliasbyname_r (__const char *__restrict __name, + struct aliasent *__restrict __result_buf, + char *__restrict __buffer, size_t __buflen, + struct aliasent **__restrict __result); +extern int __old_getaliasbyname_r (__const char *__restrict __name, + struct aliasent *__restrict __result_buf, + char *__restrict __buffer, size_t __buflen, + struct aliasent **__restrict __result); + +#endif diff --git a/glibc-compat/include/grp.h b/glibc-compat/include/grp.h new file mode 100644 index 0000000000..aba77c6e8c --- /dev/null +++ b/glibc-compat/include/grp.h @@ -0,0 +1,29 @@ +#ifndef _GRP_H +#include <grp/grp.h> + +/* Now define the internal interfaces. */ +extern int __getgrent_r (struct group *__resultbuf, char *buffer, + size_t __buflen, struct group **__result); +extern int __old_getgrent_r (struct group *__resultbuf, char *buffer, + size_t __buflen, struct group **__result); +extern int __fgetgrent_r (FILE * __stream, struct group *__resultbuf, + char *buffer, size_t __buflen, + struct group **__result); + +/* Search for an entry with a matching group ID. */ +extern int __getgrgid_r (__gid_t __gid, struct group *__resultbuf, + char *__buffer, size_t __buflen, + struct group **__result); +extern int __old_getgrgid_r (__gid_t __gid, struct group *__resultbuf, + char *__buffer, size_t __buflen, + struct group **__result); + +/* Search for an entry with a matching group name. */ +extern int __getgrnam_r (__const char *__name, struct group *__resultbuf, + char *__buffer, size_t __buflen, + struct group **__result); +extern int __old_getgrnam_r (__const char *__name, struct group *__resultbuf, + char *__buffer, size_t __buflen, + struct group **__result); + +#endif diff --git a/glibc-compat/include/netdb.h b/glibc-compat/include/netdb.h new file mode 100644 index 0000000000..85ab234177 --- /dev/null +++ b/glibc-compat/include/netdb.h @@ -0,0 +1,178 @@ +#ifndef _NETDB_H +#include <glibc-compat/include/rpc/netdb.h> +#include <resolv/netdb.h> + +/* Macros for accessing h_errno from inside libc. */ +# ifdef _LIBC_REENTRANT +# include <tls.h> +# if USE___THREAD +# undef h_errno +# ifndef NOT_IN_libc +# define h_errno __libc_h_errno +# else +# define h_errno h_errno /* For #ifndef h_errno tests. */ +# endif +extern __thread int h_errno attribute_tls_model_ie; +# define __set_h_errno(x) (h_errno = (x)) +# else +static inline int +__set_h_errno (int __err) +{ + return *__h_errno_location () = __err; +} +# endif +# else +# undef h_errno +# define __set_h_errno(x) (h_errno = (x)) +extern int h_errno; +# endif /* _LIBC_REENTRANT */ + +/* Document internal interfaces. */ +extern int __gethostent_r (struct hostent *__restrict __result_buf, + char *__restrict __buf, size_t __buflen, + struct hostent **__restrict __result, + int *__restrict __h_errnop); +extern int __old_gethostent_r (struct hostent *__restrict __result_buf, + char *__restrict __buf, size_t __buflen, + struct hostent **__restrict __result, + int *__restrict __h_errnop); + +extern int __gethostbyaddr_r (__const void *__restrict __addr, + socklen_t __len, int __type, + struct hostent *__restrict __result_buf, + char *__restrict __buf, size_t __buflen, + struct hostent **__restrict __result, + int *__restrict __h_errnop); +extern int __old_gethostbyaddr_r (__const void *__restrict __addr, + socklen_t __len, int __type, + struct hostent *__restrict __result_buf, + char *__restrict __buf, size_t __buflen, + struct hostent **__restrict __result, + int *__restrict __h_errnop); + +extern int __gethostbyname_r (__const char *__restrict __name, + struct hostent *__restrict __result_buf, + char *__restrict __buf, size_t __buflen, + struct hostent **__restrict __result, + int *__restrict __h_errnop); +extern int __old_gethostbyname_r (__const char *__restrict __name, + struct hostent *__restrict __result_buf, + char *__restrict __buf, size_t __buflen, + struct hostent **__restrict __result, + int *__restrict __h_errnop); + +extern int __gethostbyname2_r (__const char *__restrict __name, int __af, + struct hostent *__restrict __result_buf, + char *__restrict __buf, size_t __buflen, + struct hostent **__restrict __result, + int *__restrict __h_errnop); +extern int __old_gethostbyname2_r (__const char *__restrict __name, int __af, + struct hostent *__restrict __result_buf, + char *__restrict __buf, size_t __buflen, + struct hostent **__restrict __result, + int *__restrict __h_errnop); + +extern int __getnetent_r (struct netent *__restrict __result_buf, + char *__restrict __buf, size_t __buflen, + struct netent **__restrict __result, + int *__restrict __h_errnop); +extern int __old_getnetent_r (struct netent *__restrict __result_buf, + char *__restrict __buf, size_t __buflen, + struct netent **__restrict __result, + int *__restrict __h_errnop); + +extern int __getnetbyaddr_r (uint32_t __net, int __type, + struct netent *__restrict __result_buf, + char *__restrict __buf, size_t __buflen, + struct netent **__restrict __result, + int *__restrict __h_errnop); +extern int __old_getnetbyaddr_r (uint32_t __net, int __type, + struct netent *__restrict __result_buf, + char *__restrict __buf, size_t __buflen, + struct netent **__restrict __result, + int *__restrict __h_errnop); + +extern int __getnetbyname_r (__const char *__restrict __name, + struct netent *__restrict __result_buf, + char *__restrict __buf, size_t __buflen, + struct netent **__restrict __result, + int *__restrict __h_errnop); +extern int __old_getnetbyname_r (__const char *__restrict __name, + struct netent *__restrict __result_buf, + char *__restrict __buf, size_t __buflen, + struct netent **__restrict __result, + int *__restrict __h_errnop); + +extern int __getservent_r (struct servent *__restrict __result_buf, + char *__restrict __buf, size_t __buflen, + struct servent **__restrict __result); +extern int __old_getservent_r (struct servent *__restrict __result_buf, + char *__restrict __buf, size_t __buflen, + struct servent **__restrict __result); + +extern int __getservbyname_r (__const char *__restrict __name, + __const char *__restrict __proto, + struct servent *__restrict __result_buf, + char *__restrict __buf, size_t __buflen, + struct servent **__restrict __result); +extern int __old_getservbyname_r (__const char *__restrict __name, + __const char *__restrict __proto, + struct servent *__restrict __result_buf, + char *__restrict __buf, size_t __buflen, + struct servent **__restrict __result); + +extern int __getservbyport_r (int __port, + __const char *__restrict __proto, + struct servent *__restrict __result_buf, + char *__restrict __buf, size_t __buflen, + struct servent **__restrict __result); +extern int __old_getservbyport_r (int __port, + __const char *__restrict __proto, + struct servent *__restrict __result_buf, + char *__restrict __buf, size_t __buflen, + struct servent **__restrict __result); + +extern int __getprotoent_r (struct protoent *__restrict __result_buf, + char *__restrict __buf, size_t __buflen, + struct protoent **__restrict __result); +extern int __old_getprotoent_r (struct protoent *__restrict __result_buf, + char *__restrict __buf, size_t __buflen, + struct protoent **__restrict __result); + +extern int __getprotobyname_r (__const char *__restrict __name, + struct protoent *__restrict __result_buf, + char *__restrict __buf, size_t __buflen, + struct protoent **__restrict __result); +extern int __old_getprotobyname_r (__const char *__restrict __name, + struct protoent *__restrict __result_buf, + char *__restrict __buf, size_t __buflen, + struct protoent **__restrict __result); + +extern int __getprotobynumber_r (int __proto, + struct protoent *__restrict __res_buf, + char *__restrict __buf, size_t __buflen, + struct protoent **__restrict __result); +extern int __old_getprotobynumber_r (int __proto, + struct protoent *__restrict __res_buf, + char *__restrict __buf, size_t __buflen, + struct protoent **__restrict __result); + +extern int __getnetgrent_r (char **__restrict __hostp, + char **__restrict __userp, + char **__restrict __domainp, + char *__restrict __buffer, size_t __buflen); + +extern int ruserpass (const char *host, const char **aname, + const char **apass); + + +/* The following declarations and definitions have been removed from + the public header since we don't want people to use them. */ + +#define AI_V4MAPPED 0x0008 /* IPv4-mapped addresses are acceptable. */ +#define AI_ALL 0x0010 /* Return both IPv4 and IPv6 addresses. */ +#define AI_ADDRCONFIG 0x0020 /* Use configuration of this host to choose + returned address type. */ +#define AI_DEFAULT (AI_V4MAPPED | AI_ADDRCONFIG) + +#endif /* !_NETDB_H */ diff --git a/glibc-compat/include/pwd.h b/glibc-compat/include/pwd.h new file mode 100644 index 0000000000..a0e94e6631 --- /dev/null +++ b/glibc-compat/include/pwd.h @@ -0,0 +1,25 @@ +#ifndef _PWD_H +#include <pwd/pwd.h> + +/* Now define the internal interfaces. */ +extern int __getpwent_r (struct passwd *__resultbuf, char *__buffer, + size_t __buflen, struct passwd **__result); +extern int __old_getpwent_r (struct passwd *__resultbuf, char *__buffer, + size_t __buflen, struct passwd **__result); +extern int __getpwuid_r (__uid_t __uid, struct passwd *__resultbuf, + char *__buffer, size_t __buflen, + struct passwd **__result); +extern int __old_getpwuid_r (__uid_t __uid, struct passwd *__resultbuf, + char *__buffer, size_t __buflen, + struct passwd **__result); +extern int __getpwnam_r (__const char *__name, struct passwd *__resultbuf, + char *__buffer, size_t __buflen, + struct passwd **__result); +extern int __old_getpwnam_r (__const char *__name, struct passwd *__resultbuf, + char *__buffer, size_t __buflen, + struct passwd **__result); +extern int __fgetpwent_r (FILE * __stream, struct passwd *__resultbuf, + char *__buffer, size_t __buflen, + struct passwd **__result); + +#endif diff --git a/glibc-compat/include/rpc/netdb.h b/glibc-compat/include/rpc/netdb.h new file mode 100644 index 0000000000..54a4b70052 --- /dev/null +++ b/glibc-compat/include/rpc/netdb.h @@ -0,0 +1,24 @@ +#ifndef _RPC_NETDB_H +#include <sunrpc/rpc/netdb.h> + +extern int __getrpcbyname_r (__const char *__name, struct rpcent *__result_buf, + char *__buffer, size_t __buflen, + struct rpcent **__result); +extern int __old_getrpcbyname_r (__const char *__name, + struct rpcent *__result_buf, + char *__buffer, size_t __buflen, + struct rpcent **__result); + +extern int __getrpcbynumber_r (int __number, struct rpcent *__result_buf, + char *__buffer, size_t __buflen, + struct rpcent **__result); +extern int __old_getrpcbynumber_r (int __number, struct rpcent *__result_buf, + char *__buffer, size_t __buflen, + struct rpcent **__result); + +extern int __getrpcent_r (struct rpcent *__result_buf, char *__buffer, + size_t __buflen, struct rpcent **__result); +extern int __old_getrpcent_r (struct rpcent *__result_buf, char *__buffer, + size_t __buflen, struct rpcent **__result); + +#endif diff --git a/glibc-compat/include/shadow.h b/glibc-compat/include/shadow.h new file mode 100644 index 0000000000..e9429d7369 --- /dev/null +++ b/glibc-compat/include/shadow.h @@ -0,0 +1,24 @@ +#ifndef _SHADOW_H +#include <shadow/shadow.h> + +/* Now define the internal interfaces. */ +extern int __getspent_r (struct spwd *__result_buf, char *__buffer, + size_t __buflen, struct spwd **__result); +extern int __old_getspent_r (struct spwd *__result_buf, char *__buffer, + size_t __buflen, struct spwd **__result); +extern int __getspnam_r (__const char *__name, struct spwd *__result_buf, + char *__buffer, size_t __buflen, + struct spwd **__result); +extern int __old_getspnam_r (__const char *__name, struct spwd *__result_buf, + char *__buffer, size_t __buflen, + struct spwd **__result); +extern int __sgetspent_r (__const char *__string, + struct spwd *__result_buf, char *__buffer, + size_t __buflen, struct spwd **__result); +extern int __fgetspent_r (FILE *__stream, struct spwd *__result_buf, + char *__buffer, size_t __buflen, + struct spwd **__result); +extern int __lckpwdf (void); +extern int __ulckpwdf (void); + +#endif diff --git a/glibc-compat/nss-nis.h b/glibc-compat/nss-nis.h new file mode 100644 index 0000000000..13ba62ed9f --- /dev/null +++ b/glibc-compat/nss-nis.h @@ -0,0 +1,58 @@ +/* Copyright (C) 1996 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. */ + +#ifndef _NIS_NSS_NIS_H +#define _NIS_NSS_NIS_H 1 + +#include <rpcsvc/ypclnt.h> + +#include "nsswitch.h" + + +/* Convert YP error number to NSS error number. */ +static enum nss_status yperr2nss_tab[] = +{ + [YPERR_SUCCESS] = NSS_STATUS_SUCCESS, + [YPERR_BADARGS] = NSS_STATUS_UNAVAIL, + [YPERR_RPC] = NSS_STATUS_UNAVAIL, + [YPERR_DOMAIN] = NSS_STATUS_UNAVAIL, + [YPERR_MAP] = NSS_STATUS_UNAVAIL, + [YPERR_KEY] = NSS_STATUS_NOTFOUND, + [YPERR_YPERR] = NSS_STATUS_UNAVAIL, + [YPERR_RESRC] = NSS_STATUS_TRYAGAIN, + [YPERR_NOMORE] = NSS_STATUS_NOTFOUND, + [YPERR_PMAP] = NSS_STATUS_UNAVAIL, + [YPERR_YPBIND] = NSS_STATUS_UNAVAIL, + [YPERR_YPSERV] = NSS_STATUS_UNAVAIL, + [YPERR_NODOM] = NSS_STATUS_UNAVAIL, + [YPERR_BADDB] = NSS_STATUS_UNAVAIL, + [YPERR_VERS] = NSS_STATUS_UNAVAIL, + [YPERR_ACCESS] = NSS_STATUS_UNAVAIL, + [YPERR_BUSY] = NSS_STATUS_TRYAGAIN +}; +#define YPERR_COUNT (sizeof (yperr2nss_tab) / sizeof (yperr2nss_tab[0])) + +static inline enum nss_status +yperr2nss (int errval) +{ + if ((unsigned int) errval > YPERR_COUNT) + return NSS_STATUS_UNAVAIL; + return yperr2nss_tab[errval]; +} + +#endif /* nis/nss-nis.h */ diff --git a/glibc-compat/nss_compat/compat-grp.c b/glibc-compat/nss_compat/compat-grp.c new file mode 100644 index 0000000000..d0780c4081 --- /dev/null +++ b/glibc-compat/nss_compat/compat-grp.c @@ -0,0 +1,769 @@ +/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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 <errno.h> +#include <fcntl.h> +#include <nss.h> +#include <glibc-compat/include/grp.h> +#include <ctype.h> +#include <bits/libc-lock.h> +#include <string.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> +#include <nsswitch.h> + +/* Get the declaration of the parser function. */ +#define ENTNAME grent +#define STRUCTURE group +#define EXTERN_PARSER +#include "../nss_files/files-parse.c" + +/* Structure for remembering -group members ... */ +#define BLACKLIST_INITIAL_SIZE 512 +#define BLACKLIST_INCREMENT 256 +struct blacklist_t + { + char *data; + int current; + int size; + }; + +struct ent_t + { + bool_t nis; + bool_t nis_first; + char *oldkey; + int oldkeylen; + FILE *stream; + struct blacklist_t blacklist; +}; +typedef struct ent_t ent_t; + +static ent_t ext_ent = {0, 0, NULL, 0, NULL, {NULL, 0, 0}}; + +/* Protect global state against multiple changers. */ +__libc_lock_define_initialized (static, lock) + +/* Prototypes for local functions. */ +static void blacklist_store_name (const char *, ent_t *); +static int in_blacklist (const char *, int, ent_t *); + +static enum nss_status +internal_setgrent (ent_t *ent) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + ent->nis = ent->nis_first = 0; + + if (ent->oldkey != NULL) + { + free (ent->oldkey); + ent->oldkey = NULL; + ent->oldkeylen = 0; + } + + if (ent->blacklist.data != NULL) + { + ent->blacklist.current = 1; + ent->blacklist.data[0] = '|'; + ent->blacklist.data[1] = '\0'; + } + else + ent->blacklist.current = 0; + + if (ent->stream == NULL) + { + ent->stream = fopen ("/etc/group", "r"); + + if (ent->stream == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + else + { + /* We have to make sure the file is `closed on exec'. */ + int result, flags; + + result = flags = fcntl (fileno (ent->stream), F_GETFD, 0); + if (result >= 0) + { + flags |= FD_CLOEXEC; + result = fcntl (fileno (ent->stream), F_SETFD, flags); + } + if (result < 0) + { + /* Something went wrong. Close the stream and return a + failure. */ + fclose (ent->stream); + ent->stream = NULL; + status = NSS_STATUS_UNAVAIL; + } + } + } + else + rewind (ent->stream); + + return status; +} + + +enum nss_status +_nss_compat_setgrent (void) +{ + enum nss_status result; + + __libc_lock_lock (lock); + + result = internal_setgrent (&ext_ent); + + __libc_lock_unlock (lock); + + return result; +} + + +static enum nss_status +internal_endgrent (ent_t *ent) +{ + if (ent->stream != NULL) + { + fclose (ent->stream); + ent->stream = NULL; + } + + ent->nis = ent->nis_first = 0; + + if (ent->oldkey != NULL) + { + free (ent->oldkey); + ent->oldkey = NULL; + ent->oldkeylen = 0; + } + + if (ent->blacklist.data != NULL) + { + ent->blacklist.current = 1; + ent->blacklist.data[0] = '|'; + ent->blacklist.data[1] = '\0'; + } + else + ent->blacklist.current = 0; + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_compat_endgrent (void) +{ + enum nss_status result; + + __libc_lock_lock (lock); + + result = internal_endgrent (&ext_ent); + + __libc_lock_unlock (lock); + + return result; +} + +static enum nss_status +getgrent_next_nis (struct group *result, ent_t *ent, char *buffer, + size_t buflen) +{ + struct parser_data *data = (void *) buffer; + char *domain; + char *outkey, *outval; + int outkeylen, outvallen, parse_res; + char *p; + + if (yp_get_default_domain (&domain) != YPERR_SUCCESS) + { + ent->nis = 0; + return NSS_STATUS_NOTFOUND; + } + + do + { + char *save_oldkey; + int save_oldlen; + bool_t save_nis_first; + + if (ent->nis_first) + { + if (yp_first (domain, "group.byname", &outkey, &outkeylen, + &outval, &outvallen) != YPERR_SUCCESS) + { + ent->nis = 0; + return NSS_STATUS_UNAVAIL; + } + save_oldkey = ent->oldkey; + save_oldlen = ent->oldkeylen; + save_nis_first = TRUE; + ent->oldkey = outkey; + ent->oldkeylen = outkeylen; + ent->nis_first = FALSE; + } + else + { + if (yp_next (domain, "group.byname", ent->oldkey, ent->oldkeylen, + &outkey, &outkeylen, &outval, &outvallen) + != YPERR_SUCCESS) + { + ent->nis = 0; + return NSS_STATUS_NOTFOUND; + } + + save_oldkey = ent->oldkey; + save_oldlen = ent->oldkeylen; + save_nis_first = FALSE; + ent->oldkey = outkey; + ent->oldkeylen = outkeylen; + } + + /* Copy the found data to our buffer */ + p = strncpy (buffer, outval, buflen); + + /* ...and free the data. */ + free (outval); + + while (isspace (*p)) + ++p; + + if ((parse_res = _nss_files_parse_grent (p, result, data, buflen)) == -1) + { + free (ent->oldkey); + ent->oldkey = save_oldkey; + ent->oldkeylen = save_oldlen; + ent->nis_first = save_nis_first; + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + else + { + if (!save_nis_first) + free (save_oldkey); + } + + if (parse_res && + in_blacklist (result->gr_name, strlen (result->gr_name), ent)) + parse_res = 0; /* if result->gr_name in blacklist,search next entry */ + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +/* This function handle the +group entrys in /etc/group */ +static enum nss_status +getgrnam_plusgroup (const char *name, struct group *result, char *buffer, + size_t buflen) +{ + struct parser_data *data = (void *) buffer; + int parse_res; + char *domain, *outval, *p; + int outvallen; + + if (yp_get_default_domain (&domain) != YPERR_SUCCESS) + return NSS_STATUS_NOTFOUND; + + if (yp_match (domain, "group.byname", name, strlen (name), + &outval, &outvallen) != YPERR_SUCCESS) + return NSS_STATUS_NOTFOUND; + p = strncpy (buffer, outval, + buflen < (size_t) outvallen ? buflen : (size_t) outvallen); + free (outval); + while (isspace (*p)) + p++; + if ((parse_res = _nss_files_parse_grent (p, result, data, buflen)) == -1) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + if (parse_res) + /* We found the entry. */ + return NSS_STATUS_SUCCESS; + else + return NSS_STATUS_RETURN; +} + +static enum nss_status +getgrent_next_file (struct group *result, ent_t *ent, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + while (1) + { + fpos_t pos; + int parse_res = 0; + char *p; + + do + { + fgetpos (ent->stream, &pos); + buffer[buflen - 1] = '\xff'; + p = fgets (buffer, buflen, ent->stream); + if (p == NULL && feof (ent->stream)) + return NSS_STATUS_NOTFOUND; + if (p == NULL || buffer[buflen - 1] != '\xff') + { + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + /* Terminate the line for any case. */ + buffer[buflen - 1] = '\0'; + + /* Skip leading blanks. */ + while (isspace (*p)) + ++p; + } + while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ + /* Parse the line. If it is invalid, loop to + get the next line of the file to parse. */ + !(parse_res = _nss_files_parse_grent (p, result, data, buflen))); + + if (parse_res == -1) + { + /* The parser ran out of space. */ + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + if (result->gr_name[0] != '+' && result->gr_name[0] != '-') + /* This is a real entry. */ + break; + + /* -group */ + if (result->gr_name[0] == '-' && result->gr_name[1] != '\0' + && result->gr_name[1] != '@') + { + blacklist_store_name (&result->gr_name[1], ent); + continue; + } + + /* +group */ + if (result->gr_name[0] == '+' && result->gr_name[1] != '\0' + && result->gr_name[1] != '@') + { + enum nss_status status; + + /* Store the group in the blacklist for the "+" at the end of + /etc/group */ + blacklist_store_name (&result->gr_name[1], ent); + status = getgrnam_plusgroup (&result->gr_name[1], result, buffer, + buflen); + if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ + break; + else + if (status == NSS_STATUS_RETURN /* We couldn't parse the entry */ + || status == NSS_STATUS_NOTFOUND) /* No group in NIS */ + continue; + else + { + if (status == NSS_STATUS_TRYAGAIN) + /* The parser ran out of space. */ + fsetpos (ent->stream, &pos); + return status; + } + } + + /* +:... */ + if (result->gr_name[0] == '+' && result->gr_name[1] == '\0') + { + ent->nis = TRUE; + ent->nis_first = TRUE; + + return getgrent_next_nis (result, ent, buffer, buflen); + } + } + + return NSS_STATUS_SUCCESS; +} + + +static enum nss_status +internal_getgrent_r (struct group *gr, ent_t *ent, char *buffer, + size_t buflen) +{ + if (ent->nis) + { + return getgrent_next_nis (gr, ent, buffer, buflen); + } + else + return getgrent_next_file (gr, ent, buffer, buflen); +} + +enum nss_status +_nss_compat_getgrent_r (struct group *grp, char *buffer, size_t buflen) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + __libc_lock_lock (lock); + + /* Be prepared that the setgrent function was not called before. */ + if (ext_ent.stream == NULL) + status = internal_setgrent (&ext_ent); + + if (status == NSS_STATUS_SUCCESS) + status = internal_getgrent_r (grp, &ext_ent, buffer, buflen); + + __libc_lock_unlock (lock); + + return status; +} + +/* Searches in /etc/group and the NIS/NIS+ map for a special group */ +static enum nss_status +internal_getgrnam_r (const char *name, struct group *result, ent_t *ent, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + while (1) + { + fpos_t pos; + int parse_res = 0; + char *p; + + do + { + fgetpos (ent->stream, &pos); + buffer[buflen - 1] = '\xff'; + p = fgets (buffer, buflen, ent->stream); + if (p == NULL && feof (ent->stream)) + return NSS_STATUS_NOTFOUND; + if (p == NULL || buffer[buflen - 1] != '\xff') + { + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + /* Terminate the line for any case. */ + buffer[buflen - 1] = '\0'; + + /* Skip leading blanks. */ + while (isspace (*p)) + ++p; + } + while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ + /* Parse the line. If it is invalid, loop to + get the next line of the file to parse. */ + !(parse_res = _nss_files_parse_grent (p, result, data, buflen))); + + if (parse_res == -1) + { + /* The parser ran out of space. */ + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + /* This is a real entry. */ + if (result->gr_name[0] != '+' && result->gr_name[0] != '-') + { + if (strcmp (result->gr_name, name) == 0) + return NSS_STATUS_SUCCESS; + else + continue; + } + + /* -group */ + if (result->gr_name[0] == '-' && result->gr_name[1] != '\0') + { + if (strcmp (&result->gr_name[1], name) == 0) + return NSS_STATUS_NOTFOUND; + else + continue; + } + + /* +group */ + if (result->gr_name[0] == '+' && result->gr_name[1] != '\0') + { + if (strcmp (name, &result->gr_name[1]) == 0) + { + enum nss_status status; + + status = getgrnam_plusgroup (name, result, buffer, buflen); + if (status == NSS_STATUS_RETURN) + /* We couldn't parse the entry */ + continue; + else + return status; + } + } + /* +:... */ + if (result->gr_name[0] == '+' && result->gr_name[1] == '\0') + { + enum nss_status status; + + status = getgrnam_plusgroup (name, result, buffer, buflen); + if (status == NSS_STATUS_RETURN) + /* We couldn't parse the entry */ + continue; + else + return status; + } + } + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_compat_getgrnam_r (const char *name, struct group *grp, + char *buffer, size_t buflen) +{ + ent_t ent = {0, 0, NULL, 0, NULL, {NULL, 0, 0}}; + enum nss_status status; + + if (name[0] == '-' || name[0] == '+') + return NSS_STATUS_NOTFOUND; + + __libc_lock_lock (lock); + + status = internal_setgrent (&ent); + + __libc_lock_unlock (lock); + + if (status != NSS_STATUS_SUCCESS) + return status; + + status = internal_getgrnam_r (name, grp, &ent, buffer, buflen); + + internal_endgrent (&ent); + + return status; +} + +/* This function handle the + entry in /etc/group */ +static enum nss_status +getgrgid_plusgroup (gid_t gid, struct group *result, char *buffer, + size_t buflen) +{ + struct parser_data *data = (void *) buffer; + int parse_res; + char buf[1024]; + char *domain, *outval, *p; + int outvallen; + + if (yp_get_default_domain (&domain) != YPERR_SUCCESS) + return NSS_STATUS_TRYAGAIN; + + snprintf (buf, sizeof (buf), "%d", gid); + + if (yp_match (domain, "group.bygid", buf, strlen (buf), + &outval, &outvallen) != YPERR_SUCCESS) + return NSS_STATUS_TRYAGAIN; + p = strncpy (buffer, outval, + buflen < (size_t) outvallen ? buflen : (size_t) outvallen); + free (outval); + while (isspace (*p)) + p++; + if ((parse_res = _nss_files_parse_grent (p, result, data, buflen)) == -1) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + if (parse_res) + /* We found the entry. */ + return NSS_STATUS_SUCCESS; + else + return NSS_STATUS_RETURN; +} + +/* Searches in /etc/group and the NIS/NIS+ map for a special group id */ +static enum nss_status +internal_getgrgid_r (gid_t gid, struct group *result, ent_t *ent, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + while (1) + { + fpos_t pos; + int parse_res = 0; + char *p; + + do + { + fgetpos (ent->stream, &pos); + buffer[buflen - 1] = '\xff'; + p = fgets (buffer, buflen, ent->stream); + if (p == NULL && feof (ent->stream)) + return NSS_STATUS_NOTFOUND; + if (p == NULL || buffer[buflen - 1] != '\xff') + { + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + /* Terminate the line for any case. */ + buffer[buflen - 1] = '\0'; + + /* Skip leading blanks. */ + while (isspace (*p)) + ++p; + } + while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ + /* Parse the line. If it is invalid, loop to + get the next line of the file to parse. */ + !(parse_res = _nss_files_parse_grent (p, result, data, buflen))); + + if (parse_res == -1) + { + /* The parser ran out of space. */ + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + /* This is a real entry. */ + if (result->gr_name[0] != '+' && result->gr_name[0] != '-') + { + if (result->gr_gid == gid) + return NSS_STATUS_SUCCESS; + else + continue; + } + + /* -group */ + if (result->gr_name[0] == '-' && result->gr_name[1] != '\0') + { + blacklist_store_name (&result->gr_name[1], ent); + continue; + } + + /* +group */ + if (result->gr_name[0] == '+' && result->gr_name[1] != '\0') + { + enum nss_status status; + + /* Store the group in the blacklist for the "+" at the end of + /etc/group */ + blacklist_store_name (&result->gr_name[1], ent); + status = getgrnam_plusgroup (&result->gr_name[1], result, buffer, + buflen); + if (status == NSS_STATUS_SUCCESS && result->gr_gid == gid) + break; + else + continue; + } + /* +:... */ + if (result->gr_name[0] == '+' && result->gr_name[1] == '\0') + { + enum nss_status status; + + status = getgrgid_plusgroup (gid, result, buffer, buflen); + if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ + return NSS_STATUS_NOTFOUND; + else + return status; + } + } + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_compat_getgrgid_r (gid_t gid, struct group *grp, + char *buffer, size_t buflen) +{ + ent_t ent = {0, 0, NULL, 0, NULL, {NULL, 0, 0}}; + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_setgrent (&ent); + + __libc_lock_unlock (lock); + + if (status != NSS_STATUS_SUCCESS) + return status; + + status = internal_getgrgid_r (gid, grp, &ent, buffer, buflen); + + internal_endgrent (&ent); + + return status; +} + + +/* Support routines for remembering -@netgroup and -user entries. + The names are stored in a single string with `|' as separator. */ +static void +blacklist_store_name (const char *name, ent_t *ent) +{ + int namelen = strlen (name); + char *tmp; + + /* first call, setup cache */ + if (ent->blacklist.size == 0) + { + ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen); + ent->blacklist.data = malloc (ent->blacklist.size); + if (ent->blacklist.data == NULL) + return; + ent->blacklist.data[0] = '|'; + ent->blacklist.data[1] = '\0'; + ent->blacklist.current = 1; + } + else + { + if (in_blacklist (name, namelen, ent)) + return; /* no duplicates */ + + if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size) + { + ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen); + tmp = realloc (ent->blacklist.data, ent->blacklist.size); + if (tmp == NULL) + { + free (ent->blacklist.data); + ent->blacklist.size = 0; + return; + } + ent->blacklist.data = tmp; + } + } + + tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name); + *tmp++ = '|'; + *tmp = '\0'; + ent->blacklist.current += namelen + 1; + + return; +} + +/* returns TRUE if ent->blacklist contains name, else FALSE */ +static bool_t +in_blacklist (const char *name, int namelen, ent_t *ent) +{ + char buf[namelen + 3]; + char *cp; + + if (ent->blacklist.data == NULL) + return FALSE; + + buf[0] = '|'; + cp = stpcpy (&buf[1], name); + *cp++= '|'; + *cp = '\0'; + return strstr (ent->blacklist.data, buf) != NULL; +} diff --git a/glibc-compat/nss_compat/compat-pwd.c b/glibc-compat/nss_compat/compat-pwd.c new file mode 100644 index 0000000000..5857bf9f78 --- /dev/null +++ b/glibc-compat/nss_compat/compat-pwd.c @@ -0,0 +1,1199 @@ +/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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 <nss.h> +#include <glibc-compat/include/pwd.h> +#include <errno.h> +#include <ctype.h> +#include <fcntl.h> +#include <glibc-compat/include/netdb.h> +#include <string.h> +#include <bits/libc-lock.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> +#include <nsswitch.h> + +#include "netgroup.h" + +/* Get the declaration of the parser function. */ +#define ENTNAME pwent +#define STRUCTURE passwd +#define EXTERN_PARSER +#include "../nss_files/files-parse.c" + +/* Structure for remembering -@netgroup and -user members ... */ +#define BLACKLIST_INITIAL_SIZE 512 +#define BLACKLIST_INCREMENT 256 +struct blacklist_t + { + char *data; + int current; + int size; + }; + +struct ent_t + { + bool_t netgroup; + bool_t nis; + bool_t first; + char *oldkey; + int oldkeylen; + FILE *stream; + struct blacklist_t blacklist; + struct passwd pwd; + struct __netgrent netgrdata; + }; +typedef struct ent_t ent_t; + +static ent_t ext_ent = {0, 0, 0, NULL, 0, NULL, {NULL, 0, 0}, + {NULL, NULL, 0, 0, NULL, NULL, NULL}}; + +/* Protect global state against multiple changers. */ +__libc_lock_define_initialized (static, lock) + +/* Prototypes for local functions. */ +static void blacklist_store_name (const char *, ent_t *); +static int in_blacklist (const char *, int, ent_t *); + +static void +give_pwd_free (struct passwd *pwd) +{ + if (pwd->pw_name != NULL) + free (pwd->pw_name); + if (pwd->pw_passwd != NULL) + free (pwd->pw_passwd); + if (pwd->pw_gecos != NULL) + free (pwd->pw_gecos); + if (pwd->pw_dir != NULL) + free (pwd->pw_dir); + if (pwd->pw_shell != NULL) + free (pwd->pw_shell); + + memset (pwd, '\0', sizeof (struct passwd)); +} + +static size_t +pwd_need_buflen (struct passwd *pwd) +{ + size_t len = 0; + + if (pwd->pw_passwd != NULL) + len += strlen (pwd->pw_passwd) + 1; + + if (pwd->pw_gecos != NULL) + len += strlen (pwd->pw_gecos) + 1; + + if (pwd->pw_dir != NULL) + len += strlen (pwd->pw_dir) + 1; + + if (pwd->pw_shell != NULL) + len += strlen (pwd->pw_shell) + 1; + + return len; +} + +static void +copy_pwd_changes (struct passwd *dest, struct passwd *src, + char *buffer, size_t buflen) +{ + if (src->pw_passwd != NULL && strlen (src->pw_passwd)) + { + if (buffer == NULL) + dest->pw_passwd = strdup (src->pw_passwd); + else if (dest->pw_passwd && + strlen (dest->pw_passwd) >= strlen (src->pw_passwd)) + strcpy (dest->pw_passwd, src->pw_passwd); + else + { + dest->pw_passwd = buffer; + strcpy (dest->pw_passwd, src->pw_passwd); + buffer += strlen (dest->pw_passwd) + 1; + buflen = buflen - (strlen (dest->pw_passwd) + 1); + } + } + + if (src->pw_gecos != NULL && strlen (src->pw_gecos)) + { + if (buffer == NULL) + dest->pw_gecos = strdup (src->pw_gecos); + else if (dest->pw_gecos && + strlen (dest->pw_gecos) >= strlen (src->pw_gecos)) + strcpy (dest->pw_gecos, src->pw_gecos); + else + { + dest->pw_gecos = buffer; + strcpy (dest->pw_gecos, src->pw_gecos); + buffer += strlen (dest->pw_gecos) + 1; + buflen = buflen - (strlen (dest->pw_gecos) + 1); + } + } + if (src->pw_dir != NULL && strlen (src->pw_dir)) + { + if (buffer == NULL) + dest->pw_dir = strdup (src->pw_dir); + else if (dest->pw_dir && + strlen (dest->pw_dir) >= strlen (src->pw_dir)) + strcpy (dest->pw_dir, src->pw_dir); + else + { + dest->pw_dir = buffer; + strcpy (dest->pw_dir, src->pw_dir); + buffer += strlen (dest->pw_dir) + 1; + buflen = buflen - (strlen (dest->pw_dir) + 1); + } + } + + if (src->pw_shell != NULL && strlen (src->pw_shell)) + { + if (buffer == NULL) + dest->pw_shell = strdup (src->pw_shell); + else if (dest->pw_shell && + strlen (dest->pw_shell) >= strlen (src->pw_shell)) + strcpy (dest->pw_shell, src->pw_shell); + else + { + dest->pw_shell = buffer; + strcpy (dest->pw_shell, src->pw_shell); + buffer += strlen (dest->pw_shell) + 1; + buflen = buflen - (strlen (dest->pw_shell) + 1); + } + } +} + +static enum nss_status +internal_setpwent (ent_t *ent) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + ent->nis = ent->first = ent->netgroup = 0; + + /* If something was left over free it. */ + if (ent->netgroup) + __internal_endnetgrent (&ent->netgrdata); + + if (ent->oldkey != NULL) + { + free (ent->oldkey); + ent->oldkey = NULL; + ent->oldkeylen = 0; + } + + if (ent->blacklist.data != NULL) + { + ent->blacklist.current = 1; + ent->blacklist.data[0] = '|'; + ent->blacklist.data[1] = '\0'; + } + else + ent->blacklist.current = 0; + + if (ent->stream == NULL) + { + ent->stream = fopen ("/etc/passwd", "r"); + + if (ent->stream == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + else + { + /* We have to make sure the file is `closed on exec'. */ + int result, flags; + + result = flags = fcntl (fileno (ent->stream), F_GETFD, 0); + if (result >= 0) + { + flags |= FD_CLOEXEC; + result = fcntl (fileno (ent->stream), F_SETFD, flags); + } + if (result < 0) + { + /* Something went wrong. Close the stream and return a + failure. */ + fclose (ent->stream); + ent->stream = NULL; + status = NSS_STATUS_UNAVAIL; + } + } + } + else + rewind (ent->stream); + + give_pwd_free (&ent->pwd); + + return status; +} + + +enum nss_status +_nss_compat_setpwent (void) +{ + enum nss_status result; + + __libc_lock_lock (lock); + + result = internal_setpwent (&ext_ent); + + __libc_lock_unlock (lock); + + return result; +} + + +static enum nss_status +internal_endpwent (ent_t *ent) +{ + if (ent->stream != NULL) + { + fclose (ent->stream); + ent->stream = NULL; + } + + if (ent->netgroup) + __internal_endnetgrent (&ent->netgrdata); + + ent->nis = ent->first = ent->netgroup = 0; + + if (ent->oldkey != NULL) + { + free (ent->oldkey); + ent->oldkey = NULL; + ent->oldkeylen = 0; + } + + if (ent->blacklist.data != NULL) + { + ent->blacklist.current = 1; + ent->blacklist.data[0] = '|'; + ent->blacklist.data[1] = '\0'; + } + else + ent->blacklist.current = 0; + + give_pwd_free (&ent->pwd); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_compat_endpwent (void) +{ + enum nss_status result; + + __libc_lock_lock (lock); + + result = internal_endpwent (&ext_ent); + + __libc_lock_unlock (lock); + + return result; +} + +static enum nss_status +getpwent_next_nis_netgr (const char *name, struct passwd *result, ent_t *ent, + char *group, char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + char *ypdomain, *host, *user, *domain, *outval, *p, *p2; + int status, outvallen; + size_t p2len; + + if (yp_get_default_domain (&ypdomain) != YPERR_SUCCESS) + { + ent->netgroup = 0; + ent->first = 0; + give_pwd_free (&ent->pwd); + return NSS_STATUS_UNAVAIL; + } + + if (ent->first == TRUE) + { + memset (&ent->netgrdata, 0, sizeof (struct __netgrent)); + __internal_setnetgrent (group, &ent->netgrdata); + ent->first = FALSE; + } + + while (1) + { + char *saved_cursor; + int parse_res; + + saved_cursor = ent->netgrdata.cursor; + status = __internal_getnetgrent_r (&host, &user, &domain, + &ent->netgrdata, buffer, buflen, + &errno); + if (status != 1) + { + __internal_endnetgrent (&ent->netgrdata); + ent->netgroup = 0; + give_pwd_free (&ent->pwd); + return NSS_STATUS_RETURN; + } + + if (user == NULL || user[0] == '-') + continue; + + if (domain != NULL && strcmp (ypdomain, domain) != 0) + continue; + + /* If name != NULL, we are called from getpwnam */ + if (name != NULL) + if (strcmp (user, name) != 0) + continue; + + if (yp_match (ypdomain, "passwd.byname", user, + strlen (user), &outval, &outvallen) + != YPERR_SUCCESS) + continue; + + p2len = pwd_need_buflen (&ent->pwd); + if (p2len > buflen) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + p2 = buffer + (buflen - p2len); + buflen -= p2len; + p = strncpy (buffer, outval, buflen); + while (isspace (*p)) + p++; + free (outval); + if ((parse_res = _nss_files_parse_pwent (p, result, data, buflen)) == -1) + { + ent->netgrdata.cursor = saved_cursor; + return NSS_STATUS_TRYAGAIN; + } + + if (parse_res) + { + /* Store the User in the blacklist for the "+" at the end of + /etc/passwd */ + blacklist_store_name (result->pw_name, ent); + copy_pwd_changes (result, &ent->pwd, p2, p2len); + break; + } + } + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +getpwent_next_nis (struct passwd *result, ent_t *ent, char *buffer, + size_t buflen) +{ + struct parser_data *data = (void *) buffer; + char *domain, *outkey, *outval, *p, *p2; + int outkeylen, outvallen, parse_res; + size_t p2len; + + if (yp_get_default_domain (&domain) != YPERR_SUCCESS) + { + ent->nis = 0; + give_pwd_free (&ent->pwd); + return NSS_STATUS_UNAVAIL; + } + + p2len = pwd_need_buflen (&ent->pwd); + if (p2len > buflen) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + p2 = buffer + (buflen - p2len); + buflen -= p2len; + do + { + bool_t saved_first; + char *saved_oldkey; + int saved_oldlen; + + if (ent->first) + { + if (yp_first (domain, "passwd.byname", &outkey, &outkeylen, + &outval, &outvallen) != YPERR_SUCCESS) + { + ent->nis = 0; + give_pwd_free (&ent->pwd); + return NSS_STATUS_UNAVAIL; + } + + saved_first = TRUE; + saved_oldkey = ent->oldkey; + saved_oldlen = ent->oldkeylen; + ent->oldkey = outkey; + ent->oldkeylen = outkeylen; + ent->first = FALSE; + } + else + { + if (yp_next (domain, "passwd.byname", ent->oldkey, ent->oldkeylen, + &outkey, &outkeylen, &outval, &outvallen) + != YPERR_SUCCESS) + { + ent->nis = 0; + give_pwd_free (&ent->pwd); + return NSS_STATUS_NOTFOUND; + } + + saved_first = FALSE; + saved_oldkey = ent->oldkey; + saved_oldlen = ent->oldkeylen; + ent->oldkey = outkey; + ent->oldkeylen = outkeylen; + } + + /* Copy the found data to our buffer */ + p = strncpy (buffer, outval, buflen); + + /* ...and free the data. */ + free (outval); + + while (isspace (*p)) + ++p; + if ((parse_res = _nss_files_parse_pwent (p, result, data, buflen)) == -1) + { + free (ent->oldkey); + ent->oldkey = saved_oldkey; + ent->oldkeylen = saved_oldlen; + ent->first = saved_first; + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + else + { + if (!saved_first) + free (saved_oldkey); + } + if (parse_res && + in_blacklist (result->pw_name, strlen (result->pw_name), ent)) + parse_res = 0; + } + while (!parse_res); + + copy_pwd_changes (result, &ent->pwd, p2, p2len); + + return NSS_STATUS_SUCCESS; +} + +/* This function handle the +user entrys in /etc/passwd */ +static enum nss_status +getpwnam_plususer (const char *name, struct passwd *result, char *buffer, + size_t buflen) +{ + struct parser_data *data = (void *) buffer; + struct passwd pwd; + int parse_res; + char *p; + size_t plen; + char *domain, *outval, *ptr; + int outvallen; + + memset (&pwd, '\0', sizeof (struct passwd)); + + copy_pwd_changes (&pwd, result, NULL, 0); + + plen = pwd_need_buflen (&pwd); + if (plen > buflen) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + p = buffer + (buflen - plen); + buflen -= plen; + + + if (yp_get_default_domain (&domain) != YPERR_SUCCESS) + return NSS_STATUS_NOTFOUND; + + if (yp_match (domain, "passwd.byname", name, strlen (name), + &outval, &outvallen) != YPERR_SUCCESS) + return NSS_STATUS_NOTFOUND; + ptr = strncpy (buffer, outval, buflen < (size_t) outvallen ? + buflen : (size_t) outvallen); + buffer[buflen < (size_t) outvallen ? buflen : (size_t) outvallen] = '\0'; + free (outval); + while (isspace (*ptr)) + ptr++; + if ((parse_res = _nss_files_parse_pwent (ptr, result, data, buflen)) + == -1) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + if (parse_res > 0) + { + copy_pwd_changes (result, &pwd, p, plen); + give_pwd_free (&pwd); + /* We found the entry. */ + return NSS_STATUS_SUCCESS; + } + else + { + /* Give buffer the old len back */ + buflen += plen; + give_pwd_free (&pwd); + } + return NSS_STATUS_RETURN; +} + +/* get the next user from NIS+ (+ entry) */ +static enum nss_status +getpwent_next_file (struct passwd *result, ent_t *ent, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + while (1) + { + fpos_t pos; + char *p; + int parse_res; + + do + { + fgetpos (ent->stream, &pos); + buffer[buflen - 1] = '\xff'; + p = fgets (buffer, buflen, ent->stream); + if (p == NULL && feof (ent->stream)) + return NSS_STATUS_NOTFOUND; + if (p == NULL || buffer[buflen - 1] != '\xff') + { + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + /* Terminate the line for any case. */ + buffer[buflen - 1] = '\0'; + + /* Skip leading blanks. */ + while (isspace (*p)) + ++p; + } + while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ + /* Parse the line. If it is invalid, loop to + get the next line of the file to parse. */ + !(parse_res = _nss_files_parse_pwent (p, result, data, buflen))); + + if (parse_res == -1) + { + /* The parser ran out of space. */ + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + if (result->pw_name[0] != '+' && result->pw_name[0] != '-') + /* This is a real entry. */ + break; + + /* -@netgroup */ + if (result->pw_name[0] == '-' && result->pw_name[1] == '@' + && result->pw_name[2] != '\0') + { + char buf2[1024]; + char *user, *host, *domain; + struct __netgrent netgrdata; + + bzero (&netgrdata, sizeof (struct __netgrent)); + __internal_setnetgrent (&result->pw_name[2], &netgrdata); + while (__internal_getnetgrent_r (&host, &user, &domain, + &netgrdata, buf2, sizeof (buf2), + &errno)) + { + if (user != NULL && user[0] != '-') + blacklist_store_name (user, ent); + } + __internal_endnetgrent (&netgrdata); + continue; + } + + /* +@netgroup */ + if (result->pw_name[0] == '+' && result->pw_name[1] == '@' + && result->pw_name[2] != '\0') + { + int status; + + ent->netgroup = TRUE; + ent->first = TRUE; + copy_pwd_changes (&ent->pwd, result, NULL, 0); + + status = getpwent_next_nis_netgr (NULL, result, ent, + &result->pw_name[2], + buffer, buflen); + if (status == NSS_STATUS_RETURN) + continue; + else + return status; + } + + /* -user */ + if (result->pw_name[0] == '-' && result->pw_name[1] != '\0' + && result->pw_name[1] != '@') + { + blacklist_store_name (&result->pw_name[1], ent); + continue; + } + + /* +user */ + if (result->pw_name[0] == '+' && result->pw_name[1] != '\0' + && result->pw_name[1] != '@') + { + enum nss_status status; + + /* Store the User in the blacklist for the "+" at the end of + /etc/passwd */ + blacklist_store_name (&result->pw_name[1], ent); + status = getpwnam_plususer (&result->pw_name[1], result, buffer, + buflen); + if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ + break; + else + if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ + continue; + else + return status; + } + + /* +:... */ + if (result->pw_name[0] == '+' && result->pw_name[1] == '\0') + { + ent->nis = TRUE; + ent->first = TRUE; + copy_pwd_changes (&ent->pwd, result, NULL, 0); + + return getpwent_next_nis (result, ent, buffer, buflen); + } + } + + return NSS_STATUS_SUCCESS; +} + + +/* get the next user from NIS (+ entry) */ +static enum nss_status +internal_getpwent_r (struct passwd *pw, ent_t *ent, char *buffer, + size_t buflen) +{ + if (ent->netgroup) + { + int status; + + /* We are searching members in a netgroup */ + /* Since this is not the first call, we don't need the group name */ + status = getpwent_next_nis_netgr (NULL, pw, ent, NULL, buffer, buflen); + if (status == NSS_STATUS_RETURN) + return getpwent_next_file (pw, ent, buffer, buflen); + else + return status; + } + else + if (ent->nis) + { + return getpwent_next_nis (pw, ent, buffer, buflen); + } + else + return getpwent_next_file (pw, ent, buffer, buflen); +} + +enum nss_status +_nss_compat_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + __libc_lock_lock (lock); + + /* Be prepared that the setpwent function was not called before. */ + if (ext_ent.stream == NULL) + status = internal_setpwent (&ext_ent); + + if (status == NSS_STATUS_SUCCESS) + status = internal_getpwent_r (pwd, &ext_ent, buffer, buflen); + + __libc_lock_unlock (lock); + + return status; +} + +/* Searches in /etc/passwd and the NIS/NIS+ map for a special user */ +static enum nss_status +internal_getpwnam_r (const char *name, struct passwd *result, ent_t *ent, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + + while (1) + { + fpos_t pos; + char *p; + int parse_res; + + do + { + fgetpos (ent->stream, &pos); + buffer[buflen - 1] = '\xff'; + p = fgets (buffer, buflen, ent->stream); + if (p == NULL && feof (ent->stream)) + return NSS_STATUS_NOTFOUND; + if (p == NULL || buffer[buflen - 1] != '\xff') + { + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + /* Terminate the line for any case. */ + buffer[buflen - 1] = '\0'; + + /* Skip leading blanks. */ + while (isspace (*p)) + ++p; + } + while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ + /* Parse the line. If it is invalid, loop to + get the next line of the file to parse. */ + !(parse_res = _nss_files_parse_pwent (p, result, data, buflen))); + + if (parse_res == -1) + { + /* The parser ran out of space. */ + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + /* This is a real entry. */ + if (result->pw_name[0] != '+' && result->pw_name[0] != '-') + { + if (strcmp (result->pw_name, name) == 0) + return NSS_STATUS_SUCCESS; + else + continue; + } + + /* -@netgroup */ + if (result->pw_name[0] == '-' && result->pw_name[1] == '@' + && result->pw_name[2] != '\0') + { + char buf2[1024]; + char *user, *host, *domain; + struct __netgrent netgrdata; + + bzero (&netgrdata, sizeof (struct __netgrent)); + __internal_setnetgrent (&result->pw_name[2], &netgrdata); + while (__internal_getnetgrent_r (&host, &user, &domain, + &netgrdata, buf2, sizeof (buf2), + &errno)) + { + if (user != NULL && user[0] != '-') + if (strcmp (user, name) == 0) + return NSS_STATUS_NOTFOUND; + } + __internal_endnetgrent (&netgrdata); + continue; + } + + /* +@netgroup */ + if (result->pw_name[0] == '+' && result->pw_name[1] == '@' + && result->pw_name[2] != '\0') + { + char buf[strlen (result->pw_name)]; + int status; + + strcpy (buf, &result->pw_name[2]); + ent->netgroup = TRUE; + ent->first = TRUE; + copy_pwd_changes (&ent->pwd, result, NULL, 0); + + do + { + status = getpwent_next_nis_netgr (name, result, ent, buf, + buffer, buflen); + if (status == NSS_STATUS_RETURN) + continue; + + if (status == NSS_STATUS_SUCCESS && + strcmp (result->pw_name, name) == 0) + return NSS_STATUS_SUCCESS; + } while (status == NSS_STATUS_SUCCESS); + continue; + } + + /* -user */ + if (result->pw_name[0] == '-' && result->pw_name[1] != '\0' + && result->pw_name[1] != '@') + { + if (strcmp (&result->pw_name[1], name) == 0) + return NSS_STATUS_NOTFOUND; + else + continue; + } + + /* +user */ + if (result->pw_name[0] == '+' && result->pw_name[1] != '\0' + && result->pw_name[1] != '@') + { + if (strcmp (name, &result->pw_name[1]) == 0) + { + enum nss_status status; + + status = getpwnam_plususer (name, result, buffer, buflen); + if (status == NSS_STATUS_RETURN) + /* We couldn't parse the entry */ + return NSS_STATUS_NOTFOUND; + else + return status; + } + } + + /* +:... */ + if (result->pw_name[0] == '+' && result->pw_name[1] == '\0') + { + enum nss_status status; + + status = getpwnam_plususer (name, result, buffer, buflen); + if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ + break; + else + if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ + return NSS_STATUS_NOTFOUND; + else + return status; + } + } + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_compat_getpwnam_r (const char *name, struct passwd *pwd, + char *buffer, size_t buflen) +{ + ent_t ent = {0, 0, 0, NULL, 0, NULL, {NULL, 0, 0}, + {NULL, NULL, 0, 0, NULL, NULL, NULL}}; + enum nss_status status; + + if (name[0] == '-' || name[0] == '+') + return NSS_STATUS_NOTFOUND; + + status = internal_setpwent (&ent); + if (status != NSS_STATUS_SUCCESS) + return status; + + status = internal_getpwnam_r (name, pwd, &ent, buffer, buflen); + + internal_endpwent (&ent); + + return status; +} + +/* This function handle the + entry in /etc/passwd for getpwuid */ +static enum nss_status +getpwuid_plususer (uid_t uid, struct passwd *result, char *buffer, + size_t buflen) +{ + struct parser_data *data = (void *) buffer; + struct passwd pwd; + int parse_res; + char *p; + size_t plen; + char buf[1024]; + char *domain, *outval, *ptr; + int outvallen; + + memset (&pwd, '\0', sizeof (struct passwd)); + + copy_pwd_changes (&pwd, result, NULL, 0); + + plen = pwd_need_buflen (&pwd); + if (plen > buflen) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + p = buffer + (buflen - plen); + buflen -= plen; + + + if (yp_get_default_domain (&domain) != YPERR_SUCCESS) + return NSS_STATUS_TRYAGAIN; + + sprintf (buf, "%d", uid); + if (yp_match (domain, "passwd.byuid", buf, strlen (buf), + &outval, &outvallen) + != YPERR_SUCCESS) + return NSS_STATUS_TRYAGAIN; + ptr = strncpy (buffer, outval, buflen < (size_t) outvallen ? + buflen : (size_t) outvallen); + buffer[buflen < (size_t) outvallen ? buflen : (size_t) outvallen] = '\0'; + free (outval); + while (isspace (*ptr)) + ptr++; + if ((parse_res = _nss_files_parse_pwent (ptr, result, data, buflen)) + == -1) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + if (parse_res > 0) + { + copy_pwd_changes (result, &pwd, p, plen); + give_pwd_free (&pwd); + /* We found the entry. */ + return NSS_STATUS_SUCCESS; + } + else + { + /* Give buffer the old len back */ + buflen += plen; + give_pwd_free (&pwd); + } + return NSS_STATUS_RETURN; +} + +/* Searches in /etc/passwd and the NIS/NIS+ map for a special user id */ +static enum nss_status +internal_getpwuid_r (uid_t uid, struct passwd *result, ent_t *ent, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + + while (1) + { + fpos_t pos; + char *p; + int parse_res; + + do + { + fgetpos (ent->stream, &pos); + buffer[buflen - 1] = '\xff'; + p = fgets (buffer, buflen, ent->stream); + if (p == NULL && feof (ent->stream)) + return NSS_STATUS_NOTFOUND; + if (p == NULL || buffer[buflen - 1] != '\xff') + { + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + /* Terminate the line for any case. */ + buffer[buflen - 1] = '\0'; + + /* Skip leading blanks. */ + while (isspace (*p)) + ++p; + } + while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ + /* Parse the line. If it is invalid, loop to + get the next line of the file to parse. */ + !(parse_res = _nss_files_parse_pwent (p, result, data, buflen))); + + if (parse_res == -1) + { + /* The parser ran out of space. */ + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + /* This is a real entry. */ + if (result->pw_name[0] != '+' && result->pw_name[0] != '-') + { + if (result->pw_uid == uid) + return NSS_STATUS_SUCCESS; + else + continue; + } + + /* -@netgroup */ + if (result->pw_name[0] == '-' && result->pw_name[1] == '@' + && result->pw_name[2] != '\0') + { + char buf2[1024]; + char *user, *host, *domain; + struct __netgrent netgrdata; + + bzero (&netgrdata, sizeof (struct __netgrent)); + __internal_setnetgrent (&result->pw_name[2], &netgrdata); + while (__internal_getnetgrent_r (&host, &user, &domain, + &netgrdata, buf2, sizeof (buf2), + &errno)) + { + if (user != NULL && user[0] != '-') + blacklist_store_name (user, ent); + } + __internal_endnetgrent (&netgrdata); + continue; + } + + /* +@netgroup */ + if (result->pw_name[0] == '+' && result->pw_name[1] == '@' + && result->pw_name[2] != '\0') + { + char buf[strlen (result->pw_name)]; + int status; + + strcpy (buf, &result->pw_name[2]); + ent->netgroup = TRUE; + ent->first = TRUE; + copy_pwd_changes (&ent->pwd, result, NULL, 0); + + do + { + status = getpwent_next_nis_netgr (NULL, result, ent, buf, + buffer, buflen); + if (status == NSS_STATUS_RETURN) + continue; + + if (status == NSS_STATUS_SUCCESS && uid == result->pw_uid) + return NSS_STATUS_SUCCESS; + } while (status == NSS_STATUS_SUCCESS); + continue; + } + + /* -user */ + if (result->pw_name[0] == '-' && result->pw_name[1] != '\0' + && result->pw_name[1] != '@') + { + blacklist_store_name (&result->pw_name[1], ent); + continue; + } + + /* +user */ + if (result->pw_name[0] == '+' && result->pw_name[1] != '\0' + && result->pw_name[1] != '@') + { + enum nss_status status; + + /* Store the User in the blacklist for the "+" at the end of + /etc/passwd */ + blacklist_store_name (&result->pw_name[1], ent); + status = getpwnam_plususer (&result->pw_name[1], result, buffer, + buflen); + if (status == NSS_STATUS_SUCCESS && result->pw_uid == uid) + break; + else + continue; + } + + /* +:... */ + if (result->pw_name[0] == '+' && result->pw_name[1] == '\0') + { + enum nss_status status; + + status = getpwuid_plususer (uid, result, buffer, buflen); + if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ + break; + else + if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ + return NSS_STATUS_NOTFOUND; + else + { + if (status == NSS_STATUS_TRYAGAIN) + /* The parser ran out of space */ + fsetpos (ent->stream, &pos); + return status; + } + } + } + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_compat_getpwuid_r (uid_t uid, struct passwd *pwd, + char *buffer, size_t buflen) +{ + ent_t ent = {0, 0, 0, NULL, 0, NULL, {NULL, 0, 0}, + {NULL, NULL, 0, 0, NULL, NULL, NULL}}; + enum nss_status status; + + status = internal_setpwent (&ent); + if (status != NSS_STATUS_SUCCESS) + return status; + + status = internal_getpwuid_r (uid, pwd, &ent, buffer, buflen); + + internal_endpwent (&ent); + + return status; +} + + +/* Support routines for remembering -@netgroup and -user entries. + The names are stored in a single string with `|' as separator. */ +static void +blacklist_store_name (const char *name, ent_t *ent) +{ + int namelen = strlen (name); + char *tmp; + + /* first call, setup cache */ + if (ent->blacklist.size == 0) + { + ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen); + ent->blacklist.data = malloc (ent->blacklist.size); + if (ent->blacklist.data == NULL) + return; + ent->blacklist.data[0] = '|'; + ent->blacklist.data[1] = '\0'; + ent->blacklist.current = 1; + } + else + { + if (in_blacklist (name, namelen, ent)) + return; /* no duplicates */ + + if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size) + { + ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen); + tmp = realloc (ent->blacklist.data, ent->blacklist.size); + if (tmp == NULL) + { + free (ent->blacklist.data); + ent->blacklist.size = 0; + return; + } + ent->blacklist.data = tmp; + } + } + + tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name); + *tmp++ = '|'; + *tmp = '\0'; + ent->blacklist.current += namelen + 1; + + return; +} + +/* returns TRUE if ent->blacklist contains name, else FALSE */ +static bool_t +in_blacklist (const char *name, int namelen, ent_t *ent) +{ + char buf[namelen + 3]; + char *cp; + + if (ent->blacklist.data == NULL) + return FALSE; + + buf[0] = '|'; + cp = stpcpy (&buf[1], name); + *cp++= '|'; + *cp = '\0'; + return strstr (ent->blacklist.data, buf) != NULL; +} diff --git a/glibc-compat/nss_compat/compat-spwd.c b/glibc-compat/nss_compat/compat-spwd.c new file mode 100644 index 0000000000..2c33d80688 --- /dev/null +++ b/glibc-compat/nss_compat/compat-spwd.c @@ -0,0 +1,915 @@ +/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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 <nss.h> +#include <errno.h> +#include <ctype.h> +#include <fcntl.h> +#include <glibc-compat/include/netdb.h> +#include <glibc-compat/include/shadow.h> +#include <string.h> +#include <bits/libc-lock.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> +#include <nsswitch.h> + +#include "netgroup.h" + +/* Get the declaration of the parser function. */ +#define ENTNAME spent +#define STRUCTURE spwd +#define EXTERN_PARSER +#include "../nss_files/files-parse.c" + +/* Structure for remembering -@netgroup and -user members ... */ +#define BLACKLIST_INITIAL_SIZE 512 +#define BLACKLIST_INCREMENT 256 +struct blacklist_t + { + char *data; + int current; + int size; + }; + +struct ent_t + { + bool_t netgroup; + bool_t nis; + bool_t first; + char *oldkey; + int oldkeylen; + FILE *stream; + struct blacklist_t blacklist; + struct spwd pwd; + struct __netgrent netgrdata; + }; +typedef struct ent_t ent_t; + +static ent_t ext_ent = {0, 0, 0, NULL, 0, NULL, {NULL, 0, 0}, + {NULL, NULL, 0, 0, 0, 0, 0, 0, 0}}; + +/* Protect global state against multiple changers. */ +__libc_lock_define_initialized (static, lock) + +/* Prototypes for local functions. */ +static void blacklist_store_name (const char *, ent_t *); +static int in_blacklist (const char *, int, ent_t *); + +static void +give_spwd_free (struct spwd *pwd) +{ + if (pwd->sp_namp != NULL) + free (pwd->sp_namp); + if (pwd->sp_pwdp != NULL) + free (pwd->sp_pwdp); + + memset (pwd, '\0', sizeof (struct spwd)); +} + +static int +spwd_need_buflen (struct spwd *pwd) +{ + int len = 0; + + if (pwd->sp_pwdp != NULL) + len += strlen (pwd->sp_pwdp) + 1; + + return len; +} + +static void +copy_spwd_changes (struct spwd *dest, struct spwd *src, + char *buffer, size_t buflen) +{ + if (src->sp_pwdp != NULL && strlen (src->sp_pwdp)) + { + if (buffer == NULL) + dest->sp_pwdp = strdup (src->sp_pwdp); + else if (dest->sp_pwdp && + strlen (dest->sp_pwdp) >= strlen (src->sp_pwdp)) + strcpy (dest->sp_pwdp, src->sp_pwdp); + else + { + dest->sp_pwdp = buffer; + strcpy (dest->sp_pwdp, src->sp_pwdp); + buffer += strlen (dest->sp_pwdp) + 1; + buflen = buflen - (strlen (dest->sp_pwdp) + 1); + } + } + if (src->sp_lstchg != 0) + dest->sp_lstchg = src->sp_lstchg; + if (src->sp_min != 0) + dest->sp_min = src->sp_min; + if (src->sp_max != 0) + dest->sp_max = src->sp_max; + if (src->sp_warn != 0) + dest->sp_warn = src->sp_warn; + if (src->sp_inact != 0) + dest->sp_inact = src->sp_inact; + if (src->sp_expire != 0) + dest->sp_expire = src->sp_expire; + if (src->sp_flag != 0) + dest->sp_flag = src->sp_flag; +} + +static enum nss_status +internal_setspent (ent_t *ent) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + ent->nis = ent->first = ent->netgroup = 0; + + /* If something was left over free it. */ + if (ent->netgroup) + __internal_endnetgrent (&ent->netgrdata); + + if (ent->oldkey != NULL) + { + free (ent->oldkey); + ent->oldkey = NULL; + ent->oldkeylen = 0; + } + + if (ent->blacklist.data != NULL) + { + ent->blacklist.current = 1; + ent->blacklist.data[0] = '|'; + ent->blacklist.data[1] = '\0'; + } + else + ent->blacklist.current = 0; + + if (ent->stream == NULL) + { + ent->stream = fopen ("/etc/shadow", "r"); + + if (ent->stream == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + else + { + /* We have to make sure the file is `closed on exec'. */ + int result, flags; + + result = flags = fcntl (fileno (ent->stream), F_GETFD, 0); + if (result >= 0) + { + flags |= FD_CLOEXEC; + result = fcntl (fileno (ent->stream), F_SETFD, flags); + } + if (result < 0) + { + /* Something went wrong. Close the stream and return a + failure. */ + fclose (ent->stream); + ent->stream = NULL; + status = NSS_STATUS_UNAVAIL; + } + } + } + else + rewind (ent->stream); + + give_spwd_free (&ent->pwd); + + return status; +} + + +enum nss_status +_nss_compat_setspent (void) +{ + enum nss_status result; + + __libc_lock_lock (lock); + + result = internal_setspent (&ext_ent); + + __libc_lock_unlock (lock); + + return result; +} + + +static enum nss_status +internal_endspent (ent_t *ent) +{ + if (ent->stream != NULL) + { + fclose (ent->stream); + ent->stream = NULL; + } + + if (ent->netgroup) + __internal_endnetgrent (&ent->netgrdata); + + ent->nis = ent->first = ent->netgroup = 0; + + if (ent->oldkey != NULL) + { + free (ent->oldkey); + ent->oldkey = NULL; + ent->oldkeylen = 0; + } + + if (ent->blacklist.data != NULL) + { + ent->blacklist.current = 1; + ent->blacklist.data[0] = '|'; + ent->blacklist.data[1] = '\0'; + } + else + ent->blacklist.current = 0; + + give_spwd_free (&ent->pwd); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_compat_endspent (void) +{ + enum nss_status result; + + __libc_lock_lock (lock); + + result = internal_endspent (&ext_ent); + + __libc_lock_unlock (lock); + + return result; +} + + +static enum nss_status +getspent_next_nis_netgr (const char *name, struct spwd *result, ent_t *ent, + char *group, char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + char *ypdomain, *host, *user, *domain, *outval, *p, *p2; + int status, outvallen; + size_t p2len; + + if (yp_get_default_domain (&ypdomain) != YPERR_SUCCESS) + { + ent->netgroup = 0; + ent->first = 0; + give_spwd_free (&ent->pwd); + return NSS_STATUS_UNAVAIL; + } + + if (ent->first == TRUE) + { + bzero (&ent->netgrdata, sizeof (struct __netgrent)); + __internal_setnetgrent (group, &ent->netgrdata); + ent->first = FALSE; + } + + while (1) + { + char *saved_cursor; + int parse_res; + + saved_cursor = ent->netgrdata.cursor; + status = __internal_getnetgrent_r (&host, &user, &domain, + &ent->netgrdata, buffer, buflen, + &errno); + if (status != 1) + { + __internal_endnetgrent (&ent->netgrdata); + ent->netgroup = 0; + give_spwd_free (&ent->pwd); + return NSS_STATUS_RETURN; + } + + if (user == NULL || user[0] == '-') + continue; + + if (domain != NULL && strcmp (ypdomain, domain) != 0) + continue; + + /* If name != NULL, we are called from getpwnam */ + if (name != NULL) + if (strcmp (user, name) != 0) + continue; + + if (yp_match (ypdomain, "shadow.byname", user, + strlen (user), &outval, &outvallen) + != YPERR_SUCCESS) + continue; + + p2len = spwd_need_buflen (&ent->pwd); + if (p2len > buflen) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + p2 = buffer + (buflen - p2len); + buflen -= p2len; + p = strncpy (buffer, outval, buflen); + while (isspace (*p)) + p++; + free (outval); + if ((parse_res = _nss_files_parse_spent (p, result, data, buflen)) == -1) + { + ent->netgrdata.cursor = saved_cursor; + return NSS_STATUS_TRYAGAIN; + } + + if (parse_res) + { + /* Store the User in the blacklist for the "+" at the end of + /etc/passwd */ + blacklist_store_name (result->sp_namp, ent); + copy_spwd_changes (result, &ent->pwd, p2, p2len); + break; + } + } + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +getspent_next_nis (struct spwd *result, ent_t *ent, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + char *domain, *outkey, *outval, *p, *p2; + int outkeylen, outvallen, parse_res; + size_t p2len; + + if (yp_get_default_domain (&domain) != YPERR_SUCCESS) + { + ent->nis = 0; + give_spwd_free (&ent->pwd); + return NSS_STATUS_UNAVAIL; + } + + p2len = spwd_need_buflen (&ent->pwd); + if (p2len > buflen) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + p2 = buffer + (buflen - p2len); + buflen -= p2len; + do + { + bool_t saved_first; + char *saved_oldkey; + int saved_oldlen; + + if (ent->first) + { + if (yp_first (domain, "shadow.byname", &outkey, &outkeylen, + &outval, &outvallen) != YPERR_SUCCESS) + { + ent->nis = 0; + give_spwd_free (&ent->pwd); + return NSS_STATUS_UNAVAIL; + } + saved_first = TRUE; + saved_oldkey = ent->oldkey; + saved_oldlen = ent->oldkeylen; + ent->oldkey = outkey; + ent->oldkeylen = outkeylen; + ent->first = FALSE; + } + else + { + if (yp_next (domain, "shadow.byname", ent->oldkey, ent->oldkeylen, + &outkey, &outkeylen, &outval, &outvallen) + != YPERR_SUCCESS) + { + ent->nis = 0; + give_spwd_free (&ent->pwd); + return NSS_STATUS_NOTFOUND; + } + + saved_first = FALSE; + saved_oldkey = ent->oldkey; + saved_oldlen = ent->oldkeylen; + ent->oldkey = outkey; + ent->oldkeylen = outkeylen; + } + + /* Copy the found data to our buffer */ + p = strncpy (buffer, outval, buflen); + + /* ...and free the data. */ + free (outval); + + while (isspace (*p)) + ++p; + if ((parse_res = _nss_files_parse_spent (p, result, data, buflen)) == -1) + { + free (ent->oldkey); + ent->oldkey = saved_oldkey; + ent->oldkeylen = saved_oldlen; + ent->first = saved_first; + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + else + { + if (!saved_first) + free (saved_oldkey); + } + if (parse_res && + in_blacklist (result->sp_namp, strlen (result->sp_namp), ent)) + parse_res = 0; + } + while (!parse_res); + + copy_spwd_changes (result, &ent->pwd, p2, p2len); + + return NSS_STATUS_SUCCESS; +} + +/* This function handle the +user entrys in /etc/shadow */ +static enum nss_status +getspnam_plususer (const char *name, struct spwd *result, char *buffer, + size_t buflen) +{ + struct parser_data *data = (void *) buffer; + struct spwd pwd; + int parse_res; + char *p; + size_t plen; + char *domain, *outval, *ptr; + int outvallen; + + + memset (&pwd, '\0', sizeof (struct spwd)); + + copy_spwd_changes (&pwd, result, NULL, 0); + + plen = spwd_need_buflen (&pwd); + if (plen > buflen) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + p = buffer + (buflen - plen); + buflen -= plen; + + if (yp_get_default_domain (&domain) != YPERR_SUCCESS) + return NSS_STATUS_NOTFOUND; + + if (yp_match (domain, "shadow.byname", name, strlen (name), + &outval, &outvallen) != YPERR_SUCCESS) + return NSS_STATUS_NOTFOUND; + ptr = strncpy (buffer, outval, buflen < (size_t) outvallen ? + buflen : (size_t) outvallen); + buffer[buflen < (size_t) outvallen ? buflen : (size_t) outvallen] = '\0'; + free (outval); + while (isspace (*ptr)) + ptr++; + if ((parse_res = _nss_files_parse_spent (ptr, result, data, buflen)) == -1) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + if (parse_res) + { + copy_spwd_changes (result, &pwd, p, plen); + give_spwd_free (&pwd); + /* We found the entry. */ + return NSS_STATUS_SUCCESS; + } + else + { + /* Give buffer the old len back */ + buflen += plen; + give_spwd_free (&pwd); + } + return NSS_STATUS_RETURN; +} + +static enum nss_status +getspent_next_file (struct spwd *result, ent_t *ent, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + while (1) + { + fpos_t pos; + int parse_res = 0; + char *p; + + do + { + fgetpos (ent->stream, &pos); + buffer[buflen - 1] = '\xff'; + p = fgets (buffer, buflen, ent->stream); + if (p == NULL && feof (ent->stream)) + return NSS_STATUS_NOTFOUND; + if (p == NULL || buffer[buflen - 1] != '\xff') + { + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + /* Terminate the line for any case. */ + buffer[buflen - 1] = '\0'; + + /* Skip leading blanks. */ + while (isspace (*p)) + ++p; + } + while (*p == '\0' || *p == '#' /* Ignore empty and comment lines. */ + /* Parse the line. If it is invalid, loop to + get the next line of the file to parse. */ + || !(parse_res = _nss_files_parse_spent (p, result, data, + buflen))); + + if (parse_res == -1) + { + /* The parser ran out of space. */ + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + if (result->sp_namp[0] != '+' && result->sp_namp[0] != '-') + /* This is a real entry. */ + break; + + /* -@netgroup */ + if (result->sp_namp[0] == '-' && result->sp_namp[1] == '@' + && result->sp_namp[2] != '\0') + { + char buf2[1024]; + char *user, *host, *domain; + struct __netgrent netgrdata; + + bzero (&netgrdata, sizeof (struct __netgrent)); + __internal_setnetgrent (&result->sp_namp[2], &netgrdata); + while (__internal_getnetgrent_r (&host, &user, &domain, + &netgrdata, buf2, sizeof (buf2), + &errno)) + { + if (user != NULL && user[0] != '-') + blacklist_store_name (user, ent); + } + __internal_endnetgrent (&netgrdata); + continue; + } + + /* +@netgroup */ + if (result->sp_namp[0] == '+' && result->sp_namp[1] == '@' + && result->sp_namp[2] != '\0') + { + int status; + + ent->netgroup = TRUE; + ent->first = TRUE; + copy_spwd_changes (&ent->pwd, result, NULL, 0); + + status = getspent_next_nis_netgr (NULL, result, ent, + &result->sp_namp[2], + buffer, buflen); + if (status == NSS_STATUS_RETURN) + continue; + else + return status; + } + + /* -user */ + if (result->sp_namp[0] == '-' && result->sp_namp[1] != '\0' + && result->sp_namp[1] != '@') + { + blacklist_store_name (&result->sp_namp[1], ent); + continue; + } + + /* +user */ + if (result->sp_namp[0] == '+' && result->sp_namp[1] != '\0' + && result->sp_namp[1] != '@') + { + enum nss_status status; + + /* Store the User in the blacklist for the "+" at the end of + /etc/passwd */ + blacklist_store_name (&result->sp_namp[1], ent); + status = getspnam_plususer (&result->sp_namp[1], result, buffer, + buflen); + if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ + break; + else + if (status == NSS_STATUS_RETURN /* We couldn't parse the entry */ + || status == NSS_STATUS_NOTFOUND) /* entry doesn't exist */ + continue; + else + { + if (status == NSS_STATUS_TRYAGAIN) + fsetpos (ent->stream, &pos); + return status; + } + } + + /* +:... */ + if (result->sp_namp[0] == '+' && result->sp_namp[1] == '\0') + { + ent->nis = TRUE; + ent->first = TRUE; + copy_spwd_changes (&ent->pwd, result, NULL, 0); + + return getspent_next_nis (result, ent, buffer, buflen); + } + } + + return NSS_STATUS_SUCCESS; +} + + +static enum nss_status +internal_getspent_r (struct spwd *pw, ent_t *ent, + char *buffer, size_t buflen) +{ + if (ent->netgroup) + { + int status; + + /* We are searching members in a netgroup */ + /* Since this is not the first call, we don't need the group name */ + status = getspent_next_nis_netgr (NULL, pw, ent, NULL, buffer, buflen); + if (status == NSS_STATUS_RETURN) + return getspent_next_file (pw, ent, buffer, buflen); + else + return status; + } + else + if (ent->nis) + { + return getspent_next_nis (pw, ent, buffer, buflen); + } + else + return getspent_next_file (pw, ent, buffer, buflen); +} + +enum nss_status +_nss_compat_getspent_r (struct spwd *pwd, char *buffer, size_t buflen) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + __libc_lock_lock (lock); + + if (ext_ent.stream == NULL) + status = internal_setspent (&ext_ent); + + if (status == NSS_STATUS_SUCCESS) + status = internal_getspent_r (pwd, &ext_ent, buffer, buflen); + + __libc_lock_unlock (lock); + + return status; +} + +/* Searches in /etc/passwd and the NIS/NIS+ map for a special user */ +static enum nss_status +internal_getspnam_r (const char *name, struct spwd *result, ent_t *ent, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + + while (1) + { + fpos_t pos; + char *p; + int parse_res; + + do + { + fgetpos (ent->stream, &pos); + buffer[buflen - 1] = '\xff'; + p = fgets (buffer, buflen, ent->stream); + if (p == NULL && feof (ent->stream)) + return NSS_STATUS_NOTFOUND; + if (p == NULL || buffer[buflen - 1] != '\xff') + { + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + /* Terminate the line for any case. */ + buffer[buflen - 1] = '\0'; + + /* Skip leading blanks. */ + while (isspace (*p)) + ++p; + } + while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ + /* Parse the line. If it is invalid, loop to + get the next line of the file to parse. */ + !(parse_res = _nss_files_parse_spent (p, result, data, buflen))); + + if (parse_res == -1) + { + /* The parser ran out of space. */ + fsetpos (ent->stream, &pos); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + /* This is a real entry. */ + if (result->sp_namp[0] != '+' && result->sp_namp[0] != '-') + { + if (strcmp (result->sp_namp, name) == 0) + return NSS_STATUS_SUCCESS; + else + continue; + } + + /* -@netgroup */ + if (result->sp_namp[0] == '-' && result->sp_namp[1] == '@' + && result->sp_namp[2] != '\0') + { + char buf2[1024]; + char *user, *host, *domain; + struct __netgrent netgrdata; + + bzero (&netgrdata, sizeof (struct __netgrent)); + __internal_setnetgrent (&result->sp_namp[2], &netgrdata); + while (__internal_getnetgrent_r (&host, &user, &domain, + &netgrdata, buf2, sizeof (buf2), + &errno)) + { + if (user != NULL && user[0] != '-') + if (strcmp (user, name) == 0) + return NSS_STATUS_NOTFOUND; + } + __internal_endnetgrent (&netgrdata); + continue; + } + + /* +@netgroup */ + if (result->sp_namp[0] == '+' && result->sp_namp[1] == '@' + && result->sp_namp[2] != '\0') + { + char buf[strlen (result->sp_namp)]; + int status; + + strcpy (buf, &result->sp_namp[2]); + ent->netgroup = TRUE; + ent->first = TRUE; + copy_spwd_changes (&ent->pwd, result, NULL, 0); + + do + { + status = getspent_next_nis_netgr (name, result, ent, buf, + buffer, buflen); + if (status == NSS_STATUS_RETURN) + continue; + + if (status == NSS_STATUS_SUCCESS && + strcmp (result->sp_namp, name) == 0) + return NSS_STATUS_SUCCESS; + } while (status == NSS_STATUS_SUCCESS); + continue; + } + + /* -user */ + if (result->sp_namp[0] == '-' && result->sp_namp[1] != '\0' + && result->sp_namp[1] != '@') + { + if (strcmp (&result->sp_namp[1], name) == 0) + return NSS_STATUS_NOTFOUND; + else + continue; + } + + /* +user */ + if (result->sp_namp[0] == '+' && result->sp_namp[1] != '\0' + && result->sp_namp[1] != '@') + { + if (strcmp (name, &result->sp_namp[1]) == 0) + { + enum nss_status status; + + status = getspnam_plususer (name, result, buffer, buflen); + if (status == NSS_STATUS_RETURN) + /* We couldn't parse the entry */ + return NSS_STATUS_NOTFOUND; + else + return status; + } + } + + /* +:... */ + if (result->sp_namp[0] == '+' && result->sp_namp[1] == '\0') + { + enum nss_status status; + + status = getspnam_plususer (name, result, buffer, buflen); + if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ + return NSS_STATUS_NOTFOUND; + else + return status; + } + } + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_compat_getspnam_r (const char *name, struct spwd *pwd, + char *buffer, size_t buflen) +{ + ent_t ent = {0, 0, 0, NULL, 0, NULL, {NULL, 0, 0}, + {NULL, NULL, 0, 0, 0, 0, 0, 0, 0}}; + enum nss_status status; + + if (name[0] == '-' || name[0] == '+') + return NSS_STATUS_NOTFOUND; + + status = internal_setspent (&ent); + if (status != NSS_STATUS_SUCCESS) + return status; + + status = internal_getspnam_r (name, pwd, &ent, buffer, buflen); + + internal_endspent (&ent); + + return status; +} + +/* Support routines for remembering -@netgroup and -user entries. + The names are stored in a single string with `|' as separator. */ +static void +blacklist_store_name (const char *name, ent_t *ent) +{ + int namelen = strlen (name); + char *tmp; + + /* first call, setup cache */ + if (ent->blacklist.size == 0) + { + ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen); + ent->blacklist.data = malloc (ent->blacklist.size); + if (ent->blacklist.data == NULL) + return; + ent->blacklist.data[0] = '|'; + ent->blacklist.data[1] = '\0'; + ent->blacklist.current = 1; + } + else + { + if (in_blacklist (name, namelen, ent)) + return; /* no duplicates */ + + if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size) + { + ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen); + tmp = realloc (ent->blacklist.data, ent->blacklist.size); + if (tmp == NULL) + { + free (ent->blacklist.data); + ent->blacklist.size = 0; + return; + } + ent->blacklist.data = tmp; + } + } + + tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name); + *tmp++ = '|'; + *tmp = '\0'; + ent->blacklist.current += namelen + 1; + + return; +} + +/* Returns TRUE if ent->blacklist contains name, else FALSE. */ +static bool_t +in_blacklist (const char *name, int namelen, ent_t *ent) +{ + char buf[namelen + 3]; + char *cp; + + if (ent->blacklist.data == NULL) + return FALSE; + + buf[0] = '|'; + cp = stpcpy (&buf[1], name); + *cp++= '|'; + *cp = '\0'; + return strstr (ent->blacklist.data, buf) != NULL; +} diff --git a/glibc-compat/nss_db/db-XXX.c b/glibc-compat/nss_db/db-XXX.c new file mode 100644 index 0000000000..8c05829656 --- /dev/null +++ b/glibc-compat/nss_db/db-XXX.c @@ -0,0 +1,257 @@ +/* Common code for DB-based databases in nss_db module. + Copyright (C) 1996, 1997, 1998, 1999, 2000 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. */ + +#include <dlfcn.h> +#include <fcntl.h> +#include <bits/libc-lock.h> +#include "nsswitch.h" +#include "nss_db.h" + +/* These symbols are defined by the including source file: + + ENTNAME -- database name of the structure and functions (hostent, pwent). + STRUCTURE -- struct name, define only if not ENTNAME (passwd, group). + DATABASE -- database file name, ("hosts", "passwd") + + NEED_H_ERRNO - defined iff an arg `int *herrnop' is used. +*/ + +#define ENTNAME_r CONCAT(ENTNAME,_r) + +#include <paths.h> +#define DBFILE _PATH_VARDB DATABASE ".db" + +#ifdef NEED_H_ERRNO +#define H_ERRNO_PROTO , int *herrnop +#define H_ERRNO_ARG , herrnop +#define H_ERRNO_SET(val) (*herrnop = (val)) +#else +#define H_ERRNO_PROTO +#define H_ERRNO_ARG +#define H_ERRNO_SET(val) ((void) 0) +#endif + +/* Locks the static variables in this file. */ +__libc_lock_define_initialized (static, lock) + +/* Maintenance of the shared handle open on the database. */ + +static NSS_DB *db; +static int keep_db; +static int entidx; + + +/* Open the database. */ +enum nss_status +CONCAT(_nss_db_set,ENTNAME) (int stayopen) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_setent (DBFILE, &db); + + /* Remember STAYOPEN flag. */ + if (db != NULL) + keep_db |= stayopen; + /* Reset the sequential index. */ + entidx = 0; + + __libc_lock_unlock (lock); + + return status; +} + + +/* Close it again. */ +enum nss_status +CONCAT(_nss_db_end,ENTNAME) (void) +{ + __libc_lock_lock (lock); + + internal_endent (&db); + + /* Reset STAYOPEN flag. */ + keep_db = 0; + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +/* Do a database lookup for KEY. */ +static enum nss_status +lookup (DBT *key, struct STRUCTURE *result, + void *buffer, int buflen H_ERRNO_PROTO) +{ + char *p; + enum nss_status status; + int err; + DBT value; + + /* Open the database. */ + if (db == NULL) + { + status = internal_setent (DBFILE, &db); + if (status != NSS_STATUS_SUCCESS) + { + H_ERRNO_SET (NETDB_INTERNAL); + return status; + } + } + + /* Succeed iff it matches a value that parses correctly. */ + value.flags = 0; + err = DL_CALL_FCT (db->get, (db->db, NULL, key, &value, 0)); + if (err != 0) + { + if (err == db_notfound) + { + H_ERRNO_SET (HOST_NOT_FOUND); + status = NSS_STATUS_NOTFOUND; + } + else + { + H_ERRNO_SET (NETDB_INTERNAL); + status = NSS_STATUS_UNAVAIL; + } + } + else if (buflen < value.size) + { + /* No room to copy the data to. */ + __set_errno (ERANGE); + H_ERRNO_SET (NETDB_INTERNAL); + status = NSS_STATUS_TRYAGAIN; + } + else + { + /* Copy the result to a safe place. */ + p = (char *) memcpy (buffer, value.data, value.size); + + /* Skip leading blanks. */ + while (isspace (*p)) + ++p; + + err = parse_line (p, result, buffer, buflen); + + if (err == 0) + { + /* If the key begins with '0' we are trying to get the next + entry. We want to ignore unparsable lines in this case. */ + if (((char *) key->data)[0] == '0') + { + /* Super magical return value. We need to tell our caller + that it should continue looping. This value cannot + happen in other cases. */ + status = NSS_STATUS_RETURN; + } + else + { + H_ERRNO_SET (HOST_NOT_FOUND); + status = NSS_STATUS_NOTFOUND; + } + } + else if (err < 0) + { + H_ERRNO_SET (NETDB_INTERNAL); + status = NSS_STATUS_TRYAGAIN; + } + else + status = NSS_STATUS_SUCCESS; + } + + if (! keep_db) + internal_endent (&db); + + return status; +} + + +/* Macro for defining lookup functions for this DB-based database. + + NAME is the name of the lookup; e.g. `pwnam'. + + KEYPATTERN gives `printf' args to construct a key string; + e.g. `(".%s", name)'. + + KEYSIZE gives the allocation size of a buffer to construct it in; + e.g. `1 + strlen (name)'. + + PROTO describes the arguments for the lookup key; + e.g. `const char *name'. + + BREAK_IF_MATCH is ignored, but used by ../nss_files/files-XXX.c. */ + +#define DB_LOOKUP(name, keysize, keypattern, break_if_match, proto...) \ +enum nss_status \ +_nss_db_get##name##_r (proto, \ + struct STRUCTURE *result, \ + char *buffer, size_t buflen H_ERRNO_PROTO)\ +{ \ + DBT key; \ + enum nss_status status; \ + const size_t size = (keysize) + 1; \ + key.data = __alloca (size); \ + key.size = KEYPRINTF keypattern; \ + key.flags = 0; \ + __libc_lock_lock (lock); \ + status = lookup (&key, result, buffer, buflen H_ERRNO_ARG); \ + __libc_lock_unlock (lock); \ + return status; \ +} + +#define KEYPRINTF(pattern, args...) snprintf (key.data, size, pattern ,##args) + + + + +/* Return the next entry from the database file, doing locking. */ +enum nss_status +CONCAT(_nss_db_get,ENTNAME_r) (struct STRUCTURE *result, char *buffer, + size_t buflen H_ERRNO_PROTO) +{ + /* Return next entry in host file. */ + enum nss_status status; + char buf[20]; + DBT key; + + __libc_lock_lock (lock); + + /* Loop until we find a valid entry or hit EOF. See above for the + special meaning of the status value. */ + do + { + key.size = snprintf (key.data = buf, sizeof buf, "0%u", entidx++); + key.flags = 0; + status = lookup (&key, result, buffer, buflen H_ERRNO_ARG); + if (status == NSS_STATUS_TRYAGAIN +#ifdef NEED_H_ERRNO + && *herrnop == NETDB_INTERNAL +#endif + && errno == ERANGE) + /* Give the user a chance to get the same entry with a larger + buffer. */ + --entidx; + } + while (status == NSS_STATUS_RETURN); + + __libc_lock_unlock (lock); + + return status; +} diff --git a/glibc-compat/nss_db/db-alias.c b/glibc-compat/nss_db/db-alias.c new file mode 100644 index 0000000000..b9b9489989 --- /dev/null +++ b/glibc-compat/nss_db/db-alias.c @@ -0,0 +1,208 @@ +/* Mail alias file parser in nss_db module. + Copyright (C) 1996, 1997, 1998, 1999, 2000 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 <glibc-compat/include/aliases.h> +#include <alloca.h> +#include <ctype.h> +#include <dlfcn.h> +#include <errno.h> +#include <bits/libc-lock.h> +#include <paths.h> +#include <string.h> + +#include "nsswitch.h" +#include "nss_db.h" + +/* Locks the static variables in this file. */ +__libc_lock_define_initialized (static, lock) + +/* Maintenance of the shared handle open on the database. */ + +static NSS_DB *db; +static int keep_db; +static unsigned int entidx; /* Index for `getaliasent_r'. */ + + +/* Open database. */ +enum nss_status +_nss_db_setaliasent (int stayopen) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_setent (_PATH_VARDB "aliases.db", &db); + + /* Remember STAYOPEN flag. */ + if (db != NULL) + keep_db |= stayopen; + + /* Reset the sequential index. */ + entidx = 0; + + __libc_lock_unlock (lock); + + return status; +} + + +/* Close it again. */ +enum nss_status +_nss_db_endaliasent (void) +{ + __libc_lock_lock (lock); + + internal_endent (&db); + + /* Reset STAYOPEN flag. */ + keep_db = 0; + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +/* We provide the parse function here. The parser in libnss_files + cannot be used. The generation of the db file already resolved all + :include: statements so we simply have to parse the list and store + the result. */ +static enum nss_status +lookup (DBT *key, struct aliasent *result, char *buffer, + size_t buflen) +{ + enum nss_status status; + DBT value; + + /* Open the database. */ + if (db == NULL) + { + status = internal_setent (_PATH_VARDB "aliases.db", &db); + if (status != NSS_STATUS_SUCCESS) + return status; + } + + value.flags = 0; + if (DL_CALL_FCT (db->get, (db->db, NULL, key, &value, 0)) == 0) + { + const char *src = value.data; + char *cp; + size_t cnt; + + result->alias_members_len = 0; + + /* We now have to fill the BUFFER with all the information. */ + if (buflen < key->size + 1) + { + no_more_room: + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + buffer = stpncpy (buffer, key->data, key->size) + 1; + buflen -= key->size + 1; + + while (*src != '\0') + { + const char *end, *upto; + while (isspace (*src)) + ++src; + + end = strchr (src, ','); + if (end == NULL) + end = strchr (src, '\0'); + for (upto = end; upto > src && isspace (upto[-1]); --upto); + + if (upto != src) + { + if ((upto - src) + __alignof__ (char *) > buflen) + goto no_more_room; + buffer = stpncpy (buffer, src, upto - src) + 1; + buflen -= (upto - src) + __alignof (char *); + ++result->alias_members_len; + } + src = end + (*end != '\0'); + } + + /* Now prepare the return. Provide string pointers for the + currently selected aliases. */ + + /* Adjust the pointer so it is aligned for storing pointers. */ + buffer += __alignof__ (char *) - 1; + buffer -= ((buffer - (char *) 0) % __alignof__ (char *)); + result->alias_members = (char **) buffer; + + /* Compute addresses of alias entry strings. */ + cp = result->alias_name; + for (cnt = 0; cnt < result->alias_members_len; ++cnt) + { + cp = strchr (cp, '\0') + 1; + result->alias_members[cnt] = cp; + } + + status = (result->alias_members_len == 0 + ? NSS_STATUS_RETURN : NSS_STATUS_SUCCESS); + } + else + status = NSS_STATUS_NOTFOUND; + + if (! keep_db) + internal_endent (&db); + + return status; +} + +enum nss_status +_nss_db_getaliasent_r (struct aliasent *result, char *buffer, size_t buflen) +{ + /* Return next entry in alias file. */ + enum nss_status status; + char buf[20]; + DBT key; + + __libc_lock_lock (lock); + key.size = snprintf (key.data = buf, sizeof buf, "0%u", entidx++); + key.flags = 0; + status = lookup (&key, result, buffer, buflen); + __libc_lock_unlock (lock); + + return status; +} + + +enum nss_status +_nss_db_getaliasbyname_r (const char *name, struct aliasent *result, + char *buffer, size_t buflen) +{ + DBT key; + enum nss_status status; + + key.size = 1 + strlen (name); + + key.data = __alloca (key.size); + ((char *) key.data)[0] = '.'; + memcpy (&((char *) key.data)[1], name, key.size - 1); + key.flags = 0; + + __libc_lock_lock (lock); + status = lookup (&key, result, buffer, buflen); + __libc_lock_unlock (lock); + + return status; +} diff --git a/glibc-compat/nss_db/db-netgrp.c b/glibc-compat/nss_db/db-netgrp.c new file mode 100644 index 0000000000..73309077e1 --- /dev/null +++ b/glibc-compat/nss_db/db-netgrp.c @@ -0,0 +1,101 @@ +/* Netgroup file parser in nss_db modules. + Copyright (C) 1996, 1997, 1999, 2000 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 <dlfcn.h> +#include <errno.h> +#include <fcntl.h> +#include <netgroup.h> +#include <string.h> +#include <bits/libc-lock.h> +#include <paths.h> + +#include "nsswitch.h" +#include "nss_db.h" + + +#define DBFILE _PATH_VARDB "netgroup.db" + + +/* Locks the static variables in this file. */ +__libc_lock_define_initialized (static, lock) + +/* Maintenance of the shared handle open on the database. */ +static NSS_DB *db; +static char *entry; +static char *cursor; + +enum nss_status +_nss_db_setnetgrent (const char *group) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_setent (DBFILE, &db); + + if (status == NSS_STATUS_SUCCESS) + { + DBT key = { data: (void *) group, size: strlen (group), flags: 0 }; + DBT value; + + value.flags = 0; + if (DL_CALL_FCT (db->get, (db->db, NULL, &key, &value, 0)) != 0) + status = NSS_STATUS_NOTFOUND; + else + cursor = entry = value.data; + } + + __libc_lock_unlock (lock); + + return status; + +} + + +enum nss_status +_nss_db_endnetgrent (void) +{ + __libc_lock_lock (lock); + + internal_endent (&db); + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + + +extern enum nss_status _nss_netgroup_parseline (char **cursor, + struct __netgrent *result, + char *buffer, int buflen); + +enum nss_status +_nss_db_getnetgrent_r (struct __netgrent *result, char *buffer, size_t buflen) +{ + int status; + + __libc_lock_lock (lock); + + status = _nss_netgroup_parseline (&cursor, result, buffer, buflen); + + __libc_lock_unlock (lock); + + return status; +} diff --git a/glibc-compat/nss_db/db-open.c b/glibc-compat/nss_db/db-open.c new file mode 100644 index 0000000000..99ff3030f0 --- /dev/null +++ b/glibc-compat/nss_db/db-open.c @@ -0,0 +1 @@ +#include <nss/nss_db/db-open.c> diff --git a/glibc-compat/nss_db/dummy-db.h b/glibc-compat/nss_db/dummy-db.h new file mode 100644 index 0000000000..aed84621c1 --- /dev/null +++ b/glibc-compat/nss_db/dummy-db.h @@ -0,0 +1 @@ +#include <nss/nss_db/dummy-db.h> diff --git a/glibc-compat/nss_db/nss_db.h b/glibc-compat/nss_db/nss_db.h new file mode 100644 index 0000000000..0bd98b5866 --- /dev/null +++ b/glibc-compat/nss_db/nss_db.h @@ -0,0 +1 @@ +#include <nss/nss_db/nss_db.h> diff --git a/glibc-compat/nss_dns/dns-host.c b/glibc-compat/nss_dns/dns-host.c new file mode 100644 index 0000000000..5db030cde1 --- /dev/null +++ b/glibc-compat/nss_dns/dns-host.c @@ -0,0 +1,641 @@ +/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Extended from original form 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. */ + +/* Parts of this file are plain copies of the file `gethtnamadr.c' from + the bind package and it has the following copyright. */ + +/* + * ++Copyright++ 1985, 1988, 1993 + * - + * Copyright (c) 1985, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ + +#include <ctype.h> +#include <errno.h> +#include <glibc-compat/include/netdb.h> +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <string.h> +#include <sys/syslog.h> + +#include "nsswitch.h" + +/* Get implementation for some internal functions. */ +#include "../resolv/mapv4v6addr.h" +#include "../resolv/mapv4v6hostent.h" + +/* Maximum number of aliases we allow. */ +#define MAX_NR_ALIASES 48 +#define MAX_NR_ADDRS 48 + +#if PACKETSZ > 65536 +# define MAXPACKET PACKETSZ +#else +# define MAXPACKET 65536 +#endif +/* As per RFC 1034 and 1035 a host name cannot exceed 255 octets in length. */ +#ifdef MAXHOSTNAMELEN +# undef MAXHOSTNAMELEN +#endif +#define MAXHOSTNAMELEN 256 + +static const char AskedForGot[] = "\ +gethostby*.getanswer: asked for \"%s\", got \"%s\""; + + +/* We need this time later. */ +typedef union querybuf +{ + HEADER hdr; + u_char buf[MAXPACKET]; +} querybuf; + + +static enum nss_status getanswer_r (const querybuf *answer, int anslen, + const char *qname, int qtype, + struct hostent *result, char *buffer, + size_t buflen, int *h_errnop); + +enum nss_status +_nss_dns_gethostbyname2_r (const char *name, int af, struct hostent *result, + char *buffer, size_t buflen, int *h_errnop) +{ + union + { + querybuf *buf; + u_char *ptr; + } host_buffer; + querybuf *orig_host_buffer; + int size, type, n; + const char *cp; + enum nss_status status; + + if ((_res.options & RES_INIT) == 0 && res_init() == -1) + { + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_UNAVAIL; + } + + switch (af) { + case AF_INET: + size = INADDRSZ; + type = T_A; + break; + case AF_INET6: + size = IN6ADDRSZ; + type = T_AAAA; + break; + default: + *h_errnop = NETDB_INTERNAL; + __set_errno (EAFNOSUPPORT); + return NSS_STATUS_UNAVAIL; + } + + result->h_addrtype = af; + result->h_length = size; + + /* + * if there aren't any dots, it could be a user-level alias. + * this is also done in res_query() since we are not the only + * function that looks up host names. + */ + if (strchr (name, '.') == NULL && (cp = __hostalias (name)) != NULL) + name = cp; + + host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024); + + n = __libc_res_nsearch (&_res, name, C_IN, type, host_buffer.buf->buf, 1024, + &host_buffer.ptr); + if (n < 0) + { + *h_errnop = h_errno; + if (host_buffer.buf != orig_host_buffer) + free (host_buffer.buf); + return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND; + } + + status = getanswer_r (host_buffer.buf, n, name, type, result, buffer, buflen, + h_errnop); + if (host_buffer.buf != orig_host_buffer) + free (host_buffer.buf); + return status; +} + + +enum nss_status +_nss_dns_gethostbyname_r (const char *name, struct hostent *result, + char *buffer, size_t buflen, int *h_errnop) +{ + enum nss_status status = NSS_STATUS_NOTFOUND; + + if (_res.options & RES_USE_INET6) + status = _nss_dns_gethostbyname2_r (name, AF_INET6, result, buffer, + buflen, h_errnop); + if (status == NSS_STATUS_NOTFOUND) + status = _nss_dns_gethostbyname2_r (name, AF_INET, result, buffer, + buflen, h_errnop); + + return status; +} + + +enum nss_status +_nss_dns_gethostbyaddr_r (const char *addr, int len, int af, + struct hostent *result, char *buffer, size_t buflen, + int *h_errnop) +{ + static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff }; + static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 }; + const u_char *uaddr = (const u_char *)addr; + struct host_data + { + char *aliases[MAX_NR_ALIASES]; + unsigned char host_addr[16]; /* IPv4 or IPv6 */ + char *h_addr_ptrs[MAX_NR_ADDRS + 1]; + char linebuffer[0]; + } *host_data = (struct host_data *) buffer; + union + { + querybuf *buf; + u_char *ptr; + } host_buffer; + querybuf *orig_host_buffer; + char qbuf[MAXDNAME+1], *qp; + int size, n, status; + + if ((_res.options & RES_INIT) == 0 && res_init() == -1) + { + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_UNAVAIL; + } + + if (af == AF_INET6 && len == IN6ADDRSZ && + (memcmp (uaddr, mapped, sizeof mapped) == 0 + || memcmp (uaddr, tunnelled, sizeof tunnelled) == 0)) + { + /* Unmap. */ + addr += sizeof mapped; + uaddr += sizeof mapped; + af = AF_INET; + len = INADDRSZ; + } + + switch (af) + { + case AF_INET: + size = INADDRSZ; + break; + case AF_INET6: + size = IN6ADDRSZ; + break; + default: + __set_errno (EAFNOSUPPORT); + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_UNAVAIL; + } + if (size != len) + { + __set_errno (EAFNOSUPPORT); + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_UNAVAIL; + } + + switch (af) + { + case AF_INET: + sprintf (qbuf, "%u.%u.%u.%u.in-addr.arpa", (uaddr[3] & 0xff), + (uaddr[2] & 0xff), (uaddr[1] & 0xff), (uaddr[0] & 0xff)); + break; + case AF_INET6: + qp = qbuf; + for (n = IN6ADDRSZ - 1; n >= 0; n--) + qp += sprintf (qp, "%x.%x.", uaddr[n] & 0xf, (uaddr[n] >> 4) & 0xf); + strcpy(qp, "ip6.int"); + break; + default: + /* Cannot happen. */ + break; + } + + host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024); + + n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, host_buffer.buf->buf, + 1024, &host_buffer.ptr); + if (n < 0) + { + *h_errnop = h_errno; + if (host_buffer.buf != orig_host_buffer) + free (host_buffer.buf); + return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND; + } + + status = getanswer_r (host_buffer.buf, n, qbuf, T_PTR, result, buffer, buflen, + h_errnop); + if (host_buffer.buf != orig_host_buffer) + free (host_buffer.buf); + if (status != NSS_STATUS_SUCCESS) + { + *h_errnop = h_errno; + return status; + } + +#ifdef SUNSECURITY + This is not implemented because it is not possible to use the current + source from bind in a multi-threaded program. +#endif + + result->h_addrtype = af; + result->h_length = len; + memcpy (host_data->host_addr, addr, len); + host_data->h_addr_ptrs[0] = (char *) host_data->host_addr; + host_data->h_addr_ptrs[1] = NULL; + if (af == AF_INET && (_res.options & RES_USE_INET6)) + { + map_v4v6_address ((char *) host_data->host_addr, + (char *) host_data->host_addr); + result->h_addrtype = AF_INET6; + result->h_length = IN6ADDRSZ; + } + *h_errnop = NETDB_SUCCESS; + return NSS_STATUS_SUCCESS; +} + + +static enum nss_status +getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype, + struct hostent *result, char *buffer, size_t buflen, + int *h_errnop) +{ + struct host_data + { + char *aliases[MAX_NR_ALIASES]; + unsigned char host_addr[16]; /* IPv4 or IPv6 */ + char *h_addr_ptrs[MAX_NR_ADDRS + 1]; + char linebuffer[0]; + } *host_data = (struct host_data *) buffer; + int linebuflen = buflen - offsetof (struct host_data, linebuffer); + register const HEADER *hp; + const u_char *end_of_message, *cp; + int n, ancount, qdcount; + int haveanswer, had_error; + char *bp, **ap, **hap; + char tbuf[MAXDNAME]; + const char *tname; + int (*name_ok) (const char *); + + tname = qname; + result->h_name = NULL; + end_of_message = answer->buf + anslen; + switch (qtype) + { + case T_A: + case T_AAAA: + name_ok = res_hnok; + break; + case T_PTR: + name_ok = res_dnok; + break; + default: + return NSS_STATUS_UNAVAIL; /* XXX should be abort(); */ + } + + /* + * find first satisfactory answer + */ + hp = &answer->hdr; + bp = host_data->linebuffer; + ancount = ntohs (hp->ancount); + qdcount = ntohs (hp->qdcount); + cp = answer->buf + HFIXEDSZ; + if (qdcount != 1) + { + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; + } + + n = dn_expand (answer->buf, end_of_message, cp, bp, linebuflen); + if (n < 0 || (*name_ok) (bp) == 0) + { + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; + } + cp += n + QFIXEDSZ; + + if (qtype == T_A || qtype == T_AAAA) + { + /* res_send() has already verified that the query name is the + * same as the one we sent; this just gets the expanded name + * (i.e., with the succeeding search-domain tacked on). + */ + n = strlen (bp) + 1; /* for the \0 */ + if (n >= MAXHOSTNAMELEN) + { + __set_h_errno (NO_RECOVERY); + return NSS_STATUS_TRYAGAIN; + } + result->h_name = bp; + bp += n; + linebuflen -= n; + /* The qname can be abbreviated, but h_name is now absolute. */ + qname = result->h_name; + } + + ap = host_data->aliases; + *ap = NULL; + result->h_aliases = host_data->aliases; + hap = host_data->h_addr_ptrs; + *hap = NULL; + result->h_addr_list = host_data->h_addr_ptrs; + haveanswer = 0; + had_error = 0; + + while (ancount-- > 0 && cp < end_of_message && had_error == 0) + { + int type, class; + + n = dn_expand (answer->buf, end_of_message, cp, bp, linebuflen); + if (n < 0 || (*name_ok) (bp) == 0) + { + ++had_error; + continue; + } + cp += n; /* name */ + type = _getshort (cp); + cp += INT16SZ; /* type */ + class = _getshort(cp); + cp += INT16SZ + INT32SZ; /* class, TTL */ + n = _getshort(cp); + cp += INT16SZ; /* len */ + if (class != C_IN) + { + /* XXX - debug? syslog? */ + cp += n; + continue; /* XXX - had_error++ ? */ + } + + if ((qtype ==T_A || qtype == T_AAAA) && type == T_CNAME) + { + if (ap >= &host_data->aliases[MAX_NR_ALIASES - 1]) + continue; + n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf); + if (n < 0 || (*name_ok) (tbuf) == 0) + { + ++had_error; + continue; + } + cp += n; + /* Store alias. */ + *ap++ = bp; + n = strlen (bp) + 1; /* For the \0. */ + if (n >= MAXHOSTNAMELEN) + { + ++had_error; + continue; + } + bp += n; + linebuflen -= n; + /* Get canonical name. */ + n = strlen (tbuf) + 1; /* For the \0. */ + if ((size_t) n > linebuflen || n >= MAXHOSTNAMELEN) + { + ++had_error; + continue; + } + strcpy (bp, tbuf); /* Cannot overflow. */ + result->h_name = bp; + bp += n; + linebuflen -= n; + continue; + } + + if (qtype == T_PTR && type == T_CNAME) + { + n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf); + if (n < 0 || res_dnok (tbuf) == 0) + { + ++had_error; + continue; + } + cp += n; + /* Get canonical name. */ + n = strlen (tbuf) + 1; /* For the \0. */ + if ((size_t) n > linebuflen || n >= MAXHOSTNAMELEN) + { + ++had_error; + continue; + } + strcpy (bp, tbuf); /* Cannot overflow. */ + tname = bp; + bp += n; + linebuflen -= n; + continue; + } + if (type != qtype) + { + syslog (LOG_NOTICE | LOG_AUTH, + "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", + qname, p_class (C_IN), p_type (qtype), p_type (type)); + cp += n; + continue; /* XXX - had_error++ ? */ + } + + switch (type) + { + case T_PTR: + if (strcasecmp (tname, bp) != 0) + { + syslog (LOG_NOTICE | LOG_AUTH, AskedForGot, qname, bp); + cp += n; + continue; /* XXX - had_error++ ? */ + } + n = dn_expand (answer->buf, end_of_message, cp, bp, linebuflen); + if (n < 0 || res_hnok (bp) == 0) + { + ++had_error; + break; + } +#if MULTI_PTRS_ARE_ALIASES + cp += n; + if (haveanswer == 0) + result->h_name = bp; + else if (ap < &host_data->aliases[MAXALIASES-1]) + *ap++ = bp; + else + n = -1; + if (n != -1) + { + n = strlen (bp) + 1; /* for the \0 */ + if (n >= MAXHOSTNAMELEN) + { + ++had_error; + break; + } + bp += n; + linebuflen -= n; + } + break; +#else + result->h_name = bp; + if (_res.options & RES_USE_INET6) + { + n = strlen (bp) + 1; /* for the \0 */ + if (n >= MAXHOSTNAMELEN) + { + ++had_error; + break; + } + bp += n; + linebuflen -= n; + map_v4v6_hostent (result, &bp, &linebuflen); + } + *h_errnop = NETDB_SUCCESS; + return NSS_STATUS_SUCCESS; +#endif + case T_A: + case T_AAAA: + if (strcasecmp (result->h_name, bp) != 0) + { + syslog (LOG_NOTICE | LOG_AUTH, AskedForGot, result->h_name, bp); + cp += n; + continue; /* XXX - had_error++ ? */ + } + if (n != result->h_length) + { + cp += n; + continue; + } + if (!haveanswer) + { + register int nn; + + result->h_name = bp; + nn = strlen (bp) + 1; /* for the \0 */ + bp += nn; + linebuflen -= nn; + } + + linebuflen -= sizeof (align) - ((u_long) bp % sizeof (align)); + bp += sizeof (align) - ((u_long) bp % sizeof (align)); + + if (n >= linebuflen) + { + ++had_error; + continue; + } + if (hap >= &host_data->h_addr_ptrs[MAX_NR_ADDRS-1]) + { + cp += n; + continue; + } + memcpy (*hap++ = bp, cp, n); + bp += n; + cp += n; + linebuflen -= n; + break; + default: + abort (); + } + if (had_error == 0) + ++haveanswer; + } + + if (haveanswer > 0) + { + *ap = NULL; + *hap = NULL; +#if defined(RESOLVSORT) + /* + * Note: we sort even if host can take only one address + * in its return structures - should give it the "best" + * address in that case, not some random one + */ + if (_res.nsort && haveanswer > 1 && qtype == T_A) + addrsort (host_data->h_addr_ptrs, haveanswer); +#endif /*RESOLVSORT*/ + + if (result->h_name == NULL) + { + n = strlen (qname) + 1; /* For the \0. */ + if (n > linebuflen || n >= MAXHOSTNAMELEN) + goto no_recovery; + strcpy (bp, qname); /* Cannot overflow. */ + result->h_name = bp; + bp += n; + linebuflen -= n; + } + + if (_res.options & RES_USE_INET6) + map_v4v6_hostent (result, &bp, &linebuflen); + *h_errnop = NETDB_SUCCESS; + return NSS_STATUS_SUCCESS; + } + no_recovery: + *h_errnop = NO_RECOVERY; + return NSS_STATUS_TRYAGAIN; +} diff --git a/glibc-compat/nss_dns/dns-network.c b/glibc-compat/nss_dns/dns-network.c new file mode 100644 index 0000000000..b6c7a4fdc9 --- /dev/null +++ b/glibc-compat/nss_dns/dns-network.c @@ -0,0 +1,420 @@ +/* Copyright (C) 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Extended from original form 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. */ + +/* Parts of this file are plain copies of the file `getnetnamadr.c' from + the bind package and it has the following copyright. */ + +/* Copyright (c) 1993 Carlos Leandro and Rui Salgueiro + * Dep. Matematica Universidade de Coimbra, Portugal, Europe + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <ctype.h> +#include <errno.h> +#include <glibc-compat/include/netdb.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "nsswitch.h" +#include <arpa/inet.h> + +/* Maximum number of aliases we allow. */ +#define MAX_NR_ALIASES 48 + + +#if PACKETSZ > 65536 +#define MAXPACKET PACKETSZ +#else +#define MAXPACKET 65536 +#endif + + +typedef enum +{ + BYADDR, + BYNAME +} lookup_method; + + +/* We need this time later. */ +typedef union querybuf +{ + HEADER hdr; + u_char buf[MAXPACKET]; +} querybuf; + + +/* Prototypes for local functions. */ +static enum nss_status getanswer_r (const querybuf *answer, int anslen, + struct netent *result, char *buffer, + size_t buflen, lookup_method net_i); + + +enum nss_status +_nss_dns_getnetbyname_r (const char *name, struct netent *result, + char *buffer, size_t buflen) +{ + /* Return entry for network with NAME. */ + union + { + querybuf *buf; + u_char *ptr; + } net_buffer; + querybuf *orig_net_buffer; + int anslen; + char *qbuf; + enum nss_status status; + + if ((_res.options & RES_INIT) == 0 && res_init() == -1) + return NSS_STATUS_UNAVAIL; + + qbuf = strdupa (name); + + net_buffer.buf = orig_net_buffer = (querybuf *) alloca (1024); + + anslen = __libc_res_nsearch (&_res, qbuf, C_IN, T_PTR, net_buffer.buf->buf, + 1024, &net_buffer.ptr); + if (anslen < 0) + { + if (net_buffer.buf != orig_net_buffer) + free (net_buffer.buf); + /* Nothing found. */ + return (errno == ECONNREFUSED + || errno == EPFNOSUPPORT + || errno == EAFNOSUPPORT) + ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND; + } + + status = getanswer_r (net_buffer.buf, anslen, result, buffer, buflen, BYNAME); + if (net_buffer.buf != orig_net_buffer) + free (net_buffer.buf); + return status; +} + + +enum nss_status +_nss_dns_getnetbyaddr_r (long net, int type, struct netent *result, + char *buffer, size_t buflen) +{ + /* Return entry for network with NAME. */ + enum nss_status status; + union + { + querybuf *buf; + u_char *ptr; + } net_buffer; + querybuf *orig_net_buffer; + unsigned int net_bytes[4]; + char qbuf[MAXDNAME]; + int cnt, anslen; + u_int32_t net2; + + if ((_res.options & RES_INIT) == 0 && res_init() == -1) + return NSS_STATUS_UNAVAIL; + + /* No net address lookup for IPv6 yet. */ + if (type != AF_INET) + return NSS_STATUS_UNAVAIL; + + net2 = (u_int32_t) net; + for (cnt = 4; net2 != 0; net2 >>= 8) + net_bytes[--cnt] = net2 & 0xff; + + switch (cnt) + { + case 3: + /* Class A network. */ + sprintf (qbuf, "0.0.0.%u.in-addr.arpa", net_bytes[3]); + break; + case 2: + /* Class B network. */ + sprintf (qbuf, "0.0.%u.%u.in-addr.arpa", net_bytes[3], net_bytes[2]); + break; + case 1: + /* Class C network. */ + sprintf (qbuf, "0.%u.%u.%u.in-addr.arpa", net_bytes[3], net_bytes[2], + net_bytes[1]); + break; + case 0: + /* Class D - E network. */ + sprintf (qbuf, "%u.%u.%u.%u.in-addr.arpa", net_bytes[3], net_bytes[2], + net_bytes[1], net_bytes[0]); + break; + } + + net_buffer.buf = orig_net_buffer = (querybuf *) alloca (1024); + + anslen = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, net_buffer.buf->buf, + 1024, &net_buffer.ptr); + if (anslen < 0) + { + if (net_buffer.buf != orig_net_buffer) + free (net_buffer.buf); + /* Nothing found. */ + return (errno == ECONNREFUSED + || errno == EPFNOSUPPORT + || errno == EAFNOSUPPORT) + ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND; + } + + status = getanswer_r (net_buffer.buf, anslen, result, buffer, buflen, BYADDR); + if (net_buffer.buf != orig_net_buffer) + free (net_buffer.buf); + if (status == NSS_STATUS_SUCCESS) + { + /* Strip trailing zeros. */ + unsigned int u_net = net; /* Maybe net should be unsigned? */ + + while ((u_net & 0xff) == 0 && u_net != 0) + u_net >>= 8; + result->n_net = u_net; + } + + return status; +} + + +#undef offsetof +#define offsetof(Type, Member) ((size_t) &((Type *) NULL)->Member) + +static enum nss_status +getanswer_r (const querybuf *answer, int anslen, struct netent *result, + char *buffer, size_t buflen, lookup_method net_i) +{ + /* + * Find first satisfactory answer + * + * answer --> +------------+ ( MESSAGE ) + * | Header | + * +------------+ + * | Question | the question for the name server + * +------------+ + * | Answer | RRs answering the question + * +------------+ + * | Authority | RRs pointing toward an authority + * | Additional | RRs holding additional information + * +------------+ + */ + struct net_data + { + char *aliases[MAX_NR_ALIASES]; + char linebuffer[0]; + } *net_data = (struct net_data *) buffer; + int linebuflen = buflen - offsetof (struct net_data, linebuffer); + const char *end_of_message = &answer->buf[anslen]; + const HEADER *header_pointer = &answer->hdr; + /* #/records in the answer section. */ + int answer_count = ntohs (header_pointer->ancount); + /* #/entries in the question section. */ + int question_count = ntohs (header_pointer->qdcount); + char *bp = net_data->linebuffer; + const char *cp = &answer->buf[HFIXEDSZ]; + char **alias_pointer; + int have_answer; + char *ans; + + if (question_count == 0) + { + /* FIXME: the Sun version uses for host name lookup an additional + parameter for pointing to h_errno. this is missing here. + OSF/1 has a per-thread h_errno variable. */ + if (header_pointer->aa != 0) + { + __set_h_errno (HOST_NOT_FOUND); + return NSS_STATUS_NOTFOUND; + } + else + { + __set_h_errno (TRY_AGAIN); + return NSS_STATUS_TRYAGAIN; + } + } + + /* Skip the question part. */ + while (question_count-- > 0) + { + int n = __dn_skipname (cp, end_of_message); + if (n < 0 || end_of_message - (cp + n) < QFIXEDSZ) + { + __set_h_errno (NO_RECOVERY); + return NSS_STATUS_UNAVAIL; + } + cp += n + QFIXEDSZ; + } + + alias_pointer = result->n_aliases = &net_data->aliases[0]; + *alias_pointer = NULL; + have_answer = 0; + ans = NULL; + + while (--answer_count >= 0 && cp < end_of_message) + { + int n = dn_expand (answer->buf, end_of_message, cp, bp, linebuflen); + int type, class; + + if (n < 0 || res_dnok (bp) == 0) + break; + cp += n; + ans = strdupa (bp); + GETSHORT (type, cp); + GETSHORT (class, cp); + cp += INT32SZ; /* TTL */ + GETSHORT (n, cp); + + if (class == C_IN && type == T_PTR) + { + n = dn_expand (answer->buf, end_of_message, cp, bp, linebuflen); + if (n < 0 || !res_hnok (bp)) + { + /* XXX What does this mean? The original form from bind + returns NULL. Incrementing cp has no effect in any case. + What should I return here. ??? */ + cp += n; + return NSS_STATUS_UNAVAIL; + } + cp += n; + if (alias_pointer + 2 < &net_data->aliases[MAX_NR_ALIASES]) + { + *alias_pointer++ = bp; + n = strlen (bp) + 1; + bp += n; + linebuflen -= n; + result->n_addrtype = class == C_IN ? AF_INET : AF_UNSPEC; + ++have_answer; + } + } + } + + if (have_answer) + { + *alias_pointer = NULL; + switch (net_i) + { + case BYADDR: + result->n_name = *result->n_aliases++; + result->n_net = 0L; + return NSS_STATUS_SUCCESS; + + case BYNAME: + { + char **ap = result->n_aliases++; + while (*ap != NULL) + { + /* Check each alias name for being of the forms: + 4.3.2.1.in-addr.arpa = net 1.2.3.4 + 3.2.1.in-addr.arpa = net 0.1.2.3 + 2.1.in-addr.arpa = net 0.0.1.2 + 1.in-addr.arpa = net 0.0.0.1 + */ + uint32_t val = 0; /* Accumulator for n_net value. */ + unsigned int shift = 0; /* Which part we are parsing now. */ + const char *p = *ap; /* Consuming the string. */ + do + { + /* Match the leading 0 or 0[xX] base indicator. */ + unsigned int base = 10; + if (*p == '0' && p[1] != '.') + { + base = 8; + ++p; + if (*p == 'x' || *p == 'X') + { + base = 16; + ++p; + if (*p == '.') + break; /* No digit here. Give up on alias. */ + } + if (*p == '\0') + break; + } + + uint32_t part = 0; /* Accumulates this part's number. */ + do + { + if (isdigit (*p) && (*p - '0' < base)) + part = (part * base) + (*p - '0'); + else if (base == 16 && isxdigit (*p)) + part = (part << 4) + 10 + (tolower (*p) - 'a'); + ++p; + } while (*p != '\0' && *p != '.'); + + if (*p != '.') + break; /* Bad form. Give up on this name. */ + + /* Install this as the next more significant byte. */ + val |= part << shift; + shift += 8; + ++p; + + /* If we are out of digits now, there are two cases: + 1. We are done with digits and now see "in-addr.arpa". + 2. This is not the droid we are looking for. */ + if (!isdigit (*p) && !strcasecmp (p, "in-addr.arpa")) + { + result->n_net = val; + return NSS_STATUS_SUCCESS; + } + + /* Keep going when we have seen fewer than 4 parts. */ + } while (shift < 32); + } + } + break; + } + } + + __set_h_errno (TRY_AGAIN); + return NSS_STATUS_TRYAGAIN; +} diff --git a/glibc-compat/nss_files/files-XXX.c b/glibc-compat/nss_files/files-XXX.c new file mode 100644 index 0000000000..fde75a87b4 --- /dev/null +++ b/glibc-compat/nss_files/files-XXX.c @@ -0,0 +1,311 @@ +/* Common code for file-based databases in nss_files module. + Copyright (C) 1996, 1997, 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. */ + +#include <stdio.h> +#include <ctype.h> +#include <fcntl.h> +#include <assert.h> +#include <errno.h> +#include <bits/libc-lock.h> +#include "nsswitch.h" + +/* These symbols are defined by the including source file: + + ENTNAME -- database name of the structure and functions (hostent, pwent). + STRUCTURE -- struct name, define only if not ENTNAME (passwd, group). + DATABASE -- string of the database file's name ("hosts", "passwd"). + + NEED_H_ERRNO - defined iff an arg `int *herrnop' is used. + + Also see files-parse.c. +*/ + +#define ENTNAME_r CONCAT(ENTNAME,_r) + +#define DATAFILE "/etc/" DATABASE + +#ifdef NEED_H_ERRNO +# include <glibc-compat/include/netdb.h> +# define H_ERRNO_PROTO , int *herrnop +# define H_ERRNO_ARG , herrnop +# define H_ERRNO_SET(val) (*herrnop = (val)) +#else +# define H_ERRNO_PROTO +# define H_ERRNO_ARG +# define H_ERRNO_SET(val) ((void) 0) +#endif + +/* Locks the static variables in this file. */ +__libc_lock_define_initialized (static, lock) + +/* Maintenance of the shared stream open on the database file. */ + +static FILE *stream; +static fpos_t position; +static enum { none, getent, getby } last_use; +static int keep_stream; + +/* Open database file if not already opened. */ +static enum nss_status +internal_setent (int stayopen) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + if (stream == NULL) + { + stream = fopen (DATAFILE, "r"); + + if (stream == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + else + { + /* We have to make sure the file is `closed on exec'. */ + int result, flags; + + result = flags = fcntl (fileno (stream), F_GETFD, 0); + if (result >= 0) + { + flags |= FD_CLOEXEC; + result = fcntl (fileno (stream), F_SETFD, flags); + } + if (result < 0) + { + /* Something went wrong. Close the stream and return a + failure. */ + fclose (stream); + stream = NULL; + status = NSS_STATUS_UNAVAIL; + } + } + } + else + rewind (stream); + + /* Remember STAYOPEN flag. */ + if (stream != NULL) + keep_stream |= stayopen; + + return status; +} + + +/* Thread-safe, exported version of that. */ +enum nss_status +CONCAT(_nss_files_set,ENTNAME) (int stayopen) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_setent (stayopen); + + if (status == NSS_STATUS_SUCCESS && fgetpos (stream, &position) < 0) + { + fclose (stream); + stream = NULL; + status = NSS_STATUS_UNAVAIL; + } + + last_use = getent; + + __libc_lock_unlock (lock); + + return status; +} + + +/* Close the database file. */ +static void +internal_endent (void) +{ + if (stream != NULL) + { + fclose (stream); + stream = NULL; + } +} + + +/* Thread-safe, exported version of that. */ +enum nss_status +CONCAT(_nss_files_end,ENTNAME) (void) +{ + __libc_lock_lock (lock); + + internal_endent (); + + /* Reset STAYOPEN flag. */ + keep_stream = 0; + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +/* Parsing the database file into `struct STRUCTURE' data structures. */ + +static enum nss_status +internal_getent (struct STRUCTURE *result, + char *buffer, int buflen H_ERRNO_PROTO) +{ + char *p; + struct parser_data *data = (void *) buffer; + int linebuflen = buffer + buflen - data->linebuffer; + int parse_result; + + if (buflen < (int) sizeof *data + 1) + { + __set_errno (ERANGE); + H_ERRNO_SET (NETDB_INTERNAL); + return NSS_STATUS_TRYAGAIN; + } + + do + { + /* Terminate the line so that we can test for overflow. */ + data->linebuffer[linebuflen - 1] = '\xff'; + + p = fgets (data->linebuffer, linebuflen, stream); + if (p == NULL && feof (stream)) + { + /* End of file or read error. */ + __set_errno (ENOENT); + H_ERRNO_SET (HOST_NOT_FOUND); + return NSS_STATUS_NOTFOUND; + } + else if (p == NULL || data->linebuffer[linebuflen - 1] != '\xff') + { + /* The line is too long. Give the user the opportunity to + enlarge the buffer. */ + __set_errno (ERANGE); + H_ERRNO_SET (NETDB_INTERNAL); + return NSS_STATUS_TRYAGAIN; + } + + /* Skip leading blanks. */ + while (isspace (*p)) + ++p; + } + while (*p == '\0' || *p == '#' /* Ignore empty and comment lines. */ + /* Parse the line. If it is invalid, loop to get the next + line of the file to parse. */ + || ! (parse_result = parse_line (p, result, data, buflen))); + + /* Filled in RESULT with the next entry from the database file. */ + return parse_result == -1 ? NSS_STATUS_TRYAGAIN : NSS_STATUS_SUCCESS; +} + + +/* Return the next entry from the database file, doing locking. */ +enum nss_status +CONCAT(_nss_files_get,ENTNAME_r) (struct STRUCTURE *result, + char *buffer, size_t buflen H_ERRNO_PROTO) +{ + /* Return next entry in host file. */ + enum nss_status status = NSS_STATUS_SUCCESS; + + __libc_lock_lock (lock); + + /* Be prepared that the set*ent function was not called before. */ + if (stream == NULL) + { + status = internal_setent (0); + + if (status == NSS_STATUS_SUCCESS && fgetpos (stream, &position) < 0) + { + fclose (stream); + stream = NULL; + status = NSS_STATUS_UNAVAIL; + } + } + + if (status == NSS_STATUS_SUCCESS) + { + /* If the last use was not by the getent function we need the + position the stream. */ + if (last_use != getent) + { + if (fsetpos (stream, &position) < 0) + status = NSS_STATUS_UNAVAIL; + else + last_use = getent; + } + + if (status == NSS_STATUS_SUCCESS) + { + status = internal_getent (result, buffer, buflen H_ERRNO_ARG); + + /* Remember this position if we were successful. If the + operation failed we give the user a chance to repeat the + operation (perhaps the buffer was too small). */ + if (status == NSS_STATUS_SUCCESS) + fgetpos (stream, &position); + else + /* We must make sure we reposition the stream the next call. */ + last_use = none; + } + } + + __libc_lock_unlock (lock); + + return status; +} + +/* Macro for defining lookup functions for this file-based database. + + NAME is the name of the lookup; e.g. `hostbyname'. + + KEYSIZE and KEYPATTERN are ignored here but used by ../nss_db/db-XXX.c. + + PROTO describes the arguments for the lookup key; + e.g. `const char *hostname'. + + BREAK_IF_MATCH is a block of code which compares `struct STRUCTURE *result' + to the lookup key arguments and does `break;' if they match. */ + +#define DB_LOOKUP(name, keysize, keypattern, break_if_match, proto...) \ +enum nss_status \ +_nss_files_get##name##_r (proto, \ + struct STRUCTURE *result, \ + char *buffer, size_t buflen H_ERRNO_PROTO) \ +{ \ + enum nss_status status; \ + \ + __libc_lock_lock (lock); \ + \ + /* Reset file pointer to beginning or open file. */ \ + status = internal_setent (keep_stream); \ + \ + if (status == NSS_STATUS_SUCCESS) \ + { \ + /* Tell getent function that we have repositioned the file pointer. */ \ + last_use = getby; \ + \ + while ((status = internal_getent (result, buffer, buflen H_ERRNO_ARG)) \ + == NSS_STATUS_SUCCESS) \ + { break_if_match } \ + \ + if (! keep_stream) \ + internal_endent (); \ + } \ + \ + __libc_lock_unlock (lock); \ + \ + return status; \ +} diff --git a/glibc-compat/nss_files/files-alias.c b/glibc-compat/nss_files/files-alias.c new file mode 100644 index 0000000000..d9e5549998 --- /dev/null +++ b/glibc-compat/nss_files/files-alias.c @@ -0,0 +1,451 @@ +/* Mail alias file parser in nss_files module. + 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 <glibc-compat/include/aliases.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <bits/libc-lock.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "nsswitch.h" + +/* Locks the static variables in this file. */ +__libc_lock_define_initialized (static, lock) + +/* Maintenance of the shared stream open on the database file. */ + +static FILE *stream; +static fpos_t position; +static enum { none, getent, getby } last_use; + + +static enum nss_status +internal_setent (void) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + if (stream == NULL) + { + stream = fopen ("/etc/aliases", "r"); + + if (stream == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + else + { + /* We have to make sure the file is `closed on exec'. */ + int result, flags; + + result = flags = fcntl (fileno (stream), F_GETFD, 0); + if (result >= 0) + { + flags |= FD_CLOEXEC; + result = fcntl (fileno (stream), F_SETFD, flags); + } + if (result < 0) + { + /* Something went wrong. Close the stream and return a + failure. */ + fclose (stream); + stream = NULL; + status = NSS_STATUS_UNAVAIL; + } + } + } + else + rewind (stream); + + return status; +} + + +/* Thread-safe, exported version of that. */ +enum nss_status +_nss_files_setaliasent (void) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_setent (); + + if (status == NSS_STATUS_SUCCESS && fgetpos (stream, &position) < 0) + { + fclose (stream); + stream = NULL; + status = NSS_STATUS_UNAVAIL; + } + + last_use = getent; + + __libc_lock_unlock (lock); + + return status; +} + + +/* Close the database file. */ +static void +internal_endent (void) +{ + if (stream != NULL) + { + fclose (stream); + stream = NULL; + } +} + + +/* Thread-safe, exported version of that. */ +enum nss_status +_nss_files_endaliasent (void) +{ + __libc_lock_lock (lock); + + internal_endent (); + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +/* Parsing the database file into `struct aliasent' data structures. */ +static enum nss_status +get_next_alias (const char *match, struct aliasent *result, + char *buffer, size_t buflen) +{ + enum nss_status status = NSS_STATUS_NOTFOUND; + int ignore = 0; + + result->alias_members_len = 0; + + while (1) + { + /* Now we are ready to process the input. We have to read a + line and all its continuations and construct the array of + string pointers. This pointers and the names itself have to + be placed in BUFFER. */ + char *first_unused = buffer; + size_t room_left = buflen - (buflen % __alignof__ (char *)); + char *line; + + /* Read the first line. It must contain the alias name and + possibly some alias names. */ + first_unused[room_left - 1] = '\xff'; + line = fgets (first_unused, room_left, stream); + if (line == NULL && feof (stream)) + /* Nothing to read. */ + break; + else if (line == NULL || first_unused[room_left - 1] != '\xff') + { + /* The line is too long for our buffer. */ + no_more_room: + __set_errno (ERANGE); + status = NSS_STATUS_TRYAGAIN; + break; + } + else + { + char *cp; + + /* If we are in IGNORE mode and the first character in the + line is a white space we ignore the line and start + reading the next. */ + if (ignore && isspace (*first_unused)) + continue; + + /* Terminate the line for any case. */ + cp = strpbrk (first_unused, "#\n"); + if (cp != NULL) + *cp = '\0'; + + /* Skip leading blanks. */ + while (isspace (*line)) + ++line; + + result->alias_name = first_unused; + while (*line != '\0' && *line != ':') + *first_unused++ = *line++; + if (*line == '\0' || result->alias_name == first_unused) + /* No valid name. Ignore the line. */ + continue; + + *first_unused++ = '\0'; + if (room_left < (size_t) (first_unused - result->alias_name)) + goto no_more_room; + room_left -= first_unused - result->alias_name; + ++line; + + /* When we search for a specific alias we can avoid all the + difficult parts and compare now with the name we are + looking for. If it does not match we simply ignore all + lines until the next line containing the start of a new + alias is found. */ + ignore = (match != NULL + && __strcasecmp (result->alias_name, match) != 0); + + while (! ignore) + { + while (isspace (*line)) + ++line; + + cp = first_unused; + while (*line != '\0' && *line != ',') + *first_unused++ = *line++; + + if (first_unused != cp) + { + /* OK, we can have a regular entry or an include + request. */ + if (*line != '\0') + ++line; + *first_unused++ = '\0'; + + if (strncmp (cp, ":include:", 9) != 0) + { + if (room_left < (first_unused - cp) + sizeof (char *)) + goto no_more_room; + room_left -= (first_unused - cp) + sizeof (char *); + + ++result->alias_members_len; + } + else + { + /* Oh well, we have to read the addressed file. */ + FILE *listfile; + char *old_line = NULL; + + first_unused = cp; + + listfile = fopen (&cp[9], "r"); + /* If the file does not exist we simply ignore + the statement. */ + if (listfile != NULL + && (old_line = strdup (line)) != NULL) + { + while (! feof (listfile)) + { + first_unused[room_left - 1] = '\xff'; + line = fgets (first_unused, room_left, listfile); + if (line == NULL && feof (listfile)) + break; + if (line == NULL + || first_unused[room_left - 1] != '\xff') + { + free (old_line); + goto no_more_room; + } + + /* Parse the line. */ + cp = strpbrk (line, "#\n"); + if (cp != NULL) + *cp = '\0'; + + do + { + while (isspace (*line)) + ++line; + + cp = first_unused; + while (*line != '\0' && *line != ',') + *first_unused++ = *line++; + + if (*line != '\0') + ++line; + + if (first_unused != cp) + { + *first_unused++ = '\0'; + if (room_left < ((first_unused - cp) + + __alignof__ (char *))) + { + free (old_line); + goto no_more_room; + } + room_left -= ((first_unused - cp) + + __alignof__ (char *)); + ++result->alias_members_len; + } + } + while (*line != '\0'); + } + fclose (listfile); + + first_unused[room_left - 1] = '\0'; + strncpy (first_unused, old_line, room_left); + + if (old_line != NULL) + free (old_line); + + if (first_unused[room_left - 1] != '\0') + goto no_more_room; + } + } + } + + if (*line == '\0') + { + /* Get the next line. But we must be careful. We + must not read the whole line at once since it + might belong to the current alias. Simply read + the first character. If it is a white space we + have a continuation line. Otherwise it is the + beginning of a new alias and we can push back the + just read character. */ + int ch; + + ch = fgetc (stream); + if (ch == EOF || ch == '\n' || !isspace (ch)) + { + size_t cnt; + + /* Now prepare the return. Provide string + pointers for the currently selected aliases. */ + if (ch != EOF) + ungetc (ch, stream); + + /* Adjust the pointer so it is aligned for + storing pointers. */ + first_unused += __alignof__ (char *) - 1; + first_unused -= ((first_unused - (char *) 0) + % __alignof__ (char *)); + result->alias_members = (char **) first_unused; + + /* Compute addresses of alias entry strings. */ + cp = result->alias_name; + for (cnt = 0; cnt < result->alias_members_len; ++cnt) + { + cp = strchr (cp, '\0') + 1; + result->alias_members[cnt] = cp; + } + + status = (result->alias_members_len == 0 + ? NSS_STATUS_RETURN : NSS_STATUS_SUCCESS); + break; + } + + /* The just read character is a white space and so + can be ignored. */ + first_unused[room_left - 1] = '\xff'; + line = fgets (first_unused, room_left, stream); + if (line == NULL && feof (stream)) + break; + if (line == NULL || first_unused[room_left - 1] != '\xff') + goto no_more_room; + cp = strpbrk (line, "#\n"); + if (cp != NULL) + *cp = '\0'; + } + } + } + + if (status != NSS_STATUS_NOTFOUND) + /* We read something. In any case break here. */ + break; + } + + return status; +} + + +enum nss_status +_nss_files_getaliasent_r (struct aliasent *result, char *buffer, size_t buflen) +{ + /* Return next entry in host file. */ + enum nss_status status = NSS_STATUS_SUCCESS; + + __libc_lock_lock (lock); + + /* Be prepared that the set*ent function was not called before. */ + if (stream == NULL) + status = internal_setent (); + + if (status == NSS_STATUS_SUCCESS) + { + /* If the last use was not by the getent function we need the + position the stream. */ + if (last_use != getent) + { + if (fsetpos (stream, &position) < 0) + status = NSS_STATUS_UNAVAIL; + else + last_use = getent; + } + + if (status == NSS_STATUS_SUCCESS) + { + result->alias_local = 1; + + /* Read lines until we get a definite result. */ + do + status = get_next_alias (NULL, result, buffer, buflen); + while (status == NSS_STATUS_RETURN); + + /* If we successfully read an entry remember this position. */ + if (status == NSS_STATUS_SUCCESS) + fgetpos (stream, &position); + else + last_use = none; + } + } + + __libc_lock_unlock (lock); + + return status; +} + + +enum nss_status +_nss_files_getaliasbyname_r (const char *name, struct aliasent *result, + char *buffer, size_t buflen) +{ + /* Return next entry in host file. */ + enum nss_status status = NSS_STATUS_SUCCESS; + + if (name == NULL) + { + __set_errno (EINVAL); + return NSS_STATUS_UNAVAIL; + } + + __libc_lock_lock (lock); + + /* Open the stream or rest it. */ + status = internal_setent (); + last_use = getby; + + if (status == NSS_STATUS_SUCCESS) + { + result->alias_local = 1; + + /* Read lines until we get a definite result. */ + do + status = get_next_alias (name, result, buffer, buflen); + while (status == NSS_STATUS_RETURN); + } + + internal_endent (); + + __libc_lock_unlock (lock); + + return status; +} diff --git a/glibc-compat/nss_files/files-ethers.c b/glibc-compat/nss_files/files-ethers.c new file mode 100644 index 0000000000..290d931c97 --- /dev/null +++ b/glibc-compat/nss_files/files-ethers.c @@ -0,0 +1,75 @@ +/* Copyright (C) 1996 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. */ + +#include <string.h> +#include <netinet/if_ether.h> + +/* Because the `ethers' lookup does not fit so well in the scheme so + we define a dummy struct here which helps us to use the available + functions. */ +struct etherent +{ + const char *e_name; + struct ether_addr e_addr; +}; +struct etherent_data {}; + +#define ENTNAME etherent +#define DATABASE "ethers" +#include "files-parse.c" +LINE_PARSER +("#", + /* Read the ethernet address: 6 x 8bit hexadecimal number. */ + { + size_t cnt; + + for (cnt = 0; cnt < 6; ++cnt) + { + unsigned int number; + + if (cnt < 5) + INT_FIELD (number, ISCOLON , 0, 16, (unsigned int)) + else + INT_FIELD (number, isspace, 0, 16, (unsigned int)) + + if (number > 0xff) + return 0; + result->e_addr.ether_addr_octet[cnt] = number; + } + }; + STRING_FIELD (result->e_name, isspace, 1); + ) + + +#include GENERIC + +DB_LOOKUP (hostton, 1 + strlen (name), (".%s", name), + { + if (strcmp (result->e_name, name) == 0) + break; + }, const char *name) + +DB_LOOKUP (ntohost, 18, ("=%x:%x:%x:%x:%x:%x", + addr->ether_addr_octet[0], addr->ether_addr_octet[1], + addr->ether_addr_octet[2], addr->ether_addr_octet[3], + addr->ether_addr_octet[4], addr->ether_addr_octet[5]), + { + if (memcmp (&result->e_addr, addr, + sizeof (struct ether_addr)) == 0) + break; + }, struct ether_addr *addr) diff --git a/glibc-compat/nss_files/files-grp.c b/glibc-compat/nss_files/files-grp.c new file mode 100644 index 0000000000..ac9b632d42 --- /dev/null +++ b/glibc-compat/nss_files/files-grp.c @@ -0,0 +1,45 @@ +/* Group file parser in nss_files module. + Copyright (C) 1996, 1997 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. */ + +#include <glibc-compat/include/grp.h> + +#define STRUCTURE group +#define ENTNAME grent +#define DATABASE "group" +struct grent_data {}; + +/* Our parser function is already defined in fgetgrent.c, so use that. + to parse lines from the database file. */ +#define EXTERN_PARSER +#include "files-parse.c" +#include GENERIC + +DB_LOOKUP (grnam, 1 + strlen (name), (".%s", name), + { + if (name[0] != '-' && name[0] != '+' + && ! strcmp (name, result->gr_name)) + break; + }, const char *name) + +DB_LOOKUP (grgid, 20, ("=%lu", (unsigned long int) gid), + { + if (result->gr_gid == gid && result->gr_name[0] != '+' + && result->gr_name[0] != '-') + break; + }, gid_t gid) diff --git a/glibc-compat/nss_files/files-hosts.c b/glibc-compat/nss_files/files-hosts.c new file mode 100644 index 0000000000..1b96f74b35 --- /dev/null +++ b/glibc-compat/nss_files/files-hosts.c @@ -0,0 +1,107 @@ +/* Hosts file parser in nss_files module. + Copyright (C) 1996, 1997, 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. */ + +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> +#include <glibc-compat/include/netdb.h> +#include <resolv.h> + + +/* Get implementation for some internal functions. */ +#include "../resolv/mapv4v6addr.h" + + +#define ENTNAME hostent +#define DATABASE "hosts" +#define NEED_H_ERRNO + +#define ENTDATA hostent_data +struct hostent_data + { + unsigned char host_addr[16]; /* IPv4 or IPv6 address. */ + char *h_addr_ptrs[2]; /* Points to that and null terminator. */ + }; + +#define TRAILING_LIST_MEMBER h_aliases +#define TRAILING_LIST_SEPARATOR_P isspace +#include "files-parse.c" +LINE_PARSER +("#", + { + char *addr; + + STRING_FIELD (addr, isspace, 1); + + /* Parse address. */ + if (inet_pton (AF_INET, addr, entdata->host_addr) > 0) + { + if (_res.options & RES_USE_INET6) + { + map_v4v6_address ((char *) entdata->host_addr, + (char *) entdata->host_addr); + result->h_addrtype = AF_INET6; + result->h_length = IN6ADDRSZ; + } + else + { + result->h_addrtype = AF_INET; + result->h_length = INADDRSZ; + } + } + else if (inet_pton (AF_INET6, addr, entdata->host_addr) > 0) + { + result->h_addrtype = AF_INET6; + result->h_length = IN6ADDRSZ; + } + else + /* Illegal address: ignore line. */ + return 0; + + /* Store a pointer to the address in the expected form. */ + entdata->h_addr_ptrs[0] = entdata->host_addr; + entdata->h_addr_ptrs[1] = NULL; + result->h_addr_list = entdata->h_addr_ptrs; + + STRING_FIELD (result->h_name, isspace, 1); + }) + +#include "files-XXX.c" + +DB_LOOKUP (hostbyname, ,, + { + if (result->h_addrtype != ((_res.options & RES_USE_INET6) + ? AF_INET6 : AF_INET)) + continue; + LOOKUP_NAME_CASE (h_name, h_aliases) + }, const char *name) + +DB_LOOKUP (hostbyname2, ,, + { + if (result->h_addrtype != af) + continue; + LOOKUP_NAME_CASE (h_name, h_aliases) + }, const char *name, int af) + +DB_LOOKUP (hostbyaddr, ,, + { + if (result->h_addrtype == type && result->h_length == len && + ! memcmp (addr, result->h_addr_list[0], len)) + break; + }, const char *addr, int len, int type) diff --git a/glibc-compat/nss_files/files-netgrp.c b/glibc-compat/nss_files/files-netgrp.c new file mode 100644 index 0000000000..8820e6a02c --- /dev/null +++ b/glibc-compat/nss_files/files-netgrp.c @@ -0,0 +1,268 @@ +/* Netgroup file parser in nss_files modules. + Copyright (C) 1996, 1997 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 <ctype.h> +#include <errno.h> +#include <glibc-compat/include/netdb.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "nsswitch.h" +#include "netgroup.h" + +#define DATAFILE "/etc/netgroup" + + +#define EXPAND(needed) \ + do \ + { \ + size_t old_cursor = result->cursor - result->data; \ + \ + result->data_size += 512 > 2 * needed ? 512 : 2 * needed; \ + result->data = realloc (result->data, result->data_size); \ + \ + if (result->data == NULL) \ + { \ + status = NSS_STATUS_UNAVAIL; \ + goto the_end; \ + } \ + \ + result->cursor = result->data + old_cursor; \ + } \ + while (0) + + +enum nss_status +_nss_files_setnetgrent (const char *group, struct __netgrent *result) +{ + FILE *fp; + enum nss_status status; + + if (group[0] == '\0') + return NSS_STATUS_UNAVAIL; + + /* Find the netgroups file and open it. */ + fp = fopen (DATAFILE, "r"); + if (fp == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + else + { + /* Read the file line by line and try to find the description + GROUP. We must take care for long lines. */ + char *line = NULL; + size_t line_len = 0; + const ssize_t group_len = strlen (group); + + status = NSS_STATUS_NOTFOUND; + result->cursor = result->data; + + while (!feof (fp)) + { + ssize_t curlen = getline (&line, &line_len, fp); + int found; + + if (curlen < 0) + { + status = NSS_STATUS_NOTFOUND; + break; + } + + found = (curlen > group_len && strncmp (line, group, group_len) == 0 + && isspace (line[group_len])); + + /* Read the whole line (including continuation) and store it + if FOUND in nonzero. Otherwise we don't need it. */ + if (found) + { + /* Store the data from the first line. */ + EXPAND (curlen - group_len); + memcpy (result->cursor, &line[group_len + 1], + curlen - group_len); + result->cursor += (curlen - group_len) - 1; + } + + while (line[curlen - 1] == '\n' && line[curlen - 2] == '\\') + { + /* Yes, we have a continuation line. */ + if (found) + /* Remove these characters from the stored line. */ + result->cursor -= 2; + + /* Get next line. */ + curlen = getline (&line, &line_len, fp); + if (curlen <= 0) + break; + + if (found) + { + /* Make sure we have enough room. */ + EXPAND (1 + curlen + 1); + + /* Add separator in case next line starts immediately. */ + *result->cursor++ = ' '; + + /* Copy new line. */ + memcpy (result->cursor, line, curlen + 1); + result->cursor += curlen; + } + } + + if (found) + { + /* Now we have read the line. */ + status = NSS_STATUS_SUCCESS; + result->cursor = result->data; + result->first = 1; + break; + } + } + + the_end: + /* We don't need the file and the line buffer anymore. */ + free (line); + fclose (fp); + } + + return status; +} + + +int +_nss_files_endnetgrent (struct __netgrent *result) +{ + /* Free allocated memory for data if some is present. */ + if (result->data != NULL) + { + free (result->data); + result->data = NULL; + result->data_size = 0; + result->cursor = NULL; + } + + return NSS_STATUS_SUCCESS; +} + + +enum nss_status +_nss_netgroup_parseline (char **cursor, struct __netgrent *result, + char *buffer, int buflen) +{ + enum nss_status status; + const char *host, *user, *domain; + char *cp = *cursor; + + /* Some sanity checks. */ + if (cp == NULL) + return NSS_STATUS_NOTFOUND; + + /* First skip leading spaces. */ + while (isspace (*cp)) + ++cp; + + if (*cp != '(') + { + /* We have a list of other netgroups. */ + char *name = cp; + + while (*cp != '\0' && ! isspace (*cp)) + ++cp; + + if (name != cp) + { + /* It is another netgroup name. */ + int last = *cp == '\0'; + + result->type = group_val; + result->val.group = name; + *cp = '\0'; + if (! last) + ++cp; + *cursor = cp; + result->first = 0; + + return NSS_STATUS_SUCCESS; + } + + return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN; + } + + /* Match host name. */ + host = ++cp; + while (*cp != ',') + if (*cp++ == '\0') + return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN; + + /* Match user name. */ + user = ++cp; + while (*cp != ',') + if (*cp++ == '\0') + return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN; + + /* Match domain name. */ + domain = ++cp; + while (*cp != ')') + if (*cp++ == '\0') + return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN; + ++cp; + + + /* When we got here we have found an entry. Before we can copy it + to the private buffer we have to make sure it is big enough. */ + if (cp - host > buflen) + { + __set_errno (ERANGE); + status = NSS_STATUS_UNAVAIL; + } + else + { + memcpy (buffer, host, cp - host); + result->type = triple_val; + + buffer[(user - host) - 1] = '\0'; + result->val.triple.host = *host == ',' ? NULL : buffer; + + buffer[(domain - host) - 1] = '\0'; + result->val.triple.user = *user == ',' ? NULL : buffer + (user - host); + + buffer[(cp - host) - 1] = '\0'; + result->val.triple.domain = + *domain == ')' ? NULL : buffer + (domain - host); + + status = NSS_STATUS_SUCCESS; + + /* Remember where we stopped reading. */ + *cursor = cp; + + result->first = 0; + } + + return status; +} + + +enum nss_status +_nss_files_getnetgrent_r (struct __netgrent *result, char *buffer, int buflen) +{ + enum nss_status status; + + status = _nss_netgroup_parseline (&result->cursor, result, buffer, buflen); + + return status; +} diff --git a/glibc-compat/nss_files/files-network.c b/glibc-compat/nss_files/files-network.c new file mode 100644 index 0000000000..45ded2fedf --- /dev/null +++ b/glibc-compat/nss_files/files-network.c @@ -0,0 +1,56 @@ +/* Networks file parser in nss_files module. + Copyright (C) 1996, 1997, 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. */ + +#include <netinet/in.h> +#include <arpa/inet.h> +#include <glibc-compat/include/netdb.h> + +#define ENTNAME netent +#define DATABASE "networks" + +struct netent_data {}; + +#define TRAILING_LIST_MEMBER n_aliases +#define TRAILING_LIST_SEPARATOR_P isspace +#include "files-parse.c" +LINE_PARSER +("#", + { + char *addr; + + STRING_FIELD (result->n_name, isspace, 1); + + STRING_FIELD (addr, isspace, 1); + result->n_net = inet_network (addr); + result->n_addrtype = AF_INET; + + }) + +#include "files-XXX.c" + +DB_LOOKUP (netbyname, ,, + LOOKUP_NAME_CASE (n_name, n_aliases), + const char *name) + +DB_LOOKUP (netbyaddr, ,, + { + if (result->n_addrtype == type && result->n_net == net) + /* Bingo! */ + break; + }, unsigned long int net, int type) diff --git a/glibc-compat/nss_files/files-parse.c b/glibc-compat/nss_files/files-parse.c new file mode 100644 index 0000000000..49c08153c9 --- /dev/null +++ b/glibc-compat/nss_files/files-parse.c @@ -0,0 +1,252 @@ +/* Common code for file-based database parsers in nss_files module. + Copyright (C) 1996, 1997, 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. */ + +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> + +/* These symbols are defined by the including source file: + + ENTNAME -- database name of the structure and functions (hostent, pwent). + STRUCTURE -- struct name, define only if not ENTNAME (passwd, group). + DATABASE -- string of the database file's name ("hosts", "passwd"). + + ENTDATA -- if defined, `struct ENTDATA' is used by the parser to store + things pointed to by the resultant `struct STRUCTURE'. + + NEED_H_ERRNO - defined iff an arg `int *herrnop' is used. + + Also see files-XXX.c. */ + +#define CONCAT(a,b) CONCAT1(a,b) +#define CONCAT1(a,b) a##b + +#ifndef STRUCTURE +# define STRUCTURE ENTNAME +#endif + + +struct parser_data + { +#ifdef ENTDATA + struct ENTDATA entdata; +# define ENTDATA_DECL(data) struct ENTDATA *const entdata = &data->entdata; +#else +# define ENTDATA_DECL(data) +#endif + char linebuffer[0]; + }; + +#ifdef ENTDATA +/* The function can't be exported, because the entdata structure + is defined only in files-foo.c. */ +# define parser_stclass static +#else +/* Export the line parser function so it can be used in nss_db. */ +# define parser_stclass /* Global */ +# define parse_line CONCAT(_nss_files_parse_,ENTNAME) +#endif + + +#ifdef EXTERN_PARSER + +/* The parser is defined in a different module. */ +extern int parse_line (char *line, struct STRUCTURE *result, + struct parser_data *data, size_t datalen); + +# define LINE_PARSER(EOLSET, BODY) /* Do nothing */ + +#else + +/* Define a line parsing function. */ + +# define LINE_PARSER(EOLSET, BODY) \ +parser_stclass int \ +parse_line (char *line, struct STRUCTURE *result, \ + struct parser_data *data, size_t datalen) \ +{ \ + ENTDATA_DECL (data) \ + char *p = strpbrk (line, EOLSET "\n"); \ + if (p != NULL) \ + *p = '\0'; \ + BODY; \ + TRAILING_LIST_PARSER; \ + return 1; \ +} + + +# define STRING_FIELD(variable, terminator_p, swallow) \ + { \ + variable = line; \ + while (*line != '\0' && !terminator_p (*line)) \ + ++line; \ + if (*line != '\0') \ + { \ + *line = '\0'; \ + do \ + ++line; \ + while (swallow && terminator_p (*line)); \ + } \ + } + +# define INT_FIELD(variable, terminator_p, swallow, base, convert) \ + { \ + char *endp; \ + variable = convert (strtoul (line, &endp, base)); \ + if (endp == line) \ + return 0; \ + else if (terminator_p (*endp)) \ + do \ + ++endp; \ + while (swallow && terminator_p (*endp)); \ + else if (*endp != '\0') \ + return 0; \ + line = endp; \ + } + +# define INT_FIELD_MAYBE_NULL(variable, terminator_p, swallow, base, convert, default) \ + { \ + char *endp; \ + if (*line == '\0') \ + /* We expect some more input, so don't allow the string to end here. */ \ + return 0; \ + variable = convert (strtoul (line, &endp, base)); \ + if (endp == line) \ + variable = default; \ + if (terminator_p (*endp)) \ + do \ + ++endp; \ + while (swallow && terminator_p (*endp)); \ + else if (*endp != '\0') \ + return 0; \ + line = endp; \ + } + +# define ISCOLON(c) ((c) == ':') + + +# ifndef TRAILING_LIST_MEMBER +# define TRAILING_LIST_PARSER /* Nothing to do. */ +# else + +# define TRAILING_LIST_PARSER \ +{ \ + char **list = parse_list (line, data, datalen); \ + if (list) \ + result->TRAILING_LIST_MEMBER = list; \ + else \ + return -1; /* -1 indicates we ran out of space. */ \ +} + +static inline char ** +__attribute ((always_inline)) +parse_list (char *line, struct parser_data *data, size_t datalen) +{ + char *eol, **list, **p; + + if (line >= data->linebuffer && line < (char *) data + datalen) + /* Find the end of the line buffer, we will use the space in DATA after + it for storing the vector of pointers. */ + eol = strchr (line, '\0') + 1; + else + /* LINE does not point within DATA->linebuffer, so that space is + not being used for scratch space right now. We can use all of + it for the pointer vector storage. */ + eol = data->linebuffer; + /* Adjust the pointer so it is aligned for storing pointers. */ + eol += __alignof__ (char *) - 1; + eol -= (eol - (char *) 0) % __alignof__ (char *); + /* We will start the storage here for the vector of pointers. */ + list = (char **) eol; + + p = list; + while (1) + { + char *elt; + + if ((size_t) ((char *) &p[1] - (char *) data) > datalen) + { + /* We cannot fit another pointer in the buffer. */ + __set_errno (ERANGE); + return NULL; + } + if (*line == '\0') + break; + + /* Skip leading white space. This might not be portable but useful. */ + while (isspace (*line)) + ++line; + + elt = line; + while (1) + { + if (*line == '\0' || TRAILING_LIST_SEPARATOR_P (*line)) + { + /* End of the next entry. */ + if (line > elt) + /* We really found some data. */ + *p++ = elt; + + /* Terminate string if necessary. */ + if (*line != '\0') + *line++ = '\0'; + break; + } + ++line; + } + } + *p = NULL; + + return list; +} + +# endif /* TRAILING_LIST_MEMBER */ +#endif /* EXTERN_PARSER */ + + +#define LOOKUP_NAME(nameelt, aliaselt) \ +{ \ + char **ap; \ + if (! strcmp (name, result->nameelt)) \ + break; \ + for (ap = result->aliaselt; *ap; ++ap) \ + if (! strcmp (name, *ap)) \ + break; \ + if (*ap) \ + break; \ +} + +#define LOOKUP_NAME_CASE(nameelt, aliaselt) \ +{ \ + char **ap; \ + if (! __strcasecmp (name, result->nameelt)) \ + break; \ + for (ap = result->aliaselt; *ap; ++ap) \ + if (! __strcasecmp (name, *ap)) \ + break; \ + if (*ap) \ + break; \ +} + + +/* This is defined by db-*.c to include "../nss_db/db-XXX.c" instead. */ +#ifndef GENERIC +# define GENERIC "files-XXX.c" +#endif diff --git a/glibc-compat/nss_files/files-proto.c b/glibc-compat/nss_files/files-proto.c new file mode 100644 index 0000000000..6c53cce6a1 --- /dev/null +++ b/glibc-compat/nss_files/files-proto.c @@ -0,0 +1,47 @@ +/* Protocols file parser in nss_files module. + Copyright (C) 1996, 1997 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. */ + +#include <glibc-compat/include/netdb.h> + + +#define ENTNAME protoent +#define DATABASE "protocols" + +struct protoent_data {}; + +#define TRAILING_LIST_MEMBER p_aliases +#define TRAILING_LIST_SEPARATOR_P isspace +#include "files-parse.c" +LINE_PARSER +("#", + STRING_FIELD (result->p_name, isspace, 1); + INT_FIELD (result->p_proto, isspace, 1, 10,); + ) + +#include GENERIC + +DB_LOOKUP (protobyname, 1 + strlen (name), (".%s", name), + LOOKUP_NAME (p_name, p_aliases), + const char *name) + +DB_LOOKUP (protobynumber, 20, ("=%d", proto), + { + if (result->p_proto == proto) + break; + }, int proto) diff --git a/glibc-compat/nss_files/files-pwd.c b/glibc-compat/nss_files/files-pwd.c new file mode 100644 index 0000000000..621d70e065 --- /dev/null +++ b/glibc-compat/nss_files/files-pwd.c @@ -0,0 +1,45 @@ +/* User file parser in nss_files module. + Copyright (C) 1996, 1997 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. */ + +#include <glibc-compat/include/pwd.h> + +#define STRUCTURE passwd +#define ENTNAME pwent +#define DATABASE "passwd" +struct pwent_data {}; + +/* Our parser function is already defined in fgetpwent_r.c, so use that + to parse lines from the database file. */ +#define EXTERN_PARSER +#include "files-parse.c" +#include GENERIC + +DB_LOOKUP (pwnam, 1 + strlen (name), (".%s", name), + { + if (name[0] != '+' && name[0] != '-' + && ! strcmp (name, result->pw_name)) + break; + }, const char *name) + +DB_LOOKUP (pwuid, 20, ("=%lu", (unsigned long int) uid), + { + if (result->pw_uid == uid && result->pw_name[0] != '+' + && result->pw_name[0] != '-') + break; + }, uid_t uid) diff --git a/glibc-compat/nss_files/files-rpc.c b/glibc-compat/nss_files/files-rpc.c new file mode 100644 index 0000000000..4e73e0e06b --- /dev/null +++ b/glibc-compat/nss_files/files-rpc.c @@ -0,0 +1,47 @@ +/* SunRPC program number file parser in nss_files module. + Copyright (C) 1996, 1997 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. */ + +#include <glibc-compat/include/rpc/netdb.h> + + +#define ENTNAME rpcent +#define DATABASE "rpc" + +struct rpcent_data {}; + +#define TRAILING_LIST_MEMBER r_aliases +#define TRAILING_LIST_SEPARATOR_P isspace +#include "files-parse.c" +LINE_PARSER +("#", + STRING_FIELD (result->r_name, isspace, 1); + INT_FIELD (result->r_number, isspace, 1, 10,); + ) + +#include GENERIC + +DB_LOOKUP (rpcbyname, 1 + strlen (name), (".%s", name), + LOOKUP_NAME (r_name, r_aliases), + const char *name) + +DB_LOOKUP (rpcbynumber, 20, ("=%d", number), + { + if (result->r_number == number) + break; + }, int number) diff --git a/glibc-compat/nss_files/files-service.c b/glibc-compat/nss_files/files-service.c new file mode 100644 index 0000000000..96255dd223 --- /dev/null +++ b/glibc-compat/nss_files/files-service.c @@ -0,0 +1,60 @@ +/* Services file parser in nss_files module. + Copyright (C) 1996, 1997, 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. */ + +#include <netinet/in.h> +#include <glibc-compat/include/netdb.h> + + +#define ENTNAME servent +#define DATABASE "services" + +struct servent_data {}; + +#define TRAILING_LIST_MEMBER s_aliases +#define TRAILING_LIST_SEPARATOR_P isspace +#include "files-parse.c" +#define ISSLASH(c) ((c) == '/') +LINE_PARSER +("#", + STRING_FIELD (result->s_name, isspace, 1); + INT_FIELD (result->s_port, ISSLASH, 10, 0, htons); + STRING_FIELD (result->s_proto, isspace, 1); + ) + +#include GENERIC + +DB_LOOKUP (servbyname, 2 + strlen (name) + (proto ? strlen (proto) : 0), + (".%s/%s", name, proto ?: ""), + { + /* Must match both protocol (if specified) and name. */ + if (proto != NULL && strcmp (result->s_proto, proto)) + continue; + LOOKUP_NAME (s_name, s_aliases) + }, + const char *name, const char *proto) + +DB_LOOKUP (servbyport, 21 + (proto ? strlen (proto) : 0), + ("=%d/%s", ntohs (port), proto ?: ""), + { + /* Must match both port and protocol. */ + if (result->s_port == port + && (proto == NULL + || strcmp (result->s_proto, proto) == 0)) + break; + }, int port, const char *proto) diff --git a/glibc-compat/nss_files/files-spwd.c b/glibc-compat/nss_files/files-spwd.c new file mode 100644 index 0000000000..f7f25fd304 --- /dev/null +++ b/glibc-compat/nss_files/files-spwd.c @@ -0,0 +1,38 @@ +/* User file parser in nss_files module. + Copyright (C) 1996, 1997 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. */ + +#include <glibc-compat/include/shadow.h> + +#define STRUCTURE spwd +#define ENTNAME spent +#define DATABASE "shadow" +struct spent_data {}; + +/* Our parser function is already defined in sgetspent_r.c, so use that + to parse lines from the database file. */ +#define EXTERN_PARSER +#include "files-parse.c" +#include GENERIC + +DB_LOOKUP (spnam, 1 + strlen (name), (".%s", name), + { + if (name[0] != '+' && name[0] != '-' + && ! strcmp (name, result->sp_namp)) + break; + }, const char *name) diff --git a/glibc-compat/nss_nis/nis-alias.c b/glibc-compat/nss_nis/nis-alias.c new file mode 100644 index 0000000000..14149699d3 --- /dev/null +++ b/glibc-compat/nss_nis/nis-alias.c @@ -0,0 +1,278 @@ +/* Copyright (C) 1996, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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 <nss.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <glibc-compat/include/aliases.h> +#include <bits/libc-lock.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> + +#include "nss-nis.h" + +__libc_lock_define_initialized (static, lock) + +static bool_t new_start = 1; +static char *oldkey = NULL; +static int oldkeylen = 0; + +static int +_nss_nis_parse_aliasent (const char *key, char *alias, struct aliasent *result, + char *buffer, size_t buflen) +{ + char *first_unused = buffer + strlen (alias) + 1; + size_t room_left = + buflen - (buflen % __alignof__ (char *)) - strlen (alias) - 2; + char *line; + char *cp; + + result->alias_members_len = 0; + *first_unused = '\0'; + first_unused++; + strcpy (first_unused, key); + + if (first_unused[room_left - 1] != '\0') + { + /* The line is too long for our buffer. */ + no_more_room: + __set_errno (ERANGE); + return -1; + } + + result->alias_name = first_unused; + + /* Terminate the line for any case. */ + cp = strpbrk (alias, "#\n"); + if (cp != NULL) + *cp = '\0'; + + first_unused += strlen (result->alias_name) + 1; + /* Adjust the pointer so it is aligned for + storing pointers. */ + first_unused += __alignof__ (char *) - 1; + first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *)); + result->alias_members = (char **) first_unused; + + line = alias; + + while (*line != '\0') + { + /* Skip leading blanks. */ + while (isspace (*line)) + line++; + + if (*line == '\0') + break; + + if (room_left < sizeof (char *)) + goto no_more_room; + room_left -= sizeof (char *); + result->alias_members[result->alias_members_len] = line; + + while (*line != '\0' && *line != ',') + line++; + + if (line != result->alias_members[result->alias_members_len]) + { + *line = '\0'; + line++; + result->alias_members_len++; + } + } + return result->alias_members_len == 0 ? 0 : 1; +} + +enum nss_status +_nss_nis_setaliasent (void) +{ + __libc_lock_lock (lock); + + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_endaliasent (void) +{ + __libc_lock_lock (lock); + + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_nis_getaliasent_r (struct aliasent *alias, char *buffer, + size_t buflen) +{ + char *domain; + char *result; + int len; + char *outkey; + int keylen; + char *p; + int parse_res; + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + alias->alias_local = 0; + + /* Get the next entry until we found a correct one. */ + do + { + enum nss_status retval; + + if (new_start) + retval = yperr2nss (yp_first (domain, "mail.aliases", + &outkey, &keylen, &result, &len)); + else + retval = yperr2nss ( yp_next (domain, "mail.aliases", oldkey, + oldkeylen, &outkey, &keylen, + &result, &len)); + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_nis_parse_aliasent (outkey, p, alias, buffer, buflen); + if (parse_res == -1) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + free (oldkey); + oldkey = outkey; + oldkeylen = keylen; + new_start = 0; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getaliasent_r (struct aliasent *alias, char *buffer, size_t buflen) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_getaliasent_r (alias, buffer, buflen); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_getaliasbyname_r (const char *name, struct aliasent *alias, + char *buffer, size_t buflen) +{ + enum nss_status retval; + int parse_res; + char *domain; + char *result; + int len; + char *p; + size_t namlen = strlen (name); + char name2[namlen + 1]; + int i; + + if (name == NULL) + { + __set_errno (EINVAL); + return NSS_STATUS_UNAVAIL; + } + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + /* Convert name to lowercase. */ + for (i = 0; i < namlen; ++i) + name2[i] = tolower (name[i]); + name2[i] = '\0'; + + retval = yperr2nss (yp_match (domain, "mail.aliases", name, namlen, + &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + alias->alias_local = 0; + parse_res = _nss_nis_parse_aliasent (name, p, alias, buffer, buflen); + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + if (parse_res == 0) + return NSS_STATUS_NOTFOUND; + else + return NSS_STATUS_SUCCESS; +} diff --git a/glibc-compat/nss_nis/nis-ethers.c b/glibc-compat/nss_nis/nis-ethers.c new file mode 100644 index 0000000000..54b99dcba9 --- /dev/null +++ b/glibc-compat/nss_nis/nis-ethers.c @@ -0,0 +1,299 @@ +/* Copyright (C) 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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 <nss.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <bits/libc-lock.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> +#include <netinet/if_ether.h> + +#include "nss-nis.h" + +/* Protect global state against multiple changers */ +__libc_lock_define_initialized (static, lock) + +struct ether +{ + const char *e_name; + struct ether_addr e_addr; +}; + +/* Get the declaration of the parser function. */ +#define ENTNAME etherent +#define STRUCTURE ether +#define EXTERN_PARSER +#include "../nss_files/files-parse.c" + +struct response +{ + char *val; + struct response *next; +}; + +static struct response *start = NULL; +static struct response *next = NULL; + +static int +saveit (int instatus, char *inkey, int inkeylen, char *inval, + int invallen, char *indata) +{ + if (instatus != YP_TRUE) + return instatus; + + if (inkey && inkeylen > 0 && inval && invallen > 0) + { + if (start == NULL) + { + start = malloc (sizeof (struct response)); + next = start; + } + else + { + next->next = malloc (sizeof (struct response)); + next = next->next; + } + next->next = NULL; + next->val = malloc (invallen + 1); + strncpy (next->val, inval, invallen); + next->val[invallen] = '\0'; + } + + return 0; +} + +enum nss_status +internal_nis_setetherent (void) +{ + char *domainname; + struct ypall_callback ypcb; + enum nss_status status; + + yp_get_default_domain (&domainname); + + while (start != NULL) + { + if (start->val != NULL) + free (start->val); + next = start; + start = start->next; + free (next); + } + start = NULL; + + ypcb.foreach = saveit; + ypcb.data = NULL; + status = yperr2nss (yp_all (domainname, "ethers.byname", &ypcb)); + next = start; + + return status; +} + +enum nss_status +_nss_nis_setetherent (void) +{ + enum nss_status result; + + __libc_lock_lock (lock); + + result = internal_nis_setetherent (); + + __libc_lock_unlock (lock); + + return result; +} + +enum nss_status +_nss_nis_endetherent (void) +{ + __libc_lock_lock (lock); + + while (start != NULL) + { + if (start->val != NULL) + free (start->val); + next = start; + start = start->next; + free (next); + } + start = NULL; + next = NULL; + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_nis_getetherent_r (struct ether *eth, char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + int parse_res; + + if (start == NULL) + internal_nis_setetherent (); + + /* Get the next entry until we found a correct one. */ + do + { + char *p; + + if (next == NULL) + return NSS_STATUS_NOTFOUND; + p = strncpy (buffer, next->val, buflen); + next = next->next; + + while (isspace (*p)) + ++p; + + parse_res = _nss_files_parse_etherent (p, eth, data, buflen); + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getetherent_r (struct ether *result, char *buffer, size_t buflen) +{ + int status; + + __libc_lock_lock (lock); + + status = internal_nis_getetherent_r (result, buffer, buflen); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_gethostton_r (const char *name, struct ether *eth, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + enum nss_status retval; + char *domain, *result, *p; + int len, parse_res; + + if (name == NULL) + { + __set_errno (EINVAL); + return NSS_STATUS_UNAVAIL; + } + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + retval = yperr2nss (yp_match (domain, "ethers.byname", name, + strlen (name), &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_etherent (p, eth, data, buflen); + + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + else if (parse_res == 0) + return NSS_STATUS_NOTFOUND; + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getntohost_r (struct ether_addr *addr, struct ether *eth, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + enum nss_status retval; + char *domain, *result, *p; + int len, nlen, parse_res; + char buf[33]; + + if (addr == NULL) + { + __set_errno (EINVAL); + return NSS_STATUS_UNAVAIL; + } + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + nlen = sprintf (buf, "%x:%x:%x:%x:%x:%x", + (int) addr->ether_addr_octet[0], + (int) addr->ether_addr_octet[1], + (int) addr->ether_addr_octet[2], + (int) addr->ether_addr_octet[3], + (int) addr->ether_addr_octet[4], + (int) addr->ether_addr_octet[5]); + + retval = yperr2nss (yp_match (domain, "ethers.byaddr", buf, + nlen, &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_etherent (p, eth, data, buflen); + + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + else if (parse_res == 0) + return NSS_STATUS_NOTFOUND; + + return NSS_STATUS_SUCCESS; +} diff --git a/glibc-compat/nss_nis/nis-grp.c b/glibc-compat/nss_nis/nis-grp.c new file mode 100644 index 0000000000..5b8e838bdc --- /dev/null +++ b/glibc-compat/nss_nis/nis-grp.c @@ -0,0 +1,249 @@ +/* Copyright (C) 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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 <nss.h> +#include <glibc-compat/include/grp.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <bits/libc-lock.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> + +#include "nss-nis.h" + +/* Get the declaration of the parser function. */ +#define ENTNAME grent +#define STRUCTURE group +#define EXTERN_PARSER +#include "../nss_files/files-parse.c" + +/* Protect global state against multiple changers */ +__libc_lock_define_initialized (static, lock) + +static bool_t new_start = 1; +static char *oldkey = NULL; +static int oldkeylen = 0; + +enum nss_status +_nss_nis_setgrent (void) +{ + __libc_lock_lock (lock); + + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_endgrent (void) +{ + __libc_lock_lock (lock); + + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_nis_getgrent_r (struct group *grp, char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + char *domain, *result, *outkey; + int len, keylen, parse_res; + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + /* Get the next entry until we found a correct one. */ + do + { + enum nss_status retval; + char *p; + + if (new_start) + retval = yperr2nss (yp_first (domain, "group.byname", + &outkey, &keylen, &result, &len)); + else + retval = yperr2nss ( yp_next (domain, "group.byname", + oldkey, oldkeylen, + &outkey, &keylen, &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_grent (p, grp, data, buflen); + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + + free (oldkey); + oldkey = outkey; + oldkeylen = keylen; + new_start = 0; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getgrent_r (struct group *result, char *buffer, size_t buflen) +{ + int status; + + __libc_lock_lock (lock); + + status = internal_nis_getgrent_r (result, buffer, buflen); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_getgrnam_r (const char *name, struct group *grp, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + enum nss_status retval; + char *domain, *result, *p; + int len, parse_res; + + if (name == NULL) + { + __set_errno (EINVAL); + return NSS_STATUS_UNAVAIL; + } + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + retval = yperr2nss (yp_match (domain, "group.byname", name, + strlen (name), &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_grent (p, grp, data, buflen); + + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + else if (parse_res == 0) + return NSS_STATUS_NOTFOUND; + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getgrgid_r (gid_t gid, struct group *grp, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + enum nss_status retval; + char *domain, *result, *p; + int len, nlen, parse_res; + char buf[32]; + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + nlen = sprintf (buf, "%d", gid); + + retval = yperr2nss (yp_match (domain, "group.bygid", buf, + nlen, &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_grent (p, grp, data, buflen); + + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + else if (parse_res == 0) + return NSS_STATUS_NOTFOUND; + + return NSS_STATUS_SUCCESS; +} diff --git a/glibc-compat/nss_nis/nis-hosts.c b/glibc-compat/nss_nis/nis-hosts.c new file mode 100644 index 0000000000..c6c413c55d --- /dev/null +++ b/glibc-compat/nss_nis/nis-hosts.c @@ -0,0 +1,417 @@ +/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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 <nss.h> +#include <ctype.h> +#include <glibc-compat/include/netdb.h> +#include <string.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <resolv.h> +#include <bits/libc-lock.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> + +#include "nss-nis.h" + +/* Get implementation for some internal functions. */ +#include "../../resolv/mapv4v6addr.h" +#include "../../resolv/mapv4v6hostent.h" + +#define ENTNAME hostent +#define DATABASE "hosts" +#define NEED_H_ERRNO + +#define ENTDATA hostent_data +struct hostent_data + { + unsigned char host_addr[16]; /* IPv4 or IPv6 address. */ + char *h_addr_ptrs[2]; /* Points to that and null terminator. */ + }; + +#define TRAILING_LIST_MEMBER h_aliases +#define TRAILING_LIST_SEPARATOR_P isspace +#include "../nss_files/files-parse.c" +LINE_PARSER +("#", + { + char *addr; + + STRING_FIELD (addr, isspace, 1); + + /* Parse address. */ + if ((_res.options & RES_USE_INET6) + && inet_pton (AF_INET6, addr, entdata->host_addr) > 0) + { + result->h_addrtype = AF_INET6; + result->h_length = IN6ADDRSZ; + } + else + if (inet_pton (AF_INET, addr, entdata->host_addr) > 0) + { + if (_res.options & RES_USE_INET6) + { + map_v4v6_address ((char *) entdata->host_addr, + (char *) entdata->host_addr); + result->h_addrtype = AF_INET6; + result->h_length = IN6ADDRSZ; + } + else + { + result->h_addrtype = AF_INET; + result->h_length = INADDRSZ; + } + } + else + /* Illegal address: ignore line. */ + return 0; + + /* Store a pointer to the address in the expected form. */ + entdata->h_addr_ptrs[0] = entdata->host_addr; + entdata->h_addr_ptrs[1] = NULL; + result->h_addr_list = entdata->h_addr_ptrs; + + /* If we need the host entry in IPv6 form change it now. */ + if (_res.options & RES_USE_INET6) + { + char *bufptr = data->linebuffer; + size_t buflen = (char *) data + datalen - bufptr; + int ibuflen = buflen; /* Use this for machines with size_t > int. */ + map_v4v6_hostent (result, &bufptr, &ibuflen); + buflen = ibuflen; + } + + STRING_FIELD (result->h_name, isspace, 1); + } +) + +__libc_lock_define_initialized (static, lock) + +static bool_t new_start = 1; +static char *oldkey = NULL; +static int oldkeylen = 0; + +enum nss_status +_nss_nis_sethostent (void) +{ + __libc_lock_lock (lock); + + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_endhostent (void) +{ + __libc_lock_lock (lock); + + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_nis_gethostent_r (struct hostent *host, char *buffer, + size_t buflen, int *h_errnop) +{ + char *domain; + char *result; + int len, parse_res; + char *outkey; + int keylen; + struct parser_data *data = (void *) buffer; + size_t linebuflen = buffer + buflen - data->linebuffer; + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + if (buflen < sizeof *data + 1) + { + __set_errno (ERANGE); + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + + /* Get the next entry until we found a correct one. */ + do + { + enum nss_status retval; + char *p; + + if (new_start) + retval = yperr2nss (yp_first (domain, "hosts.byname", + &outkey, &keylen, &result, &len)); + else + retval = yperr2nss ( yp_next (domain, "hosts.byname", + oldkey, oldkeylen, + &outkey, &keylen, &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + switch (retval) + { + case NSS_STATUS_TRYAGAIN: + __set_errno (EAGAIN); + *h_errnop = TRY_AGAIN; + break; + case NSS_STATUS_NOTFOUND: + *h_errnop = HOST_NOT_FOUND; + break; + default: + *h_errnop = NO_RECOVERY; + break; + } + return retval; + } + + if ((size_t) (len + 1) > linebuflen) + { + free (result); + *h_errnop = NETDB_INTERNAL; + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (data->linebuffer, result, len); + data->linebuffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = parse_line (p, host, data, buflen); + if (parse_res == -1 && errno == ERANGE) + { + *h_errnop = NETDB_INTERNAL;; + return NSS_STATUS_TRYAGAIN; + } + free (oldkey); + oldkey = outkey; + oldkeylen = keylen; + new_start = 0; + } + while (!parse_res); + + *h_errnop = NETDB_SUCCESS; + return NSS_STATUS_SUCCESS; +} + +int +_nss_nis_gethostent_r (struct hostent *host, char *buffer, size_t buflen, + int *h_errnop) +{ + int status; + + __libc_lock_lock (lock); + + status = internal_nis_gethostent_r (host, buffer, buflen, h_errnop); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_gethostbyname2_r (const char *name, int af, struct hostent *host, + char *buffer, size_t buflen, int *h_errnop) +{ + enum nss_status retval; + char *domain, *result, *p; + int len, parse_res; + struct parser_data *data = (void *) buffer; + size_t linebuflen = buffer + buflen - data->linebuffer; + + if (name == NULL) + { + __set_errno (EINVAL); + return NSS_STATUS_UNAVAIL; + } + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + if (buflen < sizeof *data + 1) + { + *h_errnop = NETDB_INTERNAL; + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + else + { + /* Convert name to lowercase. */ + size_t namelen = strlen (name); + char name2[namelen + 1]; + int i; + + for (i = 0; i < namelen; ++i) + name2[i] = tolower (name[i]); + name2[i] = '\0'; + + retval = yperr2nss (yp_match (domain, "hosts.byname", name2, + namelen, &result, &len)); + + } + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + { + *h_errnop = TRY_AGAIN; + __set_errno (EAGAIN); + } + if (retval == NSS_STATUS_NOTFOUND) + *h_errnop = HOST_NOT_FOUND; + return retval; + } + + if ((size_t) (len + 1) > linebuflen) + { + free (result); + *h_errnop = NETDB_INTERNAL; + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (data->linebuffer, result, len); + data->linebuffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = parse_line (p, host, data, buflen); + + if (parse_res == -1 && errno == ERANGE) + { + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + + if (parse_res == 0 || host->h_addrtype != af) + { + *h_errnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } + + *h_errnop = NETDB_SUCCESS; + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_gethostbyname_r (const char *name, struct hostent *host, + char *buffer, size_t buflen, int *h_errnop) +{ + if (_res.options & RES_USE_INET6) + { + enum nss_status status; + + status = _nss_nis_gethostbyname2_r (name, AF_INET6, host, buffer, buflen, + h_errnop); + if (status == NSS_STATUS_SUCCESS) + return status; + } + + return _nss_nis_gethostbyname2_r (name, AF_INET, host, buffer, buflen, + h_errnop); +} + +enum nss_status +_nss_nis_gethostbyaddr_r (char *addr, int addrlen, int type, + struct hostent *host, char *buffer, size_t buflen, + int *h_errnop) +{ + enum nss_status retval; + char *domain, *result, *p; + int len, parse_res; + char *buf; + struct parser_data *data = (void *) buffer; + size_t linebuflen = buffer + buflen - data->linebuffer; + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + if (buflen < sizeof *data + 1) + { + __set_errno (ERANGE); + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + + buf = inet_ntoa (*(struct in_addr *) addr); + + retval = yperr2nss (yp_match (domain, "hosts.byaddr", buf, + strlen (buf), &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + { + *h_errnop = TRY_AGAIN; + __set_errno (EAGAIN); + } + if (retval == NSS_STATUS_NOTFOUND) + *h_errnop = HOST_NOT_FOUND; + return retval; + } + + if ((size_t) (len + 1) > linebuflen) + { + free (result); + __set_errno (ERANGE); + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (data->linebuffer, result, len); + data->linebuffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = parse_line (p, host, data, buflen); + + if (parse_res == -1 && errno == ERANGE) + { + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + else if (parse_res == 0) + { + *h_errnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } + + *h_errnop = NETDB_SUCCESS; + return NSS_STATUS_SUCCESS; +} diff --git a/glibc-compat/nss_nis/nis-netgrp.c b/glibc-compat/nss_nis/nis-netgrp.c new file mode 100644 index 0000000000..da87f1a605 --- /dev/null +++ b/glibc-compat/nss_nis/nis-netgrp.c @@ -0,0 +1,128 @@ +/* Copyright (C) 1996 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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 <nss.h> +#include <ctype.h> +#include <errno.h> +#include <bits/libc-lock.h> +#include <glibc-compat/include/netdb.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <netgroup.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> + +#include "nss-nis.h" + +/* Locks the static variables in this file. */ +__libc_lock_define_initialized (static, lock) + +static char *data = NULL; +static size_t data_size = 0; +static char *cursor = NULL;; + +extern enum nss_status +_nss_netgroup_parseline (char **cursor, struct __netgrent *result, + char *buffer, size_t buflen); + +enum nss_status +_nss_nis_setnetgrent (char *group) +{ + char *domain; + char *result; + int len, group_len; + enum nss_status status; + + status = NSS_STATUS_SUCCESS; + + if (group[0] == '\0') + return NSS_STATUS_UNAVAIL; + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + __libc_lock_lock (lock); + + if (data != NULL) + { + free (data); + data = NULL; + data_size = 0; + cursor = NULL; + } + + group_len = strlen (group); + + status = yperr2nss (yp_match (domain, "netgroup", group, group_len, + &result, &len)); + if (status == NSS_STATUS_SUCCESS) + { + if (len > 0) + { + data = malloc (len + 1); + data_size = len; + cursor = strncpy (data, result, len + 1); + data[len] = '\0'; + free (result); + } + else + status = NSS_STATUS_NOTFOUND; + } + + __libc_lock_unlock (lock); + + return status; +} + + +enum nss_status +_nss_nis_endnetgrent (void) +{ + __libc_lock_lock (lock); + + if (data != NULL) + { + free (data); + data = NULL; + data_size = 0; + cursor = NULL; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getnetgrent_r (struct __netgrent *result, char *buffer, size_t buflen) +{ + enum nss_status status; + + if (cursor == NULL) + return NSS_STATUS_NOTFOUND; + + __libc_lock_lock (lock); + + status = _nss_netgroup_parseline (&cursor, result, buffer, buflen); + + __libc_lock_unlock (lock); + + return status; +} diff --git a/glibc-compat/nss_nis/nis-network.c b/glibc-compat/nss_nis/nis-network.c new file mode 100644 index 0000000000..3accc2be41 --- /dev/null +++ b/glibc-compat/nss_nis/nis-network.c @@ -0,0 +1,318 @@ +/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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 <nss.h> +#include <glibc-compat/include/netdb.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <bits/libc-lock.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> + +#include "nss-nis.h" + +/* Get the declaration of the parser function. */ +#define ENTNAME netent +#define EXTERN_PARSER +#include "../nss_files/files-parse.c" + +__libc_lock_define_initialized (static, lock) + +static bool_t new_start = 1; +static char *oldkey = NULL; +static int oldkeylen = 0; + +enum nss_status +_nss_nis_setnetent (void) +{ + __libc_lock_lock (lock); + + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_endnetent (void) +{ + __libc_lock_lock (lock); + + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_nis_getnetent_r (struct netent *net, char *buffer, size_t buflen, + int *herrnop) +{ + struct parser_data *data = (void *) buffer; + char *domain, *result, *outkey; + int len, keylen, parse_res; + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + /* Get the next entry until we found a correct one. */ + do + { + enum nss_status retval; + char *p; + + if (new_start) + retval = yperr2nss (yp_first (domain, "networks.byname", + &outkey, &keylen, &result, &len)); + else + retval = yperr2nss ( yp_next (domain, "networks.byname", + oldkey, oldkeylen, + &outkey, &keylen, &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + { + *herrnop = NETDB_INTERNAL; + __set_errno (EAGAIN); + } + return retval; + } + + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + *herrnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_netent (p, net, data, buflen); + if (parse_res == -1 && errno == ERANGE) + { + *herrnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + + free (oldkey); + oldkey = outkey; + oldkeylen = keylen; + new_start = 0; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getnetent_r (struct netent *net, char *buffer, size_t buflen, + int *herrnop) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_getnetent_r (net, buffer, buflen, herrnop); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_getnetbyname_r (const char *name, struct netent *net, + char *buffer, size_t buflen, int *herrnop) +{ + enum nss_status retval; + struct parser_data *data = (void *) buffer; + char *domain, *result, *p; + int len, parse_res; + + if (name == NULL) + { + __set_errno (EINVAL); + *herrnop = NETDB_INTERNAL; + return NSS_STATUS_UNAVAIL; + } + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + if (buflen < sizeof *data + 1) + { + *herrnop = NETDB_INTERNAL; + __set_errno(ERANGE); + return NSS_STATUS_TRYAGAIN; + } + else + { + /* Convert name to lowercase. */ + size_t namlen = strlen (name); + char name2[namlen + 1]; + int i; + + for (i = 0; i < namlen; ++i) + name2[i] = tolower (name[i]); + name2[i] = '\0'; + + retval = yperr2nss (yp_match (domain, "networks.byname", name2, + namlen, &result, &len)); + } + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + { + __set_errno (EAGAIN); + *herrnop = NETDB_INTERNAL; + } + return retval; + } + + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + *herrnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_netent (p, net, data, buflen); + + if (parse_res <= 0) + { + *herrnop = NETDB_INTERNAL; + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + else + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getnetbyaddr_r (unsigned long addr, int type, struct netent *net, + char *buffer, size_t buflen, int *herrnop) +{ + struct parser_data *data = (void *) buffer; + char *domain; + char *result; + int len; + char buf[256]; + int blen; + struct in_addr in; + char *p; + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + in = inet_makeaddr (addr, 0); + strcpy (buf, inet_ntoa (in)); + blen = strlen (buf); + + while (1) + { + enum nss_status retval; + int parse_res; + + retval = yperr2nss (yp_match (domain, "networks.byaddr", buf, + strlen (buf), &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_NOTFOUND) + { + if (buf[blen - 2] == '.' && buf[blen - 1] == '0') + { + /* Try again, but with trailing dot(s) + removed (one by one) */ + buf[blen - 2] = '\0'; + blen -= 2; + continue; + } + else + return NSS_STATUS_NOTFOUND; + } + else + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + } + + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + *herrnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_netent (p, net, data, buflen); + + + if (parse_res <= 0) + { + *herrnop = NETDB_INTERNAL; + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + else + return NSS_STATUS_SUCCESS; + } +} diff --git a/glibc-compat/nss_nis/nis-proto.c b/glibc-compat/nss_nis/nis-proto.c new file mode 100644 index 0000000000..8dff7d3687 --- /dev/null +++ b/glibc-compat/nss_nis/nis-proto.c @@ -0,0 +1,280 @@ +/* Copyright (C) 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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 <nss.h> +#include <glibc-compat/include/netdb.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <bits/libc-lock.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> + +#include "nss-nis.h" + +/* Get the declaration of the parser function. */ +#define ENTNAME protoent +#define EXTERN_PARSER +#include "../nss_files/files-parse.c" + +__libc_lock_define_initialized (static, lock) + +struct response +{ + char *val; + struct response *next; +}; + +static struct response *start = NULL; +static struct response *next = NULL; + +static int +saveit (int instatus, char *inkey, int inkeylen, char *inval, + int invallen, char *indata) +{ + if (instatus != YP_TRUE) + return instatus; + + if (inkey && inkeylen > 0 && inval && invallen > 0) + { + if (start == NULL) + { + start = malloc (sizeof (struct response)); + next = start; + } + else + { + next->next = malloc (sizeof (struct response)); + next = next->next; + } + next->next = NULL; + next->val = malloc (invallen + 1); + strncpy (next->val, inval, invallen); + next->val[invallen] = '\0'; + } + + return 0; +} + +enum nss_status +internal_nis_setprotoent (void) +{ + char *domainname; + struct ypall_callback ypcb; + enum nss_status status; + + yp_get_default_domain (&domainname); + + while (start != NULL) + { + if (start->val != NULL) + free (start->val); + next = start; + start = start->next; + free (next); + } + start = NULL; + + ypcb.foreach = saveit; + ypcb.data = NULL; + status = yperr2nss (yp_all (domainname, "protocols.bynumber", &ypcb)); + next = start; + + return status; +} + +enum nss_status +_nss_nis_setprotoent (void) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_setprotoent (); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_endprotoent (void) +{ + __libc_lock_lock (lock); + + while (start != NULL) + { + if (start->val != NULL) + free (start->val); + next = start; + start = start->next; + free (next); + } + start = NULL; + next = NULL; + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_nis_getprotoent_r (struct protoent *proto, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + int parse_res; + + if (start == NULL) + internal_nis_setprotoent (); + + /* Get the next entry until we found a correct one. */ + do + { + char *p; + + if (next == NULL) + return NSS_STATUS_NOTFOUND; + p = strncpy (buffer, next->val, buflen); + next = next->next; + + while (isspace (*p)) + ++p; + + parse_res = _nss_files_parse_protoent (p, proto, data, buflen); + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getprotoent_r (struct protoent *proto, char *buffer, size_t buflen) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_getprotoent_r (proto, buffer, buflen); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_getprotobyname_r (const char *name, struct protoent *proto, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + enum nss_status retval; + char *domain, *result, *p; + int len, parse_res; + + if (name == NULL) + { + __set_errno (EINVAL); + return NSS_STATUS_UNAVAIL; + } + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + retval = yperr2nss (yp_match (domain, "protocols.byname", name, + strlen (name), &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_protoent (p, proto, data, buflen); + + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + else if (parse_res == 0) + return NSS_STATUS_NOTFOUND; + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getprotobynumber_r (int number, struct protoent *proto, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + enum nss_status retval; + char *domain, *result, *p; + int len, nlen, parse_res; + char buf[32]; + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + nlen = sprintf (buf, "%d", number); + + retval = yperr2nss (yp_match (domain, "protocols.bynumber", buf, + nlen, &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_protoent (p, proto, data, buflen); + + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + else if (parse_res == 0) + return NSS_STATUS_NOTFOUND; + + return NSS_STATUS_SUCCESS; +} diff --git a/glibc-compat/nss_nis/nis-pwd.c b/glibc-compat/nss_nis/nis-pwd.c new file mode 100644 index 0000000000..e18c80d8ac --- /dev/null +++ b/glibc-compat/nss_nis/nis-pwd.c @@ -0,0 +1,407 @@ +/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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 <nss.h> +#include <glibc-compat/include/pwd.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <bits/libc-lock.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> + +#include "nss-nis.h" + +/* Get the declaration of the parser function. */ +#define ENTNAME pwent +#define STRUCTURE passwd +#define EXTERN_PARSER +#include "../nss_files/files-parse.c" + +/* Protect global state against multiple changers */ +__libc_lock_define_initialized (static, lock) + +static bool_t new_start = 1; +static char *oldkey = NULL; +static int oldkeylen = 0; + +enum nss_status +_nss_nis_setpwent (void) +{ + __libc_lock_lock (lock); + + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_endpwent (void) +{ + __libc_lock_lock (lock); + + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_nis_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + char *domain; + int parse_res; + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + /* Get the next entry until we found a correct one. */ + do + { + enum nss_status retval; + char *result, *outkey, *result2, *p; + int len, keylen, len2; + size_t namelen; + + if (new_start) + retval = yperr2nss (yp_first (domain, "passwd.byname", + &outkey, &keylen, &result, &len)); + else + retval = yperr2nss ( yp_next (domain, "passwd.byname", + oldkey, oldkeylen, + &outkey, &keylen, &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + + /* Check for adjunct style secret passwords. They can be + recognized by a password starting with "##". */ + p = strchr (result, ':'); + if (p != NULL /* This better should be true in all cases. */ + && p[1] == '#' && p[2] == '#' + && (namelen = p - result, + yp_match (domain, "passwd.adjunct.byname", result, namelen, + &result2, &len2)) == YPERR_SUCCESS) + { + /* We found a passwd.adjunct entry. Merge encrypted + password therein into original result. */ + char *encrypted = strchr (result2, ':'); + char *endp, *tmp; + size_t restlen; + + if (encrypted == NULL + || (endp = strchr (++encrypted, ':')) == NULL + || (p = strchr (p + 1, ':')) == NULL) + { + /* Invalid format of the entry. This never should happen + unless the data from which the NIS table is generated is + wrong. We simply ignore it. */ + free (result2); + goto non_adjunct; + } + + restlen = len - (p - result); + if ((size_t) (namelen + (endp - encrypted) + restlen + 2) > buflen) + { + free (result2); + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + memcpy (buffer, result, namelen); + tmp = buffer + namelen; + *tmp++ = ':'; + memcpy (tmp, encrypted, endp - encrypted); + tmp += endp - encrypted; + memcpy (tmp, p, restlen + 1); + p = buffer; + + free (result2); + } + else + { + non_adjunct: + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_pwent (p, pwd, data, buflen); + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + + free (oldkey); + oldkey = outkey; + oldkeylen = keylen; + new_start = 0; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getpwent_r (struct passwd *result, char *buffer, size_t buflen) +{ + int status; + + __libc_lock_lock (lock); + + status = internal_nis_getpwent_r (result, buffer, buflen); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_getpwnam_r (const char *name, struct passwd *pwd, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + enum nss_status retval; + char *domain, *result, *result2, *p; + int len, len2, parse_res; + size_t namelen; + + if (name == NULL) + { + __set_errno (EINVAL); + return NSS_STATUS_UNAVAIL; + } + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + namelen = strlen (name); + + retval = yperr2nss (yp_match (domain, "passwd.byname", name, + namelen, &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + + /* Check for adjunct style secret passwords. They can be recognized + by a password starting with "##". */ + p = strchr (result, ':'); + if (p != NULL /* This better should be true in all cases. */ + && p[1] == '#' && p[2] == '#' + && (namelen = p - result, + yp_match (domain, "passwd.adjunct.byname", name, namelen, + &result2, &len2)) == YPERR_SUCCESS) + { + /* We found a passwd.adjunct entry. Merge encrypted password + therein into original result. */ + char *encrypted = strchr (result2, ':'); + char *endp, *tmp; + size_t restlen; + + if (encrypted == NULL + || (endp = strchr (++encrypted, ':')) == NULL + || (p = strchr (p + 1, ':')) == NULL) + { + /* Invalid format of the entry. This never should happen + unless the data from which the NIS table is generated is + wrong. We simply ignore it. */ + free (result2); + goto non_adjunct; + } + + restlen = len - (p - result); + if ((size_t) (namelen + (endp - encrypted) + restlen + 2) > buflen) + { + free (result2); + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + memcpy (buffer, name, namelen); + tmp = buffer + namelen; + *tmp++ = ':'; + memcpy (tmp, encrypted, endp - encrypted); + tmp += endp - encrypted; + memcpy (tmp, p, restlen + 1); + p = buffer; + + free (result2); + } + else + { + non_adjunct: + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + } + + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_pwent (p, pwd, data, buflen); + + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + else if (parse_res == 0) + return NSS_STATUS_NOTFOUND; + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getpwuid_r (uid_t uid, struct passwd *pwd, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + enum nss_status retval; + char *domain, *result, *p, *result2; + int len, nlen, parse_res, len2; + char buf[32]; + size_t namelen; + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + nlen = sprintf (buf, "%d", uid); + + retval = yperr2nss (yp_match (domain, "passwd.byuid", buf, + nlen, &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + + /* Check for adjunct style secret passwords. They can be recognized + by a password starting with "##". */ + p = strchr (result, ':'); + if (p != NULL /* This better should be true in all cases. */ + && p[1] == '#' && p[2] == '#' + && (namelen = p - result, + yp_match (domain, "passwd.adjunct.byname", result, namelen, + &result2, &len2)) == YPERR_SUCCESS) + { + /* We found a passwd.adjunct entry. Merge encrypted password + therein into original result. */ + char *encrypted = strchr (result2, ':'); + char *endp, *tmp; + size_t restlen; + + if (encrypted == NULL + || (endp = strchr (++encrypted, ':')) == NULL + || (p = strchr (p + 1, ':')) == NULL) + { + /* Invalid format of the entry. This never should happen + unless the data from which the NIS table is generated is + wrong. We simply ignore it. */ + free (result2); + goto non_adjunct; + } + + restlen = len - (p - result); + if ((size_t) (namelen + (endp - encrypted) + restlen + 2) > buflen) + { + free (result2); + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + memcpy (buffer, result, namelen); + tmp = buffer + namelen; + *tmp++ = ':'; + memcpy (tmp, encrypted, endp - encrypted); + tmp += endp - encrypted; + memcpy (tmp, p, restlen + 1); + p = buffer; + + free (result2); + } + else + { + non_adjunct: + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + } + + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_pwent (p, pwd, data, buflen); + + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + else if (parse_res == 0) + return NSS_STATUS_NOTFOUND; + + return NSS_STATUS_SUCCESS; +} diff --git a/glibc-compat/nss_nis/nis-rpc.c b/glibc-compat/nss_nis/nis-rpc.c new file mode 100644 index 0000000000..b265fcdecb --- /dev/null +++ b/glibc-compat/nss_nis/nis-rpc.c @@ -0,0 +1,295 @@ +/* Copyright (C) 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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 <nss.h> +#include <glibc-compat/include/netdb.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <bits/libc-lock.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> + +#include "nss-nis.h" + +/* Get the declaration of the parser function. */ +#define ENTNAME rpcent +#define EXTERN_PARSER +#include "../nss_files/files-parse.c" + +__libc_lock_define_initialized (static, lock) + +struct response_t +{ + char *val; + struct response_t *next; +}; + +struct intern_t +{ + struct response_t *start; + struct response_t *next; +}; +typedef struct intern_t intern_t; + +static intern_t intern = {NULL, NULL}; + +static int +saveit (int instatus, char *inkey, int inkeylen, char *inval, + int invallen, char *indata) +{ + intern_t *intern = (intern_t *)indata; + + if (instatus != YP_TRUE) + return instatus; + + if (inkey && inkeylen > 0 && inval && invallen > 0) + { + if (intern->start == NULL) + { + intern->start = malloc (sizeof (struct response_t)); + intern->next = intern->start; + } + else + { + intern->next->next = malloc (sizeof (struct response_t)); + intern->next = intern->next->next; + } + intern->next->next = NULL; + intern->next->val = malloc (invallen + 1); + strncpy (intern->next->val, inval, invallen); + intern->next->val[invallen] = '\0'; + } + + return 0; +} + +static enum nss_status +internal_nis_setrpcent (intern_t *intern) +{ + char *domainname; + struct ypall_callback ypcb; + enum nss_status status; + + if (yp_get_default_domain (&domainname)) + return NSS_STATUS_UNAVAIL; + + while (intern->start != NULL) + { + if (intern->start->val != NULL) + free (intern->start->val); + intern->next = intern->start; + intern->start = intern->start->next; + free (intern->next); + } + intern->start = NULL; + + ypcb.foreach = saveit; + ypcb.data = (char *)intern; + status = yperr2nss (yp_all(domainname, "rpc.bynumber", &ypcb)); + intern->next = intern->start; + + return status; +} + +enum nss_status +_nss_nis_setrpcent (void) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_setrpcent (&intern); + + __libc_lock_unlock (lock); + + return status; +} + +static enum nss_status +internal_nis_endrpcent (intern_t *intern) +{ + while (intern->start != NULL) + { + if (intern->start->val != NULL) + free (intern->start->val); + intern->next = intern->start; + intern->start = intern->start->next; + free (intern->next); + } + intern->start = NULL; + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_endrpcent (void) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_endrpcent (&intern); + + __libc_lock_unlock (lock); + + return status; +} + +static enum nss_status +internal_nis_getrpcent_r (struct rpcent *rpc, char *buffer, size_t buflen, + intern_t *data) +{ + struct parser_data *pdata = (void *) buffer; + int parse_res; + char *p; + + if (data->start == NULL) + internal_nis_setrpcent (data); + + /* Get the next entry until we found a correct one. */ + do + { + if (data->next == NULL) + return NSS_STATUS_NOTFOUND; + p = strncpy (buffer, data->next->val, buflen); + data->next = data->next->next; + while (isspace (*p)) + ++p; + + parse_res = _nss_files_parse_rpcent (p, rpc, pdata, buflen); + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getrpcent_r (struct rpcent *rpc, char *buffer, size_t buflen) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_getrpcent_r (rpc, buffer, buflen, &intern); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_getrpcbyname_r (const char *name, struct rpcent *rpc, + char *buffer, size_t buflen) +{ + intern_t data = {NULL, NULL}; + enum nss_status status; + int found; + + if (name == NULL) + { + __set_errno (EINVAL); + return NSS_STATUS_UNAVAIL; + } + + status = internal_nis_setrpcent (&data); + if (status != NSS_STATUS_SUCCESS) + return status; + + found = 0; + while (!found && + ((status = internal_nis_getrpcent_r (rpc, buffer, buflen, &data)) + == NSS_STATUS_SUCCESS)) + { + if (strcmp (rpc->r_name, name) == 0) + found = 1; + else + { + int i = 0; + + while (rpc->r_aliases[i] != NULL) + { + if (strcmp (rpc->r_aliases[i], name) == 0) + { + found = 1; + break; + } + else + ++i; + } + } + } + + internal_nis_endrpcent (&data); + + if (!found && status == NSS_STATUS_SUCCESS) + return NSS_STATUS_NOTFOUND; + else + return status; +} + +enum nss_status +_nss_nis_getrpcbynumber_r (int number, struct rpcent *rpc, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + enum nss_status retval; + char *domain, *result, *p; + int len, nlen, parse_res; + char buf[32]; + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + nlen = sprintf (buf, "%d", number); + + retval = yperr2nss (yp_match (domain, "rpc.bynumber", buf, + nlen, &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_rpcent (p, rpc, data, buflen); + + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + else if (parse_res == 0) + return NSS_STATUS_NOTFOUND; + + return NSS_STATUS_SUCCESS; +} diff --git a/glibc-compat/nss_nis/nis-service.c b/glibc-compat/nss_nis/nis-service.c new file mode 100644 index 0000000000..75b871e440 --- /dev/null +++ b/glibc-compat/nss_nis/nis-service.c @@ -0,0 +1,280 @@ +/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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 <nss.h> +#include <glibc-compat/include/netdb.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <bits/libc-lock.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> + +#include "nss-nis.h" + +/* Get the declaration of the parser function. */ +#define ENTNAME servent +#define EXTERN_PARSER +#include "../nss_files/files-parse.c" + +__libc_lock_define_initialized (static, lock) + +struct response_t +{ + char *val; + struct response_t *next; +}; + +struct intern_t +{ + struct response_t *start; + struct response_t *next; +}; +typedef struct intern_t intern_t; + +static intern_t intern = { NULL, NULL }; + +static int +saveit (int instatus, char *inkey, int inkeylen, char *inval, + int invallen, char *indata) +{ + intern_t *intern = (intern_t *) indata; + + if (instatus != YP_TRUE) + return instatus; + + if (inkey && inkeylen > 0 && inval && invallen > 0) + { + if (intern->start == NULL) + { + intern->start = malloc (sizeof (struct response_t)); + intern->next = intern->start; + } + else + { + intern->next->next = malloc (sizeof (struct response_t)); + intern->next = intern->next->next; + } + intern->next->next = NULL; + intern->next->val = malloc (invallen + 1); + strncpy (intern->next->val, inval, invallen); + intern->next->val[invallen] = '\0'; + } + + return 0; +} + +static enum nss_status +internal_nis_setservent (intern_t *intern) +{ + char *domainname; + struct ypall_callback ypcb; + enum nss_status status; + + if (yp_get_default_domain (&domainname)) + return NSS_STATUS_UNAVAIL; + + while (intern->start != NULL) + { + if (intern->start->val != NULL) + free (intern->start->val); + intern->next = intern->start; + intern->start = intern->start->next; + free (intern->next); + } + intern->start = NULL; + + ypcb.foreach = saveit; + ypcb.data = (char *) intern; + status = yperr2nss (yp_all (domainname, "services.byname", &ypcb)); + intern->next = intern->start; + + return status; +} +enum nss_status +_nss_nis_setservent (void) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_setservent (&intern); + + __libc_lock_unlock (lock); + + return status; +} + +static enum nss_status +internal_nis_endservent (intern_t * intern) +{ + while (intern->start != NULL) + { + if (intern->start->val != NULL) + free (intern->start->val); + intern->next = intern->start; + intern->start = intern->start->next; + free (intern->next); + } + intern->start = NULL; + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_endservent (void) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_endservent (&intern); + + __libc_lock_unlock (lock); + + return status; +} + +static enum nss_status +internal_nis_getservent_r (struct servent *serv, char *buffer, + size_t buflen, intern_t *data) +{ + struct parser_data *pdata = (void *) buffer; + int parse_res; + char *p; + + if (data->start == NULL) + internal_nis_setservent (data); + + /* Get the next entry until we found a correct one. */ + do + { + if (data->next == NULL) + return NSS_STATUS_NOTFOUND; + p = strncpy (buffer, data->next->val, buflen); + data->next = data->next->next; + while (isspace (*p)) + ++p; + + parse_res = _nss_files_parse_servent (p, serv, pdata, buflen); + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getservent_r (struct servent *serv, char *buffer, size_t buflen) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_getservent_r (serv, buffer, buflen, &intern); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_getservbyname_r (const char *name, char *protocol, + struct servent *serv, char *buffer, size_t buflen) +{ + intern_t data = { NULL, NULL }; + enum nss_status status; + int found; + + if (name == NULL) + { + __set_errno (EINVAL); + return NSS_STATUS_UNAVAIL; + } + + status = internal_nis_setservent (&data); + if (status != NSS_STATUS_SUCCESS) + return status; + + found = 0; + while (!found && + ((status = internal_nis_getservent_r (serv, buffer, buflen, &data)) + == NSS_STATUS_SUCCESS)) + { + if (protocol == NULL || strcmp (serv->s_proto, protocol) == 0) + { + char **cp; + + if (strcmp (serv->s_name, name) == 0) + found = 1; + else + for (cp = serv->s_aliases; *cp; cp++) + if (strcmp (name, *cp) == 0) + found = 1; + } + } + + internal_nis_endservent (&data); + + if (!found && status == NSS_STATUS_SUCCESS) + return NSS_STATUS_NOTFOUND; + else + return status; +} + +enum nss_status +_nss_nis_getservbyport_r (int port, char *protocol, struct servent *serv, + char *buffer, size_t buflen) +{ + intern_t data = { NULL, NULL }; + enum nss_status status; + int found; + + if (protocol == NULL) + { + __set_errno (EINVAL); + return NSS_STATUS_UNAVAIL; + } + + status = internal_nis_setservent (&data); + if (status != NSS_STATUS_SUCCESS) + return status; + + found = 0; + while (!found && + ((status = internal_nis_getservent_r (serv, buffer, buflen, &data)) + == NSS_STATUS_SUCCESS)) + { + if (htons (serv->s_port) == port) + { + if (strcmp (serv->s_proto, protocol) == 0) + { + found = 1; + } + } + } + + internal_nis_endservent (&data); + + if (!found && status == NSS_STATUS_SUCCESS) + return NSS_STATUS_NOTFOUND; + else + return status; +} diff --git a/glibc-compat/nss_nis/nis-spwd.c b/glibc-compat/nss_nis/nis-spwd.c new file mode 100644 index 0000000000..d7857b2c88 --- /dev/null +++ b/glibc-compat/nss_nis/nis-spwd.c @@ -0,0 +1,201 @@ +/* Copyright (C) 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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 <nss.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <glibc-compat/include/shadow.h> +#include <bits/libc-lock.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> + +#include "nss-nis.h" + +/* Get the declaration of the parser function. */ +#define ENTNAME spent +#define STRUCTURE spwd +#define EXTERN_PARSER +#include "../nss_files/files-parse.c" + +/* Protect global state against multiple changers */ +__libc_lock_define_initialized (static, lock) + +static bool_t new_start = 1; +static char *oldkey = NULL; +static int oldkeylen = 0; + +enum nss_status +_nss_nis_setspent (void) +{ + __libc_lock_lock (lock); + + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_endspent (void) +{ + __libc_lock_lock (lock); + + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_nis_getspent_r (struct spwd *sp, char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + char *domain, *result, *outkey; + int len, keylen, parse_res; + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + /* Get the next entry until we found a correct one. */ + do + { + enum nss_status retval; + char *p; + + if (new_start) + retval = yperr2nss (yp_first (domain, "shadow.byname", + &outkey, &keylen, &result, &len)); + else + retval = yperr2nss ( yp_next (domain, "shadow.byname", + oldkey, oldkeylen, + &outkey, &keylen, &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_spent (p, sp, data, buflen); + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + + free (oldkey); + oldkey = outkey; + oldkeylen = keylen; + new_start = 0; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getspent_r (struct spwd *result, char *buffer, size_t buflen) +{ + int status; + + __libc_lock_lock (lock); + + status = internal_nis_getspent_r (result, buffer, buflen); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_getspnam_r (const char *name, struct spwd *sp, + char *buffer, size_t buflen) +{ + struct parser_data *data = (void *) buffer; + enum nss_status retval; + char *domain, *result, *p; + int len, parse_res; + + if (name == NULL) + { + __set_errno (EINVAL); + return NSS_STATUS_UNAVAIL; + } + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + retval = yperr2nss (yp_match (domain, "shadow.byname", name, + strlen (name), &result, &len)); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + __set_errno (EAGAIN); + return retval; + } + + if ((size_t) (len + 1) > buflen) + { + free (result); + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_spent (p, sp, data, buflen); + + if (parse_res == -1 && errno == ERANGE) + return NSS_STATUS_TRYAGAIN; + else if (parse_res == 0) + return NSS_STATUS_NOTFOUND; + + return NSS_STATUS_SUCCESS; +} diff --git a/glibc-compat/oldfileops.c b/glibc-compat/oldfileops.c new file mode 100644 index 0000000000..9e11d65be4 --- /dev/null +++ b/glibc-compat/oldfileops.c @@ -0,0 +1,774 @@ +/* Copyright (C) 1993, 1995, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU IO Library. + Written by Per Bothner <bothner@cygnus.com>. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, if you link this library with files + compiled with a GNU compiler to produce an executable, this does + not cause the resulting executable to be covered by the GNU General + Public License. This exception does not however invalidate any + other reasons why the executable file might be covered by the GNU + General Public License. */ + +/* This is a compatibility file. If we don't build the libc with + versioning don't compile this file. */ + +#ifndef _POSIX_SOURCE +# define _POSIX_SOURCE +#endif +#define _IO_USE_OLD_IO_FILE +#include "libioP.h" +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <string.h> +#include <errno.h> +#ifndef errno +extern int errno; +#endif +#ifndef __set_errno +# define __set_errno(Val) errno = (Val) +#endif + + +#ifdef _LIBC +# define open(Name, Flags, Prot) __open (Name, Flags, Prot) +# define close(FD) __close (FD) +# define lseek(FD, Offset, Whence) __lseek (FD, Offset, Whence) +# define read(FD, Buf, NBytes) __read (FD, Buf, NBytes) +# define write(FD, Buf, NBytes) __write (FD, Buf, NBytes) +#endif + +/* An fstream can be in at most one of put mode, get mode, or putback mode. + Putback mode is a variant of get mode. + + In a filebuf, there is only one current position, instead of two + separate get and put pointers. In get mode, the current position + is that of gptr(); in put mode that of pptr(). + + The position in the buffer that corresponds to the position + in external file system is normally _IO_read_end, except in putback + mode, when it is _IO_save_end. + If the field _fb._offset is >= 0, it gives the offset in + the file as a whole corresponding to eGptr(). (?) + + PUT MODE: + If a filebuf is in put mode, then all of _IO_read_ptr, _IO_read_end, + and _IO_read_base are equal to each other. These are usually equal + to _IO_buf_base, though not necessarily if we have switched from + get mode to put mode. (The reason is to maintain the invariant + that _IO_read_end corresponds to the external file position.) + _IO_write_base is non-NULL and usually equal to _IO_base_base. + We also have _IO_write_end == _IO_buf_end, but only in fully buffered mode. + The un-flushed character are those between _IO_write_base and _IO_write_ptr. + + GET MODE: + If a filebuf is in get or putback mode, eback() != egptr(). + In get mode, the unread characters are between gptr() and egptr(). + The OS file position corresponds to that of egptr(). + + PUTBACK MODE: + Putback mode is used to remember "excess" characters that have + been sputbackc'd in a separate putback buffer. + In putback mode, the get buffer points to the special putback buffer. + The unread characters are the characters between gptr() and egptr() + in the putback buffer, as well as the area between save_gptr() + and save_egptr(), which point into the original reserve buffer. + (The pointers save_gptr() and save_egptr() are the values + of gptr() and egptr() at the time putback mode was entered.) + The OS position corresponds to that of save_egptr(). + + LINE BUFFERED OUTPUT: + During line buffered output, _IO_write_base==base() && epptr()==base(). + However, ptr() may be anywhere between base() and ebuf(). + This forces a call to filebuf::overflow(int C) on every put. + If there is more space in the buffer, and C is not a '\n', + then C is inserted, and pptr() incremented. + + UNBUFFERED STREAMS: + If a filebuf is unbuffered(), the _shortbuf[1] is used as the buffer. +*/ + +#define CLOSED_FILEBUF_FLAGS \ + (_IO_IS_FILEBUF+_IO_NO_READS+_IO_NO_WRITES+_IO_TIED_PUT_GET) + + +void +_IO_old_file_init (fp) + _IO_FILE *fp; +{ + /* POSIX.1 allows another file handle to be used to change the position + of our file descriptor. Hence we actually don't know the actual + position before we do the first fseek (and until a following fflush). */ + fp->_old_offset = _IO_pos_BAD; + fp->_IO_file_flags |= CLOSED_FILEBUF_FLAGS; + + _IO_link_in(fp); + fp->_vtable_offset = ((int) sizeof (struct _IO_FILE) + - (int) sizeof (struct _IO_FILE_complete)); + fp->_fileno = -1; +} + +int +_IO_old_file_close_it (fp) + _IO_FILE *fp; +{ + int write_status, close_status; + if (!_IO_file_is_open (fp)) + return EOF; + + write_status = _IO_old_do_flush (fp); + + _IO_unsave_markers(fp); + + close_status = _IO_SYSCLOSE (fp); + + /* Free buffer. */ + _IO_setb (fp, NULL, NULL, 0); + _IO_setg (fp, NULL, NULL, NULL); + _IO_setp (fp, NULL, NULL); + + _IO_un_link (fp); + fp->_flags = _IO_MAGIC|CLOSED_FILEBUF_FLAGS; + fp->_fileno = EOF; + fp->_old_offset = _IO_pos_BAD; + + return close_status ? close_status : write_status; +} + +void +_IO_old_file_finish (fp, dummy) + _IO_FILE *fp; + int dummy; +{ + if (_IO_file_is_open (fp)) + { + _IO_old_do_flush (fp); + if (!(fp->_flags & _IO_DELETE_DONT_CLOSE)) + _IO_SYSCLOSE (fp); + } + _IO_default_finish (fp, 0); +} + +_IO_FILE * +_IO_old_file_fopen (fp, filename, mode) + _IO_FILE *fp; + const char *filename; + const char *mode; +{ + int oflags = 0, omode; + int read_write, fdesc; + int oprot = 0666; + if (_IO_file_is_open (fp)) + return 0; + switch (*mode++) + { + case 'r': + omode = O_RDONLY; + read_write = _IO_NO_WRITES; + break; + case 'w': + omode = O_WRONLY; + oflags = O_CREAT|O_TRUNC; + read_write = _IO_NO_READS; + break; + case 'a': + omode = O_WRONLY; + oflags = O_CREAT|O_APPEND; + read_write = _IO_NO_READS|_IO_IS_APPENDING; + break; + default: + __set_errno (EINVAL); + return NULL; + } + if (mode[0] == '+' || (mode[0] == 'b' && mode[1] == '+')) + { + omode = O_RDWR; + read_write &= _IO_IS_APPENDING; + } + fdesc = open (filename, omode|oflags, oprot); + if (fdesc < 0) + return NULL; + fp->_fileno = fdesc; + _IO_mask_flags (fp, read_write,_IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING); + if (read_write & _IO_IS_APPENDING) + if (_IO_SEEKOFF (fp, (_IO_off_t)0, _IO_seek_end, _IOS_INPUT|_IOS_OUTPUT) + == _IO_pos_BAD && errno != ESPIPE) + return NULL; + _IO_link_in (fp); + return fp; +} + +_IO_FILE * +_IO_old_file_attach (fp, fd) + _IO_FILE *fp; + int fd; +{ + if (_IO_file_is_open (fp)) + return NULL; + fp->_fileno = fd; + fp->_flags &= ~(_IO_NO_READS+_IO_NO_WRITES); + fp->_flags |= _IO_DELETE_DONT_CLOSE; + /* Get the current position of the file. */ + /* We have to do that since that may be junk. */ + fp->_old_offset = _IO_pos_BAD; + if (_IO_SEEKOFF (fp, (_IO_off_t)0, _IO_seek_cur, _IOS_INPUT|_IOS_OUTPUT) + == _IO_pos_BAD && errno != ESPIPE) + return NULL; + return fp; +} + +_IO_FILE * +_IO_old_file_setbuf (fp, p, len) + _IO_FILE *fp; + char *p; + _IO_ssize_t len; +{ + if (_IO_default_setbuf (fp, p, len) == NULL) + return NULL; + + fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end + = fp->_IO_buf_base; + _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base); + + return fp; +} + +static int old_do_write (_IO_FILE *, const char *, _IO_size_t) __THROW; + +/* Write TO_DO bytes from DATA to FP. + Then mark FP as having empty buffers. */ + +int +_IO_old_do_write (fp, data, to_do) + _IO_FILE *fp; + const char *data; + _IO_size_t to_do; +{ + return (to_do == 0 || old_do_write (fp, data, to_do) == to_do) + ? 0 : EOF; +} + +static +int +old_do_write (fp, data, to_do) + _IO_FILE *fp; + const char *data; + _IO_size_t to_do; +{ + _IO_size_t count; + if (fp->_flags & _IO_IS_APPENDING) + /* On a system without a proper O_APPEND implementation, + you would need to sys_seek(0, SEEK_END) here, but is + is not needed nor desirable for Unix- or Posix-like systems. + Instead, just indicate that offset (before and after) is + unpredictable. */ + fp->_old_offset = _IO_pos_BAD; + else if (fp->_IO_read_end != fp->_IO_write_base) + { + _IO_pos_t new_pos + = _IO_SYSSEEK (fp, fp->_IO_write_base - fp->_IO_read_end, 1); + if (new_pos == _IO_pos_BAD) + return 0; + fp->_old_offset = new_pos; + } + count = _IO_SYSWRITE (fp, data, to_do); + if (fp->_cur_column && count) + fp->_cur_column = _IO_adjust_column (fp->_cur_column - 1, data, count) + 1; + _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base); + fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_buf_base; + fp->_IO_write_end = ((fp->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED)) + ? fp->_IO_buf_base : fp->_IO_buf_end); + return count; +} + +int +_IO_old_file_underflow (fp) + _IO_FILE *fp; +{ + _IO_ssize_t count; +#if 0 + /* SysV does not make this test; take it out for compatibility */ + if (fp->_flags & _IO_EOF_SEEN) + return (EOF); +#endif + + if (fp->_flags & _IO_NO_READS) + { + __set_errno (EBADF); + return EOF; + } + if (fp->_IO_read_ptr < fp->_IO_read_end) + return *(unsigned char *) fp->_IO_read_ptr; + + if (fp->_IO_buf_base == NULL) + _IO_doallocbuf (fp); + + /* Flush all line buffered files before reading. */ + /* FIXME This can/should be moved to genops ?? */ + if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED)) + _IO_flush_all_linebuffered (); + + _IO_switch_to_get_mode (fp); + + /* This is very tricky. We have to adjust those + pointers before we call _IO_SYSREAD () since + we may longjump () out while waiting for + input. Those pointers may be screwed up. H.J. */ + fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base; + fp->_IO_read_end = fp->_IO_buf_base; + fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end + = fp->_IO_buf_base; + + count = _IO_SYSREAD (fp, fp->_IO_buf_base, + fp->_IO_buf_end - fp->_IO_buf_base); + if (count <= 0) + { + if (count == 0) + fp->_flags |= _IO_EOF_SEEN; + else + fp->_flags |= _IO_ERR_SEEN, count = 0; + } + fp->_IO_read_end += count; + if (count == 0) + return EOF; + if (fp->_old_offset != _IO_pos_BAD) + _IO_pos_adjust (fp->_old_offset, count); + return *(unsigned char *) fp->_IO_read_ptr; +} + +int +_IO_old_file_overflow (f, ch) + _IO_FILE *f; + int ch; +{ + if (f->_flags & _IO_NO_WRITES) /* SET ERROR */ + { + f->_flags |= _IO_ERR_SEEN; + __set_errno (EBADF); + return EOF; + } + /* If currently reading or no buffer allocated. */ + if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0) + { + /* Allocate a buffer if needed. */ + if (f->_IO_write_base == 0) + { + _IO_doallocbuf (f); + _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base); + } + /* Otherwise must be currently reading. + If _IO_read_ptr (and hence also _IO_read_end) is at the buffer end, + logically slide the buffer forwards one block (by setting the + read pointers to all point at the beginning of the block). This + makes room for subsequent output. + Otherwise, set the read pointers to _IO_read_end (leaving that + alone, so it can continue to correspond to the external position). */ + if (f->_IO_read_ptr == f->_IO_buf_end) + f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base; + f->_IO_write_ptr = f->_IO_read_ptr; + f->_IO_write_base = f->_IO_write_ptr; + f->_IO_write_end = f->_IO_buf_end; + f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end; + + if (f->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED)) + f->_IO_write_end = f->_IO_write_ptr; + f->_flags |= _IO_CURRENTLY_PUTTING; + } + if (ch == EOF) + return _IO_old_do_flush (f); + if (f->_IO_write_ptr == f->_IO_buf_end ) /* Buffer is really full */ + if (_IO_old_do_flush (f) == EOF) + return EOF; + *f->_IO_write_ptr++ = ch; + if ((f->_flags & _IO_UNBUFFERED) + || ((f->_flags & _IO_LINE_BUF) && ch == '\n')) + if (_IO_old_do_flush (f) == EOF) + return EOF; + return (unsigned char) ch; +} + +int +_IO_old_file_sync (fp) + _IO_FILE *fp; +{ + _IO_size_t delta; + int retval = 0; + + _IO_cleanup_region_start ((void (*) (void *)) _IO_funlockfile, fp); + _IO_flockfile (fp); + /* char* ptr = cur_ptr(); */ + if (fp->_IO_write_ptr > fp->_IO_write_base) + if (_IO_old_do_flush(fp)) return EOF; + delta = fp->_IO_read_ptr - fp->_IO_read_end; + if (delta != 0) + { +#ifdef TODO + if (_IO_in_backup (fp)) + delta -= eGptr () - Gbase (); +#endif + _IO_off_t new_pos = _IO_SYSSEEK (fp, delta, 1); + if (new_pos != (_IO_off_t) EOF) + fp->_IO_read_end = fp->_IO_read_ptr; +#ifdef ESPIPE + else if (errno == ESPIPE) + ; /* Ignore error from unseekable devices. */ +#endif + else + retval = EOF; + } + if (retval != EOF) + fp->_old_offset = _IO_pos_BAD; + /* FIXME: Cleanup - can this be shared? */ + /* setg(base(), ptr, ptr); */ + _IO_funlockfile (fp); + _IO_cleanup_region_end (0); + return retval; +} + +_IO_fpos64_t +_IO_old_file_seekoff (fp, offset, dir, mode) + _IO_FILE *fp; + _IO_off64_t offset; + int dir; + int mode; +{ + _IO_pos_t result; + _IO_off64_t delta, new_offset; + long count; + /* POSIX.1 8.2.3.7 says that after a call the fflush() the file + offset of the underlying file must be exact. */ + int must_be_exact = (fp->_IO_read_base == fp->_IO_read_end + && fp->_IO_write_base == fp->_IO_write_ptr); + + if (mode == 0) + dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */ + + /* Flush unwritten characters. + (This may do an unneeded write if we seek within the buffer. + But to be able to switch to reading, we would need to set + egptr to ptr. That can't be done in the current design, + which assumes file_ptr() is eGptr. Anyway, since we probably + end up flushing when we close(), it doesn't make much difference.) + FIXME: simulate mem-papped files. */ + + if (fp->_IO_write_ptr > fp->_IO_write_base || _IO_in_put_mode (fp)) + if (_IO_switch_to_get_mode (fp)) + return EOF; + + if (fp->_IO_buf_base == NULL) + { + _IO_doallocbuf (fp); + _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base); + _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base); + } + + switch (dir) + { + case _IO_seek_cur: + /* Adjust for read-ahead (bytes is buffer). */ + offset -= fp->_IO_read_end - fp->_IO_read_ptr; + if (fp->_old_offset == _IO_pos_BAD) + goto dumb; + /* Make offset absolute, assuming current pointer is file_ptr(). */ + offset += _IO_pos_as_off (fp->_old_offset); + + dir = _IO_seek_set; + break; + case _IO_seek_set: + break; + case _IO_seek_end: + { + struct _G_stat64 st; + if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode)) + { + offset += st.st_size; + dir = _IO_seek_set; + } + else + goto dumb; + } + } + /* At this point, dir==_IO_seek_set. */ + + /* If destination is within current buffer, optimize: */ + if (fp->_old_offset != _IO_pos_BAD && fp->_IO_read_base != NULL + && !_IO_in_backup (fp)) + { + /* Offset relative to start of main get area. */ + _IO_pos_t rel_offset = (offset - fp->_old_offset + + (fp->_IO_read_end - fp->_IO_read_base)); + if (rel_offset >= 0) + { +#if 0 + if (_IO_in_backup (fp)) + _IO_switch_to_main_get_area (fp); +#endif + if (rel_offset <= fp->_IO_read_end - fp->_IO_read_base) + { + _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + rel_offset, + fp->_IO_read_end); + _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base); + goto resync; + } +#ifdef TODO + /* If we have streammarkers, seek forward by reading ahead. */ + if (_IO_have_markers (fp)) + { + int to_skip = rel_offset + - (fp->_IO_read_ptr - fp->_IO_read_base); + if (ignore (to_skip) != to_skip) + goto dumb; + goto resync; + } +#endif + } +#ifdef TODO + if (rel_offset < 0 && rel_offset >= Bbase () - Bptr ()) + { + if (!_IO_in_backup (fp)) + _IO_switch_to_backup_area (fp); + gbump (fp->_IO_read_end + rel_offset - fp->_IO_read_ptr); + goto resync; + } +#endif + } + +#ifdef TODO + _IO_unsave_markers (fp); +#endif + + if (fp->_flags & _IO_NO_READS) + goto dumb; + + /* Try to seek to a block boundary, to improve kernel page management. */ + new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1); + delta = offset - new_offset; + if (delta > fp->_IO_buf_end - fp->_IO_buf_base) + { + new_offset = offset; + delta = 0; + } + result = _IO_SYSSEEK (fp, new_offset, 0); + if (result < 0) + return EOF; + if (delta == 0) + count = 0; + else + { + count = _IO_SYSREAD (fp, fp->_IO_buf_base, + (must_be_exact + ? delta : fp->_IO_buf_end - fp->_IO_buf_base)); + if (count < delta) + { + /* We weren't allowed to read, but try to seek the remainder. */ + offset = count == EOF ? delta : delta-count; + dir = _IO_seek_cur; + goto dumb; + } + } + _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta, + fp->_IO_buf_base + count); + _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base); + fp->_old_offset = result + count; + _IO_mask_flags (fp, 0, _IO_EOF_SEEN); + return offset; + dumb: + + _IO_unsave_markers (fp); + result = _IO_SYSSEEK (fp, offset, dir); + if (result != EOF) + { + _IO_mask_flags (fp, 0, _IO_EOF_SEEN); + fp->_old_offset = result; + _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base); + _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base); + } + return result; + +resync: + /* We need to do it since it is possible that the file offset in + the kernel may be changed behind our back. It may happen when + we fopen a file and then do a fork. One process may access the + the file and the kernel file offset will be changed. */ + if (fp->_old_offset >= 0) + _IO_SYSSEEK (fp, fp->_old_offset, 0); + + return offset; +} + +_IO_ssize_t +_IO_old_file_write (f, data, n) + _IO_FILE *f; + const void *data; + _IO_ssize_t n; +{ + _IO_ssize_t to_do = n; + while (to_do > 0) + { + _IO_ssize_t count = write (f->_fileno, data, to_do); + if (count == EOF) + { + f->_flags |= _IO_ERR_SEEN; + break; + } + to_do -= count; + data = (void *) ((char *) data + count); + } + n -= to_do; + if (f->_old_offset >= 0) + f->_old_offset += n; + return n; +} + +_IO_size_t +_IO_old_file_xsputn (f, data, n) + _IO_FILE *f; + const void *data; + _IO_size_t n; +{ + register const char *s = (char *) data; + _IO_size_t to_do = n; + int must_flush = 0; + _IO_size_t count; + + if (n <= 0) + return 0; + /* This is an optimized implementation. + If the amount to be written straddles a block boundary + (or the filebuf is unbuffered), use sys_write directly. */ + + /* First figure out how much space is available in the buffer. */ + count = f->_IO_write_end - f->_IO_write_ptr; /* Space available. */ + if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING)) + { + count = f->_IO_buf_end - f->_IO_write_ptr; + if (count >= n) + { + register const char *p; + for (p = s + n; p > s; ) + { + if (*--p == '\n') + { + count = p - s + 1; + must_flush = 1; + break; + } + } + } + } + /* Then fill the buffer. */ + if (count > 0) + { + if (count > to_do) + count = to_do; + if (count > 20) + { + memcpy (f->_IO_write_ptr, s, count); + s += count; + } + else + { + register char *p = f->_IO_write_ptr; + register int i = (int) count; + while (--i >= 0) + *p++ = *s++; + } + f->_IO_write_ptr += count; + to_do -= count; + } + if (to_do + must_flush > 0) + { + _IO_size_t block_size, do_write; + /* Next flush the (full) buffer. */ + if (__overflow (f, EOF) == EOF) + return n - to_do; + + /* Try to maintain alignment: write a whole number of blocks. + dont_write is what gets left over. */ + block_size = f->_IO_buf_end - f->_IO_buf_base; + do_write = to_do - (block_size >= 128 ? to_do % block_size : 0); + + if (do_write) + { + count = old_do_write (f, s, do_write); + to_do -= count; + if (count < do_write) + return n - to_do; + } + + /* Now write out the remainder. Normally, this will fit in the + buffer, but it's somewhat messier for line-buffered files, + so we let _IO_default_xsputn handle the general case. */ + if (to_do) + to_do -= _IO_default_xsputn (f, s+do_write, to_do); + } + return n - to_do; +} + + +struct _IO_jump_t _IO_old_file_jumps = +{ + JUMP_INIT_DUMMY, + JUMP_INIT(finish, _IO_old_file_finish), + JUMP_INIT(overflow, _IO_old_file_overflow), + JUMP_INIT(underflow, _IO_old_file_underflow), + JUMP_INIT(uflow, _IO_default_uflow), + JUMP_INIT(pbackfail, _IO_default_pbackfail), + JUMP_INIT(xsputn, _IO_old_file_xsputn), + JUMP_INIT(xsgetn, _IO_default_xsgetn), + JUMP_INIT(seekoff, _IO_old_file_seekoff), + JUMP_INIT(seekpos, _IO_default_seekpos), + JUMP_INIT(setbuf, _IO_old_file_setbuf), + JUMP_INIT(sync, _IO_old_file_sync), + JUMP_INIT(doallocate, _IO_file_doallocate), + JUMP_INIT(read, _IO_file_read), + JUMP_INIT(write, _IO_old_file_write), + JUMP_INIT(seek, _IO_file_seek), + JUMP_INIT(close, _IO_file_close), + JUMP_INIT(stat, _IO_file_stat) +}; + +#ifdef SHARED +symbol_version (_IO_old_do_write, _IO_do_write, GLIBC_2.0); +symbol_version (_IO_old_file_attach, _IO_file_attach, GLIBC_2.0); +symbol_version (_IO_old_file_close_it, _IO_file_close_it, GLIBC_2.0); +symbol_version (_IO_old_file_finish, _IO_file_finish, GLIBC_2.0); +symbol_version (_IO_old_file_fopen, _IO_file_fopen, GLIBC_2.0); +symbol_version (_IO_old_file_init, _IO_file_init, GLIBC_2.0); +symbol_version (_IO_old_file_setbuf, _IO_file_setbuf, GLIBC_2.0); +symbol_version (_IO_old_file_sync, _IO_file_sync, GLIBC_2.0); +symbol_version (_IO_old_file_overflow, _IO_file_overflow, GLIBC_2.0); +symbol_version (_IO_old_file_seekoff, _IO_file_seekoff, GLIBC_2.0); +symbol_version (_IO_old_file_underflow, _IO_file_underflow, GLIBC_2.0); +symbol_version (_IO_old_file_write, _IO_file_write, GLIBC_2.0); +symbol_version (_IO_old_file_xsputn, _IO_file_xsputn, GLIBC_2.0); +#else +strong_alias (_IO_old_do_write, _IO_do_write); +strong_alias (_IO_old_file_attach, _IO_file_attach); +strong_alias (_IO_old_file_close_it, _IO_file_close_it); +strong_alias (_IO_old_file_finish, _IO_file_finish); +strong_alias (_IO_old_file_fopen, _IO_file_fopen); +strong_alias (_IO_old_file_init, _IO_file_init); +strong_alias (_IO_old_file_setbuf, _IO_file_setbuf); +strong_alias (_IO_old_file_sync, _IO_file_sync); +strong_alias (_IO_old_file_overflow, _IO_file_overflow); +strong_alias (_IO_old_file_seekoff, _IO_file_seekoff); +strong_alias (_IO_old_file_underflow, _IO_file_underflow); +strong_alias (_IO_old_file_write, _IO_file_write); +strong_alias (_IO_old_file_xsputn, _IO_file_xsputn); +#endif diff --git a/glibc-compat/oldiofclose.c b/glibc-compat/oldiofclose.c new file mode 100644 index 0000000000..eadad8adbe --- /dev/null +++ b/glibc-compat/oldiofclose.c @@ -0,0 +1,60 @@ +/* Copyright (C) 1993, 1995, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU IO Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, if you link this library with files + compiled with a GNU compiler to produce an executable, this does + not cause the resulting executable to be covered by the GNU General + Public License. This exception does not however invalidate any + other reasons why the executable file might be covered by the GNU + General Public License. */ + +#define _IO_USE_OLD_IO_FILE +#include "libioP.h" +#ifdef __STDC__ +#include <stdlib.h> +#endif + +int +_IO_old_fclose (fp) + _IO_FILE *fp; +{ + int status; + + CHECK_FILE(fp, EOF); + + _IO_cleanup_region_start ((void (*) (void *)) _IO_funlockfile, fp); + _IO_flockfile (fp); + if (fp->_IO_file_flags & _IO_IS_FILEBUF) + status = _IO_old_file_close_it (fp); + else + status = fp->_flags & _IO_ERR_SEEN ? -1 : 0; + _IO_FINISH (fp); + _IO_funlockfile (fp); + _IO_cleanup_region_end (0); + if (fp != _IO_stdin && fp != _IO_stdout && fp != _IO_stderr) + { + fp->_IO_file_flags = 0; + free(fp); + } + + return status; +} + +strong_alias (_IO_old_fclose, __old_fclose) +symbol_version (_IO_old_fclose, _IO_fclose, GLIBC_2.0); +symbol_version (__old_fclose, fclose, GLIBC_2.0); diff --git a/glibc-compat/oldiofdopen.c b/glibc-compat/oldiofdopen.c new file mode 100644 index 0000000000..410206412a --- /dev/null +++ b/glibc-compat/oldiofdopen.c @@ -0,0 +1,140 @@ +/* Copyright (C) 1993, 1994, 1997 Free Software Foundation, Inc. + This file is part of the GNU IO Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, if you link this library with files + compiled with a GNU compiler to produce an executable, this does + not cause the resulting executable to be covered by the GNU General + Public License. This exception does not however invalidate any + other reasons why the executable file might be covered by the GNU + General Public License. */ + +#define _IO_USE_OLD_IO_FILE +#ifdef __STDC__ +# include <stdlib.h> +#endif +#include "libioP.h" +#include <fcntl.h> + +#ifndef _IO_fcntl +# define _IO_fcntl __fcntl +#endif + +_IO_FILE * +_IO_old_fdopen (fd, mode) + int fd; + const char *mode; +{ + int read_write; + int posix_mode = 0; + struct locked_FILE + { + struct _IO_FILE_plus fp; +#ifdef _IO_MTSAFE_IO + _IO_lock_t lock; +#endif + } *new_f; + int fd_flags; + + switch (*mode++) + { + case 'r': + read_write = _IO_NO_WRITES; + break; + case 'w': + read_write = _IO_NO_READS; + break; + case 'a': + posix_mode = O_APPEND; + read_write = _IO_NO_READS|_IO_IS_APPENDING; + break; + default: + MAYBE_SET_EINVAL; + return NULL; + } + if (mode[0] == '+' || (mode[0] == 'b' && mode[1] == '+')) + read_write &= _IO_IS_APPENDING; +#ifdef F_GETFL + fd_flags = _IO_fcntl (fd, F_GETFL); +#ifndef O_ACCMODE +#define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR) +#endif + if (fd_flags == -1 + || ((fd_flags & O_ACCMODE) == O_RDONLY && !(read_write & _IO_NO_WRITES)) + || ((fd_flags & O_ACCMODE) == O_WRONLY && !(read_write & _IO_NO_READS))) + return NULL; + + /* The May 93 draft of P1003.4/D14.1 (redesignated as 1003.1b) + [System Application Program Interface (API) Amendment 1: + Realtime Extensions], Rationale B.8.3.3 + Open a Stream on a File Descriptor says: + + Although not explicitly required by POSIX.1, a good + implementation of append ("a") mode would cause the + O_APPEND flag to be set. + + (Historical implementations [such as Solaris2] do a one-time + seek in fdopen.) + + However, we do not turn O_APPEND off if the mode is "w" (even + though that would seem consistent) because that would be more + likely to break historical programs. + */ + if ((posix_mode & O_APPEND) && !(fd_flags & O_APPEND)) + { +#ifdef F_SETFL + if (_IO_fcntl (fd, F_SETFL, fd_flags | O_APPEND) == -1) +#endif + return NULL; + } +#endif + + new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE)); + if (new_f == NULL) + return NULL; +#ifdef _IO_MTSAFE_IO + new_f->fp.file._lock = &new_f->lock; +#endif + _IO_init (&new_f->fp.file, 0); + _IO_JUMPS (&new_f->fp) = &_IO_old_file_jumps; + _IO_old_file_init (&new_f->fp.file); +#if !_IO_UNIFIED_JUMPTABLES + new_f->fp.vtable = NULL; +#endif + if (_IO_old_file_attach (&new_f->fp.file, fd) == NULL) + { + _IO_un_link (&new_f->fp.file); + free (new_f); + return NULL; + } + new_f->fp.file._flags &= ~_IO_DELETE_DONT_CLOSE; + + new_f->fp.file._IO_file_flags = + _IO_mask_flags (&new_f->fp.file, read_write, + _IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING); + + return (_IO_FILE *) &new_f->fp; +} + +#ifdef SHARED +strong_alias (_IO_old_fdopen, __old_fdopen) +symbol_version (_IO_old_fdopen, _IO_fdopen, GLIBC_2.0); +symbol_version (__old_fdopen, fdopen, GLIBC_2.0); +#else +strong_alias (_IO_old_fdopen, _IO_fdopen); +strong_alias (__old_fdopen, fdopen); +#endif diff --git a/glibc-compat/oldiofopen.c b/glibc-compat/oldiofopen.c new file mode 100644 index 0000000000..e2d9a826ce --- /dev/null +++ b/glibc-compat/oldiofopen.c @@ -0,0 +1,71 @@ +/* Copyright (C) 1993, 1997 Free Software Foundation, Inc. + This file is part of the GNU IO Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, if you link this library with files + compiled with a GNU compiler to produce an executable, this does + not cause the resulting executable to be covered by the GNU General + Public License. This exception does not however invalidate any + other reasons why the executable file might be covered by the GNU + General Public License. */ + +#define _IO_USE_OLD_IO_FILE +#include "libioP.h" +#ifdef __STDC__ +#include <stdlib.h> +#endif + + +_IO_FILE * +_IO_old_fopen (filename, mode) + const char *filename; + const char *mode; +{ + struct locked_FILE + { + struct _IO_FILE_plus fp; +#ifdef _IO_MTSAFE_IO + _IO_lock_t lock; +#endif + } *new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE)); + + if (new_f == NULL) + return NULL; +#ifdef _IO_MTSAFE_IO + new_f->fp.file._lock = &new_f->lock; +#endif + _IO_init (&new_f->fp.file, 0); + _IO_JUMPS (&new_f->fp.file) = &_IO_old_file_jumps; + _IO_old_file_init (&new_f->fp.file); +#if !_IO_UNIFIED_JUMPTABLES + new_f->fp.vtable = NULL; +#endif + if (_IO_old_file_fopen (&new_f->fp.file, filename, mode) != NULL) + return (_IO_FILE *) &new_f->fp; + _IO_un_link (&new_f->fp.file); + free (new_f); + return NULL; +} + +#ifdef SHARED +strong_alias (_IO_old_fopen, __old_fopen) +symbol_version (_IO_old_fopen, _IO_fopen, GLIBC_2.0); +symbol_version (__old_fopen, fopen, GLIBC_2.0); +#else +strong_alias (_IO_old_fopen, _IO_fopen); +strong_alias (__old_fopen, fopen); +#endif diff --git a/glibc-compat/oldiopopen.c b/glibc-compat/oldiopopen.c new file mode 100644 index 0000000000..13b5d16c83 --- /dev/null +++ b/glibc-compat/oldiopopen.c @@ -0,0 +1,289 @@ +/* Copyright (C) 1998 Free Software Foundation, Inc. + This file is part of the GNU IO Library. + Written by Per Bothner <bothner@cygnus.com>. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, if you link this library with files + compiled with a GNU compiler to produce an executable, this does + not cause the resulting executable to be covered by the GNU General + Public License. This exception does not however invalidate any + other reasons why the executable file might be covered by the GNU + General Public License. */ + +#define _IO_USE_OLD_IO_FILE +#ifndef _POSIX_SOURCE +# define _POSIX_SOURCE +#endif +#include "libioP.h" +#if _IO_HAVE_SYS_WAIT +#include <signal.h> +#include <unistd.h> +#ifdef __STDC__ +#include <stdlib.h> +#endif +#ifdef _LIBC +# include <unistd.h> +#endif +#include <sys/types.h> +#include <sys/wait.h> + +#ifndef _IO_fork +#ifdef _LIBC +#define _IO_fork __vfork +#else +#define _IO_fork vfork /* defined in libiberty, if needed */ +#endif +extern _IO_pid_t _IO_fork (void); +#endif + +#endif /* _IO_HAVE_SYS_WAIT */ + +#ifndef _IO_pipe +#ifdef _LIBC +#define _IO_pipe __pipe +#else +#define _IO_pipe pipe +#endif +extern int _IO_pipe (int des[2]); +#endif + +#ifndef _IO_dup2 +#ifdef _LIBC +#define _IO_dup2 __dup2 +#else +#define _IO_dup2 dup2 +#endif +extern int _IO_dup2 (int fd, int fd2); +#endif + +#ifndef _IO_waitpid +#ifdef _LIBC +#define _IO_waitpid __waitpid +#else +#define _IO_waitpid waitpid +#endif +#endif + +#ifndef _IO_execl +#define _IO_execl execl +#endif +#ifndef _IO__exit +#define _IO__exit _exit +#endif + +#ifndef _IO_close +#ifdef _LIBC +#define _IO_close __close +#else +#define _IO_close close +#endif +#endif + +struct _IO_proc_file +{ + struct _IO_FILE_plus file; + /* Following fields must match those in class procbuf (procbuf.h) */ + _IO_pid_t pid; + struct _IO_proc_file *next; +}; +typedef struct _IO_proc_file _IO_proc_file; + +static struct _IO_proc_file *old_proc_file_chain = NULL; + +_IO_FILE * +_IO_old_proc_open (fp, command, mode) + _IO_FILE *fp; + const char *command; + const char *mode; +{ +#if _IO_HAVE_SYS_WAIT + volatile int read_or_write; + volatile int parent_end, child_end; + int pipe_fds[2]; + _IO_pid_t child_pid; + if (_IO_file_is_open (fp)) + return NULL; + if (_IO_pipe (pipe_fds) < 0) + return NULL; + if (mode[0] == 'r' && mode[1] == '\0') + { + parent_end = pipe_fds[0]; + child_end = pipe_fds[1]; + read_or_write = _IO_NO_WRITES; + } + else if (mode[0] == 'w' && mode[1] == '\0') + { + parent_end = pipe_fds[1]; + child_end = pipe_fds[0]; + read_or_write = _IO_NO_READS; + } + else + { + __set_errno (EINVAL); + return NULL; + } + ((_IO_proc_file *) fp)->pid = child_pid = _IO_fork (); + if (child_pid == 0) + { + int child_std_end = mode[0] == 'r' ? 1 : 0; + _IO_close (parent_end); + if (child_end != child_std_end) + { + _IO_dup2 (child_end, child_std_end); + _IO_close (child_end); + } + /* POSIX.2: "popen() shall ensure that any streams from previous + popen() calls that remain open in the parent process are closed + in the new child process." */ + while (old_proc_file_chain) + { + _IO_close (_IO_fileno ((_IO_FILE *) old_proc_file_chain)); + old_proc_file_chain = old_proc_file_chain->next; + } + + _IO_execl ("/bin/sh", "sh", "-c", command, (char *) 0); + _IO__exit (127); + } + _IO_close (child_end); + if (child_pid < 0) + { + _IO_close (parent_end); + return NULL; + } + _IO_fileno (fp) = parent_end; + + /* Link into old_proc_file_chain. */ + ((_IO_proc_file *) fp)->next = old_proc_file_chain; + old_proc_file_chain = (_IO_proc_file *) fp; + + _IO_mask_flags (fp, read_or_write, _IO_NO_READS|_IO_NO_WRITES); + return fp; +#else /* !_IO_HAVE_SYS_WAIT */ + return NULL; +#endif +} + +_IO_FILE * +_IO_old_popen (command, mode) + const char *command; + const char *mode; +{ + struct locked_FILE + { + struct _IO_proc_file fpx; +#ifdef _IO_MTSAFE_IO + _IO_lock_t lock; +#endif + } *new_f; + _IO_FILE *fp; + + new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE)); + if (new_f == NULL) + return NULL; +#ifdef _IO_MTSAFE_IO + new_f->fpx.file.file._lock = &new_f->lock; +#endif + fp = &new_f->fpx.file.file; + _IO_init (fp, 0); + _IO_JUMPS (fp) = &_IO_old_proc_jumps; + _IO_old_file_init (fp); +#if !_IO_UNIFIED_JUMPTABLES + new_f->fpx.file.vtable = NULL; +#endif + if (_IO_old_proc_open (fp, command, mode) != NULL) + return fp; + _IO_un_link (fp); + free (new_f); + return NULL; +} + +int +_IO_old_proc_close (fp) + _IO_FILE *fp; +{ + /* This is not name-space clean. FIXME! */ +#if _IO_HAVE_SYS_WAIT + int wstatus; + _IO_proc_file **ptr = &old_proc_file_chain; + _IO_pid_t wait_pid; + int status = -1; + + /* Unlink from old_proc_file_chain. */ + for ( ; *ptr != NULL; ptr = &(*ptr)->next) + { + if (*ptr == (_IO_proc_file *) fp) + { + *ptr = (*ptr)->next; + status = 0; + break; + } + } + + if (status < 0 || _IO_close (_IO_fileno(fp)) < 0) + return -1; + /* POSIX.2 Rationale: "Some historical implementations either block + or ignore the signals SIGINT, SIGQUIT, and SIGHUP while waiting + for the child process to terminate. Since this behavior is not + described in POSIX.2, such implementations are not conforming." */ + do + { + wait_pid = _IO_waitpid (((_IO_proc_file *) fp)->pid, &wstatus, 0); + } + while (wait_pid == -1 && errno == EINTR); + if (wait_pid == -1) + return -1; + return wstatus; +#else /* !_IO_HAVE_SYS_WAIT */ + return -1; +#endif +} + +struct _IO_jump_t _IO_old_proc_jumps = { + JUMP_INIT_DUMMY, + JUMP_INIT(finish, _IO_old_file_finish), + JUMP_INIT(overflow, _IO_old_file_overflow), + JUMP_INIT(underflow, _IO_old_file_underflow), + JUMP_INIT(uflow, _IO_default_uflow), + JUMP_INIT(pbackfail, _IO_default_pbackfail), + JUMP_INIT(xsputn, _IO_old_file_xsputn), + JUMP_INIT(xsgetn, _IO_default_xsgetn), + JUMP_INIT(seekoff, _IO_old_file_seekoff), + JUMP_INIT(seekpos, _IO_default_seekpos), + JUMP_INIT(setbuf, _IO_old_file_setbuf), + JUMP_INIT(sync, _IO_old_file_sync), + JUMP_INIT(doallocate, _IO_file_doallocate), + JUMP_INIT(read, _IO_file_read), + JUMP_INIT(write, _IO_old_file_write), + JUMP_INIT(seek, _IO_file_seek), + JUMP_INIT(close, _IO_old_proc_close), + JUMP_INIT(stat, _IO_file_stat), + JUMP_INIT(showmanyc, _IO_default_showmanyc), + JUMP_INIT(imbue, _IO_default_imbue) +}; + +#ifdef SHARED +strong_alias (_IO_old_popen, __old_popen) +symbol_version (_IO_old_popen, _IO_popen, GLIBC_2.0); +symbol_version (__old_popen, popen, GLIBC_2.0); +symbol_version (_IO_old_proc_open, _IO_proc_open, GLIBC_2.0); +symbol_version (_IO_old_proc_close, _IO_proc_close, GLIBC_2.0); +#else +strong_alias (_IO_old_popen, _IO_popen); +strong_alias (__old_popen, popen); +strong_alias (_IO_old_proc_open, _IO_proc_open); +strong_alias (_IO_old_proc_close, _IO_proc_close); +#endif diff --git a/glibc-compat/oldpclose.c b/glibc-compat/oldpclose.c new file mode 100644 index 0000000000..c33e19c431 --- /dev/null +++ b/glibc-compat/oldpclose.c @@ -0,0 +1,48 @@ +/* Copyright (C) 1998 Free Software Foundation, Inc. + This file is part of the GNU IO Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, if you link this library with files + compiled with a GNU compiler to produce an executable, this does + not cause the resulting executable to be covered by the GNU General + Public License. This exception does not however invalidate any + other reasons why the executable file might be covered by the GNU + General Public License. */ + +#define _IO_USE_OLD_IO_FILE +#include "libioP.h" +#include "stdio.h" +#include <errno.h> + +int +__old_pclose (fp) + FILE *fp; +{ +#if 0 + /* Does not actually test that stream was created by popen(). Instead, + it depends on the filebuf::sys_close() virtual to Do The Right Thing. */ + if (fp is not a proc_file) + return -1; +#endif + return _IO_old_fclose (fp); +} + +#ifdef SHARED +symbol_version (__old_pclose, pclose, GLIBC_2.0); +#else +strong_alias (__old_pclose, pclose); +#endif diff --git a/glibc-compat/oldstdfiles.c b/glibc-compat/oldstdfiles.c new file mode 100644 index 0000000000..e9c992b943 --- /dev/null +++ b/glibc-compat/oldstdfiles.c @@ -0,0 +1,97 @@ +/* Copyright (C) 1993, 1994, 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU IO Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + This 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, if you link this library with files + compiled with a GNU compiler to produce an executable, this does + not cause the resulting executable to be covered by the GNU General + Public License. This exception does not however invalidate any + other reasons why the executable file might be covered by the GNU + General Public License. */ + + +/* This file provides definitions of _IO_stdin, _IO_stdout, and _IO_stderr + for C code. Compare stdstreams.cc. + (The difference is that here the vtable field is set to 0, + so the objects defined are not valid C++ objects. On the other + hand, we don't need a C++ compiler to build this file.) */ + +#define _IO_USE_OLD_IO_FILE +#include "libioP.h" + +#ifdef _IO_MTSAFE_IO +#define DEF_STDFILE(NAME, FD, CHAIN, FLAGS) \ + static _IO_lock_t _IO_stdfile_##FD##_lock = _IO_lock_initializer; \ + struct _IO_FILE_plus NAME \ + = {FILEBUF_LITERAL(CHAIN, FLAGS, FD), &_IO_old_file_jumps}; +#else +#define DEF_STDFILE(NAME, FD, CHAIN, FLAGS) \ + struct _IO_FILE_plus NAME \ + = {FILEBUF_LITERAL(CHAIN, FLAGS, FD), &_IO_old_file_jumps}; +#endif + +DEF_STDFILE(_IO_stdin_, 0, 0, _IO_NO_WRITES); +DEF_STDFILE(_IO_stdout_, 1, &_IO_stdin_.file, _IO_NO_READS); +DEF_STDFILE(_IO_stderr_, 2, &_IO_stdout_.file, + _IO_NO_READS+_IO_UNBUFFERED); + +#if defined __GNUC__ && __GNUC__ >= 2 + +#include <stdio.h> + +extern const int _IO_stdin_used; +weak_extern (_IO_stdin_used); + +#undef stdin +#undef stdout +#undef stderr + +extern FILE *stdin; +extern FILE *stdout; +extern FILE *stderr; + +#ifdef SHARED +extern +#endif +FILE *_IO_list_all; + +static void _IO_check_libio (void) __attribute__ ((constructor)); + +/* This function determines which shared C library the application + was linked against. We then set up the stdin/stdout/stderr and + _IO_list_all accordingly. */ + +static void +_IO_check_libio () +{ +#ifdef SHARED + if (&_IO_stdin_used == NULL) +#endif + { + /* We are using the old one. */ + _IO_stdin = stdin = &_IO_stdin_.file; + _IO_stdout = stdout = &_IO_stdout_.file; + _IO_stderr = stderr = _IO_list_all = &_IO_stderr_.file; + _IO_stdin->_vtable_offset = _IO_stdout->_vtable_offset = + _IO_stderr->_vtable_offset = stdin->_vtable_offset = + stdout->_vtable_offset = stderr->_vtable_offset = + ((int) sizeof (struct _IO_FILE) + - (int) sizeof (struct _IO_FILE_complete)); + } +} + +#endif diff --git a/glibc-compat/oldtmpfile.c b/glibc-compat/oldtmpfile.c new file mode 100644 index 0000000000..9607bceefe --- /dev/null +++ b/glibc-compat/oldtmpfile.c @@ -0,0 +1,55 @@ +/* Copyright (C) 1991, 1993, 1996, 1997, 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. */ + +#define _IO_USE_OLD_IO_FILE +#include <stdio.h> +#include <unistd.h> +#include <iolibio.h> + +/* This returns a new stream opened on a temporary file (generated + by tmpnam). The file is opened with mode "w+b" (binary read/write). + If we couldn't generate a unique filename or the file couldn't + be opened, NULL is returned. */ +FILE * +__old_tmpfile (void) +{ + char buf[FILENAME_MAX]; + int fd; + FILE *f; + + if (__path_search (buf, FILENAME_MAX, NULL, "tmpf", 0)) + return NULL; + fd = __gen_tempname (buf, 1, 0); + if (fd < 0) + return NULL; + + /* Note that this relies on the Unix semantics that + a file is not really removed until it is closed. */ + (void) remove (buf); + + if ((f = _IO_old_fdopen (fd, "w+b")) == NULL) + __close (fd); + + return f; +} + +#ifdef SHARED +symbol_version (__old_tmpfile, tmpfile, GLIBC_2.0); +#else +strong_alias (__old_tmpfile, tmpfile); +#endif diff --git a/glibc-compat/rpcsvc/yp.h b/glibc-compat/rpcsvc/yp.h new file mode 100644 index 0000000000..40914c5813 --- /dev/null +++ b/glibc-compat/rpcsvc/yp.h @@ -0,0 +1,621 @@ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +#ifndef __RPCSVC_YP_H__ +#define __RPCSVC_YP_H__ + +#include <rpc/rpc.h> + +#define YPMAXRECORD 1024 +#define YPMAXDOMAIN 64 +#define YPMAXMAP 64 +#define YPMAXPEER 64 + +enum ypstat { + YP_TRUE = 1, + YP_NOMORE = 2, + YP_FALSE = 0, + YP_NOMAP = -1, + YP_NODOM = -2, + YP_NOKEY = -3, + YP_BADOP = -4, + YP_BADDB = -5, + YP_YPERR = -6, + YP_BADARGS = -7, + YP_VERS = -8, +}; +typedef enum ypstat ypstat; +#ifdef __cplusplus +extern "C" bool_t xdr_ypstat(XDR *, ypstat*); +#elif __STDC__ +extern bool_t xdr_ypstat(XDR *, ypstat*); +#else /* Old Style C */ +bool_t xdr_ypstat(); +#endif /* Old Style C */ + + +enum ypxfrstat { + YPXFR_SUCC = 1, + YPXFR_AGE = 2, + YPXFR_NOMAP = -1, + YPXFR_NODOM = -2, + YPXFR_RSRC = -3, + YPXFR_RPC = -4, + YPXFR_MADDR = -5, + YPXFR_YPERR = -6, + YPXFR_BADARGS = -7, + YPXFR_DBM = -8, + YPXFR_FILE = -9, + YPXFR_SKEW = -10, + YPXFR_CLEAR = -11, + YPXFR_FORCE = -12, + YPXFR_XFRERR = -13, + YPXFR_REFUSED = -14, +}; +typedef enum ypxfrstat ypxfrstat; +#ifdef __cplusplus +extern "C" bool_t xdr_ypxfrstat(XDR *, ypxfrstat*); +#elif __STDC__ +extern bool_t xdr_ypxfrstat(XDR *, ypxfrstat*); +#else /* Old Style C */ +bool_t xdr_ypxfrstat(); +#endif /* Old Style C */ + + +typedef char *domainname; +#ifdef __cplusplus +extern "C" bool_t xdr_domainname(XDR *, domainname*); +#elif __STDC__ +extern bool_t xdr_domainname(XDR *, domainname*); +#else /* Old Style C */ +bool_t xdr_domainname(); +#endif /* Old Style C */ + + +typedef char *mapname; +#ifdef __cplusplus +extern "C" bool_t xdr_mapname(XDR *, mapname*); +#elif __STDC__ +extern bool_t xdr_mapname(XDR *, mapname*); +#else /* Old Style C */ +bool_t xdr_mapname(); +#endif /* Old Style C */ + + +typedef char *peername; +#ifdef __cplusplus +extern "C" bool_t xdr_peername(XDR *, peername*); +#elif __STDC__ +extern bool_t xdr_peername(XDR *, peername*); +#else /* Old Style C */ +bool_t xdr_peername(); +#endif /* Old Style C */ + + +typedef struct { + u_int keydat_len; + char *keydat_val; +} keydat; +#ifdef __cplusplus +extern "C" bool_t xdr_keydat(XDR *, keydat*); +#elif __STDC__ +extern bool_t xdr_keydat(XDR *, keydat*); +#else /* Old Style C */ +bool_t xdr_keydat(); +#endif /* Old Style C */ + + +typedef struct { + u_int valdat_len; + char *valdat_val; +} valdat; +#ifdef __cplusplus +extern "C" bool_t xdr_valdat(XDR *, valdat*); +#elif __STDC__ +extern bool_t xdr_valdat(XDR *, valdat*); +#else /* Old Style C */ +bool_t xdr_valdat(); +#endif /* Old Style C */ + + +struct ypmap_parms { + domainname domain; + mapname map; + u_int ordernum; + peername peer; +}; +typedef struct ypmap_parms ypmap_parms; +#ifdef __cplusplus +extern "C" bool_t xdr_ypmap_parms(XDR *, ypmap_parms*); +#elif __STDC__ +extern bool_t xdr_ypmap_parms(XDR *, ypmap_parms*); +#else /* Old Style C */ +bool_t xdr_ypmap_parms(); +#endif /* Old Style C */ + + +struct ypreq_key { + domainname domain; + mapname map; + keydat key; +}; +typedef struct ypreq_key ypreq_key; +#ifdef __cplusplus +extern "C" bool_t xdr_ypreq_key(XDR *, ypreq_key*); +#elif __STDC__ +extern bool_t xdr_ypreq_key(XDR *, ypreq_key*); +#else /* Old Style C */ +bool_t xdr_ypreq_key(); +#endif /* Old Style C */ + + +struct ypreq_nokey { + domainname domain; + mapname map; +}; +typedef struct ypreq_nokey ypreq_nokey; +#ifdef __cplusplus +extern "C" bool_t xdr_ypreq_nokey(XDR *, ypreq_nokey*); +#elif __STDC__ +extern bool_t xdr_ypreq_nokey(XDR *, ypreq_nokey*); +#else /* Old Style C */ +bool_t xdr_ypreq_nokey(); +#endif /* Old Style C */ + + +struct ypreq_xfr { + ypmap_parms map_parms; + u_int transid; + u_int prog; + u_int port; +}; +typedef struct ypreq_xfr ypreq_xfr; +#ifdef __cplusplus +extern "C" bool_t xdr_ypreq_xfr(XDR *, ypreq_xfr*); +#elif __STDC__ +extern bool_t xdr_ypreq_xfr(XDR *, ypreq_xfr*); +#else /* Old Style C */ +bool_t xdr_ypreq_xfr(); +#endif /* Old Style C */ + + +struct ypresp_val { + ypstat stat; + valdat val; +}; +typedef struct ypresp_val ypresp_val; +#ifdef __cplusplus +extern "C" bool_t xdr_ypresp_val(XDR *, ypresp_val*); +#elif __STDC__ +extern bool_t xdr_ypresp_val(XDR *, ypresp_val*); +#else /* Old Style C */ +bool_t xdr_ypresp_val(); +#endif /* Old Style C */ + + +struct ypresp_key_val { + ypstat stat; +#ifdef STUPID_SUN_BUG + /* This is the form as distributed by Sun. But even the Sun NIS + servers expect the values in the other order. So their + implementation somehow must change the order internally. We + don't want to follow this bad example since the user should be + able to use rpcgen on this file. */ + keydat key; + valdat val; +#else + valdat val; + keydat key; +#endif +}; +typedef struct ypresp_key_val ypresp_key_val; +#ifdef __cplusplus +extern "C" bool_t xdr_ypresp_key_val(XDR *, ypresp_key_val*); +#elif __STDC__ +extern bool_t xdr_ypresp_key_val(XDR *, ypresp_key_val*); +#else /* Old Style C */ +bool_t xdr_ypresp_key_val(); +#endif /* Old Style C */ + + +struct ypresp_master { + ypstat stat; + peername peer; +}; +typedef struct ypresp_master ypresp_master; +#ifdef __cplusplus +extern "C" bool_t xdr_ypresp_master(XDR *, ypresp_master*); +#elif __STDC__ +extern bool_t xdr_ypresp_master(XDR *, ypresp_master*); +#else /* Old Style C */ +bool_t xdr_ypresp_master(); +#endif /* Old Style C */ + + +struct ypresp_order { + ypstat stat; + u_int ordernum; +}; +typedef struct ypresp_order ypresp_order; +#ifdef __cplusplus +extern "C" bool_t xdr_ypresp_order(XDR *, ypresp_order*); +#elif __STDC__ +extern bool_t xdr_ypresp_order(XDR *, ypresp_order*); +#else /* Old Style C */ +bool_t xdr_ypresp_order(); +#endif /* Old Style C */ + + +struct ypresp_all { + bool_t more; + union { + ypresp_key_val val; + } ypresp_all_u; +}; +typedef struct ypresp_all ypresp_all; +#ifdef __cplusplus +extern "C" bool_t xdr_ypresp_all(XDR *, ypresp_all*); +#elif __STDC__ +extern bool_t xdr_ypresp_all(XDR *, ypresp_all*); +#else /* Old Style C */ +bool_t xdr_ypresp_all(); +#endif /* Old Style C */ + + +struct ypresp_xfr { + u_int transid; + ypxfrstat xfrstat; +}; +typedef struct ypresp_xfr ypresp_xfr; +#ifdef __cplusplus +extern "C" bool_t xdr_ypresp_xfr(XDR *, ypresp_xfr*); +#elif __STDC__ +extern bool_t xdr_ypresp_xfr(XDR *, ypresp_xfr*); +#else /* Old Style C */ +bool_t xdr_ypresp_xfr(); +#endif /* Old Style C */ + + +struct ypmaplist { + mapname map; + struct ypmaplist *next; +}; +typedef struct ypmaplist ypmaplist; +#ifdef __cplusplus +extern "C" bool_t xdr_ypmaplist(XDR *, ypmaplist*); +#elif __STDC__ +extern bool_t xdr_ypmaplist(XDR *, ypmaplist*); +#else /* Old Style C */ +bool_t xdr_ypmaplist(); +#endif /* Old Style C */ + + +struct ypresp_maplist { + ypstat stat; + ypmaplist *maps; +}; +typedef struct ypresp_maplist ypresp_maplist; +#ifdef __cplusplus +extern "C" bool_t xdr_ypresp_maplist(XDR *, ypresp_maplist*); +#elif __STDC__ +extern bool_t xdr_ypresp_maplist(XDR *, ypresp_maplist*); +#else /* Old Style C */ +bool_t xdr_ypresp_maplist(); +#endif /* Old Style C */ + + +enum yppush_status { + YPPUSH_SUCC = 1, + YPPUSH_AGE = 2, + YPPUSH_NOMAP = -1, + YPPUSH_NODOM = -2, + YPPUSH_RSRC = -3, + YPPUSH_RPC = -4, + YPPUSH_MADDR = -5, + YPPUSH_YPERR = -6, + YPPUSH_BADARGS = -7, + YPPUSH_DBM = -8, + YPPUSH_FILE = -9, + YPPUSH_SKEW = -10, + YPPUSH_CLEAR = -11, + YPPUSH_FORCE = -12, + YPPUSH_XFRERR = -13, + YPPUSH_REFUSED = -14, +}; +typedef enum yppush_status yppush_status; +#ifdef __cplusplus +extern "C" bool_t xdr_yppush_status(XDR *, yppush_status*); +#elif __STDC__ +extern bool_t xdr_yppush_status(XDR *, yppush_status*); +#else /* Old Style C */ +bool_t xdr_yppush_status(); +#endif /* Old Style C */ + + +struct yppushresp_xfr { + u_int transid; + yppush_status status; +}; +typedef struct yppushresp_xfr yppushresp_xfr; +#ifdef __cplusplus +extern "C" bool_t xdr_yppushresp_xfr(XDR *, yppushresp_xfr*); +#elif __STDC__ +extern bool_t xdr_yppushresp_xfr(XDR *, yppushresp_xfr*); +#else /* Old Style C */ +bool_t xdr_yppushresp_xfr(); +#endif /* Old Style C */ + + +enum ypbind_resptype { + YPBIND_SUCC_VAL = 1, + YPBIND_FAIL_VAL = 2, +}; +typedef enum ypbind_resptype ypbind_resptype; +#ifdef __cplusplus +extern "C" bool_t xdr_ypbind_resptype(XDR *, ypbind_resptype*); +#elif __STDC__ +extern bool_t xdr_ypbind_resptype(XDR *, ypbind_resptype*); +#else /* Old Style C */ +bool_t xdr_ypbind_resptype(); +#endif /* Old Style C */ + + +struct ypbind_binding { + char ypbind_binding_addr[4]; + char ypbind_binding_port[2]; +}; +typedef struct ypbind_binding ypbind_binding; +#ifdef __cplusplus +extern "C" bool_t xdr_ypbind_binding(XDR *, ypbind_binding*); +#elif __STDC__ +extern bool_t xdr_ypbind_binding(XDR *, ypbind_binding*); +#else /* Old Style C */ +bool_t xdr_ypbind_binding(); +#endif /* Old Style C */ + + +struct ypbind_resp { + ypbind_resptype ypbind_status; + union { + u_int ypbind_error; + ypbind_binding ypbind_bindinfo; + } ypbind_resp_u; +}; +typedef struct ypbind_resp ypbind_resp; +#ifdef __cplusplus +extern "C" bool_t xdr_ypbind_resp(XDR *, ypbind_resp*); +#elif __STDC__ +extern bool_t xdr_ypbind_resp(XDR *, ypbind_resp*); +#else /* Old Style C */ +bool_t xdr_ypbind_resp(); +#endif /* Old Style C */ + +#define YPBIND_ERR_ERR 1 +#define YPBIND_ERR_NOSERV 2 +#define YPBIND_ERR_RESC 3 + +struct ypbind_setdom { + domainname ypsetdom_domain; + ypbind_binding ypsetdom_binding; + u_int ypsetdom_vers; +}; +typedef struct ypbind_setdom ypbind_setdom; +#ifdef __cplusplus +extern "C" bool_t xdr_ypbind_setdom(XDR *, ypbind_setdom*); +#elif __STDC__ +extern bool_t xdr_ypbind_setdom(XDR *, ypbind_setdom*); +#else /* Old Style C */ +bool_t xdr_ypbind_setdom(); +#endif /* Old Style C */ + + +#define YPPROG ((u_long)100004) +#define YPVERS ((u_long)2) + +#ifdef __cplusplus +#define YPPROC_NULL ((u_long)0) +extern "C" void * ypproc_null_2(void *, CLIENT *); +extern "C" void * ypproc_null_2_svc(void *, struct svc_req *); +#define YPPROC_DOMAIN ((u_long)1) +extern "C" bool_t * ypproc_domain_2(domainname *, CLIENT *); +extern "C" bool_t * ypproc_domain_2_svc(domainname *, struct svc_req *); +#define YPPROC_DOMAIN_NONACK ((u_long)2) +extern "C" bool_t * ypproc_domain_nonack_2(domainname *, CLIENT *); +extern "C" bool_t * ypproc_domain_nonack_2_svc(domainname *, struct svc_req *); +#define YPPROC_MATCH ((u_long)3) +extern "C" ypresp_val * ypproc_match_2(ypreq_key *, CLIENT *); +extern "C" ypresp_val * ypproc_match_2_svc(ypreq_key *, struct svc_req *); +#define YPPROC_FIRST ((u_long)4) +extern "C" ypresp_key_val * ypproc_first_2(ypreq_key *, CLIENT *); +extern "C" ypresp_key_val * ypproc_first_2_svc(ypreq_key *, struct svc_req *); +#define YPPROC_NEXT ((u_long)5) +extern "C" ypresp_key_val * ypproc_next_2(ypreq_key *, CLIENT *); +extern "C" ypresp_key_val * ypproc_next_2_svc(ypreq_key *, struct svc_req *); +#define YPPROC_XFR ((u_long)6) +extern "C" ypresp_xfr * ypproc_xfr_2(ypreq_xfr *, CLIENT *); +extern "C" ypresp_xfr * ypproc_xfr_2_svc(ypreq_xfr *, struct svc_req *); +#define YPPROC_CLEAR ((u_long)7) +extern "C" void * ypproc_clear_2(void *, CLIENT *); +extern "C" void * ypproc_clear_2_svc(void *, struct svc_req *); +#define YPPROC_ALL ((u_long)8) +extern "C" ypresp_all * ypproc_all_2(ypreq_nokey *, CLIENT *); +extern "C" ypresp_all * ypproc_all_2_svc(ypreq_nokey *, struct svc_req *); +#define YPPROC_MASTER ((u_long)9) +extern "C" ypresp_master * ypproc_master_2(ypreq_nokey *, CLIENT *); +extern "C" ypresp_master * ypproc_master_2_svc(ypreq_nokey *, struct svc_req *); +#define YPPROC_ORDER ((u_long)10) +extern "C" ypresp_order * ypproc_order_2(ypreq_nokey *, CLIENT *); +extern "C" ypresp_order * ypproc_order_2_svc(ypreq_nokey *, struct svc_req *); +#define YPPROC_MAPLIST ((u_long)11) +extern "C" ypresp_maplist * ypproc_maplist_2(domainname *, CLIENT *); +extern "C" ypresp_maplist * ypproc_maplist_2_svc(domainname *, struct svc_req *); + +#elif __STDC__ +#define YPPROC_NULL ((u_long)0) +extern void * ypproc_null_2(void *, CLIENT *); +extern void * ypproc_null_2_svc(void *, struct svc_req *); +#define YPPROC_DOMAIN ((u_long)1) +extern bool_t * ypproc_domain_2(domainname *, CLIENT *); +extern bool_t * ypproc_domain_2_svc(domainname *, struct svc_req *); +#define YPPROC_DOMAIN_NONACK ((u_long)2) +extern bool_t * ypproc_domain_nonack_2(domainname *, CLIENT *); +extern bool_t * ypproc_domain_nonack_2_svc(domainname *, struct svc_req *); +#define YPPROC_MATCH ((u_long)3) +extern ypresp_val * ypproc_match_2(ypreq_key *, CLIENT *); +extern ypresp_val * ypproc_match_2_svc(ypreq_key *, struct svc_req *); +#define YPPROC_FIRST ((u_long)4) +extern ypresp_key_val * ypproc_first_2(ypreq_key *, CLIENT *); +extern ypresp_key_val * ypproc_first_2_svc(ypreq_key *, struct svc_req *); +#define YPPROC_NEXT ((u_long)5) +extern ypresp_key_val * ypproc_next_2(ypreq_key *, CLIENT *); +extern ypresp_key_val * ypproc_next_2_svc(ypreq_key *, struct svc_req *); +#define YPPROC_XFR ((u_long)6) +extern ypresp_xfr * ypproc_xfr_2(ypreq_xfr *, CLIENT *); +extern ypresp_xfr * ypproc_xfr_2_svc(ypreq_xfr *, struct svc_req *); +#define YPPROC_CLEAR ((u_long)7) +extern void * ypproc_clear_2(void *, CLIENT *); +extern void * ypproc_clear_2_svc(void *, struct svc_req *); +#define YPPROC_ALL ((u_long)8) +extern ypresp_all * ypproc_all_2(ypreq_nokey *, CLIENT *); +extern ypresp_all * ypproc_all_2_svc(ypreq_nokey *, struct svc_req *); +#define YPPROC_MASTER ((u_long)9) +extern ypresp_master * ypproc_master_2(ypreq_nokey *, CLIENT *); +extern ypresp_master * ypproc_master_2_svc(ypreq_nokey *, struct svc_req *); +#define YPPROC_ORDER ((u_long)10) +extern ypresp_order * ypproc_order_2(ypreq_nokey *, CLIENT *); +extern ypresp_order * ypproc_order_2_svc(ypreq_nokey *, struct svc_req *); +#define YPPROC_MAPLIST ((u_long)11) +extern ypresp_maplist * ypproc_maplist_2(domainname *, CLIENT *); +extern ypresp_maplist * ypproc_maplist_2_svc(domainname *, struct svc_req *); + +#else /* Old Style C */ +#define YPPROC_NULL ((u_long)0) +extern void * ypproc_null_2(); +extern void * ypproc_null_2_svc(); +#define YPPROC_DOMAIN ((u_long)1) +extern bool_t * ypproc_domain_2(); +extern bool_t * ypproc_domain_2_svc(); +#define YPPROC_DOMAIN_NONACK ((u_long)2) +extern bool_t * ypproc_domain_nonack_2(); +extern bool_t * ypproc_domain_nonack_2_svc(); +#define YPPROC_MATCH ((u_long)3) +extern ypresp_val * ypproc_match_2(); +extern ypresp_val * ypproc_match_2_svc(); +#define YPPROC_FIRST ((u_long)4) +extern ypresp_key_val * ypproc_first_2(); +extern ypresp_key_val * ypproc_first_2_svc(); +#define YPPROC_NEXT ((u_long)5) +extern ypresp_key_val * ypproc_next_2(); +extern ypresp_key_val * ypproc_next_2_svc(); +#define YPPROC_XFR ((u_long)6) +extern ypresp_xfr * ypproc_xfr_2(); +extern ypresp_xfr * ypproc_xfr_2_svc(); +#define YPPROC_CLEAR ((u_long)7) +extern void * ypproc_clear_2(); +extern void * ypproc_clear_2_svc(); +#define YPPROC_ALL ((u_long)8) +extern ypresp_all * ypproc_all_2(); +extern ypresp_all * ypproc_all_2_svc(); +#define YPPROC_MASTER ((u_long)9) +extern ypresp_master * ypproc_master_2(); +extern ypresp_master * ypproc_master_2_svc(); +#define YPPROC_ORDER ((u_long)10) +extern ypresp_order * ypproc_order_2(); +extern ypresp_order * ypproc_order_2_svc(); +#define YPPROC_MAPLIST ((u_long)11) +extern ypresp_maplist * ypproc_maplist_2(); +extern ypresp_maplist * ypproc_maplist_2_svc(); +#endif /* Old Style C */ + +#define YPPUSH_XFRRESPPROG ((u_long)0x40000000) +#define YPPUSH_XFRRESPVERS ((u_long)1) + +#ifdef __cplusplus +#define YPPUSHPROC_NULL ((u_long)0) +extern "C" void * yppushproc_null_1(void *, CLIENT *); +extern "C" void * yppushproc_null_1_svc(void *, struct svc_req *); +#define YPPUSHPROC_XFRRESP ((u_long)1) +extern "C" void * yppushproc_xfrresp_1(yppushresp_xfr *, CLIENT *); +extern "C" void * yppushproc_xfrresp_1_svc(yppushresp_xfr *, struct svc_req *); + +#elif __STDC__ +#define YPPUSHPROC_NULL ((u_long)0) +extern void * yppushproc_null_1(void *, CLIENT *); +extern void * yppushproc_null_1_svc(void *, struct svc_req *); +#define YPPUSHPROC_XFRRESP ((u_long)1) +extern void * yppushproc_xfrresp_1(yppushresp_xfr *, CLIENT *); +extern void * yppushproc_xfrresp_1_svc(yppushresp_xfr *, struct svc_req *); + +#else /* Old Style C */ +#define YPPUSHPROC_NULL ((u_long)0) +extern void * yppushproc_null_1(); +extern void * yppushproc_null_1_svc(); +#define YPPUSHPROC_XFRRESP ((u_long)1) +extern void * yppushproc_xfrresp_1(); +extern void * yppushproc_xfrresp_1_svc(); +#endif /* Old Style C */ + +#define YPBINDPROG ((u_long)100007) +#define YPBINDVERS ((u_long)2) + +#ifdef __cplusplus +#define YPBINDPROC_NULL ((u_long)0) +extern "C" void * ypbindproc_null_2(void *, CLIENT *); +extern "C" void * ypbindproc_null_2_svc(void *, struct svc_req *); +#define YPBINDPROC_DOMAIN ((u_long)1) +extern "C" ypbind_resp * ypbindproc_domain_2(domainname *, CLIENT *); +extern "C" ypbind_resp * ypbindproc_domain_2_svc(domainname *, struct svc_req *); +#define YPBINDPROC_SETDOM ((u_long)2) +extern "C" void * ypbindproc_setdom_2(ypbind_setdom *, CLIENT *); +extern "C" void * ypbindproc_setdom_2_svc(ypbind_setdom *, struct svc_req *); + +#elif __STDC__ +#define YPBINDPROC_NULL ((u_long)0) +extern void * ypbindproc_null_2(void *, CLIENT *); +extern void * ypbindproc_null_2_svc(void *, struct svc_req *); +#define YPBINDPROC_DOMAIN ((u_long)1) +extern ypbind_resp * ypbindproc_domain_2(domainname *, CLIENT *); +extern ypbind_resp * ypbindproc_domain_2_svc(domainname *, struct svc_req *); +#define YPBINDPROC_SETDOM ((u_long)2) +extern void * ypbindproc_setdom_2(ypbind_setdom *, CLIENT *); +extern void * ypbindproc_setdom_2_svc(ypbind_setdom *, struct svc_req *); + +#else /* Old Style C */ +#define YPBINDPROC_NULL ((u_long)0) +extern void * ypbindproc_null_2(); +extern void * ypbindproc_null_2_svc(); +#define YPBINDPROC_DOMAIN ((u_long)1) +extern ypbind_resp * ypbindproc_domain_2(); +extern ypbind_resp * ypbindproc_domain_2_svc(); +#define YPBINDPROC_SETDOM ((u_long)2) +extern void * ypbindproc_setdom_2(); +extern void * ypbindproc_setdom_2_svc(); +#endif /* Old Style C */ + +#endif /* !__RPCSVC_YP_H__ */ diff --git a/glibc-compat/rpcsvc/ypclnt.h b/glibc-compat/rpcsvc/ypclnt.h new file mode 100644 index 0000000000..5c1ac389b5 --- /dev/null +++ b/glibc-compat/rpcsvc/ypclnt.h @@ -0,0 +1,90 @@ +/* +** Copyright (c) 1996 Thorsten Kukuk, Germany +** +** This 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. +** +** This 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 this library; if not, write to the Free +** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** Author: Thorsten Kukuk <kukuk@vt.uni-paderborn.de> +** +*/ + +#ifndef __RPCSVC_YPCLNT_H__ +#define __RPCSVC_YPCLNT_H__ + +#include <features.h> + +/* some defines */ +#define YPERR_SUCCESS 0 /* There is no error */ +#define YPERR_BADARGS 1 /* Args to function are bad */ +#define YPERR_RPC 2 /* RPC failure */ +#define YPERR_DOMAIN 3 /* Can't bind to a server with this domain */ +#define YPERR_MAP 4 /* No such map in server's domain */ +#define YPERR_KEY 5 /* No such key in map */ +#define YPERR_YPERR 6 /* Internal yp server or client error */ +#define YPERR_RESRC 7 /* Local resource allocation failure */ +#define YPERR_NOMORE 8 /* No more records in map database */ +#define YPERR_PMAP 9 /* Can't communicate with portmapper */ +#define YPERR_YPBIND 10 /* Can't communicate with ypbind */ +#define YPERR_YPSERV 11 /* Can't communicate with ypserv */ +#define YPERR_NODOM 12 /* Local domain name not set */ +#define YPERR_BADDB 13 /* yp data base is bad */ +#define YPERR_VERS 14 /* YP version mismatch */ +#define YPERR_ACCESS 15 /* Access violation */ +#define YPERR_BUSY 16 /* Database is busy */ + +/* Types of update operations */ +#define YPOP_CHANGE 1 /* change, do not add */ +#define YPOP_INSERT 2 /* add, do not change */ +#define YPOP_DELETE 3 /* delete this entry */ +#define YPOP_STORE 4 /* add, or change */ + +__BEGIN_DECLS + +/* struct ypall_callback * is the arg which must be passed to yp_all */ +struct ypall_callback + { + int (*foreach) (int __status, char *__key, int __keylen, + char *__val, int __vallen, char *__data); + char *data; + }; + +/* External NIS client function references. */ +extern int yp_bind (__const char *) __THROW; +extern void yp_unbind (__const char *) __THROW; +extern int yp_get_default_domain (char **) __THROW; +extern int yp_match (__const char *, __const char *, __const char *, + __const int, char **, int *) __THROW; +extern int yp_first (__const char *, __const char *, char **, + int *, char **, int *) __THROW; +extern int yp_next (__const char *, __const char *, __const char *, + __const int, char **, int *, char **, int *) __THROW; +extern int yp_master (__const char *, __const char *, char **) __THROW; +extern int yp_order (__const char *, __const char *, unsigned int *) __THROW; +extern int yp_all (__const char *, __const char *, + __const struct ypall_callback *) __THROW; +extern __const char *yperr_string (__const int) __THROW; +extern __const char *ypbinderr_string (__const int) __THROW; +extern int ypprot_err (__const int) __THROW; +extern int yp_update (char *, char *, unsigned, char *, + int, char *, int) __THROW; +#if 0 +extern int yp_maplist (__const char *, struct ypmaplist **) __THROW; +#endif + +/* Exist only under BSD and Linux systems */ +extern int __yp_check (char **) __THROW; + +__END_DECLS + +#endif /* __RPCSVC_YPCLNT_H__ */ diff --git a/glibc-compat/shlib-versions b/glibc-compat/shlib-versions new file mode 100644 index 0000000000..8b0e2e06e2 --- /dev/null +++ b/glibc-compat/shlib-versions @@ -0,0 +1,19 @@ +# Interface revision of the compat nss_* modules. +# +# This must match NSS_SHLIB_REVISION in nss/nsswitch.h, +# which determines the library names used for service +# names given in /etc/nsswitch.conf. +alpha.*-.*-linux.* libnss1_files=1.1 +alpha.*-.*-linux.* libnss1_dns=1.1 +alpha.*-.*-linux.* libnss1_db=1.1 +alpha.*-.*-linux.* libnss1_compat=1.1 +alpha.*-.*-linux.* libnss1_nis=1.1 +.*-.*-.* libnss1_files=1 +.*-.*-.* libnss1_db=1 +.*-.*-.* libnss1_dns=1 +.*-.*-.* libnss1_compat=1 +.*-.*-.* libnss1_nis=1 + +# The libNoVersion revision number +.*-.*-.* libNoVersion=1 + diff --git a/glibc-compat/stubs.c b/glibc-compat/stubs.c new file mode 100644 index 0000000000..6c796d1c78 --- /dev/null +++ b/glibc-compat/stubs.c @@ -0,0 +1,57 @@ +/* + * STAT stuff that breaks Applix + */ + +#include <sys/stat.h> + +/* 1 of 3: _xstat */ +int +_xstat (int vers, const char *name, struct stat *buf) +{ + return __xstat (vers, name, buf); +} + +/* 2 of 3: _fxstat */ +int +_fxstat (int vers, int fd, struct stat *buf) +{ + return __fxstat (vers, fd, buf); +} + +/* 3 of 3: _lxstat */ +int +_lxstat (int vers, const char *name, struct stat *buf) +{ + return __lxstat (vers, name, buf); +} + + +/* + * __setjmp stuff that breaks again Applix + */ +#include <setjmp.h> + +int __setjmp(jmp_buf env) +{ + return _setjmp(env); +} + + +/* + * __setfpucw break several math packages that ahve not heard of + * the standard _FPU_SETCW() way of setting the control word for the FPU + */ +#include <fpu_control.h> +void __setfpucw(fpu_control_t cw) +{ + _FPU_SETCW(cw); +} + + +/* Register FUNC to be executed by `exit'. */ +int +atexit (void (*func) (void)) +{ + int __cxa_atexit (void (*func) (void *), void *arg, void *d); + return __cxa_atexit ((void (*) (void *)) func, 0, 0); +} |