diff options
Diffstat (limited to 'REORG.TODO/nis')
96 files changed, 24743 insertions, 0 deletions
diff --git a/REORG.TODO/nis/Depend b/REORG.TODO/nis/Depend new file mode 100644 index 0000000000..5eb2ea41b9 --- /dev/null +++ b/REORG.TODO/nis/Depend @@ -0,0 +1 @@ +nss diff --git a/REORG.TODO/nis/Makefile b/REORG.TODO/nis/Makefile new file mode 100644 index 0000000000..6b6f5ee72c --- /dev/null +++ b/REORG.TODO/nis/Makefile @@ -0,0 +1,102 @@ +# Copyright (C) 1996-2017 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 Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 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 +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, see +# <http://www.gnu.org/licenses/>. + +# +# Makefile for NIS/NIS+ part. +# +subdir := nis + +include ../Makeconfig + +aux := nis_hash + +ifeq ($(build-obsolete-nsl),yes) +headers := $(wildcard rpcsvc/*.[hx]) + +# These are the databases available for the nis (and perhaps later nisplus) +# service. This must be a superset of the services in nss. +databases = proto service hosts network grp pwd rpc ethers \ + spwd netgrp alias publickey + +# Specify rules for the nss_* modules. +services := nis nisplus compat +endif + +extra-libs = libnsl +ifeq ($(build-obsolete-nsl),yes) +extra-libs += $(services:%=libnss_%) +endif +# 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) + +ifeq ($(build-obsolete-nsl),yes) +# The sources are found in the appropriate subdir. +subdir-dirs = $(services:%=nss_%) +vpath %.c $(subdir-dirs) +endif + +libnsl-routines = yp_xdr ypclnt ypupdate_xdr \ + nis_subr nis_local_names nis_free nis_file \ + nis_print nis_error nis_call nis_lookup\ + nis_table nis_xdr nis_server nis_ping \ + nis_checkpoint nis_mkdir nis_rmdir nis_getservlist\ + nis_verifygroup nis_ismember nis_addmember nis_util\ + nis_removemember nis_creategroup nis_destroygroup\ + nis_print_group_entry nis_domain_of nis_domain_of_r\ + nis_modify nis_remove nis_add nis_defaults\ + nis_findserv nis_callback nis_clone_dir nis_clone_obj\ + nis_clone_res nss-default + +ifeq ($(build-obsolete-nsl),yes) +libnss_compat-routines := $(addprefix compat-,grp pwd spwd initgroups) +libnss_compat-inhibit-o = $(filter-out .os,$(object-suffixes)) + +libnss_nis-routines := $(addprefix nis-,$(databases)) nis-initgroups \ + nss-nis +libnss_nis-inhibit-o = $(filter-out .os,$(object-suffixes)) + +libnss_nisplus-routines := $(addprefix nisplus-,$(databases)) nisplus-parser \ + nss-nisplus nisplus-initgroups +libnss_nisplus-inhibit-o = $(filter-out .os,$(object-suffixes)) +endif + +include ../Rules + + +ifeq ($(build-obsolete-nsl),yes) +$(objpfx)libnss_compat.so: $(objpfx)libnsl.so$(libnsl.so-version) +$(objpfx)libnss_nis.so: $(objpfx)libnsl.so$(libnsl.so-version) \ + $(common-objpfx)nss/libnss_files.so +$(objpfx)libnss_nisplus.so: $(objpfx)libnsl.so$(libnsl.so-version) +endif + +libnsl-libc = $(common-objpfx)linkobj/libc.so +# Target-specific variable setting to link objects using deprecated +# RPC interfaces with the version of libc.so that makes them available +# for new links: +$(services:%=$(objpfx)libnss_%.so) $(objpfx)libnsl.so: \ + libc-for-link = $(libnsl-libc) + + +ifeq ($(build-shared),yes) +$(others:%=$(objpfx)%): $(objpfx)libnsl.so$(libnsl.so-version) +else +ifeq ($(build-obsolete-nsl),yes) +$(others:%=$(objpfx)%): $(objpfx)libnsl.a +endif +endif diff --git a/REORG.TODO/nis/Versions b/REORG.TODO/nis/Versions new file mode 100644 index 0000000000..ef9a512417 --- /dev/null +++ b/REORG.TODO/nis/Versions @@ -0,0 +1,131 @@ +libnsl { + GLIBC_2.0 { + # Many programs expect this, but every user program should + # have it's own version, since the interface is different on + # various platforms. + xdr_domainname; xdr_keydat; xdr_mapname; + xdr_peername; xdr_valdat; xdr_yp_buf; + xdr_ypbind_binding; xdr_ypbind_resp; xdr_ypbind_resptype; + xdr_ypbind_setdom; xdr_ypdelete_args; xdr_ypmap_parms; + xdr_ypmaplist; xdr_yppush_status; xdr_yppushresp_xfr; + xdr_ypreq_key; xdr_ypreq_nokey; xdr_ypreq_xfr; + xdr_ypresp_all; xdr_ypresp_key_val; xdr_ypresp_maplist; + xdr_ypresp_master; xdr_ypresp_order; xdr_ypresp_val; + xdr_ypresp_xfr; xdr_ypstat; xdr_ypupdate_args; + xdr_ypxfrstat; + + __yp_check; + yp_all; yp_bind; yp_first; + yp_get_default_domain; yp_maplist; yp_master; + yp_match; yp_next; yp_order; + yp_unbind; yp_update; ypbinderr_string; + yperr_string; ypprot_err; + } + GLIBC_2.1 { + nis_add; nis_add_entry; nis_addmember; + nis_checkpoint; nis_clone_directory; nis_clone_object; + nis_clone_result; nis_creategroup; nis_destroy_object; + nis_destroygroup; nis_dir_cmp; nis_domain_of; + nis_domain_of_r; nis_first_entry; nis_free_directory; + nis_free_object; nis_free_request; nis_freenames; + nis_freeresult; nis_freeservlist; nis_freetags; + nis_getnames; nis_getservlist; nis_ismember; + nis_leaf_of; nis_leaf_of_r; nis_lerror; + nis_list; nis_local_directory; nis_local_group; + nis_local_host; nis_local_principal; nis_lookup; + nis_mkdir; nis_modify; nis_modify_entry; + nis_name_of; nis_name_of_r; nis_next_entry; + nis_perror; nis_ping; nis_print_directory; + nis_print_entry; nis_print_group; nis_print_group_entry; + nis_print_link; nis_print_object; nis_print_result; + nis_print_rights; nis_print_table; nis_read_obj; + nis_remove; nis_remove_entry; nis_removemember; + nis_rmdir; nis_servstate; nis_sperrno; + nis_sperror; nis_sperror_r; nis_stats; + nis_verifygroup; nis_write_obj; + + xdr_cback_data; xdr_obj_p; + + # This functions are needed by the NIS+ tools and rpc.nisd, + # they should never be used in a normal user program ! + __free_fdresult; __nis_default_access; __nis_default_group; + __nis_default_owner; __nis_default_ttl; __nis_finddirectory; + __nis_hash; __nisbind_connect; __nisbind_create; + __nisbind_destroy; __nisbind_next; + readColdStartFile; writeColdStartFile; + } + GLIBC_2.2 { + xdr_ypall; + } + GLIBC_PRIVATE { + _nsl_default_nss; __prepare_niscall; __follow_path; __do_niscall3; + __create_ib_request; _xdr_ib_request; _xdr_nis_result; + } +} + +libnss_compat { + GLIBC_PRIVATE { + _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_setgrent; _nss_compat_setpwent; _nss_compat_setspent; + _nss_compat_initgroups_dyn; + } +} + +libnss_nis { + GLIBC_PRIVATE { + _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_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; + _nss_nis_initgroups_dyn; _nss_nis_gethostbyname4_r; + } +} + +libnss_nisplus { + GLIBC_PRIVATE { + _nss_nisplus_endaliasent; _nss_nisplus_endetherent; _nss_nisplus_endgrent; + _nss_nisplus_endhostent; _nss_nisplus_endnetent; _nss_nisplus_endnetgrent; + _nss_nisplus_endprotoent; _nss_nisplus_endpwent; _nss_nisplus_endrpcent; + _nss_nisplus_endservent; _nss_nisplus_endspent; + _nss_nisplus_getaliasbyname_r; _nss_nisplus_getaliasent_r; + _nss_nisplus_getetherent_r; _nss_nisplus_getgrent_r; + _nss_nisplus_getgrgid_r; _nss_nisplus_getgrnam_r; + _nss_nisplus_gethostbyaddr_r; _nss_nisplus_gethostbyname2_r; + _nss_nisplus_gethostbyname_r; _nss_nisplus_gethostent_r; + _nss_nisplus_gethostton_r; _nss_nisplus_getnetbyaddr_r; + _nss_nisplus_getnetbyname_r; _nss_nisplus_getnetent_r; + _nss_nisplus_getnetgrent_r; _nss_nisplus_getntohost_r; + _nss_nisplus_getprotobyname_r; _nss_nisplus_getprotobynumber_r; + _nss_nisplus_getprotoent_r; _nss_nisplus_getpublickey; + _nss_nisplus_getpwent_r; _nss_nisplus_getpwnam_r; _nss_nisplus_getpwuid_r; + _nss_nisplus_getrpcbyname_r; _nss_nisplus_getrpcbynumber_r; + _nss_nisplus_getrpcent_r; _nss_nisplus_getsecretkey; + _nss_nisplus_getservbyname_r; _nss_nisplus_getservbynumber_r; + _nss_nisplus_getservent_r; _nss_nisplus_getspent_r; + _nss_nisplus_getspnam_r; _nss_nisplus_netname2user; + _nss_nisplus_setaliasent; + _nss_nisplus_setetherent; _nss_nisplus_setgrent; _nss_nisplus_sethostent; + _nss_nisplus_setnetent; _nss_nisplus_setnetgrent; _nss_nisplus_setprotoent; + _nss_nisplus_setpwent; _nss_nisplus_setrpcent; _nss_nisplus_setservent; + _nss_nisplus_setspent; _nss_nisplus_initgroups_dyn; + _nss_nisplus_gethostbyname4_r; + } +} diff --git a/REORG.TODO/nis/libnsl.h b/REORG.TODO/nis/libnsl.h new file mode 100644 index 0000000000..4d14458f86 --- /dev/null +++ b/REORG.TODO/nis/libnsl.h @@ -0,0 +1,40 @@ +/* Copyright (C) 2005-2017 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <rpcsvc/nis.h> + +#define NSS_FLAG_NETID_AUTHORITATIVE 1 +#define NSS_FLAG_SERVICES_AUTHORITATIVE 2 +#define NSS_FLAG_SETENT_BATCH_READ 4 +#define NSS_FLAG_ADJUNCT_AS_SHADOW 8 + + +/* Get current set of default flags. */ +extern int _nsl_default_nss (void); + +/* Set up everything for a call to __do_niscall3. */ +extern nis_error __prepare_niscall (const_nis_name name, directory_obj **dirp, + dir_binding *bptrp, unsigned int flags); +libnsl_hidden_proto (__prepare_niscall) + +extern struct ib_request *__create_ib_request (const_nis_name name, + unsigned int flags); +libnsl_hidden_proto (__create_ib_request) + +extern nis_error __follow_path (char **tablepath, char **tableptr, + struct ib_request *ibreq, dir_binding *bptr); +libnsl_hidden_proto (__follow_path) diff --git a/REORG.TODO/nis/nis_add.c b/REORG.TODO/nis/nis_add.c new file mode 100644 index 0000000000..a440252292 --- /dev/null +++ b/REORG.TODO/nis/nis_add.c @@ -0,0 +1,75 @@ +/* Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> +#include <rpcsvc/nis.h> +#include <shlib-compat.h> + +#include "nis_xdr.h" +#include "nis_intern.h" + +nis_result * +nis_add (const_nis_name name, const nis_object *obj2) +{ + nis_object obj; + nis_result *res; + nis_error status; + struct ns_request req; + size_t namelen = strlen (name); + char buf1 [namelen + 20]; + char buf4 [namelen + 20]; + + res = calloc (1, sizeof (nis_result)); + if (res == NULL) + return NULL; + + req.ns_name = (char *)name; + + memcpy (&obj, obj2, sizeof (nis_object)); + + if (obj.zo_name == NULL || obj.zo_name[0] == '\0') + obj.zo_name = nis_leaf_of_r (name, buf1, sizeof (buf1)); + + if (obj.zo_owner == NULL || obj.zo_owner[0] == '\0') + obj.zo_owner = nis_local_principal (); + + if (obj.zo_group == NULL || obj.zo_group[0] == '\0') + obj.zo_group = nis_local_group (); + + obj.zo_domain = nis_domain_of_r (name, buf4, sizeof (buf4)); + + req.ns_object.ns_object_val = nis_clone_object (&obj, NULL); + if (req.ns_object.ns_object_val == NULL) + { + NIS_RES_STATUS (res) = NIS_NOMEMORY; + return res; + } + req.ns_object.ns_object_len = 1; + + status = __do_niscall (req.ns_object.ns_object_val[0].zo_domain, + NIS_ADD, (xdrproc_t) _xdr_ns_request, + (caddr_t) &req, (xdrproc_t) _xdr_nis_result, + (caddr_t) res, MASTER_ONLY, NULL); + if (status != NIS_SUCCESS) + NIS_RES_STATUS (res) = status; + + nis_destroy_object (req.ns_object.ns_object_val); + + return res; +} +libnsl_hidden_nolink_def (nis_add, GLIBC_2_1) diff --git a/REORG.TODO/nis/nis_addmember.c b/REORG.TODO/nis/nis_addmember.c new file mode 100644 index 0000000000..d2c47ab18f --- /dev/null +++ b/REORG.TODO/nis/nis_addmember.c @@ -0,0 +1,94 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <string.h> +#include <rpcsvc/nis.h> +#include <shlib-compat.h> + +nis_error +nis_addmember (const_nis_name member, const_nis_name group) +{ + if (group != NULL && group[0] != '\0') + { + size_t grouplen = strlen (group); + char buf[grouplen + 14 + NIS_MAXNAMELEN]; + char domainbuf[grouplen + 2]; + nis_result *res, *res2; + nis_error status; + char *cp, *cp2; + + cp = rawmemchr (nis_leaf_of_r (group, buf, sizeof (buf) - 1), '\0'); + cp = stpcpy (cp, ".groups_dir"); + cp2 = nis_domain_of_r (group, domainbuf, sizeof (domainbuf) - 1); + if (cp2 != NULL && cp2[0] != '\0') + { + *cp++ = '.'; + stpcpy (cp, cp2); + } + res = nis_lookup (buf, FOLLOW_LINKS | EXPAND_NAME); + if (NIS_RES_STATUS (res) != NIS_SUCCESS) + { + status = NIS_RES_STATUS (res); + nis_freeresult (res); + return status; + } + if (NIS_RES_NUMOBJ (res) != 1 + || __type_of (NIS_RES_OBJECT (res)) != NIS_GROUP_OBJ) + { + nis_freeresult (res); + return NIS_INVALIDOBJ; + } + + u_int gr_members_len + = NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_len; + + nis_name *new_gr_members_val + = realloc (NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val, + (gr_members_len + 1) * sizeof (nis_name)); + if (new_gr_members_val == NULL) + goto nomem_out; + + NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val + = new_gr_members_val; + + new_gr_members_val[gr_members_len] = strdup (member); + if (new_gr_members_val[gr_members_len] == NULL) + { + nomem_out: + nis_freeresult (res); + return NIS_NOMEMORY; + } + ++NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_len; + + /* Check the buffer bounds are not exceeded. */ + assert (strlen (NIS_RES_OBJECT(res)->zo_name) + 1 < grouplen + 14); + cp = stpcpy (buf, NIS_RES_OBJECT(res)->zo_name); + *cp++ = '.'; + strncpy (cp, NIS_RES_OBJECT (res)->zo_domain, NIS_MAXNAMELEN); + res2 = nis_modify (buf, NIS_RES_OBJECT (res)); + status = NIS_RES_STATUS (res2); + nis_freeresult (res); + nis_freeresult (res2); + + return status; + } + else + return NIS_FAIL; +} +libnsl_hidden_nolink_def (nis_addmember, GLIBC_2_1) diff --git a/REORG.TODO/nis/nis_call.c b/REORG.TODO/nis/nis_call.c new file mode 100644 index 0000000000..d4f37bfb72 --- /dev/null +++ b/REORG.TODO/nis/nis_call.c @@ -0,0 +1,845 @@ +/* Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <fcntl.h> +#include <string.h> +#include <libintl.h> +#include <rpc/rpc.h> +#include <rpc/auth.h> +#include <rpcsvc/nis.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <unistd.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <libc-lock.h> + +#include "nis_xdr.h" +#include "nis_intern.h" +#include <libnsl.h> +#include <shlib-compat.h> + +static const struct timeval RPCTIMEOUT = {10, 0}; +static const struct timeval UDPTIMEOUT = {5, 0}; + +extern u_short __pmap_getnisport (struct sockaddr_in *address, u_long program, + u_long version, u_int protocol); + +unsigned long int +inetstr2int (const char *str) +{ + size_t j = 0; + for (size_t i = 0; str[i] != '\0'; ++i) + if (str[i] == '.' && __builtin_expect (++j == 4, 0)) + { + char buffer[i + 1]; + buffer[i] = '\0'; + return inet_addr (memcpy (buffer, str, i)); + } + + return inet_addr (str); +} + +void +__nisbind_destroy (dir_binding *bind) +{ + if (bind->clnt != NULL) + { + if (bind->use_auth) + auth_destroy (bind->clnt->cl_auth); + clnt_destroy (bind->clnt); + } +} +libnsl_hidden_nolink_def (__nisbind_destroy, GLIBC_2_1) + +nis_error +__nisbind_next (dir_binding *bind) +{ + if (bind->clnt != NULL) + { + if (bind->use_auth) + auth_destroy (bind->clnt->cl_auth); + clnt_destroy (bind->clnt); + bind->clnt = NULL; + } + + if (bind->trys >= bind->server_len) + return NIS_FAIL; + + for (u_int j = bind->current_ep + 1; + j < bind->server_val[bind->server_used].ep.ep_len; ++j) + if (strcmp (bind->server_val[bind->server_used].ep.ep_val[j].family, + "inet") == 0) + if (bind->server_val[bind->server_used].ep.ep_val[j].proto[0] == '-') + { + bind->current_ep = j; + return NIS_SUCCESS; + } + + ++bind->trys; + ++bind->server_used; + if (bind->server_used >= bind->server_len) + bind->server_used = 0; + + for (u_int j = 0; j < bind->server_val[bind->server_used].ep.ep_len; ++j) + if (strcmp (bind->server_val[bind->server_used].ep.ep_val[j].family, + "inet") == 0) + if (bind->server_val[bind->server_used].ep.ep_val[j].proto[0] == '-') + { + bind->current_ep = j; + return NIS_SUCCESS; + } + + return NIS_FAIL; +} +libnsl_hidden_nolink_def (__nisbind_next, GLIBC_2_1) + +static struct ckey_cache_entry +{ + struct in_addr inaddr; + in_port_t port; + unsigned int protocol; + des_block ckey; +} *ckey_cache; +static size_t ckey_cache_size; +static size_t ckey_cache_allocated; +static pid_t ckey_cache_pid; +static uid_t ckey_cache_euid; +__libc_lock_define_initialized (static, ckey_cache_lock) + +static bool_t +get_ckey (des_block *ckey, struct sockaddr_in *addr, unsigned int protocol) +{ + size_t i; + pid_t pid = getpid (); + uid_t euid = geteuid (); + bool_t ret = FALSE; + + __libc_lock_lock (ckey_cache_lock); + + if (ckey_cache_pid != pid || ckey_cache_euid != euid) + { + ckey_cache_size = 0; + ckey_cache_pid = pid; + ckey_cache_euid = euid; + } + + for (i = 0; i < ckey_cache_size; ++i) + if (ckey_cache[i].port == addr->sin_port + && ckey_cache[i].protocol == protocol + && memcmp (&ckey_cache[i].inaddr, &addr->sin_addr, + sizeof (addr->sin_addr)) == 0) + { + *ckey = ckey_cache[i].ckey; + ret = TRUE; + break; + } + + if (!ret && key_gendes (ckey) >= 0) + { + ret = TRUE; + /* Don't grow the cache indefinitely. */ + if (ckey_cache_size == 256) + ckey_cache_size = 0; + if (ckey_cache_size == ckey_cache_allocated) + { + size_t size = ckey_cache_allocated ? ckey_cache_allocated * 2 : 16; + struct ckey_cache_entry *new_cache + = realloc (ckey_cache, size * sizeof (*ckey_cache)); + if (new_cache != NULL) + { + ckey_cache = new_cache; + ckey_cache_allocated = size; + } + } + ckey_cache[ckey_cache_size].inaddr = addr->sin_addr; + ckey_cache[ckey_cache_size].port = addr->sin_port; + ckey_cache[ckey_cache_size].protocol = protocol; + ckey_cache[ckey_cache_size++].ckey = *ckey; + } + + __libc_lock_unlock (ckey_cache_lock); + return ret; +} + +nis_error +__nisbind_connect (dir_binding *dbp) +{ + nis_server *serv; + u_short port; + + if (dbp == NULL) + return NIS_FAIL; + + serv = &dbp->server_val[dbp->server_used]; + + memset (&dbp->addr, '\0', sizeof (dbp->addr)); + dbp->addr.sin_family = AF_INET; + + dbp->addr.sin_addr.s_addr = + inetstr2int (serv->ep.ep_val[dbp->current_ep].uaddr); + + if (dbp->addr.sin_addr.s_addr == INADDR_NONE) + return NIS_FAIL; + + /* Check, if the host is online and rpc.nisd is running. Much faster + then the clnt*_create functions: */ + port = __pmap_getnisport (&dbp->addr, NIS_PROG, NIS_VERSION, + dbp->use_udp ? IPPROTO_UDP : IPPROTO_TCP); + if (port == 0) + return NIS_RPCERROR; + + dbp->addr.sin_port = htons (port); + dbp->socket = RPC_ANYSOCK; + if (dbp->use_udp) + dbp->clnt = clntudp_create (&dbp->addr, NIS_PROG, NIS_VERSION, + UDPTIMEOUT, &dbp->socket); + else + dbp->clnt = clnttcp_create (&dbp->addr, NIS_PROG, NIS_VERSION, + &dbp->socket, 0, 0); + + if (dbp->clnt == NULL) + return NIS_RPCERROR; + + clnt_control (dbp->clnt, CLSET_TIMEOUT, (caddr_t) &RPCTIMEOUT); + /* If the program exists, close the socket */ + if (fcntl (dbp->socket, F_SETFD, 1) == -1) + perror ("fcntl: F_SETFD"); + + if (dbp->use_auth) + { + if (serv->key_type == NIS_PK_DH) + { + char netname[MAXNETNAMELEN + 1]; + char *p; + des_block ckey; + + p = stpcpy (netname, "unix@"); + strncpy (p, serv->name, MAXNETNAMELEN - 5); + netname[MAXNETNAMELEN] = '\0'; + dbp->clnt->cl_auth = NULL; + if (get_ckey (&ckey, &dbp->addr, + dbp->use_udp ? IPPROTO_UDP : IPPROTO_TCP)) + dbp->clnt->cl_auth = + authdes_pk_create (netname, &serv->pkey, 300, NULL, &ckey); + if (!dbp->clnt->cl_auth) + dbp->clnt->cl_auth = authunix_create_default (); + } + else + dbp->clnt->cl_auth = authunix_create_default (); + } + + return NIS_SUCCESS; +} +libnsl_hidden_nolink_def (__nisbind_connect, GLIBC_2_1) + +nis_error +__nisbind_create (dir_binding *dbp, const nis_server *serv_val, + unsigned int serv_len, unsigned int server_used, + unsigned int current_ep, unsigned int flags) +{ + dbp->clnt = NULL; + + dbp->server_len = serv_len; + dbp->server_val = (nis_server *)serv_val; + + if (flags & USE_DGRAM) + dbp->use_udp = TRUE; + else + dbp->use_udp = FALSE; + + if (flags & NO_AUTHINFO) + dbp->use_auth = FALSE; + else + dbp->use_auth = TRUE; + + if (flags & MASTER_ONLY) + dbp->master_only = TRUE; + else + dbp->master_only = FALSE; + + /* We try the first server */ + dbp->trys = 1; + + dbp->class = -1; + if (server_used == ~0) + { + if (__nis_findfastest (dbp) < 1) + return NIS_NAMEUNREACHABLE; + } + else + { + dbp->server_used = server_used; + dbp->current_ep = current_ep; + } + + return NIS_SUCCESS; +} +libnsl_hidden_nolink_def (__nisbind_create, GLIBC_2_1) + +/* __nisbind_connect (dbp) must be run before calling this function ! + So we could use the same binding twice */ +nis_error +__do_niscall3 (dir_binding *dbp, u_long prog, xdrproc_t xargs, caddr_t req, + xdrproc_t xres, caddr_t resp, unsigned int flags, nis_cb *cb) +{ + enum clnt_stat result; + nis_error retcode; + + if (dbp == NULL) + return NIS_NAMEUNREACHABLE; + + do + { + again: + result = clnt_call (dbp->clnt, prog, xargs, req, xres, resp, RPCTIMEOUT); + + if (result != RPC_SUCCESS) + retcode = NIS_RPCERROR; + else + { + switch (prog) + { + case NIS_IBLIST: + if ((((nis_result *)resp)->status == NIS_CBRESULTS) && + (cb != NULL)) + { + __nis_do_callback (dbp, &((nis_result *) resp)->cookie, cb); + break; + } + /* Yes, the missing break is correct. If we doesn't have to + start a callback, look if we have to search another server */ + case NIS_LOOKUP: + case NIS_ADD: + case NIS_MODIFY: + case NIS_REMOVE: + case NIS_IBADD: + case NIS_IBMODIFY: + case NIS_IBREMOVE: + case NIS_IBFIRST: + case NIS_IBNEXT: + if (((nis_result *)resp)->status == NIS_SYSTEMERROR + || ((nis_result *)resp)->status == NIS_NOSUCHNAME + || ((nis_result *)resp)->status == NIS_NOT_ME) + { + next_server: + if (__nisbind_next (dbp) == NIS_SUCCESS) + { + while (__nisbind_connect (dbp) != NIS_SUCCESS) + { + if (__nisbind_next (dbp) != NIS_SUCCESS) + return NIS_SUCCESS; + } + } + else + break; /* No more servers to search in */ + goto again; + } + break; + case NIS_FINDDIRECTORY: + if (((fd_result *)resp)->status == NIS_SYSTEMERROR + || ((fd_result *)resp)->status == NIS_NOSUCHNAME + || ((fd_result *)resp)->status == NIS_NOT_ME) + goto next_server; + break; + case NIS_DUMPLOG: /* log_result */ + case NIS_DUMP: + if (((log_result *)resp)->lr_status == NIS_SYSTEMERROR + || ((log_result *)resp)->lr_status == NIS_NOSUCHNAME + || ((log_result *)resp)->lr_status == NIS_NOT_ME) + goto next_server; + break; + default: + break; + } + retcode = NIS_SUCCESS; + } + } + while ((flags & HARD_LOOKUP) && retcode == NIS_RPCERROR); + + return retcode; +} +libnsl_hidden_nolink_def (__do_niscall3, GLIBC_PRIVATE) + + +nis_error +__do_niscall2 (const nis_server *server, u_int server_len, u_long prog, + xdrproc_t xargs, caddr_t req, xdrproc_t xres, caddr_t resp, + unsigned int flags, nis_cb *cb) +{ + dir_binding dbp; + nis_error status; + + if (flags & MASTER_ONLY) + server_len = 1; + + status = __nisbind_create (&dbp, server, server_len, ~0, ~0, flags); + if (status != NIS_SUCCESS) + return status; + + while (__nisbind_connect (&dbp) != NIS_SUCCESS) + if (__nisbind_next (&dbp) != NIS_SUCCESS) + return NIS_NAMEUNREACHABLE; + + status = __do_niscall3 (&dbp, prog, xargs, req, xres, resp, flags, cb); + + __nisbind_destroy (&dbp); + + return status; + +} + +static directory_obj * +rec_dirsearch (const_nis_name name, directory_obj *dir, nis_error *status) +{ + fd_result *fd_res; + XDR xdrs; + + switch (nis_dir_cmp (name, dir->do_name)) + { + case SAME_NAME: + *status = NIS_SUCCESS; + return dir; + case NOT_SEQUENTIAL: + /* NOT_SEQUENTIAL means, go one up and try it there ! */ + case HIGHER_NAME: + { /* We need data from a parent domain */ + directory_obj *obj; + const char *ndomain = __nis_domain_of (dir->do_name); + + /* The root server of our domain is a replica of the parent + domain ! (Now I understand why a root server must be a + replica of the parent domain) */ + fd_res = __nis_finddirectory (dir, ndomain); + if (fd_res == NULL) + { + nis_free_directory (dir); + *status = NIS_NOMEMORY; + return NULL; + } + *status = fd_res->status; + if (fd_res->status != NIS_SUCCESS) + { + /* Try the current directory obj, maybe it works */ + __free_fdresult (fd_res); + return dir; + } + nis_free_directory (dir); + obj = calloc (1, sizeof (directory_obj)); + if (obj == NULL) + { + __free_fdresult (fd_res); + *status = NIS_NOMEMORY; + return NULL; + } + xdrmem_create (&xdrs, fd_res->dir_data.dir_data_val, + fd_res->dir_data.dir_data_len, XDR_DECODE); + _xdr_directory_obj (&xdrs, obj); + xdr_destroy (&xdrs); + __free_fdresult (fd_res); + + /* We have found a NIS+ server serving ndomain, now + let us search for "name" */ + return rec_dirsearch (name, obj, status); + } + break; + case LOWER_NAME: + { + directory_obj *obj; + size_t namelen = strlen (name); + char leaf[namelen + 3]; + char domain[namelen + 3]; + const char *ndomain; + char *cp; + + strcpy (domain, name); + + do + { + if (domain[0] == '\0') + { + nis_free_directory (dir); + return NULL; + } + nis_leaf_of_r (domain, leaf, sizeof (leaf)); + ndomain = __nis_domain_of (domain); + memmove (domain, ndomain, strlen (ndomain) + 1); + } + while (nis_dir_cmp (domain, dir->do_name) != SAME_NAME); + + cp = rawmemchr (leaf, '\0'); + *cp++ = '.'; + strcpy (cp, domain); + + fd_res = __nis_finddirectory (dir, leaf); + if (fd_res == NULL) + { + nis_free_directory (dir); + *status = NIS_NOMEMORY; + return NULL; + } + *status = fd_res->status; + if (fd_res->status != NIS_SUCCESS) + { + /* Try the current directory object, maybe it works */ + __free_fdresult (fd_res); + return dir; + } + nis_free_directory (dir); + obj = calloc (1, sizeof(directory_obj)); + if (obj == NULL) + { + __free_fdresult (fd_res); + *status = NIS_NOMEMORY; + return NULL; + } + xdrmem_create (&xdrs, fd_res->dir_data.dir_data_val, + fd_res->dir_data.dir_data_len, XDR_DECODE); + _xdr_directory_obj (&xdrs, obj); + xdr_destroy (&xdrs); + __free_fdresult (fd_res); + /* We have found a NIS+ server serving ndomain, now + let us search for "name" */ + return rec_dirsearch (name, obj, status); + } + break; + case BAD_NAME: + nis_free_directory (dir); + *status = NIS_BADNAME; + return NULL; + } + nis_free_directory (dir); + *status = NIS_FAIL; + return NULL; +} + +/* We try to query the current server for the searched object, + maybe he know about it ? */ +static directory_obj * +first_shoot (const_nis_name name, directory_obj *dir) +{ + directory_obj *obj = NULL; + fd_result *fd_res; + XDR xdrs; + + if (nis_dir_cmp (name, dir->do_name) == SAME_NAME) + return dir; + + fd_res = __nis_finddirectory (dir, name); + if (fd_res == NULL) + return NULL; + if (fd_res->status == NIS_SUCCESS + && (obj = calloc (1, sizeof (directory_obj))) != NULL) + { + xdrmem_create (&xdrs, fd_res->dir_data.dir_data_val, + fd_res->dir_data.dir_data_len, XDR_DECODE); + _xdr_directory_obj (&xdrs, obj); + xdr_destroy (&xdrs); + + if (strcmp (dir->do_name, obj->do_name) != 0) + { + nis_free_directory (obj); + obj = NULL; + } + } + + __free_fdresult (fd_res); + + if (obj != NULL) + nis_free_directory (dir); + + return obj; +} + +static struct nis_server_cache +{ + int search_parent; + int uses; + unsigned int size; + unsigned int server_used; + unsigned int current_ep; + time_t expires; + char name[]; +} *nis_server_cache[16]; +static time_t nis_cold_start_mtime; +__libc_lock_define_initialized (static, nis_server_cache_lock) + +static directory_obj * +nis_server_cache_search (const_nis_name name, int search_parent, + unsigned int *server_used, unsigned int *current_ep, + struct timeval *now) +{ + directory_obj *ret = NULL; + int i; + char *addr; + XDR xdrs; + struct stat64 st; + + int saved_errno = errno; + if (stat64 ("/var/nis/NIS_COLD_START", &st) < 0) + st.st_mtime = nis_cold_start_mtime + 1; + __set_errno (saved_errno); + + __libc_lock_lock (nis_server_cache_lock); + + for (i = 0; i < 16; ++i) + if (nis_server_cache[i] == NULL) + continue; + else if (st.st_mtime != nis_cold_start_mtime + || now->tv_sec > nis_server_cache[i]->expires) + { + free (nis_server_cache[i]); + nis_server_cache[i] = NULL; + } + else if (nis_server_cache[i]->search_parent == search_parent + && strcmp (nis_server_cache[i]->name, name) == 0) + { + ret = calloc (1, sizeof (directory_obj)); + if (ret == NULL) + break; + + addr = rawmemchr (nis_server_cache[i]->name, '\0') + 8; + addr = (char *) ((uintptr_t) addr & ~(uintptr_t) 7); + xdrmem_create (&xdrs, addr, nis_server_cache[i]->size, XDR_DECODE); + if (!_xdr_directory_obj (&xdrs, ret)) + { + xdr_destroy (&xdrs); + free (ret); + ret = NULL; + free (nis_server_cache[i]); + nis_server_cache[i] = NULL; + break; + } + xdr_destroy (&xdrs); + *server_used = nis_server_cache[i]->server_used; + *current_ep = nis_server_cache[i]->current_ep; + break; + } + + nis_cold_start_mtime = st.st_mtime; + + __libc_lock_unlock (nis_server_cache_lock); + return ret; +} + +static void +nis_server_cache_add (const_nis_name name, int search_parent, + directory_obj *dir, unsigned int server_used, + unsigned int current_ep, struct timeval *now) +{ + struct nis_server_cache **loc; + struct nis_server_cache *new; + struct nis_server_cache *old; + int i; + char *addr; + unsigned int size; + XDR xdrs; + + if (dir == NULL) + return; + + size = xdr_sizeof ((xdrproc_t) _xdr_directory_obj, (char *) dir); + new = calloc (1, sizeof (*new) + strlen (name) + 8 + size); + if (new == NULL) + return; + new->search_parent = search_parent; + new->uses = 1; + new->expires = now->tv_sec + dir->do_ttl; + new->size = size; + new->server_used = server_used; + new->current_ep = current_ep; + addr = stpcpy (new->name, name) + 8; + addr = (char *) ((uintptr_t) addr & ~(uintptr_t) 7); + + xdrmem_create(&xdrs, addr, size, XDR_ENCODE); + if (!_xdr_directory_obj (&xdrs, dir)) + { + xdr_destroy (&xdrs); + free (new); + return; + } + xdr_destroy (&xdrs); + + __libc_lock_lock (nis_server_cache_lock); + + /* Choose which entry should be evicted from the cache. */ + loc = &nis_server_cache[0]; + if (*loc != NULL) + { + for (i = 1; i < 16; ++i) + if (nis_server_cache[i] == NULL) + { + loc = &nis_server_cache[i]; + break; + } + else if ((*loc)->uses > nis_server_cache[i]->uses + || ((*loc)->uses == nis_server_cache[i]->uses + && (*loc)->expires > nis_server_cache[i]->expires)) + loc = &nis_server_cache[i]; + } + old = *loc; + *loc = new; + + __libc_lock_unlock (nis_server_cache_lock); + free (old); +} + +nis_error +__nisfind_server (const_nis_name name, int search_parent, + directory_obj **dir, dir_binding *dbp, unsigned int flags) +{ + nis_error result = NIS_SUCCESS; + nis_error status; + directory_obj *obj; + struct timeval now; + unsigned int server_used = ~0; + unsigned int current_ep = ~0; + + if (name == NULL) + return NIS_BADNAME; + + if (*dir != NULL) + return NIS_SUCCESS; + + (void) gettimeofday (&now, NULL); + + if ((flags & NO_CACHE) == 0) + *dir = nis_server_cache_search (name, search_parent, &server_used, + ¤t_ep, &now); + if (*dir != NULL) + { + unsigned int server_len = (*dir)->do_servers.do_servers_len; + if (flags & MASTER_ONLY) + { + server_len = 1; + if (server_used != 0) + { + server_used = ~0; + current_ep = ~0; + } + } + result = __nisbind_create (dbp, (*dir)->do_servers.do_servers_val, + server_len, server_used, current_ep, flags); + if (result != NIS_SUCCESS) + { + nis_free_directory (*dir); + *dir = NULL; + } + return result; + } + + int saved_errno = errno; + *dir = readColdStartFile (); + __set_errno (saved_errno); + if (*dir == NULL) + /* No /var/nis/NIS_COLD_START->no NIS+ installed. */ + return NIS_UNAVAIL; + + /* Try at first, if servers in "dir" know our object */ + const char *search_name = name; + if (search_parent) + search_name = __nis_domain_of (name); + obj = first_shoot (search_name, *dir); + if (obj == NULL) + { + obj = rec_dirsearch (search_name, *dir, &status); + if (obj == NULL) + result = status; + } + + if (result == NIS_SUCCESS) + { + unsigned int server_len = obj->do_servers.do_servers_len; + if (flags & MASTER_ONLY) + server_len = 1; + result = __nisbind_create (dbp, obj->do_servers.do_servers_val, + server_len, ~0, ~0, flags); + if (result == NIS_SUCCESS) + { + if ((flags & MASTER_ONLY) == 0 + || obj->do_servers.do_servers_len == 1) + { + server_used = dbp->server_used; + current_ep = dbp->current_ep; + } + if ((flags & NO_CACHE) == 0) + nis_server_cache_add (name, search_parent, obj, + server_used, current_ep, &now); + } + else + { + nis_free_directory (obj); + obj = NULL; + } + } + + *dir = obj; + + return result; +} + + +nis_error +__prepare_niscall (const_nis_name name, directory_obj **dirp, + dir_binding *bptrp, unsigned int flags) +{ + nis_error retcode = __nisfind_server (name, 1, dirp, bptrp, flags); + if (__glibc_unlikely (retcode != NIS_SUCCESS)) + return retcode; + + do + if (__nisbind_connect (bptrp) == NIS_SUCCESS) + return NIS_SUCCESS; + while (__nisbind_next (bptrp) == NIS_SUCCESS); + + __nisbind_destroy (bptrp); + memset (bptrp, '\0', sizeof (*bptrp)); + + retcode = NIS_NAMEUNREACHABLE; + nis_free_directory (*dirp); + *dirp = NULL; + + return retcode; +} +libnsl_hidden_nolink_def (__prepare_niscall, GLIBC_PRIVATE) + + +nis_error +__do_niscall (const_nis_name name, u_long prog, xdrproc_t xargs, + caddr_t req, xdrproc_t xres, caddr_t resp, unsigned int flags, + nis_cb *cb) +{ + dir_binding bptr; + directory_obj *dir = NULL; + int saved_errno = errno; + + nis_error retcode = __prepare_niscall (name, &dir, &bptr, flags); + if (retcode == NIS_SUCCESS) + { + retcode = __do_niscall3 (&bptr, prog, xargs, req, xres, resp, flags, cb); + + __nisbind_destroy (&bptr); + + nis_free_directory (dir); + } + + __set_errno (saved_errno); + + return retcode; +} diff --git a/REORG.TODO/nis/nis_callback.c b/REORG.TODO/nis/nis_callback.c new file mode 100644 index 0000000000..2ad4fc0a71 --- /dev/null +++ b/REORG.TODO/nis/nis_callback.c @@ -0,0 +1,380 @@ +/* Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <libintl.h> +#include <rpc/rpc.h> +#include <rpc/pmap_clnt.h> +#include <string.h> +#include <memory.h> +#include <syslog.h> +#include <sys/poll.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <rpc/key_prot.h> +#include <rpcsvc/nis.h> +#include <rpcsvc/nis_callback.h> +#include <libc-lock.h> + +#include "nis_xdr.h" +#include "nis_intern.h" + +/* Sorry, we are not able to make this threadsafe. Stupid. But some + functions doesn't send us a nis_result obj, so we don't have a + cookie. Maybe we could use keys for threads ? Have to learn more + about pthreads -- kukuk@vt.uni-paderborn.de */ + +static nis_cb *data; + +__libc_lock_define_initialized (static, callback) + + +#if 0 +static char * +__nis_getpkey(const char *sname) +{ + char buf[(strlen (sname) + 1) * 2 + 40]; + char pkey[HEXKEYBYTES + 1]; + char *cp, *domain; + nis_result *res; + unsigned int len = 0; + + domain = strchr (sname, '.'); + if (domain == NULL) + return NULL; + + /* Remove prefixing dot */ + ++domain; + + cp = stpcpy (buf, "[cname="); + cp = stpcpy (cp, sname); + cp = stpcpy (cp, ",auth_type=DES],cred.org_dir."); + cp = stpcpy (cp, domain); + + res = nis_list (buf, USE_DGRAM|NO_AUTHINFO|FOLLOW_LINKS|FOLLOW_PATH, + NULL, NULL); + + if (res == NULL) + return NULL; + + if (NIS_RES_STATUS (res) != NIS_SUCCESS) + { + nis_freeresult (res); + return NULL; + } + + len = ENTRY_LEN(NIS_RES_OBJECT(res), 3); + strncpy (pkey, ENTRY_VAL(NIS_RES_OBJECT(res), 3), len); + pkey[len] = '\0'; + cp = strchr (pkey, ':'); + if (cp != NULL) + *cp = '\0'; + + nis_freeresult (res); + + return strdup (pkey); +} +#endif + +static void +cb_prog_1 (struct svc_req *rqstp, SVCXPRT *transp) +{ + union + { + cback_data cbproc_receive_1_arg; + nis_error cbproc_error_1_arg; + } + argument; + char *result; + xdrproc_t xdr_argument, xdr_result; + bool_t bool_result; + + switch (rqstp->rq_proc) + { + case NULLPROC: + svc_sendreply (transp, (xdrproc_t) xdr_void, (char *) NULL); + return; + + case CBPROC_RECEIVE: + { + unsigned int i; + + xdr_argument = (xdrproc_t) xdr_cback_data; + xdr_result = (xdrproc_t) xdr_bool; + memset (&argument, 0, sizeof (argument)); + if (!svc_getargs (transp, xdr_argument, (caddr_t) & argument)) + { + svcerr_decode (transp); + return; + } + bool_result = FALSE; + for (i = 0; i < argument.cbproc_receive_1_arg.entries.entries_len; ++i) + { +#define cbproc_entry(a) argument.cbproc_receive_1_arg.entries.entries_val[a] + char name[strlen (cbproc_entry(i)->zo_name) + + strlen (cbproc_entry(i)->zo_domain) + 3]; + char *cp; + + cp = stpcpy (name, cbproc_entry(i)->zo_name); + *cp++ = '.'; + cp = stpcpy (cp, cbproc_entry(i)->zo_domain); + + if ((data->callback) (name, cbproc_entry(i), data->userdata)) + { + bool_result = TRUE; + data->nomore = 1; + data->result = NIS_SUCCESS; + break; + } + } + result = (char *) &bool_result; + } + break; + case CBPROC_FINISH: + xdr_argument = (xdrproc_t) xdr_void; + xdr_result = (xdrproc_t) xdr_void; + memset (&argument, 0, sizeof (argument)); + if (!svc_getargs (transp, xdr_argument, (caddr_t) & argument)) + { + svcerr_decode (transp); + return; + } + data->nomore = 1; + data->result = NIS_SUCCESS; + bool_result = TRUE; /* to make gcc happy, not necessary */ + result = (char *) &bool_result; + break; + case CBPROC_ERROR: + xdr_argument = (xdrproc_t) _xdr_nis_error; + xdr_result = (xdrproc_t) xdr_void; + memset (&argument, 0, sizeof (argument)); + if (!svc_getargs (transp, xdr_argument, (caddr_t) & argument)) + { + svcerr_decode (transp); + return; + } + data->nomore = 1; + data->result = argument.cbproc_error_1_arg; + bool_result = TRUE; /* to make gcc happy, not necessary */ + result = (char *) &bool_result; + break; + default: + svcerr_noproc (transp); + return; + } + if (result != NULL && !svc_sendreply (transp, xdr_result, result)) + svcerr_systemerr (transp); + if (!svc_freeargs (transp, xdr_argument, (caddr_t) & argument)) + { + fputs (_ ("unable to free arguments"), stderr); + exit (1); + } + return; +} + +static nis_error +internal_nis_do_callback (struct dir_binding *bptr, netobj *cookie, + struct nis_cb *cb) +{ + struct timeval TIMEOUT = {25, 0}; + bool_t cb_is_running; + + data = cb; + + for (;;) + { + struct pollfd my_pollfd[svc_max_pollfd]; + int i; + + if (svc_max_pollfd == 0 && svc_pollfd == NULL) + return NIS_CBERROR; + + for (i = 0; i < svc_max_pollfd; ++i) + { + my_pollfd[i].fd = svc_pollfd[i].fd; + my_pollfd[i].events = svc_pollfd[i].events; + my_pollfd[i].revents = 0; + } + + switch (i = TEMP_FAILURE_RETRY (__poll (my_pollfd, svc_max_pollfd, + 25*1000))) + { + case -1: + return NIS_CBERROR; + case 0: + /* See if callback 'thread' in the server is still alive. */ + cb_is_running = FALSE; + if (clnt_call (bptr->clnt, NIS_CALLBACK, (xdrproc_t) xdr_netobj, + (caddr_t) cookie, (xdrproc_t) xdr_bool, + (caddr_t) &cb_is_running, TIMEOUT) != RPC_SUCCESS) + cb_is_running = FALSE; + + if (cb_is_running == FALSE) + { + syslog (LOG_ERR, "NIS+: callback timed out"); + return NIS_CBERROR; + } + break; + default: + svc_getreq_poll (my_pollfd, i); + if (data->nomore) + return data->result; + } + } +} + +nis_error +__nis_do_callback (struct dir_binding *bptr, netobj *cookie, + struct nis_cb *cb) +{ + nis_error result; + + __libc_lock_lock (callback); + + result = internal_nis_do_callback (bptr, cookie, cb); + + __libc_lock_unlock (callback); + + return result; +} + +struct nis_cb * +__nis_create_callback (int (*callback) (const_nis_name, const nis_object *, + const void *), + const void *userdata, unsigned int flags) +{ + struct nis_cb *cb; + int sock = RPC_ANYSOCK; + struct sockaddr_in sin; + socklen_t len = sizeof (struct sockaddr_in); + unsigned short port; + int nomsg = 0; + + cb = (struct nis_cb *) calloc (1, + sizeof (struct nis_cb) + sizeof (nis_server)); + if (__glibc_unlikely (cb == NULL)) + goto failed; + cb->serv = (nis_server *) (cb + 1); + cb->serv->name = strdup (nis_local_principal ()); + if (__glibc_unlikely (cb->serv->name == NULL)) + goto failed; + cb->serv->ep.ep_val = (endpoint *) calloc (2, sizeof (endpoint)); + if (__glibc_unlikely (cb->serv->ep.ep_val == NULL)) + goto failed; + cb->serv->ep.ep_len = 1; + cb->serv->ep.ep_val[0].family = strdup ("inet"); + if (__glibc_unlikely (cb->serv->ep.ep_val[0].family == NULL)) + goto failed; + cb->callback = callback; + cb->userdata = userdata; + + if ((flags & NO_AUTHINFO) || !key_secretkey_is_set ()) + { + cb->serv->key_type = NIS_PK_NONE; + cb->serv->pkey.n_bytes = NULL; + cb->serv->pkey.n_len = 0; + } + else + { +#if 0 + if ((cb->serv->pkey.n_bytes = __nis_getpkey (cb->serv->name)) == NULL) + { + cb->serv->pkey.n_len = 0; + cb->serv->key_type = NIS_PK_NONE; + } + else + { + cb->serv->key_type = NIS_PK_DH; + cb->serv->pkey.n_len = strlen(cb->serv->pkey.n_bytes); + } +#else + cb->serv->pkey.n_len =0; + cb->serv->pkey.n_bytes = NULL; + cb->serv->key_type = NIS_PK_NONE; +#endif + } + + cb->serv->ep.ep_val[0].proto = strdup ((flags & USE_DGRAM) ? "udp" : "tcp"); + if (__glibc_unlikely (cb->serv->ep.ep_val[0].proto == NULL)) + goto failed; + cb->xprt = ((flags & USE_DGRAM) + ? svcudp_bufcreate (sock, 100, 8192) + : svctcp_create (sock, 100, 8192)); + if (cb->xprt == NULL) + { + nomsg = 1; + goto failed; + } + cb->sock = cb->xprt->xp_sock; + if (!svc_register (cb->xprt, CB_PROG, CB_VERS, cb_prog_1, 0)) + { + xprt_unregister (cb->xprt); + svc_destroy (cb->xprt); + xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv); + free (cb); + syslog (LOG_ERR, "NIS+: failed to register callback dispatcher"); + return NULL; + } + + if (getsockname (cb->sock, (struct sockaddr *) &sin, &len) == -1) + { + xprt_unregister (cb->xprt); + svc_destroy (cb->xprt); + xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv); + free (cb); + syslog (LOG_ERR, "NIS+: failed to read local socket info"); + return NULL; + } + port = ntohs (sin.sin_port); + get_myaddress (&sin); + + if (asprintf (&cb->serv->ep.ep_val[0].uaddr, "%s.%d.%d", + inet_ntoa (sin.sin_addr), (port & 0xFF00) >> 8, port & 0x00FF) + < 0) + goto failed; + + return cb; + + failed: + if (cb) + { + if (cb->xprt) + svc_destroy (cb->xprt); + xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv); + free (cb); + } + if (!nomsg) + syslog (LOG_ERR, "NIS+: out of memory allocating callback"); + return NULL; +} + +nis_error +__nis_destroy_callback (struct nis_cb *cb) +{ + xprt_unregister (cb->xprt); + svc_destroy (cb->xprt); + close (cb->sock); + xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv); + free (cb); + + return NIS_SUCCESS; +} diff --git a/REORG.TODO/nis/nis_checkpoint.c b/REORG.TODO/nis/nis_checkpoint.c new file mode 100644 index 0000000000..f148af4170 --- /dev/null +++ b/REORG.TODO/nis/nis_checkpoint.c @@ -0,0 +1,80 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> +#include <rpcsvc/nis.h> +#include <shlib-compat.h> + +#include "nis_xdr.h" +#include "nis_intern.h" + +nis_result * +nis_checkpoint (const_nis_name dirname) +{ + nis_result *res; + + res = calloc (1, sizeof (nis_result)); + if (res == NULL) + return NULL; + + if (dirname != NULL) + { + nis_result *res2; + u_int i; + + res2 = nis_lookup (dirname, EXPAND_NAME); + if (NIS_RES_STATUS (res2) != NIS_SUCCESS) + { + free (res); + return res2; + } + + /* Check if obj is really a diryectory object */ + if (__type_of (NIS_RES_OBJECT (res2)) != NIS_DIRECTORY_OBJ) + { + nis_freeresult (res2); + NIS_RES_STATUS (res) = NIS_INVALIDOBJ; + return res; + } + + for (i = 0; + i < NIS_RES_OBJECT (res2)->DI_data.do_servers.do_servers_len; ++i) + { + cp_result cpres; + + memset (&cpres, '\0', sizeof (cp_result)); + if (__do_niscall2 (&NIS_RES_OBJECT(res2)->DI_data.do_servers.do_servers_val[i], + 1, NIS_CHECKPOINT, (xdrproc_t) _xdr_nis_name, + (caddr_t) &dirname, (xdrproc_t) _xdr_cp_result, + (caddr_t) &cpres, 0, NULL) != NIS_SUCCESS) + NIS_RES_STATUS (res) = NIS_RPCERROR; + else + { + NIS_RES_STATUS (res) = cpres.cp_status; + res->zticks += cpres.cp_zticks; + res->dticks += cpres.cp_dticks; + } + } + nis_freeresult (res2); + } + else + NIS_RES_STATUS (res) = NIS_NOSUCHNAME; + + return res; +} +libnsl_hidden_nolink_def (nis_checkpoint, GLIBC_2_1) diff --git a/REORG.TODO/nis/nis_clone_dir.c b/REORG.TODO/nis/nis_clone_dir.c new file mode 100644 index 0000000000..982f475218 --- /dev/null +++ b/REORG.TODO/nis/nis_clone_dir.c @@ -0,0 +1,75 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> +#include <rpc/rpc.h> +#include <rpcsvc/nis.h> +#include <shlib-compat.h> + +#include "nis_xdr.h" + +directory_obj * +nis_clone_directory (const directory_obj *src, directory_obj *dest) +{ + char *addr; + unsigned int size; + XDR xdrs; + + if (src == NULL) + return NULL; + + size = xdr_sizeof ((xdrproc_t)_xdr_directory_obj, (char *)src); + if ((addr = calloc(1, size)) == NULL) + return NULL; + + xdrmem_create(&xdrs, addr, size, XDR_ENCODE); + if (!_xdr_directory_obj (&xdrs, (directory_obj *)src)) + { + xdr_destroy (&xdrs); + free (addr); + return NULL; + } + xdr_destroy (&xdrs); + + directory_obj *res; + if (dest == NULL) + { + if ((res = calloc (1, sizeof (directory_obj))) == NULL) + { + free (addr); + return NULL; + } + } + else + res = dest; + + xdrmem_create (&xdrs, addr, size, XDR_DECODE); + if (!_xdr_directory_obj (&xdrs, res)) + { + xdr_destroy (&xdrs); + if (res != dest) + free (res); + free (addr); + return NULL; + } + xdr_destroy (&xdrs); + free (addr); + + return res; +} +libnsl_hidden_nolink_def(nis_clone_directory, GLIBC_2_1) diff --git a/REORG.TODO/nis/nis_clone_obj.c b/REORG.TODO/nis/nis_clone_obj.c new file mode 100644 index 0000000000..1d7e2e3ca5 --- /dev/null +++ b/REORG.TODO/nis/nis_clone_obj.c @@ -0,0 +1,68 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> +#include <rpc/rpc.h> +#include <rpcsvc/nis.h> +#include <shlib-compat.h> + +#include "nis_xdr.h" + +nis_object * +nis_clone_object (const nis_object *src, nis_object *dest) +{ + char *addr; + unsigned int size; + XDR xdrs; + nis_object *res = NULL; + + if (src == NULL) + return (NULL); + + size = xdr_sizeof ((xdrproc_t)_xdr_nis_object, (char *) src); + if ((addr = calloc (1, size)) == NULL) + return NULL; + + if (dest == NULL) + { + if ((res = calloc (1, sizeof (nis_object))) == NULL) + goto out; + } + else + res = dest; + + xdrmem_create (&xdrs, addr, size, XDR_ENCODE); + if (!_xdr_nis_object (&xdrs, (nis_object *) src)) + goto out2; + xdr_destroy (&xdrs); + xdrmem_create (&xdrs, addr, size, XDR_DECODE); + if (!_xdr_nis_object (&xdrs, res)) + { + out2: + if (dest == NULL) + free (res); + res = NULL; + } + + xdr_destroy (&xdrs); + out: + free (addr); + + return res; +} +libnsl_hidden_nolink_def (nis_clone_object, GLIBC_2_1) diff --git a/REORG.TODO/nis/nis_clone_res.c b/REORG.TODO/nis/nis_clone_res.c new file mode 100644 index 0000000000..db7716538a --- /dev/null +++ b/REORG.TODO/nis/nis_clone_res.c @@ -0,0 +1,75 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> +#include <rpc/rpc.h> +#include <rpcsvc/nis.h> +#include <shlib-compat.h> + +#include "nis_xdr.h" + +nis_result * +nis_clone_result (const nis_result *src, nis_result *dest) +{ + char *addr; + unsigned int size; + XDR xdrs; + + if (src == NULL) + return (NULL); + + size = xdr_sizeof ((xdrproc_t)_xdr_nis_result, (char *)src); + if ((addr = calloc(1, size)) == NULL) + return NULL; + + xdrmem_create (&xdrs, addr, size, XDR_ENCODE); + if (!_xdr_nis_result (&xdrs, (nis_result *)src)) + { + xdr_destroy (&xdrs); + free (addr); + return NULL; + } + xdr_destroy (&xdrs); + + nis_result *res; + if (dest == NULL) + { + if ((res = calloc (1, sizeof (nis_result))) == NULL) + { + free (addr); + return NULL; + } + } + else + res = dest; + + xdrmem_create (&xdrs, addr, size, XDR_DECODE); + if (!_xdr_nis_result (&xdrs, res)) + { + xdr_destroy (&xdrs); + if (res != dest) + free (res); + free (addr); + return NULL; + } + xdr_destroy (&xdrs); + free (addr); + + return res; +} +libnsl_hidden_nolink_def (nis_clone_result, GLIBC_2_1) diff --git a/REORG.TODO/nis/nis_creategroup.c b/REORG.TODO/nis/nis_creategroup.c new file mode 100644 index 0000000000..1d7e058710 --- /dev/null +++ b/REORG.TODO/nis/nis_creategroup.c @@ -0,0 +1,85 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <time.h> +#include <string.h> +#include <rpcsvc/nis.h> +#include <shlib-compat.h> + +nis_error +nis_creategroup (const_nis_name group, unsigned int flags) +{ + if (group != NULL && group[0] != '\0') + { + size_t grouplen = strlen (group); + char buf[grouplen + 50]; + char leafbuf[grouplen + 2]; + char domainbuf[grouplen + 2]; + nis_error status; + nis_result *res; + char *cp, *cp2; + nis_object *obj; + + cp = stpcpy (buf, nis_leaf_of_r (group, leafbuf, sizeof (leafbuf) - 1)); + cp = stpcpy (cp, ".groups_dir"); + cp2 = nis_domain_of_r (group, domainbuf, sizeof (domainbuf) - 1); + if (cp2 != NULL && cp2[0] != '\0') + { + *cp++ = '.'; + stpcpy (cp, cp2); + } + else + return NIS_BADNAME; + + obj = calloc (1, sizeof (nis_object)); + if (__glibc_unlikely (obj == NULL)) + return NIS_NOMEMORY; + + obj->zo_oid.ctime = obj->zo_oid.mtime = time (NULL); + obj->zo_name = strdup (leafbuf); + obj->zo_owner = __nis_default_owner (NULL); + obj->zo_group = __nis_default_group (NULL); + obj->zo_domain = strdup (domainbuf); + if (obj->zo_name == NULL || obj->zo_owner == NULL + || obj->zo_group == NULL || obj->zo_domain == NULL) + { + free (obj->zo_group); + free (obj->zo_owner); + free (obj->zo_name); + free (obj); + return NIS_NOMEMORY; + } + obj->zo_access = __nis_default_access (NULL, 0); + obj->zo_ttl = 60 * 60; + obj->zo_data.zo_type = NIS_GROUP_OBJ; + obj->zo_data.objdata_u.gr_data.gr_flags = flags; + obj->zo_data.objdata_u.gr_data.gr_members.gr_members_len = 0; + obj->zo_data.objdata_u.gr_data.gr_members.gr_members_val = NULL; + + res = nis_add (buf, obj); + nis_free_object (obj); + if (res == NULL) + return NIS_NOMEMORY; + status = NIS_RES_STATUS (res); + nis_freeresult (res); + + return status; + } + return NIS_FAIL; +} +libnsl_hidden_nolink_def (nis_creategroup, GLIBC_2_1) diff --git a/REORG.TODO/nis/nis_defaults.c b/REORG.TODO/nis/nis_defaults.c new file mode 100644 index 0000000000..1188a81b30 --- /dev/null +++ b/REORG.TODO/nis/nis_defaults.c @@ -0,0 +1,456 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <sys/types.h> +#include <rpc/rpc.h> +#include <rpcsvc/nis.h> +#include <shlib-compat.h> + +#define DEFAULT_TTL 43200 + +/* +** Some functions for parsing the -D param and NIS_DEFAULTS Environ +*/ +static nis_name +searchXYX (char *str, const char *what) +{ + assert (strlen (what) == 6); + assert (strncmp (str, what, 6) == 0); + str += 6; /* Points to the begin of the parameters. */ + + int i = 0; + while (str[i] != '\0' && str[i] != ':') + ++i; + if (i == 0) /* only "<WHAT>=" ? */ + return strdup (""); + + return strndup (str, i); +} + + +static nis_name +searchgroup (char *str) +{ + return searchXYX (str, "group="); +} + + +static nis_name +searchowner (char *str) +{ + return searchXYX (str, "owner="); +} + + +static uint32_t +searchttl (char *str) +{ + char buf[strlen (str) + 1]; + char *cptr, *dptr; + uint32_t time; + int i; + + dptr = strstr (str, "ttl="); + if (dptr == NULL) /* should (could) not happen */ + return DEFAULT_TTL;; + + dptr += 4; /* points to the begin of the new ttl */ + i = 0; + while (dptr[i] != '\0' && dptr[i] != ':') + i++; + if (i == 0) /* only "ttl=" ? */ + return DEFAULT_TTL; + + strncpy (buf, dptr, i); + buf[i] = '\0'; + time = 0; + + dptr = buf; + cptr = strchr (dptr, 'd'); + if (cptr != NULL) + { + *cptr = '\0'; + cptr++; + time += atoi (dptr) * 60 * 60 * 24; + dptr = cptr; + } + + cptr = strchr (dptr, 'h'); + if (cptr != NULL) + { + *cptr = '\0'; + cptr++; + time += atoi (dptr) * 60 * 60; + dptr = cptr; + } + + cptr = strchr (dptr, 'm'); + if (cptr != NULL) + { + *cptr = '\0'; + cptr++; + time += atoi (dptr) * 60; + dptr = cptr; + } + + cptr = strchr (dptr, 's'); + if (cptr != NULL) + *cptr = '\0'; + + time += atoi (dptr); + + return time; +} + +static unsigned int +searchaccess (char *str, unsigned int access) +{ + char buf[strlen (str) + 1]; + char *cptr; + unsigned int result = access; + int i; + int n, o, g, w; + + cptr = strstr (str, "access="); + if (cptr == NULL) + return 0; + + cptr += 7; /* points to the begin of the access string */ + i = 0; + while (cptr[i] != '\0' && cptr[i] != ':') + i++; + if (i == 0) /* only "access=" ? */ + return 0; + + strncpy (buf, cptr, i); + buf[i] = '\0'; + + n = o = g = w = 0; + cptr = buf; + if (*cptr == ',') /* Fix for stupid Solaris scripts */ + ++cptr; + while (*cptr != '\0') + { + switch (*cptr) + { + case 'n': + n = 1; + break; + case 'o': + o = 1; + break; + case 'g': + g = 1; + break; + case 'w': + w = 1; + break; + case 'a': + o = g = w = 1; + break; + case '-': + cptr++; /* Remove "-" from beginning */ + while (*cptr != '\0' && *cptr != ',') + { + switch (*cptr) + { + case 'r': + if (n) + result = result & ~(NIS_READ_ACC << 24); + if (o) + result = result & ~(NIS_READ_ACC << 16); + if (g) + result = result & ~(NIS_READ_ACC << 8); + if (w) + result = result & ~(NIS_READ_ACC); + break; + case 'm': + if (n) + result = result & ~(NIS_MODIFY_ACC << 24); + if (o) + result = result & ~(NIS_MODIFY_ACC << 16); + if (g) + result = result & ~(NIS_MODIFY_ACC << 8); + if (w) + result = result & ~(NIS_MODIFY_ACC); + break; + case 'c': + if (n) + result = result & ~(NIS_CREATE_ACC << 24); + if (o) + result = result & ~(NIS_CREATE_ACC << 16); + if (g) + result = result & ~(NIS_CREATE_ACC << 8); + if (w) + result = result & ~(NIS_CREATE_ACC); + break; + case 'd': + if (n) + result = result & ~(NIS_DESTROY_ACC << 24); + if (o) + result = result & ~(NIS_DESTROY_ACC << 16); + if (g) + result = result & ~(NIS_DESTROY_ACC << 8); + if (w) + result = result & ~(NIS_DESTROY_ACC); + break; + default: + return (~0U); + } + cptr++; + } + n = o = g = w = 0; + break; + case '+': + cptr++; /* Remove "+" from beginning */ + while (*cptr != '\0' && *cptr != ',') + { + switch (*cptr) + { + case 'r': + if (n) + result = result | (NIS_READ_ACC << 24); + if (o) + result = result | (NIS_READ_ACC << 16); + if (g) + result = result | (NIS_READ_ACC << 8); + if (w) + result = result | (NIS_READ_ACC); + break; + case 'm': + if (n) + result = result | (NIS_MODIFY_ACC << 24); + if (o) + result = result | (NIS_MODIFY_ACC << 16); + if (g) + result = result | (NIS_MODIFY_ACC << 8); + if (w) + result = result | (NIS_MODIFY_ACC); + break; + case 'c': + if (n) + result = result | (NIS_CREATE_ACC << 24); + if (o) + result = result | (NIS_CREATE_ACC << 16); + if (g) + result = result | (NIS_CREATE_ACC << 8); + if (w) + result = result | (NIS_CREATE_ACC); + break; + case 'd': + if (n) + result = result | (NIS_DESTROY_ACC << 24); + if (o) + result = result | (NIS_DESTROY_ACC << 16); + if (g) + result = result | (NIS_DESTROY_ACC << 8); + if (w) + result = result | (NIS_DESTROY_ACC); + break; + default: + return (~0U); + } + cptr++; + } + n = o = g = w = 0; + break; + case '=': + cptr++; /* Remove "=" from beginning */ + /* Clear */ + if (n) + result = result & ~((NIS_READ_ACC + NIS_MODIFY_ACC + + NIS_CREATE_ACC + NIS_DESTROY_ACC) << 24); + + if (o) + result = result & ~((NIS_READ_ACC + NIS_MODIFY_ACC + + NIS_CREATE_ACC + NIS_DESTROY_ACC) << 16); + if (g) + result = result & ~((NIS_READ_ACC + NIS_MODIFY_ACC + + NIS_CREATE_ACC + NIS_DESTROY_ACC) << 8); + if (w) + result = result & ~(NIS_READ_ACC + NIS_MODIFY_ACC + + NIS_CREATE_ACC + NIS_DESTROY_ACC); + while (*cptr != '\0' && *cptr != ',') + { + switch (*cptr) + { + case 'r': + if (n) + result = result | (NIS_READ_ACC << 24); + if (o) + result = result | (NIS_READ_ACC << 16); + if (g) + result = result | (NIS_READ_ACC << 8); + if (w) + result = result | (NIS_READ_ACC); + break; + case 'm': + if (n) + result = result | (NIS_MODIFY_ACC << 24); + if (o) + result = result | (NIS_MODIFY_ACC << 16); + if (g) + result = result | (NIS_MODIFY_ACC << 8); + if (w) + result = result | (NIS_MODIFY_ACC); + break; + case 'c': + if (n) + result = result | (NIS_CREATE_ACC << 24); + if (o) + result = result | (NIS_CREATE_ACC << 16); + if (g) + result = result | (NIS_CREATE_ACC << 8); + if (w) + result = result | (NIS_CREATE_ACC); + break; + case 'd': + if (n) + result = result | (NIS_DESTROY_ACC << 24); + if (o) + result = result | (NIS_DESTROY_ACC << 16); + if (g) + result = result | (NIS_DESTROY_ACC << 8); + if (w) + result = result | (NIS_DESTROY_ACC); + break; + default: + return result = (~0U); + } + cptr++; + } + n = o = g = w = 0; + break; + default: + return result = (~0U); + } + if (*cptr != '\0') + cptr++; + } + + return result; +} + + +nis_name +__nis_default_owner (char *defaults) +{ + char *default_owner = NULL; + + char *cptr = defaults; + if (cptr == NULL) + cptr = getenv ("NIS_DEFAULTS"); + + if (cptr != NULL) + { + char *dptr = strstr (cptr, "owner="); + if (dptr != NULL) + { + char *p = searchowner (dptr); + if (p == NULL) + return NULL; + default_owner = strdupa (p); + free (p); + } + } + + return strdup (default_owner ?: nis_local_principal ()); +} +libnsl_hidden_nolink_def (__nis_default_owner, GLIBC_2_1) + + +nis_name +__nis_default_group (char *defaults) +{ + char *default_group = NULL; + + char *cptr = defaults; + if (cptr == NULL) + cptr = getenv ("NIS_DEFAULTS"); + + if (cptr != NULL) + { + char *dptr = strstr (cptr, "group="); + if (dptr != NULL) + { + char *p = searchgroup (dptr); + if (p == NULL) + return NULL; + default_group = strdupa (p); + free (p); + } + } + + return strdup (default_group ?: nis_local_group ()); +} +libnsl_hidden_nolink_def (__nis_default_group, GLIBC_2_1) + + +uint32_t +__nis_default_ttl (char *defaults) +{ + char *cptr, *dptr; + + if (defaults != NULL) + { + dptr = strstr (defaults, "ttl="); + if (dptr != NULL) + return searchttl (defaults); + } + + cptr = getenv ("NIS_DEFAULTS"); + if (cptr == NULL) + return DEFAULT_TTL; + + dptr = strstr (cptr, "ttl="); + if (dptr == NULL) + return DEFAULT_TTL; + + return searchttl (cptr); +} + +/* Default access rights are ----rmcdr---r---, but we could change + this with the NIS_DEFAULTS variable. */ +unsigned int +__nis_default_access (char *param, unsigned int defaults) +{ + unsigned int result; + char *cptr; + + if (defaults == 0) + result = 0 | OWNER_DEFAULT | GROUP_DEFAULT | WORLD_DEFAULT; + else + result = defaults; + + if (param != NULL && strstr (param, "access=") != NULL) + result = searchaccess (param, result); + else + { + cptr = getenv ("NIS_DEFAULTS"); + if (cptr != NULL && strstr (cptr, "access=") != NULL) + result = searchaccess (cptr, result); + } + + return result; +} +libnsl_hidden_nolink_def (__nis_default_access, GLIBC_2_1) diff --git a/REORG.TODO/nis/nis_destroygroup.c b/REORG.TODO/nis/nis_destroygroup.c new file mode 100644 index 0000000000..fbcd5efddf --- /dev/null +++ b/REORG.TODO/nis/nis_destroygroup.c @@ -0,0 +1,53 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> +#include <rpcsvc/nis.h> +#include <shlib-compat.h> + +nis_error +nis_destroygroup (const_nis_name group) +{ + if (group != NULL && group[0] != '\0') + { + size_t grouplen = strlen (group); + char buf[grouplen + 50]; + char leafbuf[grouplen + 3]; + char domainbuf[grouplen + 3]; + nis_error status; + nis_result *res; + char *cp, *cp2; + + cp = stpcpy (buf, nis_leaf_of_r (group, leafbuf, sizeof (leafbuf) - 1)); + cp = stpcpy (cp, ".groups_dir"); + cp2 = nis_domain_of_r (group, domainbuf, sizeof (domainbuf) - 1); + if (cp2 != NULL && cp2[0] != '\0') + { + *cp++ = '.'; + stpcpy (cp, cp2); + } + res = nis_remove (buf, NULL); + status = NIS_RES_STATUS (res); + nis_freeresult (res); + return status; + } + else + return NIS_FAIL; + +} +libnsl_hidden_nolink_def (nis_destroygroup, GLIBC_2_1) diff --git a/REORG.TODO/nis/nis_domain_of.c b/REORG.TODO/nis/nis_domain_of.c new file mode 100644 index 0000000000..68d958f75e --- /dev/null +++ b/REORG.TODO/nis/nis_domain_of.c @@ -0,0 +1,43 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <rpcsvc/nis.h> +#include <shlib-compat.h> + +nis_name +nis_domain_of (const_nis_name name) +{ + static char result[NIS_MAXNAMELEN + 1]; + + return nis_domain_of_r (name, result, NIS_MAXNAMELEN); +} +libnsl_hidden_nolink_def (nis_domain_of, GLIBC_2_1) + +const_nis_name +__nis_domain_of (const_nis_name name) +{ + const_nis_name cptr = strchr (name, '.'); + + if (cptr == NULL) + return ""; + + if (*++cptr == '\0') + return "."; + + return cptr; +} diff --git a/REORG.TODO/nis/nis_domain_of_r.c b/REORG.TODO/nis/nis_domain_of_r.c new file mode 100644 index 0000000000..9711eca605 --- /dev/null +++ b/REORG.TODO/nis/nis_domain_of_r.c @@ -0,0 +1,62 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <string.h> +#include <rpcsvc/nis.h> +#include <shlib-compat.h> + +nis_name +nis_domain_of_r (const_nis_name name, char *buffer, size_t buflen) +{ + char *cptr; + size_t cptr_len; + + if (buffer == NULL) + { + erange: + __set_errno (ERANGE); + return NULL; + } + + buffer[0] = '\0'; + + cptr = strchr (name, '.'); + + if (cptr == NULL) + return buffer; + + ++cptr; + cptr_len = strlen (cptr); + + if (cptr_len == 0) + { + if (buflen < 2) + goto erange; + return strcpy (buffer, "."); + } + + if (__glibc_unlikely (cptr_len >= buflen)) + { + __set_errno (ERANGE); + return NULL; + } + + return memcpy (buffer, cptr, cptr_len + 1); +} +libnsl_hidden_nolink_def (nis_domain_of_r, GLIBC_2_1) diff --git a/REORG.TODO/nis/nis_error.c b/REORG.TODO/nis/nis_error.c new file mode 100644 index 0000000000..32b2a100f6 --- /dev/null +++ b/REORG.TODO/nis/nis_error.c @@ -0,0 +1,101 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <syslog.h> +#include <string.h> +#include <libintl.h> +#include <rpcsvc/nis.h> +#include <shlib-compat.h> + + +#define MF(line) MF1 (line) +#define MF1(line) str##line +static const union msgstr_t +{ + struct + { +#define S(s) char MF(__LINE__)[sizeof (s)]; +#include "nis_error.h" +#undef S + }; + char str[0]; +} msgstr = + { + { +#define S(s) s, +#include "nis_error.h" +#undef S + } + }; + +static const unsigned short int msgidx[] = + { +#define S(s) offsetof (union msgstr_t, MF (__LINE__)), +#include "nis_error.h" +#undef S + }; + + +const char * +nis_sperrno (const nis_error status) +{ + if (status >= sizeof (msgidx) / sizeof (msgidx[0])) + return "???"; + else + return gettext (msgstr.str + msgidx[status]); +} +libnsl_hidden_nolink_def (nis_sperrno, GLIBC_2_1) + +void +nis_perror (const nis_error status, const char *label) +{ + fprintf (stderr, "%s: %s\n", label, nis_sperrno (status)); +} +libnsl_hidden_nolink_def (nis_perror, GLIBC_2_1) + +void +nis_lerror (const nis_error status, const char *label) +{ + syslog (LOG_ERR, "%s: %s", label, nis_sperrno (status)); +} +libnsl_hidden_nolink_def (nis_lerror, GLIBC_2_1) + +char * +nis_sperror_r (const nis_error status, const char *label, + char *buffer, size_t buflen) +{ + if (snprintf (buffer, buflen, "%s: %s", label, nis_sperrno (status)) + >= buflen) + { + __set_errno (ERANGE); + return NULL; + } + + return buffer; +} +libnsl_hidden_nolink_def (nis_sperror_r, GLIBC_2_1) + +char * +nis_sperror (const nis_error status, const char *label) +{ + static char buffer[NIS_MAXNAMELEN + 1]; + + return nis_sperror_r (status, label, buffer, sizeof (buffer)); +} +libnsl_hidden_nolink_def (nis_sperror, GLIBC_2_1) diff --git a/REORG.TODO/nis/nis_error.h b/REORG.TODO/nis/nis_error.h new file mode 100644 index 0000000000..add1316d9f --- /dev/null +++ b/REORG.TODO/nis/nis_error.h @@ -0,0 +1,48 @@ +S(N_("Success")) +S(N_("Probable success")) +S(N_("Not found")) +S(N_("Probably not found")) +S(N_("Cache expired")) +S(N_("NIS+ servers unreachable")) +S(N_("Unknown object")) +S(N_("Server busy, try again")) +S(N_("Generic system error")) +S(N_("First/next chain broken")) +S(N_("Permission denied")) +S(N_("Not owner")) +S(N_("Name not served by this server")) +S(N_("Server out of memory")) +S(N_("Object with same name exists")) +S(N_("Not master server for this domain")) +S(N_("Invalid object for operation")) +S(N_("Malformed name, or illegal name")) +S(N_("Unable to create callback")) +S(N_("Results sent to callback proc")) +S(N_("Not found, no such name")) +S(N_("Name/entry isn't unique")) +S(N_("Modification failed")) +S(N_("Database for table does not exist")) +S(N_("Entry/table type mismatch")) +S(N_("Link points to illegal name")) +S(N_("Partial success")) +S(N_("Too many attributes")) +S(N_("Error in RPC subsystem")) +S(N_("Missing or malformed attribute")) +S(N_("Named object is not searchable")) +S(N_("Error while talking to callback proc")) +S(N_("Non NIS+ namespace encountered")) +S(N_("Illegal object type for operation")) +S(N_("Passed object is not the same object on server")) +S(N_("Modify operation failed")) +S(N_("Query illegal for named table")) +S(N_("Attempt to remove a non-empty table")) +S(N_("Error in accessing NIS+ cold start file. Is NIS+ installed?")) +S(N_("Full resync required for directory")) +S(N_("NIS+ operation failed")) +S(N_("NIS+ service is unavailable or not installed")) +S(N_("Yes, 42 is the meaning of life")) +S(N_("Unable to authenticate NIS+ server")) +S(N_("Unable to authenticate NIS+ client")) +S(N_("No file space on server")) +S(N_("Unable to create process on server")) +S(N_("Master server busy, full dump rescheduled.")) diff --git a/REORG.TODO/nis/nis_file.c b/REORG.TODO/nis/nis_file.c new file mode 100644 index 0000000000..d6c1d14aae --- /dev/null +++ b/REORG.TODO/nis/nis_file.c @@ -0,0 +1,106 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <rpcsvc/nis.h> +#include <shlib-compat.h> +#include "nis_xdr.h" + +typedef bool_t (*iofct_t) (XDR *, void *); +typedef void (*freefct_t) (void *); + + +static void * +read_nis_obj (const char *name, iofct_t readfct, freefct_t freefct, + size_t objsize) +{ + FILE *in = fopen (name, "rce"); + if (in == NULL) + return NULL; + + void *obj = calloc (1, objsize); + + if (obj != NULL) + { + XDR xdrs; + xdrstdio_create (&xdrs, in, XDR_DECODE); + bool_t status = readfct (&xdrs, obj); + xdr_destroy (&xdrs); + + if (!status) + { + freefct (obj); + obj = NULL; + } + } + + fclose (in); + + return obj; +} + +static bool_t +write_nis_obj (const char *name, const void *obj, iofct_t writefct) +{ + FILE *out = fopen (name, "wce"); + if (out == NULL) + return FALSE; + + XDR xdrs; + xdrstdio_create (&xdrs, out, XDR_ENCODE); + bool_t status = writefct (&xdrs, (void *) obj); + xdr_destroy (&xdrs); + fclose (out); + + return status; +} + + +static const char cold_start_file[] = "/var/nis/NIS_COLD_START"; + +directory_obj * +readColdStartFile (void) +{ + return read_nis_obj (cold_start_file, (iofct_t) _xdr_directory_obj, + (freefct_t) nis_free_directory, sizeof (directory_obj)); +} +libnsl_hidden_nolink_def (readColdStartFile, GLIBC_2_1) + +bool_t +writeColdStartFile (const directory_obj *obj) +{ + return write_nis_obj (cold_start_file, obj, (iofct_t) _xdr_directory_obj); +} +libnsl_hidden_nolink_def (writeColdStartFile, GLIBC_2_1) + +nis_object * +nis_read_obj (const char *name) +{ + return read_nis_obj (name, (iofct_t) _xdr_nis_object, + (freefct_t) nis_free_object, sizeof (nis_object)); +} +libnsl_hidden_nolink_def (nis_read_obj, GLIBC_2_1) + +bool_t +nis_write_obj (const char *name, const nis_object *obj) +{ + return write_nis_obj (name, obj, (iofct_t) _xdr_nis_object); +} +libnsl_hidden_nolink_def (nis_write_obj, GLIBC_2_1) diff --git a/REORG.TODO/nis/nis_findserv.c b/REORG.TODO/nis/nis_findserv.c new file mode 100644 index 0000000000..8e01164e3d --- /dev/null +++ b/REORG.TODO/nis/nis_findserv.c @@ -0,0 +1,218 @@ +/* Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <rpc/pmap_prot.h> +#include <rpc/pmap_clnt.h> +#include <rpcsvc/nis.h> + +#include "nis_intern.h" + +/* Private data kept per client handle, from sunrpc/clnt_udp.c */ +struct cu_data + { + int cu_sock; + bool_t cu_closeit; + struct sockaddr_in cu_raddr; + int cu_rlen; + struct timeval cu_wait; + struct timeval cu_total; + struct rpc_err cu_error; + XDR cu_outxdrs; + u_int cu_xdrpos; + u_int cu_sendsz; + char *cu_outbuf; + u_int cu_recvsz; + char cu_inbuf[1]; + }; + + +/* + * Find the mapped port for program,version. + * Calls the pmap service remotely to do the lookup. + * Returns 0 if no map exists. + */ +u_short +__pmap_getnisport (struct sockaddr_in *address, u_long program, + u_long version, u_int protocol) +{ + return __libc_rpc_getport (address, program, version, protocol, 1, 1); +} + +/* This is now the public function, which should find the fastest server */ + +struct findserv_req +{ + struct sockaddr_in sin; + u_int32_t xid; + u_int server_nr; + u_int server_ep; +}; + + +static long int +__nis_findfastest_with_timeout (dir_binding *bind, + const struct timeval *timeout) +{ + static const struct timeval TIMEOUT00 = { 0, 0 }; + struct findserv_req *pings; + struct sockaddr_in sin, saved_sin; + int found = -1; + u_int32_t xid_seed; + int sock, dontblock = 1; + CLIENT *clnt; + u_long i, j, pings_count, pings_max, fastest = -1; + struct cu_data *cu; + + pings_max = bind->server_len * 2; /* Reserve a little bit more memory + for multihomed hosts */ + pings_count = 0; + pings = malloc (sizeof (struct findserv_req) * pings_max); + xid_seed = (u_int32_t) (time (NULL) ^ getpid ()); + + if (__glibc_unlikely (pings == NULL)) + return -1; + + memset (&sin, '\0', sizeof (sin)); + sin.sin_family = AF_INET; + for (i = 0; i < bind->server_len; i++) + for (j = 0; j < bind->server_val[i].ep.ep_len; ++j) + if (strcmp (bind->server_val[i].ep.ep_val[j].family, "inet") == 0) + if ((bind->server_val[i].ep.ep_val[j].proto == NULL) || + (bind->server_val[i].ep.ep_val[j].proto[0] == '-') || + (bind->server_val[i].ep.ep_val[j].proto[0] == '\0')) + { + sin.sin_addr.s_addr = + inetstr2int (bind->server_val[i].ep.ep_val[j].uaddr); + if (sin.sin_addr.s_addr == 0) + continue; + sin.sin_port = htons (__pmap_getnisport (&sin, NIS_PROG, + NIS_VERSION, + IPPROTO_UDP)); + if (sin.sin_port == 0) + continue; + + if (pings_count >= pings_max) + { + struct findserv_req *new_pings; + + pings_max += 10; + new_pings = realloc (pings, sizeof (struct findserv_req) * + pings_max); + if (__glibc_unlikely (new_pings == NULL)) + { + free (pings); + return -1; + } + pings = new_pings; + } + memcpy ((char *) &pings[pings_count].sin, (char *) &sin, + sizeof (sin)); + memcpy ((char *)&saved_sin, (char *)&sin, sizeof(sin)); + pings[pings_count].xid = xid_seed + pings_count; + pings[pings_count].server_nr = i; + pings[pings_count].server_ep = j; + ++pings_count; + } + + /* Make sure at least one server was assigned */ + if (pings_count == 0) + { + free (pings); + return -1; + } + + /* Create RPC handle */ + sock = socket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP); + clnt = clntudp_create (&saved_sin, NIS_PROG, NIS_VERSION, *timeout, &sock); + if (clnt == NULL) + { + close (sock); + free (pings); + return -1; + } + auth_destroy (clnt->cl_auth); + clnt->cl_auth = authunix_create_default (); + cu = (struct cu_data *) clnt->cl_private; + ioctl (sock, FIONBIO, &dontblock); + /* Send to all servers the NULLPROC */ + for (i = 0; i < pings_count; ++i) + { + /* clntudp_call() will increment, subtract one */ + *((u_int32_t *) (cu->cu_outbuf)) = pings[i].xid - 1; + memcpy ((char *) &cu->cu_raddr, (char *) &pings[i].sin, + sizeof (struct sockaddr_in)); + /* Transmit to NULLPROC, return immediately. */ + clnt_call (clnt, NULLPROC, + (xdrproc_t) xdr_void, (caddr_t) 0, + (xdrproc_t) xdr_void, (caddr_t) 0, TIMEOUT00); + } + + while (found == -1) { + /* Receive reply from NULLPROC asynchronously. Note null inproc. */ + int rc = clnt_call (clnt, NULLPROC, + (xdrproc_t) NULL, (caddr_t) 0, + (xdrproc_t) xdr_void, (caddr_t) 0, + *timeout); + if (RPC_SUCCESS == rc) { + u_int32_t val; + memcpy (&val, cu->cu_inbuf, sizeof (u_int32_t)); + fastest = val - xid_seed; + if (fastest < pings_count) { + bind->server_used = pings[fastest].server_nr; + bind->current_ep = pings[fastest].server_ep; + found = 1; + } + } else { + /* clnt_perror(clnt, "__nis_findfastest"); */ + break; + } + } + + + auth_destroy (clnt->cl_auth); + clnt_destroy (clnt); + close (sock); + + free (pings); + + return found; +} + + +long int +__nis_findfastest (dir_binding *bind) +{ + struct timeval timeout = { __NIS_PING_TIMEOUT_START, 0 }; + long int found = -1; + long int retry = __NIS_PING_RETRY + 1; + + while (retry--) + { + found = __nis_findfastest_with_timeout (bind, &timeout); + if (found != -1) + break; + timeout.tv_sec += __NIS_PING_TIMEOUT_INCREMENT; + } + + return found; +} diff --git a/REORG.TODO/nis/nis_free.c b/REORG.TODO/nis/nis_free.c new file mode 100644 index 0000000000..1d3298f2a9 --- /dev/null +++ b/REORG.TODO/nis/nis_free.c @@ -0,0 +1,76 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <rpcsvc/nis.h> +#include <shlib-compat.h> +#include "nis_xdr.h" + +void +__free_fdresult (fd_result *res) +{ + if (res != NULL) + { + xdr_free ((xdrproc_t)_xdr_fd_result, (char *)res); + free (res); + } +} +libnsl_hidden_nolink_def (__free_fdresult, GLIBC_2_1) + +void +nis_free_request (ib_request *ibreq) +{ + if (ibreq != NULL) + { + xdr_free ((xdrproc_t)_xdr_ib_request, (char *)ibreq); + free (ibreq); + } +} +libnsl_hidden_nolink_def (nis_free_request, GLIBC_2_1) + +void +nis_free_directory (directory_obj *obj) +{ + if (obj != NULL) + { + xdr_free ((xdrproc_t)_xdr_directory_obj, (char *)obj); + free (obj); + } +} +libnsl_hidden_nolink_def (nis_free_directory, GLIBC_2_1) + +void +nis_free_object (nis_object *obj) +{ + if (obj != NULL) + { + xdr_free ((xdrproc_t)_xdr_nis_object, (char *)obj); + free (obj); + } +} +libnsl_hidden_nolink_def (nis_free_object, GLIBC_2_1) + +void +nis_freeresult (nis_result *res) +{ + if (res != NULL) + { + xdr_free ((xdrproc_t)_xdr_nis_result, (char *)res); + free (res); + } +} +libnsl_hidden_nolink_def (nis_freeresult, GLIBC_2_1) diff --git a/REORG.TODO/nis/nis_getservlist.c b/REORG.TODO/nis/nis_getservlist.c new file mode 100644 index 0000000000..fba18c77ca --- /dev/null +++ b/REORG.TODO/nis/nis_getservlist.c @@ -0,0 +1,171 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> +#include <rpcsvc/nis.h> +#include <shlib-compat.h> + +#include "nis_xdr.h" +#include "nis_intern.h" + +nis_server ** +nis_getservlist (const_nis_name dir) +{ + nis_result *res; + nis_server **serv; + + res = nis_lookup (dir, FOLLOW_LINKS); + + if (res != NULL && NIS_RES_STATUS (res) == NIS_SUCCESS) + { + unsigned long i; + nis_server *server; + + serv = + malloc (sizeof (nis_server *) * + (NIS_RES_OBJECT (res)->DI_data.do_servers.do_servers_len + 1)); + if (__glibc_unlikely (serv == NULL)) + { + nis_freeresult (res); + return NULL; + } + + for (i = 0; i < NIS_RES_OBJECT (res)->DI_data.do_servers.do_servers_len; + ++i) + { + server = + &NIS_RES_OBJECT (res)->DI_data.do_servers.do_servers_val[i]; + serv[i] = calloc (1, sizeof (nis_server)); + if (__glibc_unlikely (serv[i] == NULL)) + { + free_all: + while (i-- > 0) + { + free (serv[i]->pkey.n_bytes); + if (serv[i]->ep.ep_val != NULL) + { + unsigned long int j; + for (j = 0; j < serv[i]->ep.ep_len; ++j) + { + free (serv[i]->ep.ep_val[j].proto); + free (serv[i]->ep.ep_val[j].family); + free (serv[i]->ep.ep_val[j].uaddr); + } + free (serv[i]->ep.ep_val); + } + free (serv[i]->name); + free (serv[i]); + } + + free (serv); + + nis_freeresult (res); + + return NULL; + } + + if (server->name != NULL) + { + serv[i]->name = strdup (server->name); + if (__glibc_unlikely (serv[i]->name == NULL)) + { + ++i; + goto free_all; + } + } + + serv[i]->ep.ep_len = server->ep.ep_len; + if (serv[i]->ep.ep_len > 0) + { + unsigned long int j; + + serv[i]->ep.ep_val = + malloc (server->ep.ep_len * sizeof (endpoint)); + if (__glibc_unlikely (serv[i]->ep.ep_val == NULL)) + { + ++i; + goto free_all; + } + + for (j = 0; j < serv[i]->ep.ep_len; ++j) + { + if (server->ep.ep_val[j].uaddr) + serv[i]->ep.ep_val[j].uaddr = + strdup (server->ep.ep_val[j].uaddr); + else + serv[i]->ep.ep_val[j].uaddr = NULL; + if (server->ep.ep_val[j].family) + serv[i]->ep.ep_val[j].family = + strdup (server->ep.ep_val[j].family); + else + serv[i]->ep.ep_val[j].family = NULL; + if (server->ep.ep_val[j].proto) + serv[i]->ep.ep_val[j].proto = + strdup (server->ep.ep_val[j].proto); + else + serv[i]->ep.ep_val[j].proto = NULL; + } + } + + serv[i]->key_type = server->key_type; + serv[i]->pkey.n_len = server->pkey.n_len; + if (server->pkey.n_len > 0) + { + serv[i]->pkey.n_bytes = malloc (server->pkey.n_len); + if (__glibc_unlikely (serv[i]->pkey.n_bytes == NULL)) + { + ++i; + goto free_all; + } + memcpy (serv[i]->pkey.n_bytes, server->pkey.n_bytes, + server->pkey.n_len); + } + } + serv[i] = NULL; + } + else + { + serv = malloc (sizeof (nis_server *)); + if (__glibc_unlikely (serv != NULL)) + serv[0] = NULL; + } + + nis_freeresult (res); + + return serv; +} +libnsl_hidden_nolink_def (nis_getservlist, GLIBC_2_1) + +void +nis_freeservlist (nis_server **serv) +{ + int i; + + if (serv == NULL) + return; + + i = 0; + while (serv[i] != NULL) + { + xdr_free ((xdrproc_t)_xdr_nis_server, (char *)serv[i]); + free (serv[i]); + ++i; + } + free (serv); +} +libnsl_hidden_nolink_def (nis_freeservlist, GLIBC_2_1) diff --git a/REORG.TODO/nis/nis_hash.c b/REORG.TODO/nis/nis_hash.c new file mode 100644 index 0000000000..cc42ac8911 --- /dev/null +++ b/REORG.TODO/nis/nis_hash.c @@ -0,0 +1,76 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <stdint.h> +#include <rpcsvc/nis.h> + +/* This is from libc/db/hash/hash_func.c, hash3 is static there */ +/* + * This is INCREDIBLY ugly, but fast. We break the string up into 8 byte + * units. On the first time through the loop we get the "leftover bytes" + * (strlen % 8). On every other iteration, we perform 8 HASHC's so we handle + * all 8 bytes. Essentially, this saves us 7 cmp & branch instructions. If + * this routine is heavily used enough, it's worth the ugly coding. + * + * OZ's original sdbm hash + */ +uint32_t +__nis_hash (const void *keyarg, size_t len) +{ + const u_char *key; + size_t loop; + uint32_t h; + +#define HASHC h = *key++ + 65599 * h + + h = 0; + key = keyarg; + if (len > 0) + { + loop = (len + 8 - 1) >> 3; + switch (len & (8 - 1)) + { + case 0: + do { + HASHC; + /* FALLTHROUGH */ + case 7: + HASHC; + /* FALLTHROUGH */ + case 6: + HASHC; + /* FALLTHROUGH */ + case 5: + HASHC; + /* FALLTHROUGH */ + case 4: + HASHC; + /* FALLTHROUGH */ + case 3: + HASHC; + /* FALLTHROUGH */ + case 2: + HASHC; + /* FALLTHROUGH */ + case 1: + HASHC; + } while (--loop); + } + } + return h; +} diff --git a/REORG.TODO/nis/nis_intern.h b/REORG.TODO/nis/nis_intern.h new file mode 100644 index 0000000000..a541c287cf --- /dev/null +++ b/REORG.TODO/nis/nis_intern.h @@ -0,0 +1,83 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef __NIS_INTERN_H + +#define __NIS_INTERN_H +#include <features.h> + +/* Configurable parameters for pinging NIS servers: */ + +/* Number of retries. */ +#ifndef __NIS_PING_RETRY +# define __NIS_PING_RETRY 2 +#endif +/* Initial timeout in seconds. */ +#ifndef __NIS_PING_TIMEOUT_START +# define __NIS_PING_TIMEOUT_START 3 +#endif +/* Timeout increment for retries in seconds. */ +#ifndef __NIS_PING_TIMEOUT_INCREMENT +# define __NIS_PING_TIMEOUT_INCREMENT 3 +#endif + + +__BEGIN_DECLS + +struct nis_cb + { + nis_server *serv; + SVCXPRT *xprt; + int sock; + int nomore; + nis_error result; + int (*callback) (const_nis_name, const nis_object *, const void *); + const void *userdata; + }; +typedef struct nis_cb nis_cb; + +extern unsigned long int inetstr2int (const char *str); +extern long int __nis_findfastest (dir_binding *bind); +extern nis_error __do_niscall2 (const nis_server *serv, u_int serv_len, + u_long prog, xdrproc_t xargs, caddr_t req, + xdrproc_t xres, caddr_t resp, + unsigned int flags, nis_cb *cb); +extern nis_error __do_niscall (const_nis_name name, u_long prog, + xdrproc_t xargs, caddr_t req, + xdrproc_t xres, caddr_t resp, + unsigned int flags, nis_cb *cb); +extern nis_error __do_niscall3 (dir_binding *dbp, u_long prog, + xdrproc_t xargs, caddr_t req, + xdrproc_t xres, caddr_t resp, + unsigned int flags, nis_cb *cb); +libnsl_hidden_proto (__do_niscall3) + +extern u_short __pmap_getnisport (struct sockaddr_in *address, u_long program, + u_long version, u_int protocol); + +/* NIS+ callback */ +extern nis_error __nis_do_callback (struct dir_binding *bptr, + netobj *cookie, struct nis_cb *cb); +extern struct nis_cb *__nis_create_callback + (int (*callback)(const_nis_name, const nis_object *, const void *), + const void *userdata, unsigned int flags); +extern nis_error __nis_destroy_callback (struct nis_cb *cb); + +__END_DECLS + +#endif diff --git a/REORG.TODO/nis/nis_ismember.c b/REORG.TODO/nis/nis_ismember.c new file mode 100644 index 0000000000..5aba3367f5 --- /dev/null +++ b/REORG.TODO/nis/nis_ismember.c @@ -0,0 +1,150 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> +#include <rpcsvc/nis.h> +#include <shlib-compat.h> + +/* internal_nis_ismember () + return codes: -1 principal is in -group + 0 principal isn't in any group + 1 pirncipal is in group */ +static int +internal_ismember (const_nis_name principal, const_nis_name group) +{ + size_t grouplen = strlen (group); + char buf[grouplen + 50]; + char leafbuf[grouplen + 2]; + char domainbuf[grouplen + 2]; + nis_result *res; + char *cp, *cp2; + u_int i; + + cp = stpcpy (buf, nis_leaf_of_r (group, leafbuf, sizeof (leafbuf) - 1)); + cp = stpcpy (cp, ".groups_dir"); + cp2 = nis_domain_of_r (group, domainbuf, sizeof (domainbuf) - 1); + if (cp2 != NULL && cp2[0] != '\0') + { + *cp++ = '.'; + strcpy (cp, cp2); + } + + res = nis_lookup (buf, EXPAND_NAME|FOLLOW_LINKS); + if (res == NULL || NIS_RES_STATUS (res) != NIS_SUCCESS) + { + nis_freeresult (res); + return 0; + } + + if ((NIS_RES_NUMOBJ (res) != 1) || + (__type_of (NIS_RES_OBJECT (res)) != NIS_GROUP_OBJ)) + { + nis_freeresult (res); + return 0; + } + + /* We search twice in the list, at first, if we have the name + with a "-", then if without. "-member" has priority */ + for (i = 0; i < NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_len; ++i) + { + cp = NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val[i]; + if (cp[0] == '-') + { + if (strcmp (&cp[1], principal) == 0) + { + nis_freeresult (res); + return -1; + } + if (cp[1] == '@') + switch (internal_ismember (principal, &cp[2])) + { + case -1: + nis_freeresult (res); + return -1; + case 1: + nis_freeresult (res); + return 1; + default: + break; + } + else + if (cp[1] == '*') + { + char buf1[strlen (principal) + 2]; + char buf2[strlen (cp) + 2]; + + if (strcmp (nis_domain_of_r (principal, buf1, sizeof buf1), + nis_domain_of_r (cp, buf2, sizeof buf2)) == 0) + { + nis_freeresult (res); + return -1; + } + } + } + } + + for (i = 0; i < NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_len; ++i) + { + cp = NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val[i]; + if (cp[0] != '-') + { + if (strcmp (cp, principal) == 0) + { + nis_freeresult (res); + return 1; + } + if (cp[0] == '@') + switch (internal_ismember (principal, &cp[1])) + { + case -1: + nis_freeresult (res); + return -1; + case 1: + nis_freeresult (res); + return 1; + default: + break; + } + else + if (cp[0] == '*') + { + char buf1[strlen (principal) + 2]; + char buf2[strlen (cp) + 2]; + + if (strcmp (nis_domain_of_r (principal, buf1, sizeof buf1), + nis_domain_of_r (cp, buf2, sizeof buf2)) == 0) + { + nis_freeresult (res); + return 1; + } + } + } + } + nis_freeresult (res); + return 0; +} + +bool_t +nis_ismember (const_nis_name principal, const_nis_name group) +{ + if (group != NULL && group[0] != '\0' && principal != NULL) + return internal_ismember (principal, group) == 1 ? TRUE : FALSE; + else + return FALSE; +} +libnsl_hidden_nolink_def (nis_ismember, GLIBC_2_1) diff --git a/REORG.TODO/nis/nis_local_names.c b/REORG.TODO/nis/nis_local_names.c new file mode 100644 index 0000000000..99d8f99e27 --- /dev/null +++ b/REORG.TODO/nis/nis_local_names.c @@ -0,0 +1,178 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include <libintl.h> +#include <rpcsvc/nis.h> +#include <shlib-compat.h> + +nis_name +nis_local_group (void) +{ + static char __nisgroup[NIS_MAXNAMELEN + 1]; + + char *cptr; + if (__nisgroup[0] == '\0' + && (cptr = getenv ("NIS_GROUP")) != NULL + && strlen (cptr) < NIS_MAXNAMELEN) + { + char *cp = stpcpy (__nisgroup, cptr); + + if (cp[-1] != '.') + { + cptr = nis_local_directory (); + if ((cp - __nisgroup) + strlen (cptr) + 1 < NIS_MAXNAMELEN) + { + *cp++ = '.'; + strcpy (cp, cptr); + } + else + __nisgroup[0] = '\0'; + } + } + + return __nisgroup; +} +libnsl_hidden_nolink_def (nis_local_group, GLIBC_2_1) + +nis_name +nis_local_directory (void) +{ + static char __nisdomainname[NIS_MAXNAMELEN + 1]; + + if (__nisdomainname[0] == '\0') + { + if (getdomainname (__nisdomainname, NIS_MAXNAMELEN) < 0) + __nisdomainname[0] = '\0'; + else + { + char *cp = rawmemchr (__nisdomainname, '\0'); + + /* Missing trailing dot? */ + if (cp[-1] != '.') + { + *cp++ = '.'; + *cp = '\0'; + } + } + } + + return __nisdomainname; +} +libnsl_hidden_nolink_def (nis_local_directory, GLIBC_2_1) + +nis_name +nis_local_principal (void) +{ + static char __principal[NIS_MAXNAMELEN + 1]; + + if (__principal[0] == '\0') + { + char buf[NIS_MAXNAMELEN + 1]; + nis_result *res; + uid_t uid = geteuid (); + + if (uid != 0) + { + int len = snprintf (buf, NIS_MAXNAMELEN - 1, + "[auth_name=%d,auth_type=LOCAL],cred.org_dir.%s", + uid, nis_local_directory ()); + + if (len >= NIS_MAXNAMELEN - 1) + nobody: + /* XXX The buffer is too small. Can this happen??? */ + return strcpy (__principal, "nobody"); + + if (buf[len - 1] != '.') + { + buf[len++] = '.'; + buf[len] = '\0'; + } + + res = nis_list (buf, USE_DGRAM + NO_AUTHINFO + FOLLOW_LINKS + + FOLLOW_PATH, NULL, NULL); + + if (res == NULL) + goto nobody; + + if (NIS_RES_STATUS (res) == NIS_SUCCESS) + { + if (res->objects.objects_len > 1) + { + /* More than one principal with same uid? something + wrong with cred table. Should be unique. Warn user + and continue. */ + printf (_("\ +LOCAL entry for UID %d in directory %s not unique\n"), + uid, nis_local_directory ()); + } + strcpy (__principal, ENTRY_VAL (res->objects.objects_val, 0)); + nis_freeresult (res); + return __principal; + } + else + { + nis_freeresult (res); + goto nobody; + } + } + else + return strcpy (__principal, nis_local_host ()); + + /* Should be never reached */ + goto nobody; + } + return __principal; +} +libnsl_hidden_nolink_def (nis_local_principal, GLIBC_2_1) + +nis_name +nis_local_host (void) +{ + static char __nishostname[NIS_MAXNAMELEN + 1]; + + if (__nishostname[0] == '\0') + { + if (gethostname (__nishostname, NIS_MAXNAMELEN) < 0) + __nishostname[0] = '\0'; + else + { + char *cp = rawmemchr (__nishostname, '\0'); + int len = cp - __nishostname; + + /* Hostname already fully qualified? */ + if (cp[-1] == '.') + return __nishostname; + + if (len + strlen (nis_local_directory ()) + 1 > NIS_MAXNAMELEN) + { + __nishostname[0] = '\0'; + return __nishostname; + } + + *cp++ = '.'; + strncpy (cp, nis_local_directory (), NIS_MAXNAMELEN - len -1); + __nishostname[NIS_MAXNAMELEN] = '\0'; + } + } + + return __nishostname; +} +libnsl_hidden_nolink_def (nis_local_host, GLIBC_2_1) diff --git a/REORG.TODO/nis/nis_lookup.c b/REORG.TODO/nis/nis_lookup.c new file mode 100644 index 0000000000..f6d84abecd --- /dev/null +++ b/REORG.TODO/nis/nis_lookup.c @@ -0,0 +1,219 @@ +/* Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> +#include <rpcsvc/nis.h> +#include "nis_xdr.h" +#include "nis_intern.h" +#include <libnsl.h> +#include <shlib-compat.h> + + +nis_result * +nis_lookup (const_nis_name name, const unsigned int flags) +{ + nis_result *res = calloc (1, sizeof (nis_result)); + struct ns_request req; + nis_name *names; + nis_error status; + int link_first_try = 0; + int count_links = 0; /* We will follow only 16 links in the deep */ + int done = 0; + int name_nr = 0; + nis_name namebuf[2] = {NULL, NULL}; + + if (res == NULL) + return NULL; + + if ((flags & EXPAND_NAME) && (name[strlen (name) - 1] != '.')) + { + names = nis_getnames (name); + if (names == NULL) + { + NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE; + return res; + } + } + else + { + names = namebuf; + names[0] = (nis_name)name; + } + + req.ns_name = names[0]; + while (!done) + { + dir_binding bptr; + directory_obj *dir = NULL; + req.ns_object.ns_object_len = 0; + req.ns_object.ns_object_val = NULL; + + status = __prepare_niscall (req.ns_name, &dir, &bptr, flags); + if (__glibc_unlikely (status != NIS_SUCCESS)) + { + NIS_RES_STATUS (res) = status; + goto out; + } + + do + { + static const struct timeval RPCTIMEOUT = {10, 0}; + enum clnt_stat result; + + again: + result = clnt_call (bptr.clnt, NIS_LOOKUP, + (xdrproc_t) _xdr_ns_request, + (caddr_t) &req, (xdrproc_t) _xdr_nis_result, + (caddr_t) res, RPCTIMEOUT); + + if (result != RPC_SUCCESS) + status = NIS_RPCERROR; + else + { + status = NIS_SUCCESS; + + if (NIS_RES_STATUS (res) == NIS_SUCCESS) + { + if (__type_of (NIS_RES_OBJECT (res)) == NIS_LINK_OBJ + && (flags & FOLLOW_LINKS)) /* We are following links */ + { + /* if we hit the link limit, bail */ + if (count_links > NIS_MAXLINKS) + { + NIS_RES_STATUS (res) = NIS_LINKNAMEERROR; + break; + } + ++count_links; + req.ns_name = + strdupa (NIS_RES_OBJECT (res)->LI_data.li_name); + + /* The following is a non-obvious optimization. A + nis_freeresult call would call xdr_free as the + following code. But it also would unnecessarily + free the result structure. We avoid this here + along with the necessary tests. */ + xdr_free ((xdrproc_t) _xdr_nis_result, (char *) res); + memset (res, '\0', sizeof (*res)); + + link_first_try = 1; /* Try at first the old binding */ + goto again; + } + } + else + if (NIS_RES_STATUS (res) == NIS_SYSTEMERROR + || NIS_RES_STATUS (res) == NIS_NOSUCHNAME + || NIS_RES_STATUS (res) == NIS_NOT_ME) + { + if (link_first_try) + { + __nisbind_destroy (&bptr); + nis_free_directory (dir); + /* Otherwise __nisfind_server will not do anything. */ + dir = NULL; + + if (__nisfind_server (req.ns_name, 1, &dir, &bptr, + flags & ~MASTER_ONLY) + != NIS_SUCCESS) + goto out; + } + else + if (__nisbind_next (&bptr) != NIS_SUCCESS) + { + /* No more servers to search. Try parent. */ + const char *ndomain = __nis_domain_of (req.ns_name); + req.ns_name = strdupa (ndomain); + if (strcmp (req.ns_name, ".") == 0) + { + NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE; + goto out; + } + + __nisbind_destroy (&bptr); + nis_free_directory (dir); + dir = NULL; + status = __prepare_niscall (req.ns_name, &dir, + &bptr, flags); + if (__glibc_unlikely (status != NIS_SUCCESS)) + { + NIS_RES_STATUS (res) = status; + goto out; + } + goto again; + } + + while (__nisbind_connect (&bptr) != NIS_SUCCESS) + { + if (__nisbind_next (&bptr) != NIS_SUCCESS) + { + nis_free_directory (dir); + goto out; + } + } + goto again; + } + break; + } + link_first_try = 0; /* Set it back */ + } + while ((flags & HARD_LOOKUP) && status == NIS_RPCERROR); + + __nisbind_destroy (&bptr); + nis_free_directory (dir); + + if (status != NIS_SUCCESS) + { + NIS_RES_STATUS (res) = status; + goto out; + } + + switch (NIS_RES_STATUS (res)) + { + case NIS_PARTIAL: + case NIS_SUCCESS: + case NIS_S_SUCCESS: + case NIS_LINKNAMEERROR: /* We follow to max links */ + case NIS_UNAVAIL: /* NIS+ is not installed, or all servers are down */ + ++done; + break; + default: + /* Try the next domainname if we don't follow a link */ + if (count_links) + { + free (req.ns_name); + NIS_RES_STATUS (res) = NIS_LINKNAMEERROR; + ++done; + break; + } + ++name_nr; + if (names[name_nr] == NULL) + { + ++done; + break; + } + req.ns_name = names[name_nr]; + break; + } + } + + out: + if (names != namebuf) + nis_freenames (names); + + return res; +} +libnsl_hidden_nolink_def (nis_lookup, GLIBC_2_1) diff --git a/REORG.TODO/nis/nis_mkdir.c b/REORG.TODO/nis/nis_mkdir.c new file mode 100644 index 0000000000..da6690cdcb --- /dev/null +++ b/REORG.TODO/nis/nis_mkdir.c @@ -0,0 +1,44 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <rpcsvc/nis.h> +#include <shlib-compat.h> + +#include "nis_xdr.h" +#include "nis_intern.h" + +nis_error +nis_mkdir (const_nis_name dir, const nis_server *server) +{ + nis_error res, res2; + + if (server == NULL) + res2 = __do_niscall (dir, NIS_MKDIR, (xdrproc_t) _xdr_nis_name, + (caddr_t) &dir, (xdrproc_t) _xdr_nis_error, + (caddr_t) &res, 0, NULL); + else + res2 = __do_niscall2 (server, 1, NIS_MKDIR, + (xdrproc_t) _xdr_nis_name, + (caddr_t) &dir, (xdrproc_t) _xdr_nis_error, + (caddr_t) &res, 0, NULL); + if (res2 != NIS_SUCCESS) + return res2; + + return res; +} +libnsl_hidden_nolink_def (nis_mkdir, GLIBC_2_1) diff --git a/REORG.TODO/nis/nis_modify.c b/REORG.TODO/nis/nis_modify.c new file mode 100644 index 0000000000..67315165bc --- /dev/null +++ b/REORG.TODO/nis/nis_modify.c @@ -0,0 +1,75 @@ +/* Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> +#include <rpcsvc/nis.h> +#include <shlib-compat.h> + +#include "nis_xdr.h" +#include "nis_intern.h" + +nis_result * +nis_modify (const_nis_name name, const nis_object *obj2) +{ + nis_object obj; + nis_result *res; + nis_error status; + struct ns_request req; + size_t namelen = strlen (name); + char buf1[namelen + 20]; + char buf4[namelen + 20]; + + res = calloc (1, sizeof (nis_result)); + if (res == NULL) + return NULL; + + req.ns_name = (char *) name; + + memcpy (&obj, obj2, sizeof (nis_object)); + + if (obj.zo_name == NULL || obj.zo_name[0] == '\0') + obj.zo_name = nis_leaf_of_r (name, buf1, sizeof (buf1)); + + if (obj.zo_owner == NULL || obj.zo_owner[0] == '\0') + obj.zo_owner = nis_local_principal (); + + if (obj.zo_group == NULL || obj.zo_group[0] == '\0') + obj.zo_group = nis_local_group (); + + obj.zo_domain = nis_domain_of_r (name, buf4, sizeof (buf4)); + + req.ns_object.ns_object_val = nis_clone_object (&obj, NULL); + if (req.ns_object.ns_object_val == NULL) + { + NIS_RES_STATUS (res) = NIS_NOMEMORY; + return res; + } + req.ns_object.ns_object_len = 1; + + status = __do_niscall (name, NIS_MODIFY, (xdrproc_t) _xdr_ns_request, + (caddr_t) & req, (xdrproc_t) _xdr_nis_result, + (caddr_t) res, MASTER_ONLY, + NULL); + if (status != NIS_SUCCESS) + NIS_RES_STATUS (res) = status; + + nis_destroy_object (req.ns_object.ns_object_val); + + return res; +} +libnsl_hidden_nolink_def (nis_modify, GLIBC_2_1) diff --git a/REORG.TODO/nis/nis_ping.c b/REORG.TODO/nis/nis_ping.c new file mode 100644 index 0000000000..b744898ba2 --- /dev/null +++ b/REORG.TODO/nis/nis_ping.c @@ -0,0 +1,71 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <rpcsvc/nis.h> +#include <shlib-compat.h> + +#include "nis_xdr.h" +#include "nis_intern.h" + +void +nis_ping (const_nis_name dirname, unsigned int utime, + const nis_object *dirobj) +{ + nis_result *res = NULL; + nis_object *obj; + ping_args args; + unsigned int i; + + if (dirname == NULL && dirobj == NULL) + abort (); + + if (dirobj == NULL) + { + res = nis_lookup (dirname, MASTER_ONLY); + if (res == NULL || NIS_RES_STATUS (res) != NIS_SUCCESS) + { + nis_freeresult (res); + return; + } + obj = res->objects.objects_val; + } + else + obj = (nis_object *) dirobj; + + /* Check if obj is really a diryectory object */ + if (__type_of (obj) != NIS_DIRECTORY_OBJ) + { + nis_freeresult (res); + return; + } + + if (dirname == NULL) + args.dir = obj->DI_data.do_name; + else + args.dir = (char *) dirname; + args.stamp = utime; + + /* Send the ping only to replicas */ + for (i = 1; i < obj->DI_data.do_servers.do_servers_len; ++i) + __do_niscall2 (&obj->DI_data.do_servers.do_servers_val[i], 1, + NIS_PING, (xdrproc_t) _xdr_ping_args, + (caddr_t) &args, (xdrproc_t) xdr_void, + (caddr_t) NULL, 0, NULL); + nis_freeresult (res); +} +libnsl_hidden_nolink_def (nis_ping, GLIBC_2_1) diff --git a/REORG.TODO/nis/nis_print.c b/REORG.TODO/nis/nis_print.c new file mode 100644 index 0000000000..869f6aad61 --- /dev/null +++ b/REORG.TODO/nis/nis_print.c @@ -0,0 +1,382 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <time.h> +#include <string.h> +#include <libintl.h> +#include <stdint.h> + +#include <rpcsvc/nis.h> +#include <shlib-compat.h> + +static const char * +nis_nstype2str (const nstype type) +{ + +/* Name service names mustn't be translated, only UNKNOWN needs it */ + + switch (type) + { + case NIS: + return "NIS"; + case SUNYP: + return "SUNYP"; + case IVY: + return "IVY"; + case DNS: + return "DNS"; + case X500: + return "X500"; + case DNANS: + return "DNANS"; + case XCHS: + return "XCHS"; + case CDS: + return "CDS"; + default: + return N_("UNKNOWN"); + } +} + +static void +print_ttl (const uint32_t ttl) +{ + uint32_t time, s, m, h; + + time = ttl; + + h = time / (60 * 60); + time %= (60 * 60); + m = time / 60; + time %= 60; + s = time; + printf ("%u:%u:%u\n", h, m, s); +} + +static void +print_flags (const unsigned int flags) +{ + fputs ("(", stdout); + + if (flags & TA_SEARCHABLE) + fputs ("SEARCHABLE, ", stdout); + + if (flags & TA_BINARY) + { + fputs ("BINARY DATA", stdout); + if (flags & TA_XDR) + fputs (", XDR ENCODED", stdout); + if (flags & TA_ASN1) + fputs (", ASN.1 ENCODED", stdout); + if (flags & TA_CRYPT) + fputs (", ENCRYPTED", stdout); + } + else + { + fputs ("TEXTUAL DATA", stdout); + if (flags & TA_SEARCHABLE) + { + if (flags & TA_CASE) + fputs (", CASE INSENSITIVE", stdout); + else + fputs (", CASE SENSITIVE", stdout); + } + } + + fputs (")\n", stdout); +} + +static void +nis_print_objtype (enum zotypes type) +{ + switch (type) + { + case NIS_BOGUS_OBJ: + fputs (_("BOGUS OBJECT\n"), stdout); + break; + case NIS_NO_OBJ: + fputs (_("NO OBJECT\n"), stdout); + break; + case NIS_DIRECTORY_OBJ: + fputs (_("DIRECTORY\n"), stdout); + break; + case NIS_GROUP_OBJ: + fputs (_("GROUP\n"), stdout); + break; + case NIS_TABLE_OBJ: + fputs (_("TABLE\n"), stdout); + break; + case NIS_ENTRY_OBJ: + fputs (_("ENTRY\n"), stdout); + break; + case NIS_LINK_OBJ: + fputs (_("LINK\n"), stdout); + break; + case NIS_PRIVATE_OBJ: + fputs (_("PRIVATE\n"), stdout); + break; + default: + fputs (_("(Unknown object)\n"), stdout); + break; + } +} + +void +nis_print_rights (const unsigned int access) +{ + char result[17]; + unsigned int acc; + int i; + + acc = access; /* Parameter is const ! */ + result[i = 16] = '\0'; + while (i > 0) + { + i -= 4; + result[i + 0] = (acc & NIS_READ_ACC) ? 'r' : '-'; + result[i + 1] = (acc & NIS_MODIFY_ACC) ? 'm' : '-'; + result[i + 2] = (acc & NIS_CREATE_ACC) ? 'c' : '-'; + result[i + 3] = (acc & NIS_DESTROY_ACC) ? 'd' : '-'; + + acc >>= 8; + } + fputs (result, stdout); +} +libnsl_hidden_nolink_def (nis_print_rights, GLIBC_2_1) + +void +nis_print_directory (const directory_obj *dir) +{ + nis_server *sptr; + unsigned int i; + + printf (_("Name : `%s'\n"), dir->do_name); + printf (_("Type : %s\n"), nis_nstype2str (dir->do_type)); + sptr = dir->do_servers.do_servers_val; + for (i = 0; i < dir->do_servers.do_servers_len; i++) + { + if (i == 0) + fputs (_("Master Server :\n"), stdout); + else + fputs (_("Replicate :\n"), stdout); + printf (_("\tName : %s\n"), sptr->name); + fputs (_("\tPublic Key : "), stdout); + switch (sptr->key_type) + { + case NIS_PK_NONE: + fputs (_("None.\n"), stdout); + break; + case NIS_PK_DH: + printf (_("Diffie-Hellmann (%d bits)\n"), + (sptr->pkey.n_len - 1) * 4); + /* sptr->pkey.n_len counts the last 0, too */ + break; + case NIS_PK_RSA: + printf (_("RSA (%d bits)\n"), (sptr->pkey.n_len - 1) * 4); + break; + case NIS_PK_KERB: + fputs (_("Kerberos.\n"), stdout); + break; + default: + printf (_("Unknown (type = %d, bits = %d)\n"), sptr->key_type, + (sptr->pkey.n_len - 1) * 4); + break; + } + + if (sptr->ep.ep_len != 0) + { + unsigned int j; + + endpoint *ptr; + ptr = sptr->ep.ep_val; + printf (_("\tUniversal addresses (%u)\n"), sptr->ep.ep_len); + for (j = 0; j < sptr->ep.ep_len; j++) + { + printf ("\t[%d] - ", j + 1); + if (ptr->proto != NULL && ptr->proto[0] != '\0') + printf ("%s, ", ptr->proto); + else + printf ("-, "); + if (ptr->family != NULL && ptr->family[0] != '\0') + printf ("%s, ", ptr->family); + else + printf ("-, "); + if (ptr->uaddr != NULL && ptr->uaddr[0] != '\0') + printf ("%s\n", ptr->uaddr); + else + fputs ("-\n", stdout); + ptr++; + } + } + sptr++; + } + + fputs (_("Time to live : "), stdout); + print_ttl (dir->do_ttl); + fputs (_("Default Access rights :\n"), stdout); + if (dir->do_armask.do_armask_len != 0) + { + oar_mask *ptr; + + ptr = dir->do_armask.do_armask_val; + for (i = 0; i < dir->do_armask.do_armask_len; i++) + { + nis_print_rights (ptr->oa_rights); + printf (_("\tType : %s\n"), nis_nstype2str (ptr->oa_otype)); + fputs (_("\tAccess rights: "), stdout); + nis_print_rights (ptr->oa_rights); + fputs ("\n", stdout); + ptr++; + } + } +} +libnsl_hidden_nolink_def (nis_print_directory, GLIBC_2_1) + +void +nis_print_group (const group_obj *obj) +{ + unsigned int i; + + fputs (_("Group Flags :"), stdout); + if (obj->gr_flags) + printf ("0x%08X", obj->gr_flags); + fputs (_("\nGroup Members :\n"), stdout); + + for (i = 0; i < obj->gr_members.gr_members_len; i++) + printf ("\t%s\n", obj->gr_members.gr_members_val[i]); +} +libnsl_hidden_nolink_def (nis_print_group, GLIBC_2_1) + +void +nis_print_table (const table_obj *obj) +{ + unsigned int i; + + printf (_("Table Type : %s\n"), obj->ta_type); + printf (_("Number of Columns : %d\n"), obj->ta_maxcol); + printf (_("Character Separator : %c\n"), obj->ta_sep); + printf (_("Search Path : %s\n"), obj->ta_path); + fputs (_("Columns :\n"), stdout); + for (i = 0; i < obj->ta_cols.ta_cols_len; i++) + { + printf (_("\t[%d]\tName : %s\n"), i, + obj->ta_cols.ta_cols_val[i].tc_name); + fputs (_("\t\tAttributes : "), stdout); + print_flags (obj->ta_cols.ta_cols_val[i].tc_flags); + fputs (_("\t\tAccess Rights : "), stdout); + nis_print_rights (obj->ta_cols.ta_cols_val[i].tc_rights); + fputc ('\n', stdout); + } +} +libnsl_hidden_nolink_def (nis_print_table, GLIBC_2_1) + +void +nis_print_link (const link_obj *obj) +{ + fputs (_("Linked Object Type : "), stdout); + nis_print_objtype (obj->li_rtype); + printf (_("Linked to : %s\n"), obj->li_name); + /* XXX Print the attributes here, if they exists */ +} +libnsl_hidden_nolink_def (nis_print_link, GLIBC_2_1) + +void +nis_print_entry (const entry_obj *obj) +{ + unsigned int i; + + printf (_("\tEntry data of type %s\n"), obj->en_type); + for (i = 0; i < obj->en_cols.en_cols_len; i++) + { + printf (_("\t[%u] - [%u bytes] "), i, + obj->en_cols.en_cols_val[i].ec_value.ec_value_len); + if ((obj->en_cols.en_cols_val[i].ec_flags & EN_CRYPT) == EN_CRYPT) + fputs (_("Encrypted data\n"), stdout); + else if ((obj->en_cols.en_cols_val[i].ec_flags & EN_BINARY) == EN_BINARY) + fputs (_("Binary data\n"), stdout); + else if (obj->en_cols.en_cols_val[i].ec_value.ec_value_len == 0) + fputs ("'(nil)'\n", stdout); + else + printf ("'%.*s'\n", + (int)obj->en_cols.en_cols_val[i].ec_value.ec_value_len, + obj->en_cols.en_cols_val[i].ec_value.ec_value_val); + } +} +libnsl_hidden_nolink_def (nis_print_entry, GLIBC_2_1) + +void +nis_print_object (const nis_object * obj) +{ + time_t buf; + + printf (_("Object Name : %s\n"), obj->zo_name); + printf (_("Directory : %s\n"), obj->zo_domain); + printf (_("Owner : %s\n"), obj->zo_owner); + printf (_("Group : %s\n"), obj->zo_group); + fputs (_("Access Rights : "), stdout); + nis_print_rights (obj->zo_access); + printf (_("\nTime to Live : ")); + print_ttl (obj->zo_ttl); + buf = obj->zo_oid.ctime; + printf (_("Creation Time : %s"), ctime (&buf)); + buf = obj->zo_oid.mtime; + printf (_("Mod. Time : %s"), ctime (&buf)); + fputs (_("Object Type : "), stdout); + nis_print_objtype (obj->zo_data.zo_type); + switch (obj->zo_data.zo_type) + { + case NIS_DIRECTORY_OBJ: + nis_print_directory (&obj->zo_data.objdata_u.di_data); + break; + case NIS_GROUP_OBJ: + nis_print_group (&obj->zo_data.objdata_u.gr_data); + break; + case NIS_TABLE_OBJ: + nis_print_table (&obj->zo_data.objdata_u.ta_data); + break; + case NIS_ENTRY_OBJ: + nis_print_entry (&obj->zo_data.objdata_u.en_data); + break; + case NIS_LINK_OBJ: + nis_print_link (&obj->zo_data.objdata_u.li_data); + break; + case NIS_PRIVATE_OBJ: + printf (_(" Data Length = %u\n"), + obj->zo_data.objdata_u.po_data.po_data_len); + break; + default: + break; + } +} +libnsl_hidden_nolink_def (nis_print_object, GLIBC_2_1) + +void +nis_print_result (const nis_result *res) +{ + unsigned int i; + + printf (_("Status : %s\n"), nis_sperrno (NIS_RES_STATUS (res))); + printf (_("Number of objects : %u\n"), res->objects.objects_len); + + for (i = 0; i < res->objects.objects_len; i++) + { + printf (_("Object #%d:\n"), i); + nis_print_object (&res->objects.objects_val[i]); + } +} +libnsl_hidden_nolink_def (nis_print_result, GLIBC_2_1) diff --git a/REORG.TODO/nis/nis_print_group_entry.c b/REORG.TODO/nis/nis_print_group_entry.c new file mode 100644 index 0000000000..3a717e71d7 --- /dev/null +++ b/REORG.TODO/nis/nis_print_group_entry.c @@ -0,0 +1,175 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <alloca.h> +#include <string.h> +#include <libintl.h> +#include <rpcsvc/nis.h> +#include <shlib-compat.h> + +void +nis_print_group_entry (const_nis_name group) +{ + if (group != NULL && group[0] != '\0') + { + size_t grouplen = strlen (group); + char buf[grouplen + 50]; + char leafbuf[grouplen + 3]; + char domainbuf[grouplen + 3]; + nis_result *res; + char *cp, *cp2; + u_int i; + + cp = stpcpy (buf, nis_leaf_of_r (group, leafbuf, sizeof (leafbuf) - 1)); + cp = stpcpy (cp, ".groups_dir"); + cp2 = nis_domain_of_r (group, domainbuf, sizeof (domainbuf) - 1); + if (cp2 != NULL && cp2[0] != '\0') + { + *cp++ = '.'; + stpcpy (cp, cp2); + } + res = nis_lookup (buf, FOLLOW_LINKS | EXPAND_NAME); + + if (res == NULL) + return; + + if (NIS_RES_STATUS (res) != NIS_SUCCESS + || NIS_RES_NUMOBJ (res) != 1 + || __type_of (NIS_RES_OBJECT (res)) != NIS_GROUP_OBJ) + { + nis_freeresult (res); + return; + } + + char *mem_exp[NIS_RES_NUMOBJ (res)]; + char *mem_imp[NIS_RES_NUMOBJ (res)]; + char *mem_rec[NIS_RES_NUMOBJ (res)]; + char *nomem_exp[NIS_RES_NUMOBJ (res)]; + char *nomem_imp[NIS_RES_NUMOBJ (res)]; + char *nomem_rec[NIS_RES_NUMOBJ (res)]; + unsigned long mem_exp_cnt = 0, mem_imp_cnt = 0, mem_rec_cnt = 0; + unsigned long nomem_exp_cnt = 0, nomem_imp_cnt = 0, nomem_rec_cnt = 0; + + for (i = 0; + i < NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_len; ++i) + { + char *grmem = + NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val[i]; + int neg = grmem[0] == '-'; + + switch (grmem[neg]) + { + case '*': + if (neg) + { + nomem_imp[nomem_imp_cnt] = grmem; + ++nomem_imp_cnt; + } + else + { + mem_imp[mem_imp_cnt] = grmem; + ++mem_imp_cnt; + } + break; + case '@': + if (neg) + { + nomem_rec[nomem_rec_cnt] = grmem; + ++nomem_rec_cnt; + } + else + { + mem_rec[mem_rec_cnt] = grmem; + ++mem_rec_cnt; + } + break; + default: + if (neg) + { + nomem_exp[nomem_exp_cnt] = grmem; + ++nomem_exp_cnt; + } + else + { + mem_exp[mem_exp_cnt] = grmem; + ++mem_exp_cnt; + } + break; + } + } + { + char buf[strlen (NIS_RES_OBJECT (res)->zo_domain) + 10]; + printf (_("Group entry for \"%s.%s\" group:\n"), + NIS_RES_OBJECT (res)->zo_name, + nis_domain_of_r (NIS_RES_OBJECT (res)->zo_domain, + buf, strlen (NIS_RES_OBJECT (res)->zo_domain) + + 10)); + } + if (mem_exp_cnt) + { + fputs (_(" Explicit members:\n"), stdout); + for (i = 0; i < mem_exp_cnt; ++i) + printf ("\t%s\n", mem_exp[i]); + } + else + fputs (_(" No explicit members\n"), stdout); + if (mem_imp_cnt) + { + fputs (_(" Implicit members:\n"), stdout); + for (i = 0; i < mem_imp_cnt; ++i) + printf ("\t%s\n", &mem_imp[i][2]); + } + else + fputs (_(" No implicit members\n"), stdout); + if (mem_rec_cnt) + { + fputs (_(" Recursive members:\n"), stdout); + for (i = 0; i < mem_rec_cnt; ++i) + printf ("\t%s\n", &mem_rec[i][1]); + } + else + fputs (_(" No recursive members\n"), stdout); + if (nomem_exp_cnt) + { + fputs (_(" Explicit nonmembers:\n"), stdout); + for (i = 0; i < nomem_exp_cnt; ++i) + printf ("\t%s\n", &nomem_exp[i][1]); + } + else + fputs (_(" No explicit nonmembers\n"), stdout); + if (nomem_imp_cnt) + { + fputs (_(" Implicit nonmembers:\n"), stdout); + for (i = 0; i < nomem_imp_cnt; ++i) + printf ("\t%s\n", &nomem_imp[i][3]); + } + else + fputs (_(" No implicit nonmembers\n"), stdout); + if (nomem_rec_cnt) + { + fputs (_(" Recursive nonmembers:\n"), stdout); + for (i = 0; i < nomem_rec_cnt; ++i) + printf ("\t%s=n", &nomem_rec[i][2]); + } + else + fputs (_(" No recursive nonmembers\n"), stdout); + + nis_freeresult (res); + } +} +libnsl_hidden_nolink_def (nis_print_group_entry, GLIBC_2_1) diff --git a/REORG.TODO/nis/nis_remove.c b/REORG.TODO/nis/nis_remove.c new file mode 100644 index 0000000000..87c539793d --- /dev/null +++ b/REORG.TODO/nis/nis_remove.c @@ -0,0 +1,59 @@ +/* Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <rpcsvc/nis.h> +#include <shlib-compat.h> + +#include "nis_xdr.h" +#include "nis_intern.h" + +nis_result * +nis_remove (const_nis_name name, const nis_object *obj) +{ + nis_result *res; + nis_error status; + struct ns_request req; + + res = calloc (1, sizeof (nis_result)); + if (res == NULL) + return NULL; + + req.ns_name = (char *)name; + + if (obj != NULL) + { + req.ns_object.ns_object_len = 1; + req.ns_object.ns_object_val = nis_clone_object (obj, NULL); + } + else + { + req.ns_object.ns_object_len = 0; + req.ns_object.ns_object_val = NULL; + } + + if ((status = __do_niscall (name, NIS_REMOVE, (xdrproc_t) _xdr_ns_request, + (caddr_t) &req, (xdrproc_t) _xdr_nis_result, + (caddr_t) res, MASTER_ONLY, + NULL)) != NIS_SUCCESS) + NIS_RES_STATUS (res) = status; + + nis_destroy_object (req.ns_object.ns_object_val); + + return res; +} +libnsl_hidden_nolink_def (nis_remove, GLIBC_2_1) diff --git a/REORG.TODO/nis/nis_removemember.c b/REORG.TODO/nis/nis_removemember.c new file mode 100644 index 0000000000..af9e2a899c --- /dev/null +++ b/REORG.TODO/nis/nis_removemember.c @@ -0,0 +1,93 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <string.h> +#include <rpcsvc/nis.h> +#include <shlib-compat.h> + +nis_error +nis_removemember (const_nis_name member, const_nis_name group) +{ + if (group != NULL && group[0] != '\0') + { + size_t grouplen = strlen (group); + char buf[grouplen + 14 + NIS_MAXNAMELEN]; + char domainbuf[grouplen + 2]; + nis_result *res, *res2; + nis_error status; + char *cp, *cp2; + + cp = rawmemchr (nis_leaf_of_r (group, buf, sizeof (buf) - 1), '\0'); + cp = stpcpy (cp, ".groups_dir"); + cp2 = nis_domain_of_r (group, domainbuf, sizeof (domainbuf) - 1); + if (cp2 != NULL && cp2[0] != '\0') + { + cp = stpcpy (cp, "."); + stpcpy (cp, cp2); + } + res = nis_lookup (buf, FOLLOW_LINKS | EXPAND_NAME); + if (res == NULL) + return NIS_NOMEMORY; + if (NIS_RES_STATUS (res) != NIS_SUCCESS) + { + status = NIS_RES_STATUS (res); + nis_freeresult (res); + return status; + } + + if (NIS_RES_NUMOBJ (res) != 1 + || __type_of (NIS_RES_OBJECT (res)) != NIS_GROUP_OBJ) + { + nis_freeresult (res); + return NIS_INVALIDOBJ; + } + + nis_name *gr_members_val + = NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_val; + u_int gr_members_len + = NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_len; + + u_int j = 0; + for (u_int i = 0; i < gr_members_len; ++i) + if (strcmp (gr_members_val[i], member) != 0) + gr_members_val[j++] = gr_members_val[i]; + else + free (gr_members_val[i]); + + /* There is no need to reallocate the gr_members_val array. We + just adjust the size to match the number of strings still in + it. Yes, xdr_array will use mem_free with a size parameter + but this is mapped to a simple free call which determines the + size of the block by itself. */ + NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_len = j; + + cp = stpcpy (buf, NIS_RES_OBJECT (res)->zo_name); + *cp++ = '.'; + strncpy (cp, NIS_RES_OBJECT (res)->zo_domain, NIS_MAXNAMELEN); + res2 = nis_modify (buf, NIS_RES_OBJECT (res)); + status = NIS_RES_STATUS (res2); + nis_freeresult (res); + nis_freeresult (res2); + + return status; + } + else + return NIS_FAIL; +} +libnsl_hidden_nolink_def (nis_removemember, GLIBC_2_1) diff --git a/REORG.TODO/nis/nis_rmdir.c b/REORG.TODO/nis/nis_rmdir.c new file mode 100644 index 0000000000..53a0509e05 --- /dev/null +++ b/REORG.TODO/nis/nis_rmdir.c @@ -0,0 +1,42 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <rpcsvc/nis.h> +#include <shlib-compat.h> + +#include "nis_xdr.h" +#include "nis_intern.h" + +nis_error +nis_rmdir (const_nis_name dir, const nis_server *server) +{ + nis_error res, res2; + + if (server == NULL) + return NIS_SYSTEMERROR; + + res2 = __do_niscall2 (server, 1, NIS_RMDIR, + (xdrproc_t) _xdr_nis_name, + (caddr_t) &dir, (xdrproc_t) _xdr_nis_error, + (caddr_t) &res, 0, NULL); + if (res2 != NIS_SUCCESS) + return res2; + + return res; +} +libnsl_hidden_nolink_def (nis_rmdir, GLIBC_2_1) diff --git a/REORG.TODO/nis/nis_server.c b/REORG.TODO/nis/nis_server.c new file mode 100644 index 0000000000..63857721f2 --- /dev/null +++ b/REORG.TODO/nis/nis_server.c @@ -0,0 +1,89 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> +#include <rpcsvc/nis.h> +#include <shlib-compat.h> + +#include "nis_xdr.h" +#include "nis_intern.h" + +nis_error +nis_servstate (const nis_server *serv, const nis_tag *tags, + const int numtags, nis_tag **result) +{ + nis_taglist taglist; + nis_taglist tagres; + + *result = 0; + tagres.tags.tags_len = 0; + tagres.tags.tags_val = NULL; + taglist.tags.tags_len = numtags; + taglist.tags.tags_val = (nis_tag *) tags; + + if (serv == NULL) + return NIS_BADOBJECT; + + if (__do_niscall2 (serv, 1, NIS_SERVSTATE, (xdrproc_t) _xdr_nis_taglist, + (caddr_t) &taglist, (xdrproc_t) _xdr_nis_taglist, + (caddr_t) &tagres, 0, NULL) != NIS_SUCCESS) + return NIS_RPCERROR; + + *result = tagres.tags.tags_val; + + return NIS_SUCCESS; +} +libnsl_hidden_nolink_def (nis_servstate, GLIBC_2_1) + +nis_error +nis_stats (const nis_server *serv, const nis_tag *tags, + const int numtags, nis_tag **result) +{ + nis_taglist taglist; + nis_taglist tagres; + + *result = NULL; + tagres.tags.tags_len = 0; + tagres.tags.tags_val = NULL; + taglist.tags.tags_len = numtags; + taglist.tags.tags_val = (nis_tag *) tags; + + if (serv == NULL) + return NIS_BADOBJECT; + + if (__do_niscall2 (serv, 1, NIS_STATUS, (xdrproc_t) _xdr_nis_taglist, + (caddr_t) &taglist, (xdrproc_t) _xdr_nis_taglist, + (caddr_t) &tagres, 0, NULL) != NIS_SUCCESS) + return NIS_RPCERROR; + + *result = tagres.tags.tags_val; + + return NIS_SUCCESS; +} +libnsl_hidden_nolink_def (nis_stats, GLIBC_2_1) + +void +nis_freetags (nis_tag *tags, const int numtags) +{ + int i; + + for (i = 0; i < numtags; ++i) + free (tags[i].tag_val); + free (tags); +} +libnsl_hidden_nolink_def (nis_freetags, GLIBC_2_1) diff --git a/REORG.TODO/nis/nis_subr.c b/REORG.TODO/nis/nis_subr.c new file mode 100644 index 0000000000..5d93e77330 --- /dev/null +++ b/REORG.TODO/nis/nis_subr.c @@ -0,0 +1,354 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <string.h> +#include <rpcsvc/nis.h> +#include <shlib-compat.h> + +nis_name +nis_leaf_of (const_nis_name name) +{ + static char result[NIS_MAXNAMELEN + 1]; + + return nis_leaf_of_r (name, result, NIS_MAXNAMELEN); +} +libnsl_hidden_nolink_def (nis_leaf_of, GLIBC_2_1) + +nis_name +nis_leaf_of_r (const_nis_name name, char *buffer, size_t buflen) +{ + size_t i = 0; + + buffer[0] = '\0'; + + while (name[i] != '.' && name[i] != '\0') + i++; + + if (__glibc_unlikely (i >= buflen)) + { + __set_errno (ERANGE); + return NULL; + } + + *((char *) __mempcpy (buffer, name, i)) = '\0'; + + return buffer; +} +libnsl_hidden_nolink_def (nis_leaf_of_r, GLIBC_2_1) + +nis_name +nis_name_of (const_nis_name name) +{ + static char result[NIS_MAXNAMELEN + 1]; + + return nis_name_of_r (name, result, NIS_MAXNAMELEN); +} +libnsl_hidden_nolink_def (nis_name_of, GLIBC_2_1) + +nis_name +nis_name_of_r (const_nis_name name, char *buffer, size_t buflen) +{ + char *local_domain; + int diff; + + local_domain = nis_local_directory (); + + diff = strlen (name) - strlen (local_domain); + if (diff <= 0) + return NULL; + + if (strcmp (&name[diff], local_domain) != 0) + return NULL; + + if ((size_t) diff >= buflen) + { + __set_errno (ERANGE); + return NULL; + } + + *((char *) __mempcpy (buffer, name, diff - 1)) = '\0'; + + if (diff - 1 == 0) + return NULL; + + return buffer; +} +libnsl_hidden_nolink_def (nis_name_of_r, GLIBC_2_1) + +static int __always_inline +count_dots (const_nis_name str) +{ + int count = 0; + + for (size_t i = 0; str[i] != '\0'; ++i) + if (str[i] == '.') + ++count; + + return count; +} + +/* If we run out of memory, we don't give already allocated memory + free. The overhead for bringing getnames back in a safe state to + free it is to big. */ +nis_name * +nis_getnames (const_nis_name name) +{ + const char *local_domain = nis_local_directory (); + size_t local_domain_len = strlen (local_domain); + size_t name_len = strlen (name); + char *path; + int pos = 0; + char *saveptr = NULL; + int have_point; + const char *cp; + const char *cp2; + + int count = 2; + nis_name *getnames = malloc ((count + 1) * sizeof (char *)); + if (__glibc_unlikely (getnames == NULL)) + return NULL; + + /* Do we have a fully qualified NIS+ name ? If yes, give it back */ + if (name[name_len - 1] == '.') + { + if ((getnames[0] = strdup (name)) == NULL) + { + free_null: + while (pos-- > 0) + free (getnames[pos]); + free (getnames); + return NULL; + } + + getnames[1] = NULL; + + return getnames; + } + + /* If the passed NAME is shared a suffix (the latter of course with + a final dot) with each other we pass back NAME with a final + dot. */ + if (local_domain_len > 2) + { + have_point = 0; + cp = &local_domain[local_domain_len - 2]; + cp2 = &name[name_len - 1]; + + while (*cp == *cp2) + { + if (*cp == '.') + have_point = 1; + --cp; + --cp2; + if (cp < local_domain) + { + have_point = cp2 < name || *cp2 == '.'; + break; + } + if (cp2 < name) + { + have_point = *cp == '.'; + break; + } + } + + if (have_point) + { + getnames[0] = malloc (name_len + 2); + if (getnames[0] == NULL) + goto free_null; + + strcpy (stpcpy (getnames[0], name), "."); + ++pos; + } + } + + /* Get the search path, where we have to search "name" */ + path = getenv ("NIS_PATH"); + if (path == NULL) + path = strdupa ("$"); + else + path = strdupa (path); + + have_point = strchr (name, '.') != NULL; + + cp = __strtok_r (path, ":", &saveptr); + while (cp) + { + if (strcmp (cp, "$") == 0) + { + const char *cptr = local_domain; + char *tmp; + + while (*cptr != '\0' && count_dots (cptr) >= 2) + { + if (pos >= count) + { + count += 5; + nis_name *newp = realloc (getnames, + (count + 1) * sizeof (char *)); + if (__glibc_unlikely (newp == NULL)) + goto free_null; + getnames = newp; + } + tmp = malloc (strlen (cptr) + local_domain_len + name_len + 2); + if (__glibc_unlikely (tmp == NULL)) + goto free_null; + + getnames[pos] = tmp; + tmp = stpcpy (tmp, name); + *tmp++ = '.'; + if (cptr[1] != '\0') + stpcpy (tmp, cptr); + else + ++cptr; + + ++pos; + + while (*cptr != '.' && *cptr != '\0') + ++cptr; + if (cptr[0] != '\0' && cptr[1] != '\0') + /* If we have only ".", don't remove the "." */ + ++cptr; + } + } + else + { + char *tmp; + size_t cplen = strlen (cp); + + if (cp[cplen - 1] == '$') + { + char *p; + + tmp = malloc (cplen + local_domain_len + name_len + 2); + if (__glibc_unlikely (tmp == NULL)) + goto free_null; + + p = __stpcpy (tmp, name); + *p++ = '.'; + p = __mempcpy (p, cp, cplen); + --p; + if (p[-1] != '.') + *p++ = '.'; + __stpcpy (p, local_domain); + } + else + { + char *p; + + tmp = malloc (cplen + name_len + 3); + if (__glibc_unlikely (tmp == NULL)) + goto free_null; + + p = __mempcpy (tmp, name, name_len); + *p++ = '.'; + p = __mempcpy (p, cp, cplen); + if (p[-1] != '.') + *p++ = '.'; + *p = '\0'; + } + + if (pos >= count) + { + count += 5; + nis_name *newp = realloc (getnames, + (count + 1) * sizeof (char *)); + if (__glibc_unlikely (newp == NULL)) + goto free_null; + getnames = newp; + } + getnames[pos] = tmp; + ++pos; + } + cp = __strtok_r (NULL, ":", &saveptr); + } + + if (pos == 0 + && __asprintf (&getnames[pos++], "%s%s%s%s", + name, name[name_len - 1] == '.' ? "" : ".", + local_domain, + local_domain[local_domain_len - 1] == '.' ? "" : ".") < 0) + goto free_null; + + getnames[pos] = NULL; + + return getnames; +} +libnsl_hidden_nolink_def (nis_getnames, GLIBC_2_1) + +void +nis_freenames (nis_name *names) +{ + int i = 0; + + while (names[i] != NULL) + { + free (names[i]); + ++i; + } + + free (names); +} +libnsl_hidden_nolink_def (nis_freenames, GLIBC_2_1) + +name_pos +nis_dir_cmp (const_nis_name n1, const_nis_name n2) +{ + int len1, len2; + + len1 = strlen (n1); + len2 = strlen (n2); + + if (len1 == len2) + { + if (strcmp (n1, n2) == 0) + return SAME_NAME; + else + return NOT_SEQUENTIAL; + } + + if (len1 < len2) + { + if (n2[len2 - len1 - 1] != '.') + return NOT_SEQUENTIAL; + else if (strcmp (&n2[len2 - len1], n1) == 0) + return HIGHER_NAME; + else + return NOT_SEQUENTIAL; + } + else + { + if (n1[len1 - len2 - 1] != '.') + return NOT_SEQUENTIAL; + else if (strcmp (&n1[len1 - len2], n2) == 0) + return LOWER_NAME; + else + return NOT_SEQUENTIAL; + + } +} +libnsl_hidden_nolink_def (nis_dir_cmp, GLIBC_2_1) + +void +nis_destroy_object (nis_object *obj) +{ + nis_free_object (obj); +} +libnsl_hidden_nolink_def (nis_destroy_object, GLIBC_2_1) diff --git a/REORG.TODO/nis/nis_table.c b/REORG.TODO/nis/nis_table.c new file mode 100644 index 0000000000..88eb6797e6 --- /dev/null +++ b/REORG.TODO/nis/nis_table.c @@ -0,0 +1,813 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <string.h> +#include <rpcsvc/nis.h> +#include <libc-diag.h> +#include <shlib-compat.h> + +#include "nis_xdr.h" +#include "nis_intern.h" +#include "libnsl.h" + + +struct ib_request * +__create_ib_request (const_nis_name name, unsigned int flags) +{ + struct ib_request *ibreq = calloc (1, sizeof (struct ib_request)); + nis_attr *search_val = NULL; + size_t search_len = 0; + size_t size = 0; + + if (ibreq == NULL) + return NULL; + + ibreq->ibr_flags = flags; + + char *cptr = strdupa (name); + + /* Not of "[key=value,key=value,...],foo.." format? */ + if (cptr[0] != '[') + { + ibreq->ibr_name = strdup (cptr); + if (ibreq->ibr_name == NULL) + { + free (ibreq); + return NULL; + } + return ibreq; + } + + /* "[key=value,...],foo" format */ + ibreq->ibr_name = strchr (cptr, ']'); + if (ibreq->ibr_name == NULL || ibreq->ibr_name[1] != ',') + { + /* The object has not really been built yet so we use free. */ + free (ibreq); + return NULL; + } + + /* Check if we have an entry of "[key=value,],bar". If, remove the "," */ + if (ibreq->ibr_name[-1] == ',') + ibreq->ibr_name[-1] = '\0'; + else + ibreq->ibr_name[0] = '\0'; + ibreq->ibr_name += 2; + ibreq->ibr_name = strdup (ibreq->ibr_name); + if (ibreq->ibr_name == NULL) + { + free_null: + while (search_len-- > 0) + { + free (search_val[search_len].zattr_ndx); + free (search_val[search_len].zattr_val.zattr_val_val); + } + free (search_val); + nis_free_request (ibreq); + return NULL; + } + + ++cptr; /* Remove "[" */ + + while (cptr != NULL && cptr[0] != '\0') + { + char *key = cptr; + char *val = strchr (cptr, '='); + + cptr = strchr (key, ','); + if (cptr != NULL) + *cptr++ = '\0'; + + if (__glibc_unlikely (val == NULL)) + { + nis_free_request (ibreq); + return NULL; + } + *val++ = '\0'; + if (search_len + 1 >= size) + { + size += 1; + nis_attr *newp = realloc (search_val, size * sizeof (nis_attr)); + if (newp == NULL) + goto free_null; + search_val = newp; + } + search_val[search_len].zattr_ndx = strdup (key); + if (search_val[search_len].zattr_ndx == NULL) + goto free_null; + + search_val[search_len].zattr_val.zattr_val_len = strlen (val) + 1; + search_val[search_len].zattr_val.zattr_val_val = strdup (val); + if (search_val[search_len].zattr_val.zattr_val_val == NULL) + { + free (search_val[search_len].zattr_ndx); + goto free_null; + } + + ++search_len; + } + + ibreq->ibr_srch.ibr_srch_val = search_val; + ibreq->ibr_srch.ibr_srch_len = search_len; + + return ibreq; +} +libnsl_hidden_nolink_def (__create_ib_request, GLIBC_PRIVATE) + +static const struct timeval RPCTIMEOUT = {10, 0}; + +static char * +get_tablepath (char *name, dir_binding *bptr) +{ + enum clnt_stat result; + nis_result res; + struct ns_request req; + + memset (&res, '\0', sizeof (res)); + + req.ns_name = name; + req.ns_object.ns_object_len = 0; + req.ns_object.ns_object_val = NULL; + + result = clnt_call (bptr->clnt, NIS_LOOKUP, (xdrproc_t) _xdr_ns_request, + (caddr_t) &req, (xdrproc_t) _xdr_nis_result, + (caddr_t) &res, RPCTIMEOUT); + + const char *cptr; + if (result == RPC_SUCCESS && NIS_RES_STATUS (&res) == NIS_SUCCESS + && __type_of (NIS_RES_OBJECT (&res)) == NIS_TABLE_OBJ) + cptr = NIS_RES_OBJECT (&res)->TA_data.ta_path; + else + cptr = ""; + + char *str = strdup (cptr); + + if (result == RPC_SUCCESS) + xdr_free ((xdrproc_t) _xdr_nis_result, (char *) &res); + + return str; +} + + +nis_error +__follow_path (char **tablepath, char **tableptr, struct ib_request *ibreq, + dir_binding *bptr) +{ + if (*tablepath == NULL) + { + *tablepath = get_tablepath (ibreq->ibr_name, bptr); + if (*tablepath == NULL) + return NIS_NOMEMORY; + + *tableptr = *tablepath; + } + + /* Since tableptr is only set here, and it's set when tablepath is NULL, + which it is initially defined as, we know it will always be set here. */ + DIAG_PUSH_NEEDS_COMMENT; + DIAG_IGNORE_NEEDS_COMMENT (4.7, "-Wmaybe-uninitialized"); + + if (*tableptr == NULL) + return NIS_NOTFOUND; + + char *newname = strsep (tableptr, ":"); + if (newname[0] == '\0') + return NIS_NOTFOUND; + + DIAG_POP_NEEDS_COMMENT; + + newname = strdup (newname); + if (newname == NULL) + return NIS_NOMEMORY; + + free (ibreq->ibr_name); + ibreq->ibr_name = newname; + + return NIS_SUCCESS; +} +libnsl_hidden_nolink_def (__follow_path, GLIBC_PRIVATE) + + +nis_result * +nis_list (const_nis_name name, unsigned int flags, + int (*callback) (const_nis_name name, + const nis_object *object, + const void *userdata), + const void *userdata) +{ + nis_result *res = malloc (sizeof (nis_result)); + ib_request *ibreq; + int status; + enum clnt_stat clnt_status; + int count_links = 0; /* We will only follow NIS_MAXLINKS links! */ + int done = 0; + nis_name *names; + nis_name namebuf[2] = {NULL, NULL}; + int name_nr = 0; + nis_cb *cb = NULL; + char *tableptr; + char *tablepath = NULL; + int first_try = 0; /* Do we try the old binding at first ? */ + nis_result *allres = NULL; + + if (res == NULL) + return NULL; + + if (name == NULL) + { + status = NIS_BADNAME; + err_out: + nis_freeresult (allres); + memset (res, '\0', sizeof (nis_result)); + NIS_RES_STATUS (res) = status; + return res; + } + + ibreq = __create_ib_request (name, flags); + if (ibreq == NULL) + { + status = NIS_BADNAME; + goto err_out; + } + + if ((flags & EXPAND_NAME) + && ibreq->ibr_name[strlen (ibreq->ibr_name) - 1] != '.') + { + names = nis_getnames (ibreq->ibr_name); + free (ibreq->ibr_name); + ibreq->ibr_name = NULL; + if (names == NULL) + { + nis_free_request (ibreq); + status = NIS_BADNAME; + goto err_out; + } + ibreq->ibr_name = strdup (names[name_nr]); + if (ibreq->ibr_name == NULL) + { + nis_freenames (names); + nis_free_request (ibreq); + status = NIS_NOMEMORY; + goto err_out; + } + } + else + { + names = namebuf; + names[name_nr] = ibreq->ibr_name; + } + + cb = NULL; + + while (!done) + { + dir_binding bptr; + directory_obj *dir = NULL; + + memset (res, '\0', sizeof (nis_result)); + + status = __nisfind_server (ibreq->ibr_name, + ibreq->ibr_srch.ibr_srch_val != NULL, + &dir, &bptr, flags & ~MASTER_ONLY); + if (status != NIS_SUCCESS) + { + NIS_RES_STATUS (res) = status; + goto fail3; + } + + while (__nisbind_connect (&bptr) != NIS_SUCCESS) + if (__glibc_unlikely (__nisbind_next (&bptr) != NIS_SUCCESS)) + { + NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE; + goto fail; + } + + if (callback != NULL) + { + assert (cb == NULL); + cb = __nis_create_callback (callback, userdata, flags); + ibreq->ibr_cbhost.ibr_cbhost_len = 1; + ibreq->ibr_cbhost.ibr_cbhost_val = cb->serv; + } + + again: + clnt_status = clnt_call (bptr.clnt, NIS_IBLIST, + (xdrproc_t) _xdr_ib_request, (caddr_t) ibreq, + (xdrproc_t) _xdr_nis_result, + (caddr_t) res, RPCTIMEOUT); + + if (__glibc_unlikely (clnt_status != RPC_SUCCESS)) + NIS_RES_STATUS (res) = NIS_RPCERROR; + else + switch (NIS_RES_STATUS (res)) + { /* start switch */ + case NIS_PARTIAL: + case NIS_SUCCESS: + case NIS_S_SUCCESS: + if (__type_of (NIS_RES_OBJECT (res)) == NIS_LINK_OBJ + && (flags & FOLLOW_LINKS)) /* We are following links. */ + { + free (ibreq->ibr_name); + ibreq->ibr_name = NULL; + /* If we hit the link limit, bail. */ + if (__glibc_unlikely (count_links > NIS_MAXLINKS)) + { + NIS_RES_STATUS (res) = NIS_LINKNAMEERROR; + ++done; + break; + } + ++count_links; + ibreq->ibr_name = + strdup (NIS_RES_OBJECT (res)->LI_data.li_name); + if (ibreq->ibr_name == NULL) + { + NIS_RES_STATUS (res) = NIS_NOMEMORY; + fail: + __nisbind_destroy (&bptr); + nis_free_directory (dir); + fail3: + free (tablepath); + if (cb) + { + __nis_destroy_callback (cb); + ibreq->ibr_cbhost.ibr_cbhost_len = 0; + ibreq->ibr_cbhost.ibr_cbhost_val = NULL; + } + if (names != namebuf) + nis_freenames (names); + nis_free_request (ibreq); + nis_freeresult (allres); + return res; + } + if (NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len) + if (ibreq->ibr_srch.ibr_srch_len == 0) + { + ibreq->ibr_srch.ibr_srch_len = + NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len; + ibreq->ibr_srch.ibr_srch_val = + NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_val; + } + /* The following is a non-obvious optimization. A + nis_freeresult call would call xdr_free as the + following code. But it also would unnecessarily + free the result structure. We avoid this here + along with the necessary tests. */ + xdr_free ((xdrproc_t) _xdr_nis_result, (char *)res); + memset (res, '\0', sizeof (*res)); + first_try = 1; /* Try at first the old binding */ + goto again; + } + else if ((flags & FOLLOW_PATH) + && NIS_RES_STATUS (res) == NIS_PARTIAL) + { + enum nis_error err = __follow_path (&tablepath, &tableptr, + ibreq, &bptr); + if (err != NIS_SUCCESS) + { + if (err == NIS_NOMEMORY) + NIS_RES_STATUS (res) = err; + ++done; + } + else + { + /* The following is a non-obvious optimization. A + nis_freeresult call would call xdr_free as the + following code. But it also would unnecessarily + free the result structure. We avoid this here + along with the necessary tests. */ + xdr_free ((xdrproc_t) _xdr_nis_result, (char *) res); + memset (res, '\0', sizeof (*res)); + first_try = 1; + goto again; + } + } + else if ((flags & (FOLLOW_PATH | ALL_RESULTS)) + == (FOLLOW_PATH | ALL_RESULTS)) + { + if (allres == NULL) + { + allres = res; + res = malloc (sizeof (nis_result)); + if (res == NULL) + { + res = allres; + allres = NULL; + NIS_RES_STATUS (res) = NIS_NOMEMORY; + goto fail; + } + NIS_RES_STATUS (res) = NIS_RES_STATUS (allres); + } + else + { + nis_object *objects_val + = realloc (NIS_RES_OBJECT (allres), + (NIS_RES_NUMOBJ (allres) + + NIS_RES_NUMOBJ (res)) + * sizeof (nis_object)); + if (objects_val == NULL) + { + NIS_RES_STATUS (res) = NIS_NOMEMORY; + goto fail; + } + NIS_RES_OBJECT (allres) = objects_val; + memcpy (NIS_RES_OBJECT (allres) + NIS_RES_NUMOBJ (allres), + NIS_RES_OBJECT (res), + NIS_RES_NUMOBJ (res) * sizeof (nis_object)); + NIS_RES_NUMOBJ (allres) += NIS_RES_NUMOBJ (res); + NIS_RES_NUMOBJ (res) = 0; + free (NIS_RES_OBJECT (res)); + NIS_RES_OBJECT (res) = NULL; + NIS_RES_STATUS (allres) = NIS_RES_STATUS (res); + xdr_free ((xdrproc_t) _xdr_nis_result, (char *) res); + } + enum nis_error err = __follow_path (&tablepath, &tableptr, + ibreq, &bptr); + if (err != NIS_SUCCESS) + { + /* Prepare for the nis_freeresult call. */ + memset (res, '\0', sizeof (*res)); + + if (err == NIS_NOMEMORY) + NIS_RES_STATUS (allres) = err; + ++done; + } + } + else + ++done; + break; + case NIS_CBRESULTS: + if (cb != NULL) + { + __nis_do_callback (&bptr, &res->cookie, cb); + NIS_RES_STATUS (res) = cb->result; + + if (!(flags & ALL_RESULTS)) + ++done; + else + { + enum nis_error err + = __follow_path (&tablepath, &tableptr, ibreq, &bptr); + if (err != NIS_SUCCESS) + { + if (err == NIS_NOMEMORY) + NIS_RES_STATUS (res) = err; + ++done; + } + } + } + break; + case NIS_SYSTEMERROR: + case NIS_NOSUCHNAME: + case NIS_NOT_ME: + /* If we had first tried the old binding, do nothing, but + get a new binding */ + if (!first_try) + { + if (__nisbind_next (&bptr) != NIS_SUCCESS) + { + ++done; + break; /* No more servers to search */ + } + while (__nisbind_connect (&bptr) != NIS_SUCCESS) + { + if (__nisbind_next (&bptr) != NIS_SUCCESS) + { + ++done; + break; /* No more servers to search */ + } + } + goto again; + } + break; + default: + if (!first_try) + { + /* Try the next domainname if we don't follow a link. */ + free (ibreq->ibr_name); + ibreq->ibr_name = NULL; + if (__glibc_unlikely (count_links)) + { + NIS_RES_STATUS (res) = NIS_LINKNAMEERROR; + ++done; + break; + } + ++name_nr; + if (names[name_nr] == NULL) + { + ++done; + break; + } + ibreq->ibr_name = strdup (names[name_nr]); + if (ibreq->ibr_name == NULL) + { + NIS_RES_STATUS (res) = NIS_NOMEMORY; + goto fail; + } + first_try = 1; /* Try old binding at first */ + goto again; + } + break; + } + first_try = 0; + + if (cb) + { + __nis_destroy_callback (cb); + ibreq->ibr_cbhost.ibr_cbhost_len = 0; + ibreq->ibr_cbhost.ibr_cbhost_val = NULL; + cb = NULL; + } + + __nisbind_destroy (&bptr); + nis_free_directory (dir); + } + + free (tablepath); + + if (names != namebuf) + nis_freenames (names); + + nis_free_request (ibreq); + + if (allres) + { + nis_freeresult (res); + return allres; + } + + return res; +} +libnsl_hidden_nolink_def (nis_list, GLIBC_2_1) + +nis_result * +nis_add_entry (const_nis_name name, const nis_object *obj2, unsigned int flags) +{ + nis_result *res = calloc (1, sizeof (nis_result)); + if (res == NULL) + return NULL; + + if (name == NULL) + { + NIS_RES_STATUS (res) = NIS_BADNAME; + return res; + } + + ib_request *ibreq = __create_ib_request (name, flags); + if (ibreq == NULL) + { + NIS_RES_STATUS (res) = NIS_BADNAME; + return res; + } + + nis_object obj; + memcpy (&obj, obj2, sizeof (nis_object)); + + size_t namelen = strlen (name); + char buf1[namelen + 20]; + char buf4[namelen + 20]; + + if (obj.zo_name == NULL || strlen (obj.zo_name) == 0) + obj.zo_name = nis_leaf_of_r (name, buf1, sizeof (buf1)); + + if (obj.zo_owner == NULL || strlen (obj.zo_owner) == 0) + obj.zo_owner = nis_local_principal (); + + if (obj.zo_group == NULL || strlen (obj.zo_group) == 0) + obj.zo_group = nis_local_group (); + + obj.zo_domain = nis_domain_of_r (name, buf4, sizeof (buf4)); + + ibreq->ibr_obj.ibr_obj_val = nis_clone_object (&obj, NULL); + if (ibreq->ibr_obj.ibr_obj_val == NULL) + { + nis_free_request (ibreq); + NIS_RES_STATUS (res) = NIS_NOMEMORY; + return res; + } + ibreq->ibr_obj.ibr_obj_len = 1; + + nis_error status = __do_niscall (ibreq->ibr_name, NIS_IBADD, + (xdrproc_t) _xdr_ib_request, + (caddr_t) ibreq, + (xdrproc_t) _xdr_nis_result, + (caddr_t) res, 0, NULL); + if (__glibc_unlikely (status != NIS_SUCCESS)) + NIS_RES_STATUS (res) = status; + + nis_free_request (ibreq); + + return res; +} +libnsl_hidden_nolink_def (nis_add_entry, GLIBC_2_1) + +nis_result * +nis_modify_entry (const_nis_name name, const nis_object *obj2, + unsigned int flags) +{ + nis_object obj; + nis_result *res; + nis_error status; + ib_request *ibreq; + size_t namelen = strlen (name); + char buf1[namelen + 20]; + char buf4[namelen + 20]; + + res = calloc (1, sizeof (nis_result)); + if (res == NULL) + return NULL; + + ibreq = __create_ib_request (name, flags); + if (ibreq == NULL) + { + NIS_RES_STATUS (res) = NIS_BADNAME; + return res; + } + + memcpy (&obj, obj2, sizeof (nis_object)); + + if (obj.zo_name == NULL || strlen (obj.zo_name) == 0) + obj.zo_name = nis_leaf_of_r (name, buf1, sizeof (buf1)); + + if (obj.zo_owner == NULL || strlen (obj.zo_owner) == 0) + obj.zo_owner = nis_local_principal (); + + if (obj.zo_group == NULL || strlen (obj.zo_group) == 0) + obj.zo_group = nis_local_group (); + + obj.zo_domain = nis_domain_of_r (name, buf4, sizeof (buf4)); + + ibreq->ibr_obj.ibr_obj_val = nis_clone_object (&obj, NULL); + if (ibreq->ibr_obj.ibr_obj_val == NULL) + { + nis_free_request (ibreq); + NIS_RES_STATUS (res) = NIS_NOMEMORY; + return res; + } + ibreq->ibr_obj.ibr_obj_len = 1; + + status = __do_niscall (ibreq->ibr_name, NIS_IBMODIFY, + (xdrproc_t) _xdr_ib_request, + (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result, + (caddr_t) res, 0, NULL); + if (__glibc_unlikely (status != NIS_SUCCESS)) + NIS_RES_STATUS (res) = status; + + nis_free_request (ibreq); + + return res; +} +libnsl_hidden_nolink_def (nis_modify_entry, GLIBC_2_1) + +nis_result * +nis_remove_entry (const_nis_name name, const nis_object *obj, + unsigned int flags) +{ + nis_result *res; + ib_request *ibreq; + nis_error status; + + res = calloc (1, sizeof (nis_result)); + if (res == NULL) + return NULL; + + if (name == NULL) + { + NIS_RES_STATUS (res) = NIS_BADNAME; + return res; + } + + ibreq = __create_ib_request (name, flags); + if (ibreq == NULL) + { + NIS_RES_STATUS (res) = NIS_BADNAME; + return res; + } + + if (obj != NULL) + { + ibreq->ibr_obj.ibr_obj_val = nis_clone_object (obj, NULL); + if (ibreq->ibr_obj.ibr_obj_val == NULL) + { + nis_free_request (ibreq); + NIS_RES_STATUS (res) = NIS_NOMEMORY; + return res; + } + ibreq->ibr_obj.ibr_obj_len = 1; + } + + if ((status = __do_niscall (ibreq->ibr_name, NIS_IBREMOVE, + (xdrproc_t) _xdr_ib_request, + (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result, + (caddr_t) res, 0, NULL)) != NIS_SUCCESS) + NIS_RES_STATUS (res) = status; + + nis_free_request (ibreq); + + return res; +} +libnsl_hidden_nolink_def (nis_remove_entry, GLIBC_2_1) + +nis_result * +nis_first_entry (const_nis_name name) +{ + nis_result *res; + ib_request *ibreq; + nis_error status; + + res = calloc (1, sizeof (nis_result)); + if (res == NULL) + return NULL; + + if (name == NULL) + { + NIS_RES_STATUS (res) = NIS_BADNAME; + return res; + } + + ibreq = __create_ib_request (name, 0); + if (ibreq == NULL) + { + NIS_RES_STATUS (res) = NIS_BADNAME; + return res; + } + + status = __do_niscall (ibreq->ibr_name, NIS_IBFIRST, + (xdrproc_t) _xdr_ib_request, + (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result, + (caddr_t) res, 0, NULL); + + if (__glibc_unlikely (status != NIS_SUCCESS)) + NIS_RES_STATUS (res) = status; + + nis_free_request (ibreq); + + return res; +} +libnsl_hidden_nolink_def (nis_first_entry, GLIBC_2_1) + +nis_result * +nis_next_entry (const_nis_name name, const netobj *cookie) +{ + nis_result *res; + ib_request *ibreq; + nis_error status; + + res = calloc (1, sizeof (nis_result)); + if (res == NULL) + return NULL; + + if (name == NULL) + { + NIS_RES_STATUS (res) = NIS_BADNAME; + return res; + } + + ibreq = __create_ib_request (name, 0); + if (ibreq == NULL) + { + NIS_RES_STATUS (res) = NIS_BADNAME; + return res; + } + + if (cookie != NULL) + { + ibreq->ibr_cookie.n_bytes = cookie->n_bytes; + ibreq->ibr_cookie.n_len = cookie->n_len; + } + + status = __do_niscall (ibreq->ibr_name, NIS_IBNEXT, + (xdrproc_t) _xdr_ib_request, + (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result, + (caddr_t) res, 0, NULL); + + if (__glibc_unlikely (status != NIS_SUCCESS)) + NIS_RES_STATUS (res) = status; + + if (cookie != NULL) + { + /* Don't give cookie free, it is not from us */ + ibreq->ibr_cookie.n_bytes = NULL; + ibreq->ibr_cookie.n_len = 0; + } + + nis_free_request (ibreq); + + return res; +} +libnsl_hidden_nolink_def (nis_next_entry, GLIBC_2_1) diff --git a/REORG.TODO/nis/nis_util.c b/REORG.TODO/nis/nis_util.c new file mode 100644 index 0000000000..fcb7120e41 --- /dev/null +++ b/REORG.TODO/nis/nis_util.c @@ -0,0 +1,52 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> +#include <rpcsvc/nis.h> +#include <shlib-compat.h> + +#include "nis_xdr.h" +#include "nis_intern.h" + +fd_result * +__nis_finddirectory (directory_obj *dir, const_nis_name name) +{ + nis_error status; + fd_args fd_args; + fd_result *fd_res; + + fd_args.dir_name = (char *)name; + fd_args.requester = nis_local_host(); + fd_res = calloc (1, sizeof (fd_result)); + if (fd_res == NULL) + return NULL; + + status = __do_niscall2 (dir->do_servers.do_servers_val, + dir->do_servers.do_servers_len, + NIS_FINDDIRECTORY, (xdrproc_t) _xdr_fd_args, + (caddr_t) &fd_args, (xdrproc_t) _xdr_fd_result, + (caddr_t) fd_res, NO_AUTHINFO|USE_DGRAM, NULL); + if (status != NIS_SUCCESS) + fd_res->status = status; + + return fd_res; +} +libnsl_hidden_nolink_def (__nis_finddirectory, GLIBC_2_1) + +/* The hash implementation is in a separate file. */ +#include "nis_hash.c" diff --git a/REORG.TODO/nis/nis_verifygroup.c b/REORG.TODO/nis/nis_verifygroup.c new file mode 100644 index 0000000000..4fb2cc5977 --- /dev/null +++ b/REORG.TODO/nis/nis_verifygroup.c @@ -0,0 +1,52 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> +#include <rpcsvc/nis.h> +#include <shlib-compat.h> + +nis_error +nis_verifygroup (const_nis_name group) +{ + if (group != NULL && group[0] != '\0') + { + size_t grouplen = strlen (group); + char buf[grouplen + 50]; + char leafbuf[grouplen + 2]; + char domainbuf[grouplen + 2]; + nis_result *res; + nis_error status; + char *cp, *cp2; + + cp = stpcpy (buf, nis_leaf_of_r (group, leafbuf, sizeof (leafbuf) - 1)); + cp = stpcpy (cp, ".groups_dir"); + cp2 = nis_domain_of_r (group, domainbuf, sizeof (domainbuf) - 1); + if (cp2 != NULL && cp2[0] != '\0') + { + *cp++ = '.'; + stpcpy (cp, cp2); + } + res = nis_lookup (buf, 0); + status = NIS_RES_STATUS (res); + nis_freeresult (res); + return status; + } + else + return NIS_FAIL; +} +libnsl_hidden_nolink_def (nis_verifygroup, GLIBC_2_1) diff --git a/REORG.TODO/nis/nis_xdr.c b/REORG.TODO/nis/nis_xdr.c new file mode 100644 index 0000000000..3217dc51bd --- /dev/null +++ b/REORG.TODO/nis/nis_xdr.c @@ -0,0 +1,460 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <stdint.h> +#include <rpcsvc/nis.h> +#include <rpcsvc/nis_callback.h> /* for "official" Solaris xdr functions */ +#include <shlib-compat.h> + +/* This functions do exist without beginning "_" under Solaris 2.x, but + we have no prototypes for them. To avoid the same problems as with the + YP xdr functions, we don't make them public. */ +#include "nis_xdr.h" + +static bool_t +xdr_nis_attr (XDR *xdrs, nis_attr *objp) +{ + bool_t res = xdr_string (xdrs, &objp->zattr_ndx, ~0); + if (__builtin_expect (res, TRUE)) + res = xdr_bytes (xdrs, (char **) &objp->zattr_val.zattr_val_val, + &objp->zattr_val.zattr_val_len, ~0); + return res; +} + +static __always_inline bool_t +xdr_nis_name (XDR *xdrs, nis_name *objp) +{ + return xdr_string (xdrs, objp, ~0); +} + +bool_t +_xdr_nis_name (XDR *xdrs, nis_name *objp) +{ + return xdr_nis_name (xdrs, objp); +} + +static __always_inline bool_t +xdr_zotypes (XDR *xdrs, zotypes *objp) +{ + return xdr_enum (xdrs, (enum_t *) objp); +} + +static __always_inline bool_t +xdr_nstype (XDR *xdrs, nstype *objp) +{ + return xdr_enum (xdrs, (enum_t *) objp); +} + +static bool_t +xdr_oar_mask (XDR *xdrs, oar_mask *objp) +{ + bool_t res = xdr_u_int (xdrs, &objp->oa_rights); + if (__builtin_expect (res, TRUE)) + res = xdr_zotypes (xdrs, &objp->oa_otype); + return res; +} + +static bool_t +xdr_endpoint (XDR *xdrs, endpoint *objp) +{ + bool_t res = xdr_string (xdrs, &objp->uaddr, ~0); + if (__builtin_expect (res, TRUE)) + { + res = xdr_string (xdrs, &objp->family, ~0); + if (__glibc_likely (res)) + res = xdr_string (xdrs, &objp->proto, ~0); + } + return res; +} + +bool_t +_xdr_nis_server (XDR *xdrs, nis_server *objp) +{ + bool_t res = xdr_nis_name (xdrs, &objp->name); + if (__builtin_expect (res, TRUE)) + { + res = xdr_array (xdrs, (void *) &objp->ep.ep_val, &objp->ep.ep_len, + ~0, sizeof (endpoint), (xdrproc_t) xdr_endpoint); + if (__builtin_expect (res, TRUE)) + { + res = xdr_u_int (xdrs, &objp->key_type); + if (__builtin_expect (res, TRUE)) + res = xdr_netobj (xdrs, &objp->pkey); + } + } + return res; +} + +bool_t +_xdr_directory_obj (XDR *xdrs, directory_obj *objp) +{ + bool_t res = xdr_nis_name (xdrs, &objp->do_name); + if (__builtin_expect (res, TRUE)) + { + res = xdr_nstype (xdrs, &objp->do_type); + if (__builtin_expect (res, TRUE)) + { + res = xdr_array (xdrs, (void *) &objp->do_servers.do_servers_val, + &objp->do_servers.do_servers_len, ~0, + sizeof (nis_server), (xdrproc_t) _xdr_nis_server); + if (__builtin_expect (res, TRUE)) + { + res = xdr_uint32_t (xdrs, &objp->do_ttl); + if (__builtin_expect (res, TRUE)) + res = xdr_array (xdrs, + (void *) &objp->do_armask.do_armask_val, + &objp->do_armask.do_armask_len, ~0, + sizeof (oar_mask), (xdrproc_t) xdr_oar_mask); + } + } + } + return res; +} + +static bool_t +xdr_entry_col (XDR *xdrs, entry_col *objp) +{ + bool_t res = xdr_u_int (xdrs, &objp->ec_flags); + if (__builtin_expect (res, TRUE)) + res = xdr_bytes (xdrs, (char **) &objp->ec_value.ec_value_val, + &objp->ec_value.ec_value_len, ~0); + return res; +} + +static bool_t +xdr_entry_obj (XDR *xdrs, entry_obj *objp) +{ + bool_t res = xdr_string (xdrs, &objp->en_type, ~0); + if (__builtin_expect (res, TRUE)) + res = xdr_array (xdrs, (void *) &objp->en_cols.en_cols_val, + &objp->en_cols.en_cols_len, ~0, + sizeof (entry_col), (xdrproc_t) xdr_entry_col); + return res; +} + +static bool_t +xdr_group_obj (XDR *xdrs, group_obj *objp) +{ + bool_t res = xdr_u_int (xdrs, &objp->gr_flags); + if (__builtin_expect (res, TRUE)) + res = xdr_array (xdrs, (void *) &objp->gr_members.gr_members_val, + &objp->gr_members.gr_members_len, ~0, + sizeof (nis_name), (xdrproc_t) _xdr_nis_name); + return res; +} + +static bool_t +xdr_link_obj (XDR *xdrs, link_obj *objp) +{ + bool_t res = xdr_zotypes (xdrs, &objp->li_rtype); + if (__builtin_expect (res, TRUE)) + { + res = xdr_array (xdrs, (void *) &objp->li_attrs.li_attrs_val, + &objp->li_attrs.li_attrs_len, ~0, + sizeof (nis_attr), (xdrproc_t) xdr_nis_attr); + if (__builtin_expect (res, TRUE)) + res = xdr_nis_name (xdrs, &objp->li_name); + } + return res; +} + +static bool_t +xdr_table_col (XDR *xdrs, table_col *objp) +{ + bool_t res = xdr_string (xdrs, &objp->tc_name, 64); + if (__builtin_expect (res, TRUE)) + { + res = xdr_u_int (xdrs, &objp->tc_flags); + if (__builtin_expect (res, TRUE)) + res = xdr_u_int (xdrs, &objp->tc_rights); + } + return res; +} + +static bool_t +xdr_table_obj (XDR *xdrs, table_obj *objp) +{ + bool_t res = xdr_string (xdrs, &objp->ta_type, 64); + if (__builtin_expect (res, TRUE)) + { + res = xdr_int (xdrs, &objp->ta_maxcol); + if (__builtin_expect (res, TRUE)) + { + res = xdr_u_char (xdrs, &objp->ta_sep); + if (__builtin_expect (res, TRUE)) + { + res = xdr_array (xdrs, (void *) &objp->ta_cols.ta_cols_val, + &objp->ta_cols.ta_cols_len, ~0, + sizeof (table_col), (xdrproc_t) xdr_table_col); + if (__builtin_expect (res, TRUE)) + res = xdr_string (xdrs, &objp->ta_path, ~0); + } + } + } + return res; +} + +static bool_t +xdr_objdata (XDR *xdrs, objdata *objp) +{ + bool_t res = xdr_zotypes (xdrs, &objp->zo_type); + if (!__builtin_expect (res, TRUE)) + return res; + switch (objp->zo_type) + { + case NIS_DIRECTORY_OBJ: + return _xdr_directory_obj (xdrs, &objp->objdata_u.di_data); + case NIS_GROUP_OBJ: + return xdr_group_obj (xdrs, &objp->objdata_u.gr_data); + case NIS_TABLE_OBJ: + return xdr_table_obj (xdrs, &objp->objdata_u.ta_data); + case NIS_ENTRY_OBJ: + return xdr_entry_obj (xdrs, &objp->objdata_u.en_data); + case NIS_LINK_OBJ: + return xdr_link_obj (xdrs, &objp->objdata_u.li_data); + case NIS_PRIVATE_OBJ: + return xdr_bytes (xdrs, &objp->objdata_u.po_data.po_data_val, + &objp->objdata_u.po_data.po_data_len, ~0); + case NIS_NO_OBJ: + case NIS_BOGUS_OBJ: + default: + return TRUE; + } +} + +static bool_t +xdr_nis_oid (XDR *xdrs, nis_oid *objp) +{ + bool_t res = xdr_uint32_t (xdrs, &objp->ctime); + if (__builtin_expect (res, TRUE)) + res = xdr_uint32_t (xdrs, &objp->mtime); + return res; +} + +bool_t +_xdr_nis_object (XDR *xdrs, nis_object *objp) +{ + bool_t res = xdr_nis_oid (xdrs, &objp->zo_oid); + if (__builtin_expect (res, TRUE)) + { + res = xdr_nis_name (xdrs, &objp->zo_name); + if (__builtin_expect (res, TRUE)) + { + res = xdr_nis_name (xdrs, &objp->zo_owner); + if (__builtin_expect (res, TRUE)) + { + res = xdr_nis_name (xdrs, &objp->zo_group); + if (__builtin_expect (res, TRUE)) + { + res = xdr_nis_name (xdrs, &objp->zo_domain); + if (__builtin_expect (res, TRUE)) + { + res = xdr_u_int (xdrs, &objp->zo_access); + if (__builtin_expect (res, TRUE)) + { + res = xdr_uint32_t (xdrs, &objp->zo_ttl); + if (__builtin_expect (res, TRUE)) + res = xdr_objdata (xdrs, &objp->zo_data); + } + } + } + } + } + } + return res; +} + +static __always_inline bool_t +xdr_nis_error (XDR *xdrs, nis_error *objp) +{ + return xdr_enum (xdrs, (enum_t *) objp); +} + +bool_t +_xdr_nis_error (XDR *xdrs, nis_error *objp) +{ + return xdr_nis_error (xdrs, objp); +} + +bool_t +_xdr_nis_result (XDR *xdrs, nis_result *objp) +{ + bool_t res = xdr_nis_error (xdrs, &objp->status); + if (__builtin_expect (res, TRUE)) + { + res = xdr_array (xdrs, (void *) &objp->objects.objects_val, + &objp->objects.objects_len, ~0, + sizeof (nis_object), (xdrproc_t) _xdr_nis_object); + if (__builtin_expect (res, TRUE)) + { + res = xdr_netobj (xdrs, &objp->cookie); + if (__builtin_expect (res, TRUE)) + { + res = xdr_uint32_t (xdrs, &objp->zticks); + if (__builtin_expect (res, TRUE)) + { + res = xdr_uint32_t (xdrs, &objp->dticks); + if (__builtin_expect (res, TRUE)) + { + res = xdr_uint32_t (xdrs, &objp->aticks); + if (__builtin_expect (res, TRUE)) + res = xdr_uint32_t (xdrs, &objp->cticks); + } + } + } + } + } + return res; +} +libnsl_hidden_nolink_def (_xdr_nis_result, GLIBC_PRIVATE) + +bool_t +_xdr_ns_request (XDR *xdrs, ns_request *objp) +{ + bool_t res = xdr_nis_name (xdrs, &objp->ns_name); + if (__builtin_expect (res, TRUE)) + res = xdr_array (xdrs, (void *) &objp->ns_object.ns_object_val, + &objp->ns_object.ns_object_len, 1, + sizeof (nis_object), (xdrproc_t) _xdr_nis_object); + return res; +} + +bool_t +_xdr_ib_request (XDR *xdrs, ib_request *objp) +{ + bool_t res = xdr_nis_name (xdrs, &objp->ibr_name); + if (__builtin_expect (res, TRUE)) + { + res = xdr_array (xdrs, (void *) &objp->ibr_srch.ibr_srch_val, + &objp->ibr_srch.ibr_srch_len, ~0, + sizeof (nis_attr), (xdrproc_t) xdr_nis_attr); + if (__builtin_expect (res, TRUE)) + { + res = xdr_u_int (xdrs, &objp->ibr_flags); + if (__builtin_expect (res, TRUE)) + { + res = xdr_array (xdrs, (void *) &objp->ibr_obj.ibr_obj_val, + &objp->ibr_obj.ibr_obj_len, 1, + sizeof (nis_object), + (xdrproc_t) _xdr_nis_object); + if (__builtin_expect (res, TRUE)) + { + res = xdr_array (xdrs, + (void *) &objp->ibr_cbhost.ibr_cbhost_val, + &objp->ibr_cbhost.ibr_cbhost_len, 1, + sizeof (nis_server), + (xdrproc_t) _xdr_nis_server); + if (__builtin_expect (res, TRUE)) + { + res = xdr_u_int (xdrs, &objp->ibr_bufsize); + if (__builtin_expect (res, TRUE)) + res = xdr_netobj (xdrs, &objp->ibr_cookie); + } + } + } + } + } + return res; +} +libnsl_hidden_nolink_def (_xdr_ib_request, GLIBC_PRIVATE) + +bool_t +_xdr_ping_args (XDR *xdrs, ping_args *objp) +{ + bool_t res = xdr_nis_name (xdrs, &objp->dir); + if (__builtin_expect (res, TRUE)) + res = xdr_uint32_t (xdrs, &objp->stamp); + return res; +} + +bool_t +_xdr_cp_result (XDR *xdrs, cp_result *objp) +{ + bool_t res = xdr_nis_error (xdrs, &objp->cp_status); + if (__builtin_expect (res, TRUE)) + { + res = xdr_uint32_t (xdrs, &objp->cp_zticks); + if (__builtin_expect (res, TRUE)) + res = xdr_uint32_t (xdrs, &objp->cp_dticks); + } + return res; +} + +bool_t +_xdr_nis_tag (XDR *xdrs, nis_tag *objp) +{ + bool_t res = xdr_u_int (xdrs, &objp->tag_type); + if (__builtin_expect (res, TRUE)) + res = xdr_string (xdrs, &objp->tag_val, ~0); + return res; +} + +bool_t +_xdr_nis_taglist (XDR *xdrs, nis_taglist *objp) +{ + return xdr_array (xdrs, (void *) &objp->tags.tags_val, + &objp->tags.tags_len, ~0, sizeof (nis_tag), + (xdrproc_t) _xdr_nis_tag); +} + +bool_t +_xdr_fd_args (XDR *xdrs, fd_args *objp) +{ + bool_t res = xdr_nis_name (xdrs, &objp->dir_name); + if (__builtin_expect (res, TRUE)) + res = xdr_nis_name (xdrs, &objp->requester); + return res; +} + +bool_t +_xdr_fd_result (XDR *xdrs, fd_result *objp) +{ + bool_t res = xdr_nis_error (xdrs, &objp->status); + if (__builtin_expect (res, TRUE)) + { + res = xdr_nis_name (xdrs, &objp->source); + if (__builtin_expect (res, TRUE)) + { + res = xdr_bytes (xdrs, (char **) &objp->dir_data.dir_data_val, + &objp->dir_data.dir_data_len, ~0); + if (__builtin_expect (res, TRUE)) + res = xdr_bytes (xdrs, (char **) &objp->signature.signature_val, + &objp->signature.signature_len, ~0); + } + } + return res; +} + +/* The following functions have prototypes in nis_callback.h. So + we make them public */ +bool_t +xdr_obj_p (XDR *xdrs, obj_p *objp) +{ + return xdr_pointer (xdrs, (char **)objp, sizeof (nis_object), + (xdrproc_t)_xdr_nis_object); +} +libnsl_hidden_nolink_def (xdr_obj_p, GLIBC_2_1) + +bool_t +xdr_cback_data (XDR *xdrs, cback_data *objp) +{ + return xdr_array (xdrs, (void *) &objp->entries.entries_val, + &objp->entries.entries_len, ~0, + sizeof (obj_p), (xdrproc_t) xdr_obj_p); +} +libnsl_hidden_nolink_def (xdr_cback_data, GLIBC_2_1) diff --git a/REORG.TODO/nis/nis_xdr.h b/REORG.TODO/nis/nis_xdr.h new file mode 100644 index 0000000000..f56608b590 --- /dev/null +++ b/REORG.TODO/nis/nis_xdr.h @@ -0,0 +1,43 @@ +/* Copyright (c) 1998-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef __NIS_XDR_H +#define __NIS_XDR_H 1 + +#include <features.h> + +extern bool_t _xdr_nis_attr (XDR *, nis_attr*) attribute_hidden; +extern bool_t _xdr_nis_name (XDR *, nis_name*) attribute_hidden; +extern bool_t _xdr_nis_server (XDR *, nis_server*) attribute_hidden; +extern bool_t _xdr_directory_obj (XDR *, directory_obj*) attribute_hidden; +extern bool_t _xdr_nis_object (XDR *, nis_object*) attribute_hidden; +extern bool_t _xdr_nis_error (XDR *, nis_error*) attribute_hidden; +extern bool_t _xdr_ns_request (XDR *, ns_request*) attribute_hidden; +extern bool_t _xdr_ping_args (XDR *, ping_args*) attribute_hidden; +extern bool_t _xdr_cp_result (XDR *, cp_result*) attribute_hidden; +extern bool_t _xdr_nis_tag (XDR *, nis_tag*) attribute_hidden; +extern bool_t _xdr_nis_taglist (XDR *, nis_taglist*) attribute_hidden; +extern bool_t _xdr_fd_args (XDR *, fd_args*) attribute_hidden; +extern bool_t _xdr_fd_result (XDR *, fd_result*) attribute_hidden; + +extern bool_t _xdr_ib_request (XDR *, ib_request*); +libnsl_hidden_proto (_xdr_ib_request) +extern bool_t _xdr_nis_result (XDR *, nis_result*); +libnsl_hidden_proto (_xdr_nis_result) + +#endif diff --git a/REORG.TODO/nis/nisplus-parser.h b/REORG.TODO/nis/nisplus-parser.h new file mode 100644 index 0000000000..313c02ffbb --- /dev/null +++ b/REORG.TODO/nis/nisplus-parser.h @@ -0,0 +1,35 @@ +/* Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef __NISPLUS_PARSER_H +#define __NISPLUS_PARSER_H 1 + +#include <pwd.h> +#include <grp.h> +#include <shadow.h> + +extern int _nss_nisplus_parse_pwent (nis_result *result, struct passwd *pw, + char *buffer, size_t buflen, int *errnop); + +extern int _nss_nisplus_parse_grent (nis_result *result, struct group *gr, + char *buffer, size_t buflen, int *errnop); + +extern int _nss_nisplus_parse_spent (nis_result *result, struct spwd *sp, + char *buffer, size_t buflen, int *errnop); + +#endif diff --git a/REORG.TODO/nis/nss b/REORG.TODO/nis/nss new file mode 100644 index 0000000000..0ac6774a1f --- /dev/null +++ b/REORG.TODO/nis/nss @@ -0,0 +1,37 @@ +# /etc/default/nss +# This file can theoretically contain a bunch of customization variables +# for Name Service Switch in the GNU C library. For now there are only +# four variables: +# +# NETID_AUTHORITATIVE +# If set to TRUE, the initgroups() function will accept the information +# from the netid.byname NIS map as authoritative. This can speed up the +# function significantly if the group.byname map is large. The content +# of the netid.byname map is used AS IS. The system administrator has +# to make sure it is correctly generated. +#NETID_AUTHORITATIVE=TRUE +# +# SERVICES_AUTHORITATIVE +# If set to TRUE, the getservbyname{,_r}() function will assume +# services.byservicename NIS map exists and is authoritative, particularly +# that it contains both keys with /proto and without /proto for both +# primary service names and service aliases. The system administrator +# has to make sure it is correctly generated. +#SERVICES_AUTHORITATIVE=TRUE +# +# SETENT_BATCH_READ +# If set to TRUE, various setXXent() functions will read the entire +# database at once and then hand out the requests one by one from +# memory with every getXXent() call. Otherwise each getXXent() call +# might result into a network communication with the server to get +# the next entry. +#SETENT_BATCH_READ=TRUE +# +# ADJUNCT_AS_SHADOW +# If set to TRUE, the passwd routines in the NIS NSS module will not +# use the passwd.adjunct.byname tables to fill in the password data +# in the passwd structure. This is a security problem if the NIS +# server cannot be trusted to send the passwd.adjuct table only to +# privileged clients. Instead the passwd.adjunct.byname table is +# used to synthesize the shadow.byname table if it does not exist. +#ADJUNCT_AS_SHADOW=TRUE diff --git a/REORG.TODO/nis/nss-default.c b/REORG.TODO/nis/nss-default.c new file mode 100644 index 0000000000..092e121107 --- /dev/null +++ b/REORG.TODO/nis/nss-default.c @@ -0,0 +1,127 @@ +/* Copyright (C) 1996-2017 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <stdio_ext.h> +#include <stdlib.h> +#include <string.h> +#include <libc-lock.h> + +#include <libnsl.h> + + +/* Path of the file. */ +static const char default_nss[] = "/etc/default/nss"; + +/* Flags once read from the file. */ +static int default_nss_flags; + +/* Code to make sure we call 'init' once. */ +__libc_once_define (static, once); + +/* Table of the recognized variables. */ +static const struct +{ + char name[23]; + unsigned int len; + int flag; +} vars[] = + { +#define STRNLEN(s) s, sizeof (s) - 1 + { STRNLEN ("NETID_AUTHORITATIVE"), NSS_FLAG_NETID_AUTHORITATIVE }, + { STRNLEN ("SERVICES_AUTHORITATIVE"), NSS_FLAG_SERVICES_AUTHORITATIVE }, + { STRNLEN ("SETENT_BATCH_READ"), NSS_FLAG_SETENT_BATCH_READ }, + { STRNLEN ("ADJUNCT_AS_SHADOW"), NSS_FLAG_ADJUNCT_AS_SHADOW }, + }; +#define nvars (sizeof (vars) / sizeof (vars[0])) + + +static void +init (void) +{ + int saved_errno = errno; + FILE *fp = fopen (default_nss, "rce"); + if (fp != NULL) + { + char *line = NULL; + size_t linelen = 0; + + __fsetlocking (fp, FSETLOCKING_BYCALLER); + + while (!feof_unlocked (fp)) + { + ssize_t n = getline (&line, &linelen, fp); + if (n <= 0) + break; + + /* Recognize only + + <THE-VARIABLE> = TRUE + + with arbitrary white spaces. */ + char *cp = line; + while (isspace (*cp)) + ++cp; + + /* Recognize comment lines. */ + if (*cp == '#') + continue; + + int idx; + for (idx = 0; idx < nvars; ++idx) + if (strncmp (cp, vars[idx].name, vars[idx].len) == 0) + break; + if (idx == nvars) + continue; + + cp += vars[idx].len; + while (isspace (*cp)) + ++cp; + if (*cp++ != '=') + continue; + while (isspace (*cp)) + ++cp; + + if (strncmp (cp, "TRUE", 4) != 0) + continue; + cp += 4; + + while (isspace (*cp)) + ++cp; + + if (*cp == '\0') + default_nss_flags |= vars[idx].flag; + } + + free (line); + + fclose (fp); + } + __set_errno (saved_errno); +} + + +int +_nsl_default_nss (void) +{ + /* If we have not yet read the file yet do it now. */ + __libc_once (once, init); + + return default_nss_flags; +} diff --git a/REORG.TODO/nis/nss-nis.c b/REORG.TODO/nis/nss-nis.c new file mode 100644 index 0000000000..31ebc4263a --- /dev/null +++ b/REORG.TODO/nis/nss-nis.c @@ -0,0 +1,44 @@ +/* Copyright (C) 1996-2017 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include "nss-nis.h" +#include "nsswitch.h" + + +/* Convert YP error number to NSS error number. */ +const 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 +}; +const unsigned int __yperr2nss_count = (sizeof (__yperr2nss_tab) + / sizeof (__yperr2nss_tab[0])); diff --git a/REORG.TODO/nis/nss-nis.h b/REORG.TODO/nis/nss-nis.h new file mode 100644 index 0000000000..3bb04991e7 --- /dev/null +++ b/REORG.TODO/nis/nss-nis.h @@ -0,0 +1,58 @@ +/* Copyright (C) 1996-2017 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#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. */ +extern const enum nss_status __yperr2nss_tab[] attribute_hidden; +extern const unsigned int __yperr2nss_count attribute_hidden; + +static inline enum nss_status +yperr2nss (int errval) +{ + if ((unsigned int) errval >= __yperr2nss_count) + return NSS_STATUS_UNAVAIL; + return __yperr2nss_tab[(unsigned int) errval]; +} + + +struct response_t +{ + struct response_t *next; + size_t size; + char mem[0]; +}; + +typedef struct intern_t +{ + struct response_t *start; + struct response_t *next; + size_t offset; +} intern_t; + + +extern int _nis_saveit (int instatus, char *inkey, int inkeylen, char *inval, + int invallen, char *indata) attribute_hidden; + + +#endif /* nis/nss-nis.h */ diff --git a/REORG.TODO/nis/nss-nisplus.c b/REORG.TODO/nis/nss-nisplus.c new file mode 100644 index 0000000000..9ff37d76ab --- /dev/null +++ b/REORG.TODO/nis/nss-nisplus.c @@ -0,0 +1,78 @@ +/* Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <rpcsvc/nis.h> + +#include "nss-nisplus.h" +#include "nsswitch.h" + + +/* Convert NIS+ error number to NSS error number. */ +const enum nss_status __niserr2nss_tab[] = +{ + [NIS_SUCCESS] = NSS_STATUS_SUCCESS, + [NIS_S_SUCCESS] = NSS_STATUS_SUCCESS, + [NIS_NOTFOUND] = NSS_STATUS_NOTFOUND, + [NIS_S_NOTFOUND] = NSS_STATUS_NOTFOUND, + [NIS_CACHEEXPIRED] = NSS_STATUS_UNAVAIL, + [NIS_NAMEUNREACHABLE] = NSS_STATUS_UNAVAIL, + [NIS_UNKNOWNOBJ] = NSS_STATUS_NOTFOUND, + [NIS_TRYAGAIN] = NSS_STATUS_TRYAGAIN, + [NIS_SYSTEMERROR] = NSS_STATUS_UNAVAIL, + [NIS_CHAINBROKEN] = NSS_STATUS_UNAVAIL, + [NIS_PERMISSION] = NSS_STATUS_UNAVAIL, + [NIS_NOTOWNER] = NSS_STATUS_UNAVAIL, + [NIS_NOT_ME] = NSS_STATUS_UNAVAIL, + [NIS_NOMEMORY] = NSS_STATUS_TRYAGAIN, + [NIS_NAMEEXISTS] = NSS_STATUS_UNAVAIL, + [NIS_NOTMASTER] = NSS_STATUS_UNAVAIL, + [NIS_INVALIDOBJ] = NSS_STATUS_UNAVAIL, + [NIS_BADNAME] = NSS_STATUS_UNAVAIL, + [NIS_NOCALLBACK] = NSS_STATUS_UNAVAIL, + [NIS_CBRESULTS] = NSS_STATUS_UNAVAIL, + [NIS_NOSUCHNAME] = NSS_STATUS_NOTFOUND, + [NIS_NOTUNIQUE] = NSS_STATUS_UNAVAIL, + [NIS_IBMODERROR] = NSS_STATUS_UNAVAIL, + [NIS_NOSUCHTABLE] = NSS_STATUS_UNAVAIL, + [NIS_TYPEMISMATCH] = NSS_STATUS_UNAVAIL, + [NIS_LINKNAMEERROR] = NSS_STATUS_UNAVAIL, + [NIS_PARTIAL] = NSS_STATUS_NOTFOUND, + [NIS_TOOMANYATTRS] = NSS_STATUS_UNAVAIL, + [NIS_RPCERROR] = NSS_STATUS_UNAVAIL, + [NIS_BADATTRIBUTE] = NSS_STATUS_UNAVAIL, + [NIS_NOTSEARCHABLE] = NSS_STATUS_UNAVAIL, + [NIS_CBERROR] = NSS_STATUS_UNAVAIL, + [NIS_FOREIGNNS] = NSS_STATUS_UNAVAIL, + [NIS_BADOBJECT] = NSS_STATUS_UNAVAIL, + [NIS_NOTSAMEOBJ] = NSS_STATUS_UNAVAIL, + [NIS_MODFAIL] = NSS_STATUS_UNAVAIL, + [NIS_BADREQUEST] = NSS_STATUS_UNAVAIL, + [NIS_NOTEMPTY] = NSS_STATUS_UNAVAIL, + [NIS_COLDSTART_ERR] = NSS_STATUS_UNAVAIL, + [NIS_RESYNC] = NSS_STATUS_UNAVAIL, + [NIS_FAIL] = NSS_STATUS_UNAVAIL, + [NIS_UNAVAIL] = NSS_STATUS_UNAVAIL, + [NIS_RES2BIG] = NSS_STATUS_UNAVAIL, + [NIS_SRVAUTH] = NSS_STATUS_UNAVAIL, + [NIS_CLNTAUTH] = NSS_STATUS_UNAVAIL, + [NIS_NOFILESPACE] = NSS_STATUS_UNAVAIL, + [NIS_NOPROC] = NSS_STATUS_UNAVAIL, + [NIS_DUMPLATER] = NSS_STATUS_UNAVAIL +}; +const unsigned int __niserr2nss_count = (sizeof (__niserr2nss_tab) + / sizeof (__niserr2nss_tab[0])); diff --git a/REORG.TODO/nis/nss-nisplus.h b/REORG.TODO/nis/nss-nisplus.h new file mode 100644 index 0000000000..8f16760ac2 --- /dev/null +++ b/REORG.TODO/nis/nss-nisplus.h @@ -0,0 +1,40 @@ +/* Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _NIS_NSS_NISPLUS_H +#define _NIS_NSS_NISPLUS_H 1 + +#include <rpcsvc/nis.h> + +#include "nsswitch.h" + + +/* Convert NIS+ error number to NSS error number. */ +extern const enum nss_status __niserr2nss_tab[] attribute_hidden; +extern const unsigned int __niserr2nss_count attribute_hidden; + +static enum nss_status +__attribute__ ((unused)) +niserr2nss (int errval) +{ + if ((unsigned int) errval >= __niserr2nss_count) + return NSS_STATUS_UNAVAIL; + return __niserr2nss_tab[(unsigned int) errval]; +} + +#endif /* nis/nss-nisplus.h */ diff --git a/REORG.TODO/nis/nss_compat/compat-grp.c b/REORG.TODO/nis/nss_compat/compat-grp.c new file mode 100644 index 0000000000..0381458c0c --- /dev/null +++ b/REORG.TODO/nis/nss_compat/compat-grp.c @@ -0,0 +1,683 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <grp.h> +#include <nss.h> +#include <nsswitch.h> +#include <stdio_ext.h> +#include <string.h> +#include <rpc/types.h> +#include <libc-lock.h> +#include <kernel-features.h> + +static service_user *ni; +static enum nss_status (*nss_setgrent) (int stayopen); +static enum nss_status (*nss_getgrnam_r) (const char *name, + struct group * grp, char *buffer, + size_t buflen, int *errnop); +static enum nss_status (*nss_getgrgid_r) (gid_t gid, struct group * grp, + char *buffer, size_t buflen, + int *errnop); +static enum nss_status (*nss_getgrent_r) (struct group * grp, char *buffer, + size_t buflen, int *errnop); +static enum nss_status (*nss_endgrent) (void); + +/* Get the declaration of the parser function. */ +#define ENTNAME grent +#define STRUCTURE group +#define EXTERN_PARSER +#include <nss/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 files; + enum nss_status setent_status; + FILE *stream; + struct blacklist_t blacklist; +}; +typedef struct ent_t ent_t; + +static ent_t ext_ent = { TRUE, NSS_STATUS_SUCCESS, 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 *); + +/* Initialize the NSS interface/functions. The calling function must + hold the lock. */ +static void +init_nss_interface (void) +{ + if (__nss_database_lookup ("group_compat", NULL, "nis", &ni) >= 0) + { + nss_setgrent = __nss_lookup_function (ni, "setgrent"); + nss_getgrnam_r = __nss_lookup_function (ni, "getgrnam_r"); + nss_getgrgid_r = __nss_lookup_function (ni, "getgrgid_r"); + nss_getgrent_r = __nss_lookup_function (ni, "getgrent_r"); + nss_endgrent = __nss_lookup_function (ni, "endgrent"); + } +} + +static enum nss_status +internal_setgrent (ent_t *ent, int stayopen, int needent) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + ent->files = TRUE; + + 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", "rme"); + + if (ent->stream == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + else + /* We take care of locking ourself. */ + __fsetlocking (ent->stream, FSETLOCKING_BYCALLER); + } + else + rewind (ent->stream); + + if (needent && status == NSS_STATUS_SUCCESS && nss_setgrent) + ent->setent_status = nss_setgrent (stayopen); + + return status; +} + + +enum nss_status +_nss_compat_setgrent (int stayopen) +{ + enum nss_status result; + + __libc_lock_lock (lock); + + if (ni == NULL) + init_nss_interface (); + + result = internal_setgrent (&ext_ent, stayopen, 1); + + __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; + } + + 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); + + if (nss_endgrent) + nss_endgrent (); + + result = internal_endgrent (&ext_ent); + + __libc_lock_unlock (lock); + + return result; +} + +/* get the next group from NSS (+ entry) */ +static enum nss_status +getgrent_next_nss (struct group *result, ent_t *ent, char *buffer, + size_t buflen, int *errnop) +{ + if (!nss_getgrent_r) + return NSS_STATUS_UNAVAIL; + + /* If the setgrent call failed, say so. */ + if (ent->setent_status != NSS_STATUS_SUCCESS) + return ent->setent_status; + + do + { + enum nss_status status; + + if ((status = nss_getgrent_r (result, buffer, buflen, errnop)) != + NSS_STATUS_SUCCESS) + return status; + } + while (in_blacklist (result->gr_name, strlen (result->gr_name), ent)); + + 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, ent_t *ent, + char *buffer, size_t buflen, int *errnop) +{ + if (!nss_getgrnam_r) + return NSS_STATUS_UNAVAIL; + + enum nss_status status = nss_getgrnam_r (name, result, buffer, buflen, + errnop); + if (status != NSS_STATUS_SUCCESS) + return status; + + if (in_blacklist (result->gr_name, strlen (result->gr_name), ent)) + return NSS_STATUS_NOTFOUND; + + /* We found the entry. */ + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +getgrent_next_file (struct group *result, ent_t *ent, + char *buffer, size_t buflen, int *errnop) +{ + struct parser_data *data = (void *) buffer; + while (1) + { + fpos_t pos; + int parse_res = 0; + char *p; + + do + { + /* We need at least 3 characters for one line. */ + if (__glibc_unlikely (buflen < 3)) + { + erange: + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + fgetpos (ent->stream, &pos); + buffer[buflen - 1] = '\xff'; + p = fgets_unlocked (buffer, buflen, ent->stream); + if (p == NULL && feof_unlocked (ent->stream)) + return NSS_STATUS_NOTFOUND; + + if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) + { + erange_reset: + fsetpos (ent->stream, &pos); + goto erange; + } + + /* 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, + errnop))); + + if (__glibc_unlikely (parse_res == -1)) + /* The parser ran out of space. */ + goto erange_reset; + + 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] != '@') + { + size_t len = strlen (result->gr_name); + char buf[len]; + enum nss_status status; + + /* Store the group in the blacklist for the "+" at the end of + /etc/group */ + memcpy (buf, &result->gr_name[1], len); + status = getgrnam_plusgroup (&result->gr_name[1], result, ent, + buffer, buflen, errnop); + blacklist_store_name (buf, ent); + 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. */ + goto erange_reset; + + return status; + } + } + + /* +:... */ + if (result->gr_name[0] == '+' && result->gr_name[1] == '\0') + { + ent->files = FALSE; + + return getgrent_next_nss (result, ent, buffer, buflen, errnop); + } + } + + return NSS_STATUS_SUCCESS; +} + + +enum nss_status +_nss_compat_getgrent_r (struct group *grp, char *buffer, size_t buflen, + int *errnop) +{ + enum nss_status result = NSS_STATUS_SUCCESS; + + __libc_lock_lock (lock); + + /* Be prepared that the setgrent function was not called before. */ + if (ni == NULL) + init_nss_interface (); + + if (ext_ent.stream == NULL) + result = internal_setgrent (&ext_ent, 1, 1); + + if (result == NSS_STATUS_SUCCESS) + { + if (ext_ent.files) + result = getgrent_next_file (grp, &ext_ent, buffer, buflen, errnop); + else + result = getgrent_next_nss (grp, &ext_ent, buffer, buflen, errnop); + } + __libc_lock_unlock (lock); + + return result; +} + +/* 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, int *errnop) +{ + struct parser_data *data = (void *) buffer; + while (1) + { + fpos_t pos; + int parse_res = 0; + char *p; + + do + { + /* We need at least 3 characters for one line. */ + if (__glibc_unlikely (buflen < 3)) + { + erange: + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + fgetpos (ent->stream, &pos); + buffer[buflen - 1] = '\xff'; + p = fgets_unlocked (buffer, buflen, ent->stream); + if (p == NULL && feof_unlocked (ent->stream)) + return NSS_STATUS_NOTFOUND; + + if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) + { + erange_reset: + fsetpos (ent->stream, &pos); + goto erange; + } + + /* 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, + errnop))); + + if (__glibc_unlikely (parse_res == -1)) + /* The parser ran out of space. */ + goto erange_reset; + + /* 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, ent, + buffer, buflen, errnop); + 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, ent, + buffer, buflen, errnop); + 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, int *errnop) +{ + ent_t ent = { TRUE, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }}; + enum nss_status result; + + if (name[0] == '-' || name[0] == '+') + return NSS_STATUS_NOTFOUND; + + __libc_lock_lock (lock); + + if (ni == NULL) + init_nss_interface (); + + __libc_lock_unlock (lock); + + result = internal_setgrent (&ent, 0, 0); + + if (result == NSS_STATUS_SUCCESS) + result = internal_getgrnam_r (name, grp, &ent, buffer, buflen, errnop); + + internal_endgrent (&ent); + + return result; +} + +/* 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, int *errnop) +{ + struct parser_data *data = (void *) buffer; + while (1) + { + fpos_t pos; + int parse_res = 0; + char *p; + + do + { + /* We need at least 3 characters for one line. */ + if (__glibc_unlikely (buflen < 3)) + { + erange: + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + fgetpos (ent->stream, &pos); + buffer[buflen - 1] = '\xff'; + p = fgets_unlocked (buffer, buflen, ent->stream); + if (p == NULL && feof_unlocked (ent->stream)) + return NSS_STATUS_NOTFOUND; + + if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) + { + erange_reset: + fsetpos (ent->stream, &pos); + goto erange; + } + + /* 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, + errnop))); + + if (__glibc_unlikely (parse_res == -1)) + /* The parser ran out of space. */ + goto erange_reset; + + /* 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') + { + /* Yes, no +1, see the memcpy call below. */ + size_t len = strlen (result->gr_name); + char buf[len]; + enum nss_status status; + + /* Store the group in the blacklist for the "+" at the end of + /etc/group */ + memcpy (buf, &result->gr_name[1], len); + status = getgrnam_plusgroup (&result->gr_name[1], result, ent, + buffer, buflen, errnop); + blacklist_store_name (buf, ent); + if (status == NSS_STATUS_SUCCESS && result->gr_gid == gid) + break; + else + continue; + } + /* +:... */ + if (result->gr_name[0] == '+' && result->gr_name[1] == '\0') + { + if (!nss_getgrgid_r) + return NSS_STATUS_UNAVAIL; + + enum nss_status status = nss_getgrgid_r (gid, result, buffer, buflen, + errnop); + 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, int *errnop) +{ + ent_t ent = { TRUE, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }}; + enum nss_status result; + + __libc_lock_lock (lock); + + if (ni == NULL) + init_nss_interface (); + + __libc_lock_unlock (lock); + + result = internal_setgrent (&ent, 0, 0); + + if (result == NSS_STATUS_SUCCESS) + result = internal_getgrgid_r (gid, grp, &ent, buffer, buflen, errnop); + + internal_endgrent (&ent); + + return result; +} + + +/* 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/REORG.TODO/nis/nss_compat/compat-initgroups.c b/REORG.TODO/nis/nss_compat/compat-initgroups.c new file mode 100644 index 0000000000..795213448c --- /dev/null +++ b/REORG.TODO/nis/nss_compat/compat-initgroups.c @@ -0,0 +1,576 @@ +/* Copyright (C) 1998-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <grp.h> +#include <nss.h> +#include <stdio_ext.h> +#include <string.h> +#include <unistd.h> +#include <rpc/types.h> +#include <sys/param.h> +#include <nsswitch.h> +#include <libc-lock.h> +#include <kernel-features.h> +#include <scratch_buffer.h> + +static service_user *ni; +/* Type of the lookup function. */ +static enum nss_status (*nss_initgroups_dyn) (const char *, gid_t, + long int *, long int *, + gid_t **, long int, int *); +static enum nss_status (*nss_getgrnam_r) (const char *name, + struct group * grp, char *buffer, + size_t buflen, int *errnop); +static enum nss_status (*nss_getgrgid_r) (gid_t gid, struct group * grp, + char *buffer, size_t buflen, + int *errnop); +static enum nss_status (*nss_setgrent) (int stayopen); +static enum nss_status (*nss_getgrent_r) (struct group * grp, char *buffer, + size_t buflen, int *errnop); +static enum nss_status (*nss_endgrent) (void); + +/* Protect global state against multiple changers. */ +__libc_lock_define_initialized (static, lock) + + +/* Get the declaration of the parser function. */ +#define ENTNAME grent +#define STRUCTURE group +#define EXTERN_PARSER +#include <nss/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 files; + bool need_endgrent; + bool skip_initgroups_dyn; + FILE *stream; + struct blacklist_t blacklist; +}; +typedef struct ent_t ent_t; + +/* Prototypes for local functions. */ +static void blacklist_store_name (const char *, ent_t *); +static int in_blacklist (const char *, int, ent_t *); + +/* Initialize the NSS interface/functions. The calling function must + hold the lock. */ +static void +init_nss_interface (void) +{ + __libc_lock_lock (lock); + + /* Retest. */ + if (ni == NULL + && __nss_database_lookup ("group_compat", NULL, "nis", &ni) >= 0) + { + nss_initgroups_dyn = __nss_lookup_function (ni, "initgroups_dyn"); + nss_getgrnam_r = __nss_lookup_function (ni, "getgrnam_r"); + nss_getgrgid_r = __nss_lookup_function (ni, "getgrgid_r"); + nss_setgrent = __nss_lookup_function (ni, "setgrent"); + nss_getgrent_r = __nss_lookup_function (ni, "getgrent_r"); + nss_endgrent = __nss_lookup_function (ni, "endgrent"); + } + + __libc_lock_unlock (lock); +} + +static enum nss_status +internal_setgrent (ent_t *ent) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + ent->files = true; + + if (ni == NULL) + init_nss_interface (); + + if (ent->blacklist.data != NULL) + { + ent->blacklist.current = 1; + ent->blacklist.data[0] = '|'; + ent->blacklist.data[1] = '\0'; + } + else + ent->blacklist.current = 0; + + ent->stream = fopen ("/etc/group", "rme"); + + if (ent->stream == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + else + /* We take care of locking ourself. */ + __fsetlocking (ent->stream, FSETLOCKING_BYCALLER); + + return status; +} + + +static enum nss_status +internal_endgrent (ent_t *ent) +{ + if (ent->stream != NULL) + { + fclose (ent->stream); + ent->stream = NULL; + } + + 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->need_endgrent && nss_endgrent != NULL) + nss_endgrent (); + + return NSS_STATUS_SUCCESS; +} + +/* Add new group record. */ +static void +add_group (long int *start, long int *size, gid_t **groupsp, long int limit, + gid_t gid) +{ + gid_t *groups = *groupsp; + + /* Matches user. Insert this group. */ + if (__glibc_unlikely (*start == *size)) + { + /* Need a bigger buffer. */ + gid_t *newgroups; + long int newsize; + + if (limit > 0 && *size == limit) + /* We reached the maximum. */ + return; + + if (limit <= 0) + newsize = 2 * *size; + else + newsize = MIN (limit, 2 * *size); + + newgroups = realloc (groups, newsize * sizeof (*groups)); + if (newgroups == NULL) + return; + *groupsp = groups = newgroups; + *size = newsize; + } + + groups[*start] = gid; + *start += 1; +} + +/* This function checks, if the user is a member of this group and if + yes, add the group id to the list. Return nonzero is we couldn't + handle the group because the user is not in the member list. */ +static int +check_and_add_group (const char *user, gid_t group, long int *start, + long int *size, gid_t **groupsp, long int limit, + struct group *grp) +{ + char **member; + + /* Don't add main group to list of groups. */ + if (grp->gr_gid == group) + return 0; + + for (member = grp->gr_mem; *member != NULL; ++member) + if (strcmp (*member, user) == 0) + { + add_group (start, size, groupsp, limit, grp->gr_gid); + return 0; + } + + return 1; +} + +/* Get the next group from NSS (+ entry). If the NSS module supports + initgroups_dyn, get all entries at once. */ +static enum nss_status +getgrent_next_nss (ent_t *ent, char *buffer, size_t buflen, const char *user, + gid_t group, long int *start, long int *size, + gid_t **groupsp, long int limit, int *errnop) +{ + enum nss_status status; + struct group grpbuf; + + /* Try nss_initgroups_dyn if supported. We also need getgrgid_r. + If this function is not supported, step through the whole group + database with getgrent_r. */ + if (! ent->skip_initgroups_dyn) + { + long int mystart = 0; + long int mysize = limit <= 0 ? *size : limit; + gid_t *mygroups = malloc (mysize * sizeof (gid_t)); + + if (mygroups == NULL) + return NSS_STATUS_TRYAGAIN; + + /* For every gid in the list we get from the NSS module, + get the whole group entry. We need to do this, since we + need the group name to check if it is in the blacklist. + In worst case, this is as twice as slow as stepping with + getgrent_r through the whole group database. But for large + group databases this is faster, since the user can only be + in a limited number of groups. */ + if (nss_initgroups_dyn (user, group, &mystart, &mysize, &mygroups, + limit, errnop) == NSS_STATUS_SUCCESS) + { + status = NSS_STATUS_NOTFOUND; + + /* If there is no blacklist we can trust the underlying + initgroups implementation. */ + if (ent->blacklist.current <= 1) + for (int i = 0; i < mystart; i++) + add_group (start, size, groupsp, limit, mygroups[i]); + else + { + /* A temporary buffer. We use the normal buffer, until we find + an entry, for which this buffer is to small. In this case, we + overwrite the pointer with one to a bigger buffer. */ + char *tmpbuf = buffer; + size_t tmplen = buflen; + bool use_malloc = false; + + for (int i = 0; i < mystart; i++) + { + while ((status = nss_getgrgid_r (mygroups[i], &grpbuf, + tmpbuf, tmplen, errnop)) + == NSS_STATUS_TRYAGAIN + && *errnop == ERANGE) + { + if (__libc_use_alloca (tmplen * 2)) + { + if (tmpbuf == buffer) + { + tmplen *= 2; + tmpbuf = __alloca (tmplen); + } + else + tmpbuf = extend_alloca (tmpbuf, tmplen, tmplen * 2); + } + else + { + tmplen *= 2; + char *newbuf = realloc (use_malloc ? tmpbuf : NULL, tmplen); + + if (newbuf == NULL) + { + status = NSS_STATUS_TRYAGAIN; + goto done; + } + use_malloc = true; + tmpbuf = newbuf; + } + } + + if (__builtin_expect (status != NSS_STATUS_NOTFOUND, 1)) + { + if (__builtin_expect (status != NSS_STATUS_SUCCESS, 0)) + goto done; + + if (!in_blacklist (grpbuf.gr_name, + strlen (grpbuf.gr_name), ent) + && check_and_add_group (user, group, start, size, + groupsp, limit, &grpbuf)) + { + if (nss_setgrent != NULL) + { + nss_setgrent (1); + ent->need_endgrent = true; + } + ent->skip_initgroups_dyn = true; + + goto iter; + } + } + } + + status = NSS_STATUS_NOTFOUND; + + done: + if (use_malloc) + free (tmpbuf); + } + + free (mygroups); + + return status; + } + + free (mygroups); + } + + /* If we come here, the NSS module does not support initgroups_dyn + or we were confronted with a split group. In these cases we have + to step through the whole list ourself. */ + iter: + do + { + if ((status = nss_getgrent_r (&grpbuf, buffer, buflen, errnop)) != + NSS_STATUS_SUCCESS) + break; + } + while (in_blacklist (grpbuf.gr_name, strlen (grpbuf.gr_name), ent)); + + if (status == NSS_STATUS_SUCCESS) + check_and_add_group (user, group, start, size, groupsp, limit, &grpbuf); + + return status; +} + +static enum nss_status +internal_getgrent_r (ent_t *ent, char *buffer, size_t buflen, const char *user, + gid_t group, long int *start, long int *size, + gid_t **groupsp, long int limit, int *errnop) +{ + struct parser_data *data = (void *) buffer; + struct group grpbuf; + + if (!ent->files) + return getgrent_next_nss (ent, buffer, buflen, user, group, + start, size, groupsp, limit, errnop); + + while (1) + { + fpos_t pos; + int parse_res = 0; + char *p; + + do + { + /* We need at least 3 characters for one line. */ + if (__glibc_unlikely (buflen < 3)) + { + erange: + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + fgetpos (ent->stream, &pos); + buffer[buflen - 1] = '\xff'; + p = fgets_unlocked (buffer, buflen, ent->stream); + if (p == NULL && feof_unlocked (ent->stream)) + return NSS_STATUS_NOTFOUND; + + if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) + { + erange_reset: + fsetpos (ent->stream, &pos); + goto erange; + } + + /* 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, &grpbuf, data, buflen, + errnop))); + + if (__glibc_unlikely (parse_res == -1)) + /* The parser ran out of space. */ + goto erange_reset; + + if (grpbuf.gr_name[0] != '+' && grpbuf.gr_name[0] != '-') + /* This is a real entry. */ + break; + + /* -group */ + if (grpbuf.gr_name[0] == '-' && grpbuf.gr_name[1] != '\0' + && grpbuf.gr_name[1] != '@') + { + blacklist_store_name (&grpbuf.gr_name[1], ent); + continue; + } + + /* +group */ + if (grpbuf.gr_name[0] == '+' && grpbuf.gr_name[1] != '\0' + && grpbuf.gr_name[1] != '@') + { + if (in_blacklist (&grpbuf.gr_name[1], + strlen (&grpbuf.gr_name[1]), ent)) + continue; + /* Store the group in the blacklist for the "+" at the end of + /etc/group */ + blacklist_store_name (&grpbuf.gr_name[1], ent); + if (nss_getgrnam_r == NULL) + return NSS_STATUS_UNAVAIL; + else if (nss_getgrnam_r (&grpbuf.gr_name[1], &grpbuf, buffer, + buflen, errnop) != NSS_STATUS_SUCCESS) + continue; + + check_and_add_group (user, group, start, size, groupsp, + limit, &grpbuf); + + return NSS_STATUS_SUCCESS; + } + + /* +:... */ + if (grpbuf.gr_name[0] == '+' && grpbuf.gr_name[1] == '\0') + { + /* If the selected module does not support getgrent_r or + initgroups_dyn, abort. We cannot find the needed group + entries. */ + if (nss_initgroups_dyn == NULL || nss_getgrgid_r == NULL) + { + if (nss_setgrent != NULL) + { + nss_setgrent (1); + ent->need_endgrent = true; + } + ent->skip_initgroups_dyn = true; + + if (nss_getgrent_r == NULL) + return NSS_STATUS_UNAVAIL; + } + + ent->files = false; + + return getgrent_next_nss (ent, buffer, buflen, user, group, + start, size, groupsp, limit, errnop); + } + } + + check_and_add_group (user, group, start, size, groupsp, limit, &grpbuf); + + return NSS_STATUS_SUCCESS; +} + + +enum nss_status +_nss_compat_initgroups_dyn (const char *user, gid_t group, long int *start, + long int *size, gid_t **groupsp, long int limit, + int *errnop) +{ + enum nss_status status; + ent_t intern = { true, false, false, NULL, {NULL, 0, 0} }; + + status = internal_setgrent (&intern); + if (status != NSS_STATUS_SUCCESS) + return status; + + struct scratch_buffer tmpbuf; + scratch_buffer_init (&tmpbuf); + + do + { + while ((status = internal_getgrent_r (&intern, tmpbuf.data, tmpbuf.length, + user, group, start, size, + groupsp, limit, errnop)) + == NSS_STATUS_TRYAGAIN && *errnop == ERANGE) + if (!scratch_buffer_grow (&tmpbuf)) + goto done; + } + while (status == NSS_STATUS_SUCCESS); + + status = NSS_STATUS_SUCCESS; + + done: + scratch_buffer_free (&tmpbuf); + + internal_endgrent (&intern); + + 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/REORG.TODO/nis/nss_compat/compat-pwd.c b/REORG.TODO/nis/nss_compat/compat-pwd.c new file mode 100644 index 0000000000..0583a10b84 --- /dev/null +++ b/REORG.TODO/nis/nss_compat/compat-pwd.c @@ -0,0 +1,1132 @@ +/* Copyright (C) 1996-2017 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <netdb.h> +#include <nss.h> +#include <nsswitch.h> +#include <pwd.h> +#include <stdio_ext.h> +#include <string.h> +#include <rpc/types.h> +#include <rpcsvc/ypclnt.h> +#include <libc-lock.h> +#include <kernel-features.h> + +#include "netgroup.h" + +static service_user *ni; +static enum nss_status (*nss_setpwent) (int stayopen); +static enum nss_status (*nss_getpwnam_r) (const char *name, + struct passwd * pwd, char *buffer, + size_t buflen, int *errnop); +static enum nss_status (*nss_getpwuid_r) (uid_t uid, struct passwd * pwd, + char *buffer, size_t buflen, + int *errnop); +static enum nss_status (*nss_getpwent_r) (struct passwd * pwd, char *buffer, + size_t buflen, int *errnop); +static enum nss_status (*nss_endpwent) (void); + +/* Get the declaration of the parser function. */ +#define ENTNAME pwent +#define STRUCTURE passwd +#define EXTERN_PARSER +#include <nss/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 netgroup; + bool first; + bool files; + enum nss_status setent_status; + FILE *stream; + struct blacklist_t blacklist; + struct passwd pwd; + struct __netgrent netgrdata; +}; +typedef struct ent_t ent_t; + +static ent_t ext_ent = { false, false, true, NSS_STATUS_SUCCESS, 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 *); + +/* Initialize the NSS interface/functions. The calling function must + hold the lock. */ +static void +init_nss_interface (void) +{ + if (__nss_database_lookup ("passwd_compat", NULL, "nis", &ni) >= 0) + { + nss_setpwent = __nss_lookup_function (ni, "setpwent"); + nss_getpwnam_r = __nss_lookup_function (ni, "getpwnam_r"); + nss_getpwuid_r = __nss_lookup_function (ni, "getpwuid_r"); + nss_getpwent_r = __nss_lookup_function (ni, "getpwent_r"); + nss_endpwent = __nss_lookup_function (ni, "endpwent"); + } +} + +static void +give_pwd_free (struct passwd *pwd) +{ + free (pwd->pw_name); + free (pwd->pw_passwd); + free (pwd->pw_gecos); + free (pwd->pw_dir); + 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, int stayopen, int needent) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + ent->first = ent->netgroup = false; + ent->files = true; + ent->setent_status = NSS_STATUS_SUCCESS; + + /* If something was left over free it. */ + if (ent->netgroup) + __internal_endnetgrent (&ent->netgrdata); + + 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", "rme"); + + if (ent->stream == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + else + /* We take care of locking ourself. */ + __fsetlocking (ent->stream, FSETLOCKING_BYCALLER); + } + else + rewind (ent->stream); + + give_pwd_free (&ent->pwd); + + if (needent && status == NSS_STATUS_SUCCESS && nss_setpwent) + ent->setent_status = nss_setpwent (stayopen); + + return status; +} + + +enum nss_status +_nss_compat_setpwent (int stayopen) +{ + enum nss_status result; + + __libc_lock_lock (lock); + + if (ni == NULL) + init_nss_interface (); + + result = internal_setpwent (&ext_ent, stayopen, 1); + + __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->first = ent->netgroup = false; + + 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); + + if (nss_endpwent) + nss_endpwent (); + + result = internal_endpwent (&ext_ent); + + __libc_lock_unlock (lock); + + return result; +} + + +static enum nss_status +getpwent_next_nss_netgr (const char *name, struct passwd *result, ent_t *ent, + char *group, char *buffer, size_t buflen, + int *errnop) +{ + char *curdomain = NULL, *host, *user, *domain, *p2; + int status; + size_t p2len; + + /* Leave function if NSS module does not support getpwnam_r, + we need this function here. */ + if (!nss_getpwnam_r) + return NSS_STATUS_UNAVAIL; + + if (ent->first) + { + memset (&ent->netgrdata, 0, sizeof (struct __netgrent)); + __internal_setnetgrent (group, &ent->netgrdata); + ent->first = false; + } + + while (1) + { + status = __internal_getnetgrent_r (&host, &user, &domain, + &ent->netgrdata, buffer, buflen, + errnop); + 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) + { + if (curdomain == NULL + && yp_get_default_domain (&curdomain) != YPERR_SUCCESS) + { + __internal_endnetgrent (&ent->netgrdata); + ent->netgroup = false; + give_pwd_free (&ent->pwd); + return NSS_STATUS_UNAVAIL; + } + if (strcmp (curdomain, domain) != 0) + continue; + } + + /* If name != NULL, we are called from getpwnam. */ + if (name != NULL) + if (strcmp (user, name) != 0) + continue; + + p2len = pwd_need_buflen (&ent->pwd); + if (p2len > buflen) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + p2 = buffer + (buflen - p2len); + buflen -= p2len; + + if (nss_getpwnam_r (user, result, buffer, buflen, errnop) != + NSS_STATUS_SUCCESS) + continue; + + if (!in_blacklist (result->pw_name, strlen (result->pw_name), ent)) + { + /* Store the User in the blacklist for possible 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; +} + +/* get the next user from NSS (+ entry) */ +static enum nss_status +getpwent_next_nss (struct passwd *result, ent_t *ent, char *buffer, + size_t buflen, int *errnop) +{ + enum nss_status status; + char *p2; + size_t p2len; + + /* Return if NSS module does not support getpwent_r. */ + if (!nss_getpwent_r) + return NSS_STATUS_UNAVAIL; + + /* If the setpwent call failed, say so. */ + if (ent->setent_status != NSS_STATUS_SUCCESS) + return ent->setent_status; + + p2len = pwd_need_buflen (&ent->pwd); + if (p2len > buflen) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + p2 = buffer + (buflen - p2len); + buflen -= p2len; + + if (ent->first) + ent->first = false; + + do + { + if ((status = nss_getpwent_r (result, buffer, buflen, errnop)) != + NSS_STATUS_SUCCESS) + return status; + } + while (in_blacklist (result->pw_name, strlen (result->pw_name), ent)); + + 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, ent_t *ent, + char *buffer, size_t buflen, int *errnop) +{ + if (!nss_getpwnam_r) + return NSS_STATUS_UNAVAIL; + + struct passwd pwd; + memset (&pwd, '\0', sizeof (struct passwd)); + + copy_pwd_changes (&pwd, result, NULL, 0); + + size_t plen = pwd_need_buflen (&pwd); + if (plen > buflen) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + char *p = buffer + (buflen - plen); + buflen -= plen; + + enum nss_status status = nss_getpwnam_r (name, result, buffer, buflen, + errnop); + if (status != NSS_STATUS_SUCCESS) + return status; + + if (in_blacklist (result->pw_name, strlen (result->pw_name), ent)) + return NSS_STATUS_NOTFOUND; + + copy_pwd_changes (result, &pwd, p, plen); + give_pwd_free (&pwd); + /* We found the entry. */ + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +getpwent_next_file (struct passwd *result, ent_t *ent, + char *buffer, size_t buflen, int *errnop) +{ + struct parser_data *data = (void *) buffer; + while (1) + { + fpos_t pos; + char *p; + int parse_res; + + do + { + /* We need at least 3 characters for one line. */ + if (__glibc_unlikely (buflen < 3)) + { + erange: + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + fgetpos (ent->stream, &pos); + buffer[buflen - 1] = '\xff'; + p = fgets_unlocked (buffer, buflen, ent->stream); + if (p == NULL && feof_unlocked (ent->stream)) + return NSS_STATUS_NOTFOUND; + + if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) + { + erange_reset: + fsetpos (ent->stream, &pos); + goto erange; + } + + /* 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, + errnop))); + + if (__glibc_unlikely (parse_res == -1)) + /* The parser ran out of space. */ + goto erange_reset; + + 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') + { + /* XXX Do not use fixed length buffer. */ + char buf2[1024]; + char *user, *host, *domain; + struct __netgrent netgrdata; + + memset (&netgrdata, 0, sizeof (struct __netgrent)); + __internal_setnetgrent (&result->pw_name[2], &netgrdata); + while (__internal_getnetgrent_r (&host, &user, &domain, &netgrdata, + buf2, sizeof (buf2), errnop)) + { + 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') + { + enum nss_status status; + + ent->netgroup = true; + ent->first = true; + copy_pwd_changes (&ent->pwd, result, NULL, 0); + + status = getpwent_next_nss_netgr (NULL, result, ent, + &result->pw_name[2], + buffer, buflen, errnop); + 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] != '@') + { + size_t len = strlen (result->pw_name); + char buf[len]; + enum nss_status status; + + /* Store the User in the blacklist for the "+" at the end of + /etc/passwd */ + memcpy (buf, &result->pw_name[1], len); + status = getpwnam_plususer (&result->pw_name[1], result, ent, + buffer, buflen, errnop); + blacklist_store_name (buf, ent); + + 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) + { + /* The parser ran out of space */ + fsetpos (ent->stream, &pos); + *errnop = ERANGE; + } + return status; + } + } + + /* +:... */ + if (result->pw_name[0] == '+' && result->pw_name[1] == '\0') + { + ent->files = false; + ent->first = true; + copy_pwd_changes (&ent->pwd, result, NULL, 0); + + return getpwent_next_nss (result, ent, buffer, buflen, errnop); + } + } + + return NSS_STATUS_SUCCESS; +} + + +static enum nss_status +internal_getpwent_r (struct passwd *pw, ent_t *ent, char *buffer, + size_t buflen, int *errnop) +{ + if (ent->netgroup) + { + enum nss_status 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_nss_netgr (NULL, pw, ent, NULL, buffer, buflen, + errnop); + if (status == NSS_STATUS_RETURN) + return getpwent_next_file (pw, ent, buffer, buflen, errnop); + else + return status; + } + else if (ent->files) + return getpwent_next_file (pw, ent, buffer, buflen, errnop); + else + return getpwent_next_nss (pw, ent, buffer, buflen, errnop); + +} + +enum nss_status +_nss_compat_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen, + int *errnop) +{ + enum nss_status result = NSS_STATUS_SUCCESS; + + __libc_lock_lock (lock); + + /* Be prepared that the setpwent function was not called before. */ + if (ni == NULL) + init_nss_interface (); + + if (ext_ent.stream == NULL) + result = internal_setpwent (&ext_ent, 1, 1); + + if (result == NSS_STATUS_SUCCESS) + result = internal_getpwent_r (pwd, &ext_ent, buffer, buflen, errnop); + + __libc_lock_unlock (lock); + + return result; +} + +/* 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, int *errnop) +{ + struct parser_data *data = (void *) buffer; + + while (1) + { + fpos_t pos; + char *p; + int parse_res; + + do + { + /* We need at least 3 characters for one line. */ + if (__glibc_unlikely (buflen < 3)) + { + erange: + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + fgetpos (ent->stream, &pos); + buffer[buflen - 1] = '\xff'; + p = fgets_unlocked (buffer, buflen, ent->stream); + if (p == NULL && feof_unlocked (ent->stream)) + { + return NSS_STATUS_NOTFOUND; + } + if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) + { + erange_reset: + fsetpos (ent->stream, &pos); + goto erange; + } + + /* 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, + errnop))); + + if (__glibc_unlikely (parse_res == -1)) + /* The parser ran out of space. */ + goto erange_reset; + + /* 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') + { + if (innetgr (&result->pw_name[2], NULL, name, NULL)) + return NSS_STATUS_NOTFOUND; + continue; + } + + /* +@netgroup */ + if (result->pw_name[0] == '+' && result->pw_name[1] == '@' + && result->pw_name[2] != '\0') + { + enum nss_status status; + + if (innetgr (&result->pw_name[2], NULL, name, NULL)) + { + status = getpwnam_plususer (name, result, ent, buffer, + buflen, errnop); + + if (status == NSS_STATUS_RETURN) + continue; + + return status; + } + 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, ent, buffer, buflen, + errnop); + 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, ent, + buffer, buflen, errnop); + 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, int *errnop) +{ + enum nss_status result; + ent_t ent = { false, false, true, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }, + { NULL, NULL, 0, 0, NULL, NULL, NULL }}; + + if (name[0] == '-' || name[0] == '+') + return NSS_STATUS_NOTFOUND; + + __libc_lock_lock (lock); + + if (ni == NULL) + init_nss_interface (); + + __libc_lock_unlock (lock); + + result = internal_setpwent (&ent, 0, 0); + + if (result == NSS_STATUS_SUCCESS) + result = internal_getpwnam_r (name, pwd, &ent, buffer, buflen, errnop); + + internal_endpwent (&ent); + + return result; +} + +/* 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, int *errnop) +{ + struct passwd pwd; + char *p; + size_t plen; + + if (!nss_getpwuid_r) + return NSS_STATUS_UNAVAIL; + + memset (&pwd, '\0', sizeof (struct passwd)); + + copy_pwd_changes (&pwd, result, NULL, 0); + + plen = pwd_need_buflen (&pwd); + if (plen > buflen) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + p = buffer + (buflen - plen); + buflen -= plen; + + if (nss_getpwuid_r (uid, result, buffer, buflen, errnop) == + NSS_STATUS_SUCCESS) + { + 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 NSS subsystem 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, int *errnop) +{ + struct parser_data *data = (void *) buffer; + + while (1) + { + fpos_t pos; + char *p; + int parse_res; + + do + { + /* We need at least 3 characters for one line. */ + if (__glibc_unlikely (buflen < 3)) + { + erange: + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + fgetpos (ent->stream, &pos); + buffer[buflen - 1] = '\xff'; + p = fgets_unlocked (buffer, buflen, ent->stream); + if (p == NULL && feof_unlocked (ent->stream)) + return NSS_STATUS_NOTFOUND; + + if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) + { + erange_reset: + fsetpos (ent->stream, &pos); + goto erange; + } + + /* 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, + errnop))); + + if (__glibc_unlikely (parse_res == -1)) + /* The parser ran out of space. */ + goto erange_reset; + + /* 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') + { + /* -1, because we remove first two character of pw_name. */ + size_t len = strlen (result->pw_name) - 1; + char buf[len]; + enum nss_status status; + + memcpy (buf, &result->pw_name[2], len); + + status = getpwuid_plususer (uid, result, buffer, buflen, errnop); + if (status == NSS_STATUS_SUCCESS && + innetgr (buf, NULL, result->pw_name, NULL)) + return NSS_STATUS_NOTFOUND; + + continue; + } + + /* +@netgroup */ + if (result->pw_name[0] == '+' && result->pw_name[1] == '@' + && result->pw_name[2] != '\0') + { + /* -1, because we remove first two characters of pw_name. */ + size_t len = strlen (result->pw_name) - 1; + char buf[len]; + enum nss_status status; + + memcpy (buf, &result->pw_name[2], len); + + status = getpwuid_plususer (uid, result, buffer, buflen, errnop); + + if (status == NSS_STATUS_RETURN) + continue; + + if (status == NSS_STATUS_SUCCESS) + { + if (innetgr (buf, NULL, result->pw_name, NULL)) + return NSS_STATUS_SUCCESS; + } + else if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ + return NSS_STATUS_NOTFOUND; + else + return status; + + continue; + } + + /* -user */ + if (result->pw_name[0] == '-' && result->pw_name[1] != '\0' + && result->pw_name[1] != '@') + { + size_t len = strlen (result->pw_name); + char buf[len]; + enum nss_status status; + + memcpy (buf, &result->pw_name[1], len); + + status = getpwuid_plususer (uid, result, buffer, buflen, errnop); + if (status == NSS_STATUS_SUCCESS && + innetgr (buf, NULL, result->pw_name, NULL)) + return NSS_STATUS_NOTFOUND; + continue; + } + + /* +user */ + if (result->pw_name[0] == '+' && result->pw_name[1] != '\0' + && result->pw_name[1] != '@') + { + size_t len = strlen (result->pw_name); + char buf[len]; + enum nss_status status; + + memcpy (buf, &result->pw_name[1], len); + + status = getpwuid_plususer (uid, result, buffer, buflen, errnop); + + if (status == NSS_STATUS_RETURN) + continue; + + if (status == NSS_STATUS_SUCCESS) + { + if (strcmp (buf, result->pw_name) == 0) + return NSS_STATUS_SUCCESS; + } + else if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ + return NSS_STATUS_NOTFOUND; + else + return status; + + continue; + } + + /* +:... */ + if (result->pw_name[0] == '+' && result->pw_name[1] == '\0') + { + enum nss_status status; + + status = getpwuid_plususer (uid, result, buffer, buflen, errnop); + 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_getpwuid_r (uid_t uid, struct passwd *pwd, + char *buffer, size_t buflen, int *errnop) +{ + enum nss_status result; + ent_t ent = { false, false, true, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }, + { NULL, NULL, 0, 0, NULL, NULL, NULL }}; + + __libc_lock_lock (lock); + + if (ni == NULL) + init_nss_interface (); + + __libc_lock_unlock (lock); + + result = internal_setpwent (&ent, 0, 0); + + if (result == NSS_STATUS_SUCCESS) + result = internal_getpwuid_r (uid, pwd, &ent, buffer, buflen, errnop); + + internal_endpwent (&ent); + + return result; +} + + +/* 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/REORG.TODO/nis/nss_compat/compat-spwd.c b/REORG.TODO/nis/nss_compat/compat-spwd.c new file mode 100644 index 0000000000..eec3af3d15 --- /dev/null +++ b/REORG.TODO/nis/nss_compat/compat-spwd.c @@ -0,0 +1,858 @@ +/* Copyright (C) 1996-2017 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <netdb.h> +#include <nss.h> +#include <nsswitch.h> +#include <shadow.h> +#include <stdio_ext.h> +#include <string.h> +#include <rpc/types.h> +#include <rpcsvc/ypclnt.h> +#include <libc-lock.h> +#include <kernel-features.h> + +#include "netgroup.h" + +static service_user *ni; +static enum nss_status (*nss_setspent) (int stayopen); +static enum nss_status (*nss_getspnam_r) (const char *name, struct spwd * sp, + char *buffer, size_t buflen, + int *errnop); +static enum nss_status (*nss_getspent_r) (struct spwd * sp, char *buffer, + size_t buflen, int *errnop); +static enum nss_status (*nss_endspent) (void); + +/* Get the declaration of the parser function. */ +#define ENTNAME spent +#define STRUCTURE spwd +#define EXTERN_PARSER +#include <nss/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 netgroup; + bool files; + bool first; + enum nss_status setent_status; + FILE *stream; + struct blacklist_t blacklist; + struct spwd pwd; + struct __netgrent netgrdata; +}; +typedef struct ent_t ent_t; + +static ent_t ext_ent = { false, true, false, NSS_STATUS_SUCCESS, 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 *); + +/* Initialize the NSS interface/functions. The calling function must + hold the lock. */ +static void +init_nss_interface (void) +{ + if (__nss_database_lookup ("shadow_compat", "passwd_compat", + "nis", &ni) >= 0) + { + nss_setspent = __nss_lookup_function (ni, "setspent"); + nss_getspnam_r = __nss_lookup_function (ni, "getspnam_r"); + nss_getspent_r = __nss_lookup_function (ni, "getspent_r"); + nss_endspent = __nss_lookup_function (ni, "endspent"); + } +} + +static void +give_spwd_free (struct spwd *pwd) +{ + free (pwd->sp_namp); + free (pwd->sp_pwdp); + + memset (pwd, '\0', sizeof (struct spwd)); + pwd->sp_warn = -1; + pwd->sp_inact = -1; + pwd->sp_expire = -1; + pwd->sp_flag = ~0ul; +} + +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 != -1) + dest->sp_warn = src->sp_warn; + if (src->sp_inact != -1) + dest->sp_inact = src->sp_inact; + if (src->sp_expire != -1) + dest->sp_expire = src->sp_expire; + if (src->sp_flag != ~0ul) + dest->sp_flag = src->sp_flag; +} + +static enum nss_status +internal_setspent (ent_t *ent, int stayopen, int needent) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + ent->first = ent->netgroup = 0; + ent->files = true; + + /* If something was left over free it. */ + if (ent->netgroup) + __internal_endnetgrent (&ent->netgrdata); + + 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", "rme"); + + if (ent->stream == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + else + /* We take care of locking ourself. */ + __fsetlocking (ent->stream, FSETLOCKING_BYCALLER); + } + else + rewind (ent->stream); + + give_spwd_free (&ent->pwd); + + if (needent && status == NSS_STATUS_SUCCESS && nss_setspent) + ent->setent_status = nss_setspent (stayopen); + + return status; +} + + +enum nss_status +_nss_compat_setspent (int stayopen) +{ + enum nss_status result; + + __libc_lock_lock (lock); + + if (ni == NULL) + init_nss_interface (); + + result = internal_setspent (&ext_ent, stayopen, 1); + + __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->first = ent->netgroup = false; + ent->files = true; + + 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); + + if (nss_endspent) + nss_endspent (); + + result = internal_endspent (&ext_ent); + + __libc_lock_unlock (lock); + + return result; +} + + +static enum nss_status +getspent_next_nss_netgr (const char *name, struct spwd *result, ent_t *ent, + char *group, char *buffer, size_t buflen, + int *errnop) +{ + char *curdomain = NULL, *host, *user, *domain, *p2; + size_t p2len; + + if (!nss_getspnam_r) + return NSS_STATUS_UNAVAIL; + + /* If the setpwent call failed, say so. */ + if (ent->setent_status != NSS_STATUS_SUCCESS) + return ent->setent_status; + + if (ent->first) + { + memset (&ent->netgrdata, 0, sizeof (struct __netgrent)); + __internal_setnetgrent (group, &ent->netgrdata); + ent->first = false; + } + + while (1) + { + enum nss_status status; + + status = __internal_getnetgrent_r (&host, &user, &domain, + &ent->netgrdata, buffer, buflen, + errnop); + if (status != 1) + { + __internal_endnetgrent (&ent->netgrdata); + ent->netgroup = false; + give_spwd_free (&ent->pwd); + return NSS_STATUS_RETURN; + } + + if (user == NULL || user[0] == '-') + continue; + + if (domain != NULL) + { + if (curdomain == NULL + && yp_get_default_domain (&curdomain) != YPERR_SUCCESS) + { + __internal_endnetgrent (&ent->netgrdata); + ent->netgroup = false; + give_spwd_free (&ent->pwd); + return NSS_STATUS_UNAVAIL; + } + if (strcmp (curdomain, domain) != 0) + continue; + } + + /* If name != NULL, we are called from getpwnam */ + if (name != NULL) + if (strcmp (user, name) != 0) + continue; + + p2len = spwd_need_buflen (&ent->pwd); + if (p2len > buflen) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + p2 = buffer + (buflen - p2len); + buflen -= p2len; + + if (nss_getspnam_r (user, result, buffer, buflen, errnop) != + NSS_STATUS_SUCCESS) + continue; + + if (!in_blacklist (result->sp_namp, strlen (result->sp_namp), ent)) + { + /* Store the User in the blacklist for possible 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_nss (struct spwd *result, ent_t *ent, + char *buffer, size_t buflen, int *errnop) +{ + enum nss_status status; + char *p2; + size_t p2len; + + if (!nss_getspent_r) + return NSS_STATUS_UNAVAIL; + + p2len = spwd_need_buflen (&ent->pwd); + if (p2len > buflen) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + p2 = buffer + (buflen - p2len); + buflen -= p2len; + do + { + if ((status = nss_getspent_r (result, buffer, buflen, errnop)) != + NSS_STATUS_SUCCESS) + return status; + } + while (in_blacklist (result->sp_namp, strlen (result->sp_namp), ent)); + + 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, ent_t *ent, + char *buffer, size_t buflen, int *errnop) +{ + if (!nss_getspnam_r) + return NSS_STATUS_UNAVAIL; + + struct spwd pwd; + memset (&pwd, '\0', sizeof (struct spwd)); + pwd.sp_warn = -1; + pwd.sp_inact = -1; + pwd.sp_expire = -1; + pwd.sp_flag = ~0ul; + + copy_spwd_changes (&pwd, result, NULL, 0); + + size_t plen = spwd_need_buflen (&pwd); + if (plen > buflen) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + char *p = buffer + (buflen - plen); + buflen -= plen; + + enum nss_status status = nss_getspnam_r (name, result, buffer, buflen, + errnop); + if (status != NSS_STATUS_SUCCESS) + return status; + + if (in_blacklist (result->sp_namp, strlen (result->sp_namp), ent)) + return NSS_STATUS_NOTFOUND; + + copy_spwd_changes (result, &pwd, p, plen); + give_spwd_free (&pwd); + /* We found the entry. */ + return NSS_STATUS_SUCCESS; +} + + +static enum nss_status +getspent_next_file (struct spwd *result, ent_t *ent, + char *buffer, size_t buflen, int *errnop) +{ + struct parser_data *data = (void *) buffer; + while (1) + { + fpos_t pos; + int parse_res = 0; + char *p; + + do + { + /* We need at least 3 characters for one line. */ + if (__glibc_unlikely (buflen < 3)) + { + erange: + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + fgetpos (ent->stream, &pos); + buffer[buflen - 1] = '\xff'; + p = fgets_unlocked (buffer, buflen, ent->stream); + if (p == NULL && feof_unlocked (ent->stream)) + return NSS_STATUS_NOTFOUND; + + if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) + { + erange_reset: + fsetpos (ent->stream, &pos); + goto erange; + } + + /* 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, errnop))); + + if (__glibc_unlikely (parse_res == -1)) + /* The parser ran out of space. */ + goto erange_reset; + + 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') + { + /* XXX Do not use fixed length buffers. */ + char buf2[1024]; + char *user, *host, *domain; + struct __netgrent netgrdata; + + memset (&netgrdata, 0, sizeof (struct __netgrent)); + __internal_setnetgrent (&result->sp_namp[2], &netgrdata); + while (__internal_getnetgrent_r (&host, &user, &domain, + &netgrdata, buf2, sizeof (buf2), + errnop)) + { + 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_nss_netgr (NULL, result, ent, + &result->sp_namp[2], + buffer, buflen, errnop); + 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] != '@') + { + size_t len = strlen (result->sp_namp); + char buf[len]; + enum nss_status status; + + /* Store the User in the blacklist for the "+" at the end of + /etc/passwd */ + memcpy (buf, &result->sp_namp[1], len); + status = getspnam_plususer (&result->sp_namp[1], result, ent, + buffer, buflen, errnop); + blacklist_store_name (buf, ent); + + if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ + break; + /* We couldn't parse the entry */ + else if (status == NSS_STATUS_RETURN + /* entry doesn't exist */ + || status == NSS_STATUS_NOTFOUND) + continue; + else + { + if (status == NSS_STATUS_TRYAGAIN) + { + fsetpos (ent->stream, &pos); + *errnop = ERANGE; + } + return status; + } + } + + /* +:... */ + if (result->sp_namp[0] == '+' && result->sp_namp[1] == '\0') + { + ent->files = false; + ent->first = true; + copy_spwd_changes (&ent->pwd, result, NULL, 0); + + return getspent_next_nss (result, ent, buffer, buflen, errnop); + } + } + + return NSS_STATUS_SUCCESS; +} + + +static enum nss_status +internal_getspent_r (struct spwd *pw, ent_t *ent, + char *buffer, size_t buflen, int *errnop) +{ + if (ent->netgroup) + { + enum nss_status 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_nss_netgr (NULL, pw, ent, NULL, buffer, + buflen, errnop); + + if (status == NSS_STATUS_RETURN) + return getspent_next_file (pw, ent, buffer, buflen, errnop); + else + return status; + } + else if (ent->files) + return getspent_next_file (pw, ent, buffer, buflen, errnop); + else + return getspent_next_nss (pw, ent, buffer, buflen, errnop); +} + + +enum nss_status +_nss_compat_getspent_r (struct spwd *pwd, char *buffer, size_t buflen, + int *errnop) +{ + enum nss_status result = NSS_STATUS_SUCCESS; + + __libc_lock_lock (lock); + + /* Be prepared that the setpwent function was not called before. */ + if (ni == NULL) + init_nss_interface (); + + if (ext_ent.stream == NULL) + result = internal_setspent (&ext_ent, 1, 1); + + if (result == NSS_STATUS_SUCCESS) + result = internal_getspent_r (pwd, &ext_ent, buffer, buflen, errnop); + + __libc_lock_unlock (lock); + + return result; +} + + +/* 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, int *errnop) +{ + struct parser_data *data = (void *) buffer; + + while (1) + { + fpos_t pos; + char *p; + int parse_res; + + do + { + /* We need at least 3 characters for one line. */ + if (__glibc_unlikely (buflen < 3)) + { + erange: + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + fgetpos (ent->stream, &pos); + buffer[buflen - 1] = '\xff'; + p = fgets_unlocked (buffer, buflen, ent->stream); + if (p == NULL && feof_unlocked (ent->stream)) + return NSS_STATUS_NOTFOUND; + + if (p == NULL || buffer[buflen - 1] != '\xff') + { + erange_reset: + fsetpos (ent->stream, &pos); + goto erange; + } + + /* 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, + errnop))); + + if (__glibc_unlikely (parse_res == -1)) + /* The parser ran out of space. */ + goto erange_reset; + + /* 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 the loaded NSS module does not support this service, add + all users from a +@netgroup entry to the blacklist, too. */ + if (result->sp_namp[0] == '-' && result->sp_namp[1] == '@' + && result->sp_namp[2] != '\0') + { + if (innetgr (&result->sp_namp[2], NULL, name, NULL)) + return NSS_STATUS_NOTFOUND; + continue; + } + + /* +@netgroup */ + if (result->sp_namp[0] == '+' && result->sp_namp[1] == '@' + && result->sp_namp[2] != '\0') + { + enum nss_status status; + + if (innetgr (&result->sp_namp[2], NULL, name, NULL)) + { + status = getspnam_plususer (name, result, ent, buffer, + buflen, errnop); + + if (status == NSS_STATUS_RETURN) + continue; + + return status; + } + 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, ent, + buffer, buflen, errnop); + + 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, ent, + buffer, buflen, errnop); + + 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_getspnam_r (const char *name, struct spwd *pwd, + char *buffer, size_t buflen, int *errnop) +{ + enum nss_status result; + ent_t ent = { false, true, false, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0}, + { NULL, NULL, 0, 0, 0, 0, 0, 0, 0}}; + + if (name[0] == '-' || name[0] == '+') + return NSS_STATUS_NOTFOUND; + + __libc_lock_lock (lock); + + if (ni == NULL) + init_nss_interface (); + + __libc_lock_unlock (lock); + + result = internal_setspent (&ent, 0, 0); + + if (result == NSS_STATUS_SUCCESS) + result = internal_getspnam_r (name, pwd, &ent, buffer, buflen, errnop); + + internal_endspent (&ent); + + return result; +} + + +/* 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/REORG.TODO/nis/nss_nis/nis-alias.c b/REORG.TODO/nis/nss_nis/nis-alias.c new file mode 100644 index 0000000000..c9c89db6ce --- /dev/null +++ b/REORG.TODO/nis/nss_nis/nis-alias.c @@ -0,0 +1,281 @@ +/* Copyright (C) 1996-2017 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <nss.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <aliases.h> +#include <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; +static int oldkeylen; + +static int +_nss_nis_parse_aliasent (const char *key, char *alias, struct aliasent *result, + char *buffer, size_t buflen, int *errnop) +{ + 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: + *errnop = 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; +} +/* The 'endaliasent' function is identical. */ +strong_alias (_nss_nis_setaliasent, _nss_nis_endaliasent) + +static enum nss_status +internal_nis_getaliasent_r (struct aliasent *alias, char *buffer, + size_t buflen, int *errnop) +{ + char *domain; + + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + alias->alias_local = 0; + + /* Get the next entry until we found a correct one. */ + int parse_res; + do + { + char *result; + int len; + char *outkey; + int keylen; + int yperr; + + if (new_start) + yperr = yp_first (domain, "mail.aliases", &outkey, &keylen, &result, + &len); + else + yperr = yp_next (domain, "mail.aliases", oldkey, oldkeylen, &outkey, + &keylen, &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + char *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, errnop); + if (__glibc_unlikely (parse_res == -1)) + { + free (outkey); + *errnop = 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, + int *errnop) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_getaliasent_r (alias, buffer, buflen, errnop); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_getaliasbyname_r (const char *name, struct aliasent *alias, + char *buffer, size_t buflen, int *errnop) +{ + if (name == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + size_t namlen = strlen (name); + char *name2; + int use_alloca = __libc_use_alloca (namlen + 1); + if (use_alloca) + name2 = __alloca (namlen + 1); + else + { + name2 = malloc (namlen + 1); + if (name2 == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } + } + + /* Convert name to lowercase. */ + size_t i; + for (i = 0; i < namlen; ++i) + name2[i] = _tolower (name[i]); + name2[i] = '\0'; + + char *result; + int len; + int yperr = yp_match (domain, "mail.aliases", name2, namlen, &result, &len); + + if (!use_alloca) + free (name2); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + alias->alias_local = 0; + int parse_res = _nss_nis_parse_aliasent (name, p, alias, buffer, buflen, + errnop); + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + + return NSS_STATUS_SUCCESS; +} diff --git a/REORG.TODO/nis/nss_nis/nis-ethers.c b/REORG.TODO/nis/nss_nis/nis-ethers.c new file mode 100644 index 0000000000..2a466626e8 --- /dev/null +++ b/REORG.TODO/nis/nss_nis/nis-ethers.c @@ -0,0 +1,292 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <nss.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <libc-lock.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> +#include <netinet/ether.h> +#include <netinet/if_ether.h> + +#include "nss-nis.h" + +/* Protect global state against multiple changers */ +__libc_lock_define_initialized (static, lock) + +/* Get the declaration of the parser function. */ +#define ENTNAME etherent +#define STRUCTURE etherent +#define EXTERN_PARSER +#include <nss/nss_files/files-parse.c> + +struct response +{ + struct response *next; + char val[0]; +}; + +static struct response *start; +static struct response *next; + +static int +saveit (int instatus, char *inkey, int inkeylen, char *inval, + int invallen, char *indata) +{ + if (instatus != YP_TRUE) + return 1; + + if (inkey && inkeylen > 0 && inval && invallen > 0) + { + struct response *newp = malloc (sizeof (struct response) + invallen + 1); + if (newp == NULL) + return 1; /* We have no error code for out of memory */ + + if (start == NULL) + start = newp; + else + next->next = newp; + next = newp; + + newp->next = NULL; + *((char *) mempcpy (newp->val, inval, invallen)) = '\0'; + } + + return 0; +} + +static void +internal_nis_endetherent (void) +{ + while (start != NULL) + { + next = start; + start = start->next; + free (next); + } +} + +enum nss_status +_nss_nis_endetherent (void) +{ + __libc_lock_lock (lock); + + internal_nis_endetherent (); + next = NULL; + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_nis_setetherent (void) +{ + char *domainname; + struct ypall_callback ypcb; + enum nss_status status; + + yp_get_default_domain (&domainname); + + internal_nis_endetherent (); + + ypcb.foreach = saveit; + ypcb.data = NULL; + status = yperr2nss (yp_all (domainname, "ethers.byname", &ypcb)); + next = start; + + return status; +} + +enum nss_status +_nss_nis_setetherent (int stayopen) +{ + enum nss_status result; + + __libc_lock_lock (lock); + + result = internal_nis_setetherent (); + + __libc_lock_unlock (lock); + + return result; +} + +static enum nss_status +internal_nis_getetherent_r (struct etherent *eth, char *buffer, size_t buflen, + int *errnop) +{ + 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); + + while (isspace (*p)) + ++p; + + parse_res = _nss_files_parse_etherent (p, eth, data, buflen, errnop); + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + next = next->next; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getetherent_r (struct etherent *result, char *buffer, size_t buflen, + int *errnop) +{ + int status; + + __libc_lock_lock (lock); + + status = internal_nis_getetherent_r (result, buffer, buflen, errnop); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_gethostton_r (const char *name, struct etherent *eth, + char *buffer, size_t buflen, int *errnop) +{ + if (name == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + char *result; + int len; + int yperr = yp_match (domain, "ethers.byname", name, strlen (name), &result, + &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + int parse_res = _nss_files_parse_etherent (p, eth, (void *) buffer, buflen, + errnop); + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getntohost_r (const struct ether_addr *addr, struct etherent *eth, + char *buffer, size_t buflen, int *errnop) +{ + if (addr == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + char buf[33]; + int nlen = snprintf (buf, sizeof (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]); + + char *result; + int len; + int yperr = yp_match (domain, "ethers.byaddr", buf, nlen, &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + int parse_res = _nss_files_parse_etherent (p, eth, (void *) buffer, buflen, + errnop); + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + return NSS_STATUS_SUCCESS; +} diff --git a/REORG.TODO/nis/nss_nis/nis-grp.c b/REORG.TODO/nis/nss_nis/nis-grp.c new file mode 100644 index 0000000000..05b33920fc --- /dev/null +++ b/REORG.TODO/nis/nss_nis/nis-grp.c @@ -0,0 +1,359 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <ctype.h> +#include <errno.h> +#include <grp.h> +#include <nss.h> +#include <string.h> +#include <libc-lock.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> + +#include "nss-nis.h" +#include <libnsl.h> + +/* Get the declaration of the parser function. */ +#define ENTNAME grent +#define STRUCTURE group +#define EXTERN_PARSER +#include <nss/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; +static int oldkeylen; +static intern_t intern; + + +static void +internal_nis_endgrent (void) +{ + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + struct response_t *curr = intern.start; + + while (curr != NULL) + { + struct response_t *last = curr; + curr = curr->next; + free (last); + } + + intern.next = intern.start = NULL; +} + + +enum nss_status +_nss_nis_endgrent (void) +{ + __libc_lock_lock (lock); + + internal_nis_endgrent (); + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + + +enum nss_status +internal_nis_setgrent (void) +{ + /* We have to read all the data now. */ + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + struct ypall_callback ypcb; + + ypcb.foreach = _nis_saveit; + ypcb.data = (char *) &intern; + enum nss_status status = yperr2nss (yp_all (domain, "group.byname", &ypcb)); + + + /* Mark the last buffer as full. */ + if (intern.next != NULL) + intern.next->size = intern.offset; + + intern.next = intern.start; + intern.offset = 0; + + return status; +} + + +enum nss_status +_nss_nis_setgrent (int stayopen) +{ + enum nss_status result = NSS_STATUS_SUCCESS; + + __libc_lock_lock (lock); + + internal_nis_endgrent (); + + if (_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ) + result = internal_nis_setgrent (); + + __libc_lock_unlock (lock); + + return result; +} + + +static enum nss_status +internal_nis_getgrent_r (struct group *grp, char *buffer, size_t buflen, + int *errnop) +{ + /* If we read the entire database at setpwent time we just iterate + over the data we have in memory. */ + bool batch_read = intern.start != NULL; + + char *domain = NULL; + if (!batch_read && __builtin_expect (yp_get_default_domain (&domain), 0)) + return NSS_STATUS_UNAVAIL; + + /* Get the next entry until we found a correct one. */ + int parse_res; + do + { + char *result; + char *outkey; + int len; + int keylen; + + if (batch_read) + { + struct response_t *bucket; + + handle_batch_read: + bucket = intern.next; + + if (__glibc_unlikely (intern.offset >= bucket->size)) + { + if (bucket->next == NULL) + return NSS_STATUS_NOTFOUND; + + /* We look at all the content in the current bucket. Go on + to the next. */ + bucket = intern.next = bucket->next; + intern.offset = 0; + } + + for (result = &bucket->mem[intern.offset]; isspace (*result); + ++result) + ++intern.offset; + + len = strlen (result); + } + else + { + int yperr; + + if (new_start) + { + /* Maybe we should read the database in one piece. */ + if ((_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ) + && internal_nis_setgrent () == NSS_STATUS_SUCCESS + && intern.start != NULL) + { + batch_read = true; + goto handle_batch_read; + } + + yperr = yp_first (domain, "group.byname", &outkey, &keylen, + &result, &len); + } + else + yperr = yp_next (domain, "group.byname", oldkey, oldkeylen, + &outkey, &keylen, &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + } + + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + if (!batch_read) + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + if (!batch_read) + free (result); + + parse_res = _nss_files_parse_grent (p, grp, (void *) buffer, buflen, + errnop); + if (__glibc_unlikely (parse_res == -1)) + { + if (!batch_read) + free (outkey); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + if (batch_read) + intern.offset += len + 1; + else + { + free (oldkey); + oldkey = outkey; + oldkeylen = keylen; + new_start = 0; + } + } + while (parse_res < 1); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getgrent_r (struct group *result, char *buffer, size_t buflen, + int *errnop) +{ + int status; + + __libc_lock_lock (lock); + + status = internal_nis_getgrent_r (result, buffer, buflen, errnop); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_getgrnam_r (const char *name, struct group *grp, + char *buffer, size_t buflen, int *errnop) +{ + if (name == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + char *result; + int len; + int yperr = yp_match (domain, "group.byname", name, strlen (name), &result, + &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + int parse_res = _nss_files_parse_grent (p, grp, (void *) buffer, buflen, + errnop); + if (__builtin_expect (parse_res < 1, 0)) + { + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + 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, int *errnop) +{ + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + char buf[32]; + int nlen = sprintf (buf, "%lu", (unsigned long int) gid); + + char *result; + int len; + int yperr = yp_match (domain, "group.bygid", buf, nlen, &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + int parse_res = _nss_files_parse_grent (p, grp, (void *) buffer, buflen, + errnop); + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + return NSS_STATUS_SUCCESS; +} diff --git a/REORG.TODO/nis/nss_nis/nis-hosts.c b/REORG.TODO/nis/nss_nis/nis-hosts.c new file mode 100644 index 0000000000..f64dbdaecb --- /dev/null +++ b/REORG.TODO/nis/nss_nis/nis-hosts.c @@ -0,0 +1,567 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <nss.h> +#include <ctype.h> +/* The following is an ugly trick to avoid a prototype declaration for + _nss_nis_endgrent. */ +#define _nss_nis_endhostent _nss_nis_endhostent_XXX +#include <netdb.h> +#undef _nss_nis_endhostent +#include <string.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <resolv/resolv-internal.h> +#include <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> + +#define ENTNAME hostent +#define DATABASE "hosts" +#define NEED_H_ERRNO + +#define EXTRA_ARGS , af, flags +#define EXTRA_ARGS_DECL , int af, int flags + +#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/nss_files/files-parse.c> +LINE_PARSER +("#", + { + char *addr; + + STRING_FIELD (addr, isspace, 1); + + assert (af == AF_INET || af == AF_INET6 || af == AF_UNSPEC); + + /* Parse address. */ + if (af != AF_INET6 && inet_pton (AF_INET, addr, entdata->host_addr) > 0) + { + assert ((flags & AI_V4MAPPED) == 0 || af != AF_UNSPEC); + if (flags & AI_V4MAPPED) + { + 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 (af != AF_INET + && 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] = (char *) entdata->host_addr; + entdata->h_addr_ptrs[1] = NULL; + result->h_addr_list = entdata->h_addr_ptrs; + + 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 (int stayopen) +{ + __libc_lock_lock (lock); + + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} +/* Make _nss_nis_endhostent an alias of _nss_nis_sethostent. We do this + even though the prototypes don't match. The argument of sethostent + is used so this makes no difference. */ +strong_alias (_nss_nis_sethostent, _nss_nis_endhostent) + + +/* The calling function always need to get a lock first. */ +static enum nss_status +internal_nis_gethostent_r (struct hostent *host, char *buffer, + size_t buflen, int *errnop, int *h_errnop, + int af, int flags) +{ + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct parser_data); + buffer += pad; + + struct parser_data *data = (void *) buffer; + if (__glibc_unlikely (buflen < sizeof *data + 1 + pad)) + { + *errnop = ERANGE; + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + buflen -= pad; + + /* Get the next entry until we found a correct one. */ + const size_t linebuflen = buffer + buflen - data->linebuffer; + int parse_res; + do + { + char *result; + int len; + char *outkey; + int keylen; + int yperr; + if (new_start) + yperr = yp_first (domain, "hosts.byname", &outkey, &keylen, &result, + &len); + else + yperr = yp_next (domain, "hosts.byname", oldkey, oldkeylen, &outkey, + &keylen, &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + switch (retval) + { + case NSS_STATUS_TRYAGAIN: + *errnop = errno; + *h_errnop = TRY_AGAIN; + break; + case NSS_STATUS_NOTFOUND: + *h_errnop = HOST_NOT_FOUND; + break; + default: + *h_errnop = NO_RECOVERY; + break; + } + return retval; + } + + if (__glibc_unlikely ((size_t) (len + 1) > linebuflen)) + { + free (result); + *h_errnop = NETDB_INTERNAL; + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (data->linebuffer, result, len); + data->linebuffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = parse_line (p, host, data, buflen, errnop, af, flags); + if (__glibc_unlikely (parse_res == -1)) + { + free (outkey); + *h_errnop = NETDB_INTERNAL; + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + free (oldkey); + oldkey = outkey; + oldkeylen = keylen; + new_start = 0; + } + while (!parse_res); + + *h_errnop = NETDB_SUCCESS; + return NSS_STATUS_SUCCESS; +} + + +enum nss_status +_nss_nis_gethostent_r (struct hostent *host, char *buffer, size_t buflen, + int *errnop, int *h_errnop) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_gethostent_r (host, buffer, buflen, errnop, h_errnop, + (res_use_inet6 () ? AF_INET6 : AF_INET), + (res_use_inet6 () ? AI_V4MAPPED : 0 )); + + __libc_lock_unlock (lock); + + return status; +} + + +static enum nss_status +internal_gethostbyname2_r (const char *name, int af, struct hostent *host, + char *buffer, size_t buflen, int *errnop, + int *h_errnop, int flags) +{ + uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct parser_data); + buffer += pad; + + struct parser_data *data = (void *) buffer; + + if (name == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + char *domain; + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + if (buflen < sizeof *data + 1 + pad) + { + *h_errnop = NETDB_INTERNAL; + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + buflen -= pad; + + /* Convert name to lowercase. */ + size_t namlen = strlen (name); + /* Limit name length to the maximum size of an RPC packet. */ + if (namlen > UDPMSGSIZE) + { + *errnop = ERANGE; + return NSS_STATUS_UNAVAIL; + } + + char name2[namlen + 1]; + size_t i; + + for (i = 0; i < namlen; ++i) + name2[i] = tolower (name[i]); + name2[i] = '\0'; + + char *result; + int len; + int yperr = yp_match (domain, "hosts.byname", name2, namlen, &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + { + *h_errnop = TRY_AGAIN; + *errnop = errno; + } + if (retval == NSS_STATUS_NOTFOUND) + *h_errnop = HOST_NOT_FOUND; + return retval; + } + + const size_t linebuflen = buffer + buflen - data->linebuffer; + if (__glibc_unlikely ((size_t) (len + 1) > linebuflen)) + { + free (result); + *h_errnop = NETDB_INTERNAL; + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (data->linebuffer, result, len); + data->linebuffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + int parse_res = parse_line (p, host, data, buflen, errnop, af, flags); + + if (__glibc_unlikely (parse_res < 1 || host->h_addrtype != af)) + { + if (parse_res == -1) + { + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + else + { + *h_errnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } + } + + *h_errnop = NETDB_SUCCESS; + return NSS_STATUS_SUCCESS; +} + + +enum nss_status +_nss_nis_gethostbyname2_r (const char *name, int af, struct hostent *host, + char *buffer, size_t buflen, int *errnop, + int *h_errnop) +{ + if (af != AF_INET && af != AF_INET6) + { + *h_errnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } + + return internal_gethostbyname2_r (name, af, host, buffer, buflen, errnop, + h_errnop, + (res_use_inet6 () ? AI_V4MAPPED : 0)); +} + + +enum nss_status +_nss_nis_gethostbyname_r (const char *name, struct hostent *host, char *buffer, + size_t buflen, int *errnop, int *h_errnop) +{ + if (res_use_inet6 ()) + { + enum nss_status status; + + status = internal_gethostbyname2_r (name, AF_INET6, host, buffer, buflen, + errnop, h_errnop, AI_V4MAPPED); + if (status == NSS_STATUS_SUCCESS) + return status; + } + + return internal_gethostbyname2_r (name, AF_INET, host, buffer, buflen, + errnop, h_errnop, 0); +} + + +enum nss_status +_nss_nis_gethostbyaddr_r (const void *addr, socklen_t addrlen, int af, + struct hostent *host, char *buffer, size_t buflen, + int *errnop, int *h_errnop) +{ + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct parser_data); + buffer += pad; + + struct parser_data *data = (void *) buffer; + if (__glibc_unlikely (buflen < sizeof *data + 1 + pad)) + { + *errnop = ERANGE; + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + buflen -= pad; + + char *buf = inet_ntoa (*(const struct in_addr *) addr); + + char *result; + int len; + int yperr = yp_match (domain, "hosts.byaddr", buf, strlen (buf), &result, + &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + { + *h_errnop = TRY_AGAIN; + *errnop = errno; + } + else if (retval == NSS_STATUS_NOTFOUND) + *h_errnop = HOST_NOT_FOUND; + + return retval; + } + + const size_t linebuflen = buffer + buflen - data->linebuffer; + if (__glibc_unlikely ((size_t) (len + 1) > linebuflen)) + { + free (result); + *errnop = ERANGE; + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (data->linebuffer, result, len); + data->linebuffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + int parse_res = parse_line (p, host, data, buflen, errnop, af, + (res_use_inet6 () ? AI_V4MAPPED : 0)); + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + { + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + else + { + *h_errnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } + } + + *h_errnop = NETDB_SUCCESS; + return NSS_STATUS_SUCCESS; +} + + +enum nss_status +_nss_nis_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, + char *buffer, size_t buflen, int *errnop, + int *herrnop, int32_t *ttlp) +{ + char *domain; + if (yp_get_default_domain (&domain)) + { + *herrnop = NO_DATA; + return NSS_STATUS_UNAVAIL; + } + + /* Convert name to lowercase. */ + size_t namlen = strlen (name); + /* Limit name length to the maximum size of an RPC packet. */ + if (namlen > UDPMSGSIZE) + { + *errnop = ERANGE; + return NSS_STATUS_UNAVAIL; + } + + char name2[namlen + 1]; + size_t i; + + for (i = 0; i < namlen; ++i) + name2[i] = tolower (name[i]); + name2[i] = '\0'; + + char *result; + int len; + int yperr = yp_match (domain, "hosts.byname", name2, namlen, &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + { + *herrnop = TRY_AGAIN; + *errnop = errno; + } + if (retval == NSS_STATUS_NOTFOUND) + *herrnop = HOST_NOT_FOUND; + return retval; + } + + if (*pat == NULL) + { + uintptr_t pad = (-(uintptr_t) buffer + % __alignof__ (struct gaih_addrtuple)); + buffer += pad; + buflen = buflen > pad ? buflen - pad : 0; + + if (__glibc_unlikely (buflen < sizeof (struct gaih_addrtuple))) + { + erange: + free (result); + *errnop = ERANGE; + *herrnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + + *pat = (struct gaih_addrtuple *) buffer; + buffer += sizeof (struct gaih_addrtuple); + buflen -= sizeof (struct gaih_addrtuple); + } + + uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct parser_data); + buffer += pad; + + struct parser_data *data = (void *) buffer; + + if (__glibc_unlikely (buflen < sizeof *data + 1 + pad)) + goto erange; + buflen -= pad; + + struct hostent host; + int parse_res = parse_line (result, &host, data, buflen, errnop, AF_UNSPEC, + 0); + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + { + *herrnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + else + { + *herrnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } + } + + (*pat)->next = NULL; + (*pat)->family = host.h_addrtype; + memcpy ((*pat)->addr, host.h_addr_list[0], host.h_length); + (*pat)->scopeid = 0; + assert (host.h_addr_list[1] == NULL); + + /* Undo the alignment for parser_data. */ + buffer -= pad; + buflen += pad; + + size_t h_name_len = strlen (host.h_name) + 1; + if (h_name_len >= buflen) + goto erange; + (*pat)->name = memcpy (buffer, host.h_name, h_name_len); + + free (result); + + return NSS_STATUS_SUCCESS; +} diff --git a/REORG.TODO/nis/nss_nis/nis-initgroups.c b/REORG.TODO/nis/nss_nis/nis-initgroups.c new file mode 100644 index 0000000000..3784c101f7 --- /dev/null +++ b/REORG.TODO/nis/nss_nis/nis-initgroups.c @@ -0,0 +1,336 @@ +/* Copyright (C) 1998-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <alloca.h> +#include <ctype.h> +#include <errno.h> +#include <grp.h> +#include <nss.h> +#include <pwd.h> +#include <string.h> +#include <unistd.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> +#include <sys/param.h> + +#include "nss-nis.h" +#include <libnsl.h> + +/* Get the declaration of the parser function. */ +#define ENTNAME grent +#define STRUCTURE group +#define EXTERN_PARSER +#include <nss/nss_files/files-parse.c> + + +static enum nss_status +internal_setgrent (char *domainname, intern_t *intern) +{ + struct ypall_callback ypcb; + enum nss_status status; + + ypcb.foreach = _nis_saveit; + ypcb.data = (char *) intern; + status = yperr2nss (yp_all (domainname, "group.byname", &ypcb)); + + /* Mark the last buffer as full. */ + if (intern->next != NULL) + intern->next->size = intern->offset; + + intern->next = intern->start; + intern->offset = 0; + + return status; +} + + +static enum nss_status +internal_getgrent_r (struct group *grp, char *buffer, size_t buflen, + int *errnop, intern_t *intern) +{ + if (intern->start == NULL) + return NSS_STATUS_NOTFOUND; + + /* Get the next entry until we found a correct one. */ + int parse_res; + do + { + struct response_t *bucket = intern->next; + + if (__glibc_unlikely (intern->offset >= bucket->size)) + { + if (bucket->next == NULL) + return NSS_STATUS_NOTFOUND; + + /* We look at all the content in the current bucket. Go on + to the next. */ + bucket = intern->next = bucket->next; + intern->offset = 0; + } + + char *p; + for (p = &bucket->mem[intern->offset]; isspace (*p); ++p) + ++intern->offset; + + size_t len = strlen (p) + 1; + if (__glibc_unlikely (len > buflen)) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + /* We unfortunately have to copy the data in the user-provided + buffer because that buffer might be around for a very long + time and the servent structure must remain valid. If we would + rely on the BUCKET memory the next 'setservent' or 'endservent' + call would destroy it. + + The important thing is that it is a single NUL-terminated + string. This is what the parsing routine expects. */ + p = memcpy (buffer, &bucket->mem[intern->offset], len); + + parse_res = _nss_files_parse_grent (p, grp, (void *) buffer, buflen, + errnop); + if (__glibc_unlikely (parse_res == -1)) + return NSS_STATUS_TRYAGAIN; + + intern->offset += len; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + + +static int +get_uid (const char *user, uid_t *uidp) +{ + size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX); + char *buf = (char *) alloca (buflen); + + while (1) + { + struct passwd result; + struct passwd *resp; + + int r = getpwnam_r (user, &result, buf, buflen, &resp); + if (r == 0 && resp != NULL) + { + *uidp = resp->pw_uid; + return 0; + } + + if (r != ERANGE) + break; + + buf = extend_alloca (buf, buflen, 2 * buflen); + } + + return 1; +} + + +static enum nss_status +initgroups_netid (uid_t uid, gid_t group, long int *start, long int *size, + gid_t **groupsp, long int limit, int *errnop, + const char *domainname) +{ + /* Limit domainname length to the maximum size of an RPC packet. */ + if (strlen (domainname) > UDPMSGSIZE) + { + *errnop = ERANGE; + return NSS_STATUS_UNAVAIL; + } + + /* Prepare the key. The form is "unix.UID@DOMAIN" with the UID and + DOMAIN field filled in appropriately. */ + char key[sizeof ("unix.@") + sizeof (uid_t) * 3 + strlen (domainname)]; + ssize_t keylen = snprintf (key, sizeof (key), "unix.%lu@%s", + (unsigned long int) uid, domainname); + + char *result; + int reslen; + int yperr = yp_match (domainname, "netid.byname", key, keylen, &result, + &reslen); + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + return yperr2nss (yperr); + + /* Parse the result: following the colon is a comma separated list of + group IDs. */ + char *cp = strchr (result, ':'); + if (cp == NULL) + { + errout: + free (result); + return NSS_STATUS_NOTFOUND; + } + /* Skip the colon. */ + ++cp; + + gid_t *groups = *groupsp; + while (*cp != '\0') + { + char *endp; + unsigned long int gid = strtoul (cp, &endp, 0); + if (cp == endp) + goto errout; + if (*endp == ',') + ++endp; + else if (*endp != '\0') + goto errout; + cp = endp; + + if (gid == group) + /* We do not need this group again. */ + continue; + + /* Insert this group. */ + if (*start == *size) + { + /* Need a bigger buffer. */ + long int newsize; + + if (limit > 0 && *size == limit) + /* We reached the maximum. */ + break; + + if (limit <= 0) + newsize = 2 * *size; + else + newsize = MIN (limit, 2 * *size); + + gid_t *newgroups = realloc (groups, newsize * sizeof (*groups)); + if (newgroups == NULL) + goto errout; + *groupsp = groups = newgroups; + *size = newsize; + } + + groups[*start] = gid; + *start += 1; + } + + free (result); + + return NSS_STATUS_SUCCESS; +} + + +enum nss_status +_nss_nis_initgroups_dyn (const char *user, gid_t group, long int *start, + long int *size, gid_t **groupsp, long int limit, + int *errnop) +{ + /* We always need the domain name. */ + char *domainname; + if (yp_get_default_domain (&domainname)) + return NSS_STATUS_UNAVAIL; + + /* Check whether we are supposed to use the netid.byname map. */ + if (_nsl_default_nss () & NSS_FLAG_NETID_AUTHORITATIVE) + { + /* We need the user ID. */ + uid_t uid; + + if (get_uid (user, &uid) == 0 + && initgroups_netid (uid, group, start, size, groupsp, limit, + errnop, domainname) == NSS_STATUS_SUCCESS) + return NSS_STATUS_SUCCESS; + } + + struct group grpbuf, *g; + size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX); + char *tmpbuf; + enum nss_status status; + intern_t intern = { NULL, NULL, 0 }; + gid_t *groups = *groupsp; + + status = internal_setgrent (domainname, &intern); + if (status != NSS_STATUS_SUCCESS) + return status; + + tmpbuf = __alloca (buflen); + + while (1) + { + while ((status = + internal_getgrent_r (&grpbuf, tmpbuf, buflen, errnop, + &intern)) == NSS_STATUS_TRYAGAIN + && *errnop == ERANGE) + tmpbuf = extend_alloca (tmpbuf, buflen, 2 * buflen); + + if (status != NSS_STATUS_SUCCESS) + { + if (status == NSS_STATUS_NOTFOUND) + status = NSS_STATUS_SUCCESS; + goto done; + } + + g = &grpbuf; + if (g->gr_gid != group) + { + char **m; + + for (m = g->gr_mem; *m != NULL; ++m) + if (strcmp (*m, user) == 0) + { + /* Matches user. Insert this group. */ + if (*start == *size) + { + /* Need a bigger buffer. */ + gid_t *newgroups; + long int newsize; + + if (limit > 0 && *size == limit) + /* We reached the maximum. */ + goto done; + + if (limit <= 0) + newsize = 2 * *size; + else + newsize = MIN (limit, 2 * *size); + + newgroups = realloc (groups, newsize * sizeof (*groups)); + if (newgroups == NULL) + { + status = NSS_STATUS_TRYAGAIN; + *errnop = errno; + goto done; + } + *groupsp = groups = newgroups; + *size = newsize; + } + + groups[*start] = g->gr_gid; + *start += 1; + + break; + } + } + } + +done: + while (intern.start != NULL) + { + intern.next = intern.start; + intern.start = intern.start->next; + free (intern.next); + } + + return status; +} diff --git a/REORG.TODO/nis/nss_nis/nis-netgrp.c b/REORG.TODO/nis/nss_nis/nis-netgrp.c new file mode 100644 index 0000000000..ab3835fffa --- /dev/null +++ b/REORG.TODO/nis/nss_nis/nis-netgrp.c @@ -0,0 +1,98 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <ctype.h> +#include <errno.h> +#include <malloc.h> +#include <netdb.h> +#include <nss.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" + +extern enum nss_status +_nss_netgroup_parseline (char **cursor, struct __netgrent *netgrp, + char *buffer, size_t buflen, int *errnop); + + +static void +internal_nis_endnetgrent (struct __netgrent *netgrp) +{ + free (netgrp->data); + netgrp->data = NULL; + netgrp->data_size = 0; + netgrp->cursor = NULL; +} + + +enum nss_status +_nss_nis_setnetgrent (const char *group, struct __netgrent *netgrp) +{ + int len; + enum nss_status status; + + status = NSS_STATUS_SUCCESS; + + if (__glibc_unlikely (group == NULL || group[0] == '\0')) + return NSS_STATUS_UNAVAIL; + + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + status = yperr2nss (yp_match (domain, "netgroup", group, strlen (group), + &netgrp->data, &len)); + if (__glibc_likely (status == NSS_STATUS_SUCCESS)) + { + /* Our implementation of yp_match already allocates a buffer + which is one byte larger than the value in LEN specifies + and the last byte is filled with NUL. So we can simply + use that buffer. */ + assert (len >= 0); + assert (netgrp->data[len] == '\0'); + + netgrp->data_size = len; + netgrp->cursor = netgrp->data; + } + + return status; +} + + +enum nss_status +_nss_nis_endnetgrent (struct __netgrent *netgrp) +{ + internal_nis_endnetgrent (netgrp); + + return NSS_STATUS_SUCCESS; +} + + +enum nss_status +_nss_nis_getnetgrent_r (struct __netgrent *result, char *buffer, size_t buflen, + int *errnop) +{ + return _nss_netgroup_parseline (&result->cursor, result, buffer, buflen, + errnop); +} diff --git a/REORG.TODO/nis/nss_nis/nis-network.c b/REORG.TODO/nis/nss_nis/nis-network.c new file mode 100644 index 0000000000..baf0ce4b8a --- /dev/null +++ b/REORG.TODO/nis/nss_nis/nis-network.c @@ -0,0 +1,315 @@ +/* Copyright (C) 1996-2017 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <nss.h> +/* The following is an ugly trick to avoid a prototype declaration for + _nss_nis_endgrent. */ +#define _nss_nis_endnetent _nss_nis_endnetent_XXX +#include <netdb.h> +#undef _nss_nis_endnetent +#include <ctype.h> +#include <errno.h> +#include <stdint.h> +#include <string.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <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/nss_files/files-parse.c> + +__libc_lock_define_initialized (static, lock) + +static bool_t new_start = 1; +static char *oldkey; +static int oldkeylen; + +enum nss_status +_nss_nis_setnetent (int stayopen) +{ + __libc_lock_lock (lock); + + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} +/* Make _nss_nis_endnetent an alias of _nss_nis_setnetent. We do this + even though the prototypes don't match. The argument of setnetent + is not used so this makes no difference. */ +strong_alias (_nss_nis_setnetent, _nss_nis_endnetent) + +static enum nss_status +internal_nis_getnetent_r (struct netent *net, char *buffer, size_t buflen, + int *errnop, int *herrnop) +{ + struct parser_data *data = (void *) buffer; + + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + /* Get the next entry until we found a correct one. */ + int parse_res; + do + { + char *result; + char *outkey; + int len; + int keylen; + int yperr; + + if (new_start) + yperr = yp_first (domain, "networks.byname", &outkey, &keylen, &result, + &len); + else + yperr = yp_next (domain, "networks.byname", oldkey, oldkeylen, &outkey, + &keylen, &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + { + *herrnop = NETDB_INTERNAL; + *errnop = errno; + } + return retval; + } + + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + *herrnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_netent (p, net, data, buflen, errnop); + if (__glibc_unlikely (parse_res == -1)) + { + free (outkey); + *herrnop = NETDB_INTERNAL; + *errnop = 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_getnetent_r (struct netent *net, char *buffer, size_t buflen, + int *errnop, int *herrnop) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_getnetent_r (net, buffer, buflen, errnop, 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 *errnop, int *herrnop) +{ + if (name == NULL) + { + *errnop = EINVAL; + *herrnop = NETDB_INTERNAL; + return NSS_STATUS_UNAVAIL; + } + + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + struct parser_data *data = (void *) buffer; + if (buflen < sizeof *data + 1) + { + *herrnop = NETDB_INTERNAL; + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + /* Convert name to lowercase. */ + size_t namlen = strlen (name); + /* Limit name length to the maximum size of an RPC packet. */ + if (namlen > UDPMSGSIZE) + { + *errnop = ERANGE; + return NSS_STATUS_UNAVAIL; + } + + char name2[namlen + 1]; + size_t i; + + for (i = 0; i < namlen; ++i) + name2[i] = _tolower (name[i]); + name2[i] = '\0'; + + char *result; + int len; + int yperr = yp_match (domain, "networks.byname", name2, namlen, &result, + &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + { + *errnop = errno; + *herrnop = NETDB_INTERNAL; + } + return retval; + } + + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + *herrnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + int parse_res = _nss_files_parse_netent (p, net, data, buflen, errnop); + + if (__glibc_unlikely (parse_res < 1)) + { + *herrnop = NETDB_INTERNAL; + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + else + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getnetbyaddr_r (uint32_t addr, int type, struct netent *net, + char *buffer, size_t buflen, int *errnop, + int *herrnop) +{ + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + struct in_addr in = { .s_addr = htonl (addr) }; + char *buf = inet_ntoa (in); + size_t blen = strlen (buf); + + while (1) + { + char *result; + int len; + + int yperr = yp_match (domain, "networks.byaddr", buf, blen, &result, + &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + 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) + *errnop = errno; + return retval; + } + } + + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + *herrnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + int parse_res = _nss_files_parse_netent (p, net, (void *) buffer, + buflen, errnop); + + if (__glibc_unlikely (parse_res < 1)) + { + *herrnop = NETDB_INTERNAL; + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + else + return NSS_STATUS_SUCCESS; + } +} diff --git a/REORG.TODO/nis/nss_nis/nis-proto.c b/REORG.TODO/nis/nss_nis/nis-proto.c new file mode 100644 index 0000000000..df0739aaad --- /dev/null +++ b/REORG.TODO/nis/nss_nis/nis-proto.c @@ -0,0 +1,278 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <nss.h> +#include <netdb.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <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/nss_files/files-parse.c> + +__libc_lock_define_initialized (static, lock) + +struct response +{ + struct response *next; + char val[0]; +}; + +static struct response *start; +static struct response *next; + +static int +saveit (int instatus, char *inkey, int inkeylen, char *inval, + int invallen, char *indata) +{ + if (instatus != YP_TRUE) + return 1; + + if (inkey && inkeylen > 0 && inval && invallen > 0) + { + struct response *newp = malloc (sizeof (struct response) + invallen + 1); + if (newp == NULL) + return 1; /* We have no error code for out of memory */ + + if (start == NULL) + start = newp; + else + next->next = newp; + next = newp; + + newp->next = NULL; + *((char *) mempcpy (newp->val, inval, invallen)) = '\0'; + } + + return 0; +} + +static void +internal_nis_endprotoent (void) +{ + while (start != NULL) + { + next = start; + start = start->next; + free (next); + } +} + +static enum nss_status +internal_nis_setprotoent (void) +{ + char *domainname; + struct ypall_callback ypcb; + enum nss_status status; + + yp_get_default_domain (&domainname); + + internal_nis_endprotoent (); + + ypcb.foreach = saveit; + ypcb.data = NULL; + status = yperr2nss (yp_all (domainname, "protocols.bynumber", &ypcb)); + next = start; + + return status; +} + +enum nss_status +_nss_nis_setprotoent (int stayopen) +{ + 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); + + internal_nis_endprotoent (); + 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, int *errnop) +{ + 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); + + while (isspace (*p)) + ++p; + + parse_res = _nss_files_parse_protoent (p, proto, data, buflen, errnop); + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + next = next->next; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getprotoent_r (struct protoent *proto, char *buffer, size_t buflen, + int *errnop) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_getprotoent_r (proto, buffer, buflen, errnop); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_getprotobyname_r (const char *name, struct protoent *proto, + char *buffer, size_t buflen, int *errnop) +{ + if (name == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + char *result; + int len; + int yperr = yp_match (domain, "protocols.byname", name, strlen (name), + &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + int parse_res = _nss_files_parse_protoent (p, proto, (void *) buffer, buflen, + errnop); + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + 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, int *errnop) +{ + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + char buf[32]; + int nlen = snprintf (buf, sizeof (buf), "%d", number); + + char *result; + int len; + int yperr = yp_match (domain, "protocols.bynumber", buf, nlen, &result, + &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + int parse_res = _nss_files_parse_protoent (p, proto, (void *) buffer, buflen, + errnop); + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + return NSS_STATUS_SUCCESS; +} diff --git a/REORG.TODO/nis/nss_nis/nis-publickey.c b/REORG.TODO/nis/nss_nis/nis-publickey.c new file mode 100644 index 0000000000..188e80cd5d --- /dev/null +++ b/REORG.TODO/nis/nss_nis/nis-publickey.c @@ -0,0 +1,234 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <nss.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <syslog.h> +#include <rpc/rpc.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> +#include <rpc/key_prot.h> +#include <rpc/des_crypt.h> + +#include "nss-nis.h" + +/* If we haven't found the entry, we give a SUCCESS and an empty key back. + Solaris docu says: sizeof (pkey) == HEXKEYBYTES + 1. +*/ +enum nss_status +_nss_nis_getpublickey (const char *netname, char *pkey, int *errnop) +{ + pkey[0] = 0; + + if (netname == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + char *domain = strchr (netname, '@'); + if (domain == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + ++domain; + + char *result; + int len; + int yperr = yp_match (domain, "publickey.byname", netname, strlen (netname), + &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + + if (result != NULL) + { + char *p = strchr (result, ':'); + if (p != NULL) + *p = 0; + strncpy (pkey, result, HEXKEYBYTES + 1); + pkey[HEXKEYBYTES] = '\0'; + free (result); + } + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getsecretkey (const char *netname, char *skey, char *passwd, + int *errnop) +{ + skey[0] = 0; + + if (netname == NULL || passwd == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + char *domain = strchr (netname, '@'); + if (domain == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + ++domain; + + char *result; + int len; + int yperr = yp_match (domain, "publickey.byname", netname, strlen (netname), + &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + + if (result != NULL) + { + char *p = strchr (result, ':'); + if (p != NULL) + { + char buf[2 * (HEXKEYBYTES + 1)]; + + ++p; + strncpy (buf, p, 2 * (HEXKEYBYTES + 1)); + buf[2 * HEXKEYBYTES + 1] = '\0'; + if (xdecrypt (buf, passwd) + && memcmp (buf, &(buf[HEXKEYBYTES]), KEYCHECKSUMSIZE) == 0) + { + buf[HEXKEYBYTES] = '\0'; + strcpy (skey, buf); + } + } + + free (result); + } + return NSS_STATUS_SUCCESS; +} + +/* Parse uid and group information from the passed string. + The format of the string passed is uid:gid,grp,grp, ... */ +static enum nss_status +parse_netid_str (const char *s, uid_t *uidp, gid_t *gidp, int *gidlenp, + gid_t *gidlist) +{ + char *p, *ep; + int gidlen; + + if (!s || !isdigit (*s)) + { + syslog (LOG_ERR, "netname2user: expecting uid '%s'", s); + return NSS_STATUS_NOTFOUND; /* XXX need a better error */ + } + + /* Fetch the uid */ + *uidp = strtoul (s, NULL, 10); + + if (*uidp == 0) + { + syslog (LOG_ERR, "netname2user: should not have uid 0"); + return NSS_STATUS_NOTFOUND; + } + + /* Now get the group list */ + p = strchr (s, ':'); + if (!p) + { + syslog (LOG_ERR, "netname2user: missing group id list in '%s'", s); + return NSS_STATUS_NOTFOUND; + } + ++p; /* skip ':' */ + if (!p || (!isdigit (*p))) + { + syslog (LOG_ERR, "netname2user: missing group id list in '%s'.", p); + return NSS_STATUS_NOTFOUND; + } + + *gidp = strtoul (p, &ep, 10); + + gidlen = 0; + + /* After strtoul() ep should point to the first invalid character. + This is the marker "," we search for the next value. */ + while (ep != NULL && *ep == ',') + { + ep++; + p = ep; + gidlist[gidlen++] = strtoul (p, &ep, 10); + } + + *gidlenp = gidlen; + + return NSS_STATUS_SUCCESS; +} + + +enum nss_status +_nss_nis_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp, + gid_t *gidp, int *gidlenp, gid_t *gidlist, int *errnop) +{ + char *domain = strchr (netname, '@'); + if (domain == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + /* Point past the '@' character */ + ++domain; + char *lookup = NULL; + int len; + int yperr = yp_match (domain, "netid.byname", netname, strlen (netname), + &lookup, &len); + switch (yperr) + { + case YPERR_SUCCESS: + break; /* the successful case */ + case YPERR_DOMAIN: + case YPERR_KEY: + return NSS_STATUS_NOTFOUND; + case YPERR_MAP: + default: + return NSS_STATUS_UNAVAIL; + } + + if (lookup == NULL) + return NSS_STATUS_NOTFOUND; + + + lookup[len] = '\0'; + + enum nss_status err = parse_netid_str (lookup, uidp, gidp, gidlenp, gidlist); + + free (lookup); + + return err; +} diff --git a/REORG.TODO/nis/nss_nis/nis-pwd.c b/REORG.TODO/nis/nss_nis/nis-pwd.c new file mode 100644 index 0000000000..6a759eeaec --- /dev/null +++ b/REORG.TODO/nis/nss_nis/nis-pwd.c @@ -0,0 +1,581 @@ +/* Copyright (C) 1996-2017 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <ctype.h> +#include <errno.h> +#include <nss.h> +#include <pwd.h> +#include <string.h> +#include <libc-lock.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> + +#include "nss-nis.h" +#include <libnsl.h> + +/* Get the declaration of the parser function. */ +#define ENTNAME pwent +#define STRUCTURE passwd +#define EXTERN_PARSER +#include <nss/nss_files/files-parse.c> + +/* Protect global state against multiple changers */ +__libc_lock_define_initialized (static, lock) + +static bool new_start = true; +static char *oldkey; +static int oldkeylen; +static intern_t intern; + + +int +_nis_saveit (int instatus, char *inkey, int inkeylen, char *inval, + int invallen, char *indata) +{ + intern_t *intern = (intern_t *) indata; + + if (instatus != YP_TRUE) + return 1; + + if (inkey && inkeylen > 0 && inval && invallen > 0) + { + struct response_t *bucket = intern->next; + + if (__glibc_unlikely (bucket == NULL)) + { +#define MINSIZE 4096 - 4 * sizeof (void *) + const size_t minsize = MAX (MINSIZE, 2 * (invallen + 1)); + bucket = malloc (sizeof (struct response_t) + minsize); + if (bucket == NULL) + /* We have no error code for out of memory. */ + return 1; + + bucket->next = NULL; + bucket->size = minsize; + intern->start = intern->next = bucket; + intern->offset = 0; + } + else if (__builtin_expect (invallen + 1 > bucket->size - intern->offset, + 0)) + { + /* We need a new (larger) buffer. */ + const size_t newsize = 2 * MAX (bucket->size, invallen + 1); + struct response_t *newp = malloc (sizeof (struct response_t) + + newsize); + if (newp == NULL) + /* We have no error code for out of memory. */ + return 1; + + /* Mark the old bucket as full. */ + bucket->size = intern->offset; + + newp->next = NULL; + newp->size = newsize; + bucket = intern->next = bucket->next = newp; + intern->offset = 0; + } + + char *p = mempcpy (&bucket->mem[intern->offset], inval, invallen); + if (__glibc_unlikely (p[-1] != '\0')) + { + *p = '\0'; + ++invallen; + } + intern->offset += invallen; + } + + return 0; +} + + +static void +internal_nis_endpwent (void) +{ + new_start = true; + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + + struct response_t *curr = intern.start; + + while (curr != NULL) + { + struct response_t *last = curr; + curr = curr->next; + free (last); + } + + intern.next = intern.start = NULL; +} + + +enum nss_status +_nss_nis_endpwent (void) +{ + __libc_lock_lock (lock); + + internal_nis_endpwent (); + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + + +enum nss_status +internal_nis_setpwent (void) +{ + /* We have to read all the data now. */ + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + struct ypall_callback ypcb; + + ypcb.foreach = _nis_saveit; + ypcb.data = (char *) &intern; + enum nss_status status = yperr2nss (yp_all (domain, "passwd.byname", &ypcb)); + + + /* Mark the last buffer as full. */ + if (intern.next != NULL) + intern.next->size = intern.offset; + + intern.next = intern.start; + intern.offset = 0; + + return status; +} + + +enum nss_status +_nss_nis_setpwent (int stayopen) +{ + enum nss_status result = NSS_STATUS_SUCCESS; + + __libc_lock_lock (lock); + + internal_nis_endpwent (); + + if (_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ) + result = internal_nis_setpwent (); + + __libc_lock_unlock (lock); + + return result; +} + + +static enum nss_status +internal_nis_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen, + int *errnop) +{ + /* If we read the entire database at setpwent time we just iterate + over the data we have in memory. */ + bool batch_read = intern.start != NULL; + + char *domain = NULL; + if (!batch_read && __builtin_expect (yp_get_default_domain (&domain), 0)) + return NSS_STATUS_UNAVAIL; + + /* Get the next entry until we found a correct one. */ + int parse_res; + do + { + char *result; + char *outkey; + int len; + int keylen; + + if (batch_read) + { + struct response_t *bucket; + + handle_batch_read: + bucket = intern.next; + + if (__glibc_unlikely (intern.offset >= bucket->size)) + { + if (bucket->next == NULL) + return NSS_STATUS_NOTFOUND; + + /* We look at all the content in the current bucket. Go on + to the next. */ + bucket = intern.next = bucket->next; + intern.offset = 0; + } + + for (result = &bucket->mem[intern.offset]; isspace (*result); + ++result) + ++intern.offset; + + len = strlen (result); + } + else + { + int yperr; + + if (new_start) + { + /* Maybe we should read the database in one piece. */ + if ((_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ) + && internal_nis_setpwent () == NSS_STATUS_SUCCESS + && intern.start != NULL) + { + batch_read = true; + goto handle_batch_read; + } + + yperr = yp_first (domain, "passwd.byname", &outkey, &keylen, + &result, &len); + } + else + yperr = yp_next (domain, "passwd.byname", oldkey, oldkeylen, + &outkey, &keylen, &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + } + + /* Check for adjunct style secret passwords. They can be + recognized by a password starting with "##". We do not use + it if the passwd.adjunct.byname table is supposed to be used + as a shadow.byname replacement. */ + char *p = strchr (result, ':'); + size_t namelen; + char *result2; + int len2; + if ((_nsl_default_nss () & NSS_FLAG_ADJUNCT_AS_SHADOW) == 0 + && 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.byname entry. Merge encrypted + password therein into original result. */ + char *encrypted = strchr (result2, ':'); + char *endp; + 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 (__builtin_expect ((size_t) (namelen + (endp - encrypted) + + restlen + 2) > buflen, 0)) + { + free (result2); + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + mempcpy (mempcpy (mempcpy (mempcpy (buffer, result, namelen), + ":", 1), + encrypted, endp - encrypted), + p, restlen + 1); + p = buffer; + + free (result2); + } + else + { + non_adjunct: + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + p = buffer; + *((char *) mempcpy (buffer, result, len)) = '\0'; + } + + while (isspace (*p)) + ++p; + if (!batch_read) + free (result); + + parse_res = _nss_files_parse_pwent (p, pwd, (void *) buffer, buflen, + errnop); + if (__glibc_unlikely (parse_res == -1)) + { + if (!batch_read) + free (outkey); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + if (batch_read) + intern.offset += len + 1; + else + { + free (oldkey); + oldkey = outkey; + oldkeylen = keylen; + new_start = false; + } + } + while (parse_res < 1); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getpwent_r (struct passwd *result, char *buffer, size_t buflen, + int *errnop) +{ + int status; + + __libc_lock_lock (lock); + + status = internal_nis_getpwent_r (result, buffer, buflen, errnop); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_getpwnam_r (const char *name, struct passwd *pwd, + char *buffer, size_t buflen, int *errnop) +{ + if (name == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + size_t namelen = strlen (name); + + char *result; + int len; + int yperr = yp_match (domain, "passwd.byname", name, namelen, &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + + /* Check for adjunct style secret passwords. They can be recognized + by a password starting with "##". We do not use it if the + passwd.adjunct.byname table is supposed to be used as a shadow.byname + replacement. */ + char *result2; + int len2; + char *p = strchr (result, ':'); + if ((_nsl_default_nss () & NSS_FLAG_ADJUNCT_AS_SHADOW) == 0 + && p != NULL /* This better should be true in all cases. */ + && p[1] == '#' && p[2] == '#' + && yp_match (domain, "passwd.adjunct.byname", name, namelen, + &result2, &len2) == YPERR_SUCCESS) + { + /* We found a passwd.adjunct.byname entry. Merge encrypted password + therein into original result. */ + char *encrypted = strchr (result2, ':'); + char *endp; + + 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; + } + + size_t restlen = len - (p - result); + if (__builtin_expect ((size_t) (namelen + (endp - encrypted) + + restlen + 2) > buflen, 0)) + { + free (result2); + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + __mempcpy (__mempcpy (__mempcpy (__mempcpy (buffer, name, namelen), + ":", 1), + encrypted, endp - encrypted), + p, restlen + 1); + p = buffer; + + free (result2); + } + else + { + non_adjunct: + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + } + + while (isspace (*p)) + ++p; + free (result); + + int parse_res = _nss_files_parse_pwent (p, pwd, (void *) buffer, buflen, + errnop); + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + else + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getpwuid_r (uid_t uid, struct passwd *pwd, + char *buffer, size_t buflen, int *errnop) +{ + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + char buf[32]; + int nlen = snprintf (buf, sizeof (buf), "%lu", (unsigned long int) uid); + + char *result; + int len; + int yperr = yp_match (domain, "passwd.byuid", buf, nlen, &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + + /* Check for adjunct style secret passwords. They can be recognized + by a password starting with "##". We do not use it if the + passwd.adjunct.byname table is supposed to be used as a shadow.byname + replacement. */ + char *result2; + int len2; + size_t namelen; + char *p = strchr (result, ':'); + if ((_nsl_default_nss () & NSS_FLAG_ADJUNCT_AS_SHADOW) == 0 + && 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.byname entry. Merge encrypted password + therein into original result. */ + char *encrypted = strchr (result2, ':'); + char *endp; + 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 (__builtin_expect ((size_t) (namelen + (endp - encrypted) + + restlen + 2) > buflen, 0)) + { + free (result2); + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + __mempcpy (__mempcpy (__mempcpy (__mempcpy (buffer, result, namelen), + ":", 1), + encrypted, endp - encrypted), + p, restlen + 1); + p = buffer; + + free (result2); + } + else + { + non_adjunct: + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + } + + while (isspace (*p)) + ++p; + free (result); + + int parse_res = _nss_files_parse_pwent (p, pwd, (void *) buffer, buflen, + errnop); + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + else + return NSS_STATUS_SUCCESS; +} diff --git a/REORG.TODO/nis/nss_nis/nis-rpc.c b/REORG.TODO/nis/nss_nis/nis-rpc.c new file mode 100644 index 0000000000..24e47e9884 --- /dev/null +++ b/REORG.TODO/nis/nss_nis/nis-rpc.c @@ -0,0 +1,279 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <nss.h> +#include <netdb.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <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/nss_files/files-parse.c> + +__libc_lock_define_initialized (static, lock) + +static intern_t intern; + + +static void +internal_nis_endrpcent (intern_t *intern) +{ + struct response_t *curr = intern->next; + + while (curr != NULL) + { + struct response_t *last = curr; + curr = curr->next; + free (last); + } + + intern->next = intern->start = NULL; +} + +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; + + internal_nis_endrpcent (intern); + + ypcb.foreach = _nis_saveit; + ypcb.data = (char *) intern; + status = yperr2nss (yp_all (domainname, "rpc.bynumber", &ypcb)); + + /* Mark the last buffer as full. */ + if (intern->next != NULL) + intern->next->size = intern->offset; + + intern->next = intern->start; + intern->offset = 0; + + return status; +} + +enum nss_status +_nss_nis_setrpcent (int stayopen) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_setrpcent (&intern); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_endrpcent (void) +{ + __libc_lock_lock (lock); + + internal_nis_endrpcent (&intern); + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_nis_getrpcent_r (struct rpcent *rpc, char *buffer, size_t buflen, + int *errnop, intern_t *intern) +{ + struct parser_data *pdata = (void *) buffer; + int parse_res; + char *p; + + if (intern->start == NULL) + internal_nis_setrpcent (intern); + + if (intern->next == NULL) + /* Not one entry in the map. */ + return NSS_STATUS_NOTFOUND; + + /* Get the next entry until we found a correct one. */ + do + { + struct response_t *bucket = intern->next; + + if (__glibc_unlikely (intern->offset >= bucket->size)) + { + if (bucket->next == NULL) + return NSS_STATUS_NOTFOUND; + + /* We look at all the content in the current bucket. Go on + to the next. */ + bucket = intern->next = bucket->next; + intern->offset = 0; + } + + for (p = &bucket->mem[intern->offset]; isspace (*p); ++p) + ++intern->offset; + + size_t len = strlen (p) + 1; + if (__glibc_unlikely (len > buflen)) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + /* We unfortunately have to copy the data in the user-provided + buffer because that buffer might be around for a very long + time and the servent structure must remain valid. If we would + rely on the BUCKET memory the next 'setservent' or 'endservent' + call would destroy it. + + The important thing is that it is a single NUL-terminated + string. This is what the parsing routine expects. */ + p = memcpy (buffer, &bucket->mem[intern->offset], len); + + parse_res = _nss_files_parse_rpcent (p, rpc, pdata, buflen, errnop); + if (__glibc_unlikely (parse_res == -1)) + return NSS_STATUS_TRYAGAIN; + + intern->offset += len; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getrpcent_r (struct rpcent *rpc, char *buffer, size_t buflen, + int *errnop) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_getrpcent_r (rpc, buffer, buflen, errnop, &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, int *errnop) +{ + if (name == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + intern_t data = { NULL, NULL, 0 }; + enum nss_status status = internal_nis_setrpcent (&data); + if (__glibc_unlikely (status != NSS_STATUS_SUCCESS)) + return status; + + int found = 0; + while (!found && + ((status = internal_nis_getrpcent_r (rpc, buffer, buflen, errnop, + &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 (__glibc_unlikely (!found && status == NSS_STATUS_SUCCESS)) + return NSS_STATUS_NOTFOUND; + + return status; +} + +enum nss_status +_nss_nis_getrpcbynumber_r (int number, struct rpcent *rpc, + char *buffer, size_t buflen, int *errnop) +{ + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + char buf[32]; + int nlen = snprintf (buf, sizeof (buf), "%d", number); + + char *result; + int len; + int yperr = yp_match (domain, "rpc.bynumber", buf, nlen, &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + int parse_res = _nss_files_parse_rpcent (p, rpc, (void *) buffer, buflen, + errnop); + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + else + return NSS_STATUS_SUCCESS; +} diff --git a/REORG.TODO/nis/nss_nis/nis-service.c b/REORG.TODO/nis/nss_nis/nis-service.c new file mode 100644 index 0000000000..fe628aa139 --- /dev/null +++ b/REORG.TODO/nis/nss_nis/nis-service.c @@ -0,0 +1,438 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <nss.h> +#include <netdb.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <libc-lock.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> + +#include "nss-nis.h" +#include <libnsl.h> + + +/* Get the declaration of the parser function. */ +#define ENTNAME servent +#define EXTERN_PARSER +#include <nss/nss_files/files-parse.c> + +__libc_lock_define_initialized (static, lock) + +static intern_t intern; + +struct search_t +{ + const char *name; + const char *proto; + int port; + enum nss_status status; + struct servent *serv; + char *buffer; + size_t buflen; + int *errnop; +}; + +static int +dosearch (int instatus, char *inkey, int inkeylen, char *inval, + int invallen, char *indata) +{ + struct search_t *req = (struct search_t *) indata; + + if (__glibc_unlikely (instatus != YP_TRUE)) + return 1; + + if (inkey && inkeylen > 0 && inval && invallen > 0) + { + if (__glibc_unlikely ((size_t) (invallen + 1) > req->buflen)) + { + *req->errnop = ERANGE; + req->status = NSS_STATUS_TRYAGAIN; + return 1; + } + + char *p = strncpy (req->buffer, inval, invallen); + req->buffer[invallen] = '\0'; + while (isspace (*p)) + ++p; + + int parse_res = _nss_files_parse_servent (p, req->serv, + (void *) req->buffer, + req->buflen, req->errnop); + if (parse_res == -1) + { + req->status = NSS_STATUS_TRYAGAIN; + return 1; + } + + if (!parse_res) + return 0; + + if (req->proto != NULL && strcmp (req->serv->s_proto, req->proto) != 0) + return 0; + + if (req->port != -1 && req->serv->s_port != req->port) + return 0; + + if (req->name != NULL && strcmp (req->serv->s_name, req->name) != 0) + { + char **cp; + for (cp = req->serv->s_aliases; *cp; cp++) + if (strcmp (req->name, *cp) == 0) + break; + + if (*cp == NULL) + return 0; + } + + req->status = NSS_STATUS_SUCCESS; + return 1; + } + + return 0; +} + +static void +internal_nis_endservent (void) +{ + struct response_t *curr = intern.next; + + while (curr != NULL) + { + struct response_t *last = curr; + curr = curr->next; + free (last); + } + + intern.next = intern.start = NULL; +} + +enum nss_status +_nss_nis_endservent (void) +{ + __libc_lock_lock (lock); + + internal_nis_endservent (); + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_nis_setservent (void) +{ + char *domainname; + struct ypall_callback ypcb; + enum nss_status status; + + if (yp_get_default_domain (&domainname)) + return NSS_STATUS_UNAVAIL; + + internal_nis_endservent (); + + ypcb.foreach = _nis_saveit; + ypcb.data = (char *) &intern; + status = yperr2nss (yp_all (domainname, "services.byname", &ypcb)); + + /* Mark the last buffer as full. */ + if (intern.next != NULL) + intern.next->size = intern.offset; + + intern.next = intern.start; + intern.offset = 0; + + return status; +} + +enum nss_status +_nss_nis_setservent (int stayopen) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_setservent (); + + __libc_lock_unlock (lock); + + return status; +} + +static enum nss_status +internal_nis_getservent_r (struct servent *serv, char *buffer, + size_t buflen, int *errnop) +{ + struct parser_data *pdata = (void *) buffer; + int parse_res; + char *p; + + if (intern.start == NULL) + internal_nis_setservent (); + + if (intern.next == NULL) + /* Not one entry in the map. */ + return NSS_STATUS_NOTFOUND; + + /* Get the next entry until we found a correct one. */ + do + { + struct response_t *bucket = intern.next; + + if (__glibc_unlikely (intern.offset >= bucket->size)) + { + if (bucket->next == NULL) + return NSS_STATUS_NOTFOUND; + + /* We look at all the content in the current bucket. Go on + to the next. */ + bucket = intern.next = bucket->next; + intern.offset = 0; + } + + for (p = &bucket->mem[intern.offset]; isspace (*p); ++p) + ++intern.offset; + + size_t len = strlen (p) + 1; + if (__glibc_unlikely (len > buflen)) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + /* We unfortunately have to copy the data in the user-provided + buffer because that buffer might be around for a very long + time and the servent structure must remain valid. If we would + rely on the BUCKET memory the next 'setservent' or 'endservent' + call would destroy it. + + The important thing is that it is a single NUL-terminated + string. This is what the parsing routine expects. */ + p = memcpy (buffer, &bucket->mem[intern.offset], len); + + parse_res = _nss_files_parse_servent (p, serv, pdata, buflen, errnop); + if (__glibc_unlikely (parse_res == -1)) + return NSS_STATUS_TRYAGAIN; + + intern.offset += len; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getservent_r (struct servent *serv, char *buffer, size_t buflen, + int *errnop) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_getservent_r (serv, buffer, buflen, errnop); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_getservbyname_r (const char *name, const char *protocol, + struct servent *serv, char *buffer, size_t buflen, + int *errnop) +{ + if (name == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + /* If the protocol is given, we could try if our NIS server knows + about services.byservicename map. If yes, we only need one query. */ + size_t keylen = strlen (name) + (protocol ? 1 + strlen (protocol) : 0); + /* Limit key length to the maximum size of an RPC packet. */ + if (keylen > UDPMSGSIZE) + { + *errnop = ERANGE; + return NSS_STATUS_UNAVAIL; + } + + char key[keylen + 1]; + + /* key is: "name/proto" */ + char *cp = stpcpy (key, name); + if (protocol != NULL) + { + *cp++ = '/'; + strcpy (cp, protocol); + } + + char *result; + int int_len; + int status = yp_match (domain, "services.byservicename", key, + keylen, &result, &int_len); + size_t len = int_len; + + /* If we found the key, it's ok and parse the result. If not, + fall through and parse the complete table. */ + if (__glibc_likely (status == YPERR_SUCCESS)) + { + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + int parse_res = _nss_files_parse_servent (p, serv, (void *) buffer, + buflen, errnop); + if (__glibc_unlikely (parse_res < 0)) + { + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + else + return NSS_STATUS_SUCCESS; + } + + /* Check if it is safe to rely on services.byservicename. */ + if (_nsl_default_nss () & NSS_FLAG_SERVICES_AUTHORITATIVE) + return yperr2nss (status); + + struct ypall_callback ypcb; + struct search_t req; + + ypcb.foreach = dosearch; + ypcb.data = (char *) &req; + req.name = name; + req.proto = protocol; + req.port = -1; + req.serv = serv; + req.buffer = buffer; + req.buflen = buflen; + req.errnop = errnop; + req.status = NSS_STATUS_NOTFOUND; + status = yp_all (domain, "services.byname", &ypcb); + + if (__glibc_unlikely (status != YPERR_SUCCESS)) + return yperr2nss (status); + + return req.status; +} + +enum nss_status +_nss_nis_getservbyport_r (int port, const char *protocol, + struct servent *serv, char *buffer, + size_t buflen, int *errnop) +{ + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + /* If the protocol is given, we only need one query. + Otherwise try first port/tcp, then port/udp and then fallback + to sequential scanning of services.byname. */ + const char *proto = protocol != NULL ? protocol : "tcp"; + /* Limit protocol name length to the maximum size of an RPC packet. */ + if (strlen (proto) > UDPMSGSIZE) + { + *errnop = ERANGE; + return NSS_STATUS_UNAVAIL; + } + + do + { + /* key is: "port/proto" */ + char key[sizeof (int) * 3 + strlen (proto) + 2]; + size_t keylen = snprintf (key, sizeof (key), "%d/%s", ntohs (port), + proto); + + char *result; + int int_len; + int status = yp_match (domain, "services.byname", key, keylen, &result, + &int_len); + size_t len = int_len; + + /* If we found the key, it's ok and parse the result. If not, + fall through and parse the complete table. */ + if (__glibc_likely (status == YPERR_SUCCESS)) + { + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + int parse_res = _nss_files_parse_servent (p, serv, (void *) buffer, + buflen, errnop); + if (__glibc_unlikely (parse_res < 0)) + { + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + + return NSS_STATUS_SUCCESS; + } + } + while (protocol == NULL && (proto[0] == 't' ? (proto = "udp") : NULL)); + + if (port == -1) + return NSS_STATUS_NOTFOUND; + + struct ypall_callback ypcb; + struct search_t req; + + ypcb.foreach = dosearch; + ypcb.data = (char *) &req; + req.name = NULL; + req.proto = protocol; + req.port = port; + req.serv = serv; + req.buffer = buffer; + req.buflen = buflen; + req.errnop = errnop; + req.status = NSS_STATUS_NOTFOUND; + int status = yp_all (domain, "services.byname", &ypcb); + + if (__glibc_unlikely (status != YPERR_SUCCESS)) + return yperr2nss (status); + + return req.status; +} diff --git a/REORG.TODO/nis/nss_nis/nis-spwd.c b/REORG.TODO/nis/nss_nis/nis-spwd.c new file mode 100644 index 0000000000..45e9d964d2 --- /dev/null +++ b/REORG.TODO/nis/nss_nis/nis-spwd.c @@ -0,0 +1,235 @@ +/* Copyright (C) 1996-2017 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <nss.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +/* The following is an ugly trick to avoid a prototype declaration for + _nss_nis_endspent. */ +#define _nss_nis_endspent _nss_nis_endspent_XXX +#include <shadow.h> +#undef _nss_nis_endspent +#include <libc-lock.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> + +#include "nss-nis.h" +#include <libnsl.h> + +/* Get the declaration of the parser function. */ +#define ENTNAME spent +#define STRUCTURE spwd +#define EXTERN_PARSER +#include <nss/nss_files/files-parse.c> + +/* Protect global state against multiple changers */ +__libc_lock_define_initialized (static, lock) + +static bool new_start = true; +static bool ent_adjunct_used; +static char *oldkey; +static int oldkeylen; + +enum nss_status +_nss_nis_setspent (int stayopen) +{ + __libc_lock_lock (lock); + + new_start = true; + ent_adjunct_used = false; + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} +/* Make _nss_nis_endspent an alias of _nss_nis_setspent. We do this + even though the prototypes don't match. The argument of setspent + is not used so this makes no difference. */ +strong_alias (_nss_nis_setspent, _nss_nis_endspent) + +static enum nss_status +internal_nis_getspent_r (struct spwd *sp, char *buffer, size_t buflen, + int *errnop) +{ + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + /* Get the next entry until we found a correct one. */ + int parse_res; + do + { + char *result; + char *outkey; + int len; + int keylen; + int yperr; + + if (new_start) + { + yperr = yp_first (domain, "shadow.byname", &outkey, &keylen, &result, + &len); + if (__builtin_expect (yperr == YPERR_MAP, 0) + && (_nsl_default_nss () & NSS_FLAG_ADJUNCT_AS_SHADOW)) + { + free (result); + yperr = yp_first (domain, "passwd.adjunct.byname", &outkey, + &keylen, &result, &len); + ent_adjunct_used = true; + } + } + else + yperr = yp_next (domain, (ent_adjunct_used + ? "passwd.adjunct.byname" : "shadow.byname"), + oldkey, oldkeylen, &outkey, &keylen, &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + + if (__builtin_expect ((size_t) (len + (ent_adjunct_used ? 3 : 1)) + > buflen, 0)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + if (ent_adjunct_used) + /* This is an ugly trick. The format of passwd.adjunct.byname almost + matches the shadow.byname format except that the last two fields + are missing. Synthesize them by marking them empty. */ + strcpy (&buffer[len], "::"); + else + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_spent (p, sp, (void *) buffer, buflen, + errnop); + if (__builtin_expect (parse_res == -1, 0)) + { + free (outkey); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + free (oldkey); + oldkey = outkey; + oldkeylen = keylen; + new_start = false; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getspent_r (struct spwd *result, char *buffer, size_t buflen, + int *errnop) +{ + int status; + + __libc_lock_lock (lock); + + status = internal_nis_getspent_r (result, buffer, buflen, errnop); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_getspnam_r (const char *name, struct spwd *sp, + char *buffer, size_t buflen, int *errnop) +{ + if (name == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + const size_t name_len = strlen (name); + + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + bool adjunct_used = false; + char *result; + int len; + int yperr = yp_match (domain, "shadow.byname", name, name_len, &result, + &len); + if (__builtin_expect (yperr == YPERR_MAP, 0) + && (_nsl_default_nss () & NSS_FLAG_ADJUNCT_AS_SHADOW)) + { + free (result); + yperr = yp_match (domain, "passwd.adjunct.byname", name, name_len, + &result, &len); + adjunct_used = true; + } + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + + if (__glibc_unlikely ((size_t) (len + (adjunct_used ? 3 : 1)) > buflen)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + if (__builtin_expect (adjunct_used, false)) + /* This is an ugly trick. The format of passwd.adjunct.byname almost + matches the shadow.byname format except that the last two fields + are missing. Synthesize them by marking them empty. */ + strcpy (&buffer[len], "::"); + else + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + int parse_res = _nss_files_parse_spent (p, sp, (void *) buffer, buflen, + errnop); + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + return NSS_STATUS_SUCCESS; +} diff --git a/REORG.TODO/nis/nss_nisplus/nisplus-alias.c b/REORG.TODO/nis/nss_nisplus/nisplus-alias.c new file mode 100644 index 0000000000..8301e5a836 --- /dev/null +++ b/REORG.TODO/nis/nss_nisplus/nisplus-alias.c @@ -0,0 +1,337 @@ +/* Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <atomic.h> +#include <nss.h> +#include <errno.h> +#include <ctype.h> +#include <string.h> +#include <aliases.h> +#include <libc-lock.h> +#include <rpcsvc/nis.h> + +#include "nss-nisplus.h" + +__libc_lock_define_initialized (static, lock) + +static nis_result *result; +static u_long next_entry; +static nis_name tablename_val; +static size_t tablename_len; + +#define NISENTRYVAL(idx, col, res) \ + (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val) + +#define NISENTRYLEN(idx, col, res) \ + (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len) + +static enum nss_status +_nss_create_tablename (int *errnop) +{ + if (tablename_val == NULL) + { + const char *local_dir = nis_local_directory (); + size_t local_dir_len = strlen (local_dir); + static const char prefix[] = "mail_aliases.org_dir."; + + char *p = malloc (sizeof (prefix) + local_dir_len); + if (p == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } + + memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1); + + tablename_len = sizeof (prefix) - 1 + local_dir_len; + + atomic_write_barrier (); + + tablename_val = p; + } + + return NSS_STATUS_SUCCESS; +} + +static int +_nss_nisplus_parse_aliasent (nis_result *result, unsigned long entry, + struct aliasent *alias, char *buffer, + size_t buflen, int *errnop) +{ + if (result == NULL) + return 0; + + if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) + || __type_of (&NIS_RES_OBJECT (result)[entry]) != NIS_ENTRY_OBJ + || strcmp (NIS_RES_OBJECT (result)[entry].EN_data.en_type, + "mail_aliases") != 0 + || NIS_RES_OBJECT (result)[entry].EN_data.en_cols.en_cols_len < 2) + return 0; + + if (NISENTRYLEN (entry, 1, result) >= buflen) + { + /* The line is too long for our buffer. */ + no_more_room: + *errnop = ERANGE; + return -1; + } + + char *cp = __stpncpy (buffer, NISENTRYVAL (entry, 1, result), + NISENTRYLEN (entry, 1, result)); + *cp = '\0'; + + char *first_unused = cp + 1; + size_t room_left = buflen - (first_unused - buffer); + + alias->alias_local = 0; + alias->alias_members_len = 0; + + if (NISENTRYLEN (entry, 0, result) >= room_left) + goto no_more_room; + + cp = __stpncpy (first_unused, NISENTRYVAL (entry, 0, result), + NISENTRYLEN (entry, 0, result)); + *cp = '\0'; + alias->alias_name = first_unused; + + /* Terminate the line for any case. */ + cp = strpbrk (alias->alias_name, "#\n"); + if (cp != NULL) + *cp = '\0'; + + size_t len = strlen (alias->alias_name) + 1; + first_unused += len; + room_left -= len; + + /* Adjust the pointer so it is aligned for + storing pointers. */ + size_t adjust = ((__alignof__ (char *) + - (first_unused - (char *) 0) % __alignof__ (char *)) + % __alignof__ (char *)); + if (room_left < adjust) + goto no_more_room; + first_unused += adjust; + room_left -= adjust; + + alias->alias_members = (char **) first_unused; + + char *line = buffer; + 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 *); + alias->alias_members[alias->alias_members_len] = line; + + while (*line != '\0' && *line != ',') + ++line; + + if (line != alias->alias_members[alias->alias_members_len]) + { + *line++ = '\0'; + ++alias->alias_members_len; + } + else if (*line == ',') + ++line; + } + + return alias->alias_members_len == 0 ? 0 : 1; +} + +static enum nss_status +internal_setaliasent (void) +{ + enum nss_status status; + int err; + + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } + + if (_nss_create_tablename (&err) != NSS_STATUS_SUCCESS) + return NSS_STATUS_UNAVAIL; + + next_entry = 0; + result = nis_list (tablename_val, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); + if (result == NULL) + { + status = NSS_STATUS_TRYAGAIN; + __set_errno (ENOMEM); + } + else + { + status = niserr2nss (result->status); + if (status != NSS_STATUS_SUCCESS) + { + nis_freeresult (result); + result = NULL; + } + } + return status; +} + +enum nss_status +_nss_nisplus_setaliasent (void) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_setaliasent (); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nisplus_endaliasent (void) +{ + __libc_lock_lock (lock); + + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } + next_entry = 0; + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_nisplus_getaliasent_r (struct aliasent *alias, + char *buffer, size_t buflen, int *errnop) +{ + int parse_res; + + if (result == NULL) + { + enum nss_status status; + + status = internal_setaliasent (); + if (result == NULL || status != NSS_STATUS_SUCCESS) + return status; + } + + /* Get the next entry until we found a correct one. */ + do + { + if (next_entry >= result->objects.objects_len) + return NSS_STATUS_NOTFOUND; + + parse_res = _nss_nisplus_parse_aliasent (result, next_entry, alias, + buffer, buflen, errnop); + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + + ++next_entry; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nisplus_getaliasent_r (struct aliasent *result, char *buffer, + size_t buflen, int *errnop) +{ + int status; + + __libc_lock_lock (lock); + + status = internal_nisplus_getaliasent_r (result, buffer, buflen, errnop); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nisplus_getaliasbyname_r (const char *name, struct aliasent *alias, + char *buffer, size_t buflen, int *errnop) +{ + int parse_res; + + if (tablename_val == NULL) + { + __libc_lock_lock (lock); + + enum nss_status status = _nss_create_tablename (errnop); + + __libc_lock_unlock (lock); + + if (status != NSS_STATUS_SUCCESS) + return status; + } + + if (name == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + char buf[strlen (name) + 9 + tablename_len]; + int olderr = errno; + + snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val); + + nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); + + if (result == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } + + if (__glibc_unlikely (niserr2nss (result->status) != NSS_STATUS_SUCCESS)) + { + enum nss_status status = niserr2nss (result->status); + nis_freeresult (result); + return status; + } + + parse_res = _nss_nisplus_parse_aliasent (result, 0, alias, + buffer, buflen, errnop); + + /* We do not need the lookup result anymore. */ + nis_freeresult (result); + + if (__glibc_unlikely (parse_res < 1)) + { + __set_errno (olderr); + + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + + return NSS_STATUS_SUCCESS; +} diff --git a/REORG.TODO/nis/nss_nisplus/nisplus-ethers.c b/REORG.TODO/nis/nss_nisplus/nisplus-ethers.c new file mode 100644 index 0000000000..bb20696a49 --- /dev/null +++ b/REORG.TODO/nis/nss_nisplus/nisplus-ethers.c @@ -0,0 +1,356 @@ +/* Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <atomic.h> +#include <ctype.h> +#include <errno.h> +#include <inttypes.h> +#include <netdb.h> +#include <nss.h> +#include <string.h> +#include <netinet/ether.h> +#include <netinet/if_ether.h> +#include <rpcsvc/nis.h> +#include <libc-lock.h> + +#include "nss-nisplus.h" + +__libc_lock_define_initialized (static, lock) + +static nis_result *result; +static nis_name tablename_val; +static u_long tablename_len; + + +#define NISENTRYVAL(idx, col, res) \ + (NIS_RES_OBJECT (res)[idx].zo_data.objdata_u.en_data.en_cols.en_cols_val[col].ec_value.ec_value_val) + +#define NISENTRYLEN(idx, col, res) \ + (NIS_RES_OBJECT (res)[idx].zo_data.objdata_u.en_data.en_cols.en_cols_val[col].ec_value.ec_value_len) + +static int +_nss_nisplus_parse_etherent (nis_result *result, struct etherent *ether, + char *buffer, size_t buflen, int *errnop) +{ + char *p = buffer; + size_t room_left = buflen; + + if (result == NULL) + return 0; + + if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) + || NIS_RES_NUMOBJ (result) != 1 + || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ + || strcmp (NIS_RES_OBJECT (result)->EN_data.en_type, + "ethers_tbl") != 0 + || NIS_RES_OBJECT (result)->EN_data.en_cols.en_cols_len < 2) + return 0; + + /* Generate the ether entry format and use the normal parser */ + if (NISENTRYLEN (0, 0, result) + 1 > room_left) + { + *errnop = ERANGE; + return -1; + } + char *cp = __stpncpy (p, NISENTRYVAL (0, 0, result), + NISENTRYLEN (0, 0, result)); + *cp = '\0'; + room_left -= NISENTRYLEN (0, 0, result) + 1; + ether->e_name = p; + + struct ether_addr *ea = ether_aton (NISENTRYVAL (0, 1, result)); + if (ea == NULL) + { + *errnop = EINVAL; + return -2; + } + + ether->e_addr = *ea; + + return 1; +} + +static enum nss_status +_nss_create_tablename (int *errnop) +{ + if (tablename_val == NULL) + { + const char *local_dir = nis_local_directory (); + size_t local_dir_len = strlen (local_dir); + static const char prefix[] = "ethers.org_dir."; + + char *p = malloc (sizeof (prefix) + local_dir_len); + if (p == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } + + memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1); + + tablename_len = sizeof (prefix) - 1 + local_dir_len; + + atomic_write_barrier (); + + tablename_val = p; + } + return NSS_STATUS_SUCCESS; +} + + +enum nss_status +_nss_nisplus_setetherent (int stayopen) +{ + enum nss_status status; + int err; + + status = NSS_STATUS_SUCCESS; + + __libc_lock_lock (lock); + + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } + + if (_nss_create_tablename (&err) != NSS_STATUS_SUCCESS) + status = NSS_STATUS_UNAVAIL; + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nisplus_endetherent (void) +{ + __libc_lock_lock (lock); + + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_nisplus_getetherent_r (struct etherent *ether, char *buffer, + size_t buflen, int *errnop) +{ + if (tablename_val == NULL) + { + enum nss_status status = _nss_create_tablename (errnop); + + if (status != NSS_STATUS_SUCCESS) + return status; + } + + /* Get the next entry until we found a correct one. */ + int parse_res; + do + { + nis_result *saved_result; + + if (result == NULL) + { + saved_result = NULL; + result = nis_first_entry (tablename_val); + if (result == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } + if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) + return niserr2nss (result->status); + } + else + { + saved_result = result; + result = nis_next_entry (tablename_val, &result->cookie); + if (result == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } + if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) + { + nis_freeresult (saved_result); + return niserr2nss (result->status); + } + } + + parse_res = _nss_nisplus_parse_etherent (result, ether, buffer, + buflen, errnop); + if (parse_res == -1) + { + nis_freeresult (result); + result = saved_result; + return NSS_STATUS_TRYAGAIN; + } + + if (saved_result != NULL) + nis_freeresult (saved_result); + + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nisplus_getetherent_r (struct etherent *result, char *buffer, + size_t buflen, int *errnop) +{ + int status; + + __libc_lock_lock (lock); + + status = internal_nisplus_getetherent_r (result, buffer, buflen, errnop); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nisplus_gethostton_r (const char *name, struct etherent *eth, + char *buffer, size_t buflen, int *errnop) +{ + if (tablename_val == NULL) + { + enum nss_status status = _nss_create_tablename (errnop); + + if (status != NSS_STATUS_SUCCESS) + return status; + } + + if (name == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + char buf[strlen (name) + 9 + tablename_len]; + int olderr = errno; + + snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val); + + nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, + NULL, NULL); + + if (result == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } + + if (__glibc_unlikely (niserr2nss (result->status) != NSS_STATUS_SUCCESS)) + { + enum nss_status status = niserr2nss (result->status); + nis_freeresult (result); + return status; + } + + int parse_res = _nss_nisplus_parse_etherent (result, eth, buffer, + buflen, errnop); + + /* We do not need the lookup result anymore. */ + nis_freeresult (result); + + if (__glibc_unlikely (parse_res < 1)) + { + __set_errno (olderr); + + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + + return NSS_STATUS_NOTFOUND; + } + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nisplus_getntohost_r (const struct ether_addr *addr, struct etherent *eth, + char *buffer, size_t buflen, int *errnop) +{ + if (tablename_val == NULL) + { + __libc_lock_lock (lock); + + enum nss_status status = _nss_create_tablename (errnop); + + __libc_lock_unlock (lock); + + if (status != NSS_STATUS_SUCCESS) + return status; + } + + if (addr == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + char buf[26 + tablename_len]; + + snprintf (buf, sizeof (buf), + "[addr=%" PRIx8 ":%" PRIx8 ":%" PRIx8 ":%" PRIx8 ":%" PRIx8 + ":%" PRIx8 "],%s", + 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], + tablename_val); + + nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, + NULL, NULL); + + if (result == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } + + if (__glibc_unlikely (niserr2nss (result->status) != NSS_STATUS_SUCCESS)) + { + enum nss_status status = niserr2nss (result->status); + nis_freeresult (result); + return status; + } + + int parse_res = _nss_nisplus_parse_etherent (result, eth, buffer, + buflen, errnop); + + /* We do not need the lookup result anymore. */ + nis_freeresult (result); + + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + + return NSS_STATUS_NOTFOUND; + } + + return NSS_STATUS_SUCCESS; +} diff --git a/REORG.TODO/nis/nss_nisplus/nisplus-grp.c b/REORG.TODO/nis/nss_nisplus/nisplus-grp.c new file mode 100644 index 0000000000..124b8b85b5 --- /dev/null +++ b/REORG.TODO/nis/nss_nisplus/nisplus-grp.c @@ -0,0 +1,401 @@ +/* Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <atomic.h> +#include <nss.h> +#include <grp.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <libc-lock.h> +#include <rpcsvc/nis.h> + +#include "nss-nisplus.h" +#include "nisplus-parser.h" +#include <libnsl.h> +#include <nis_intern.h> +#include <nis_xdr.h> + + +__libc_lock_define_initialized (static, lock); + +/* Connection information. */ +static ib_request *ibreq; +static directory_obj *dir; +static dir_binding bptr; +static char *tablepath; +static char *tableptr; +/* Cursor. */ +static netobj cursor; + + +nis_name grp_tablename_val attribute_hidden; +size_t grp_tablename_len attribute_hidden; + +enum nss_status +_nss_grp_create_tablename (int *errnop) +{ + if (grp_tablename_val == NULL) + { + const char *local_dir = nis_local_directory (); + size_t local_dir_len = strlen (local_dir); + static const char prefix[] = "group.org_dir."; + + char *p = malloc (sizeof (prefix) + local_dir_len); + if (p == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } + + memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1); + + grp_tablename_len = sizeof (prefix) - 1 + local_dir_len; + + atomic_write_barrier (); + + if (atomic_compare_and_exchange_bool_acq (&grp_tablename_val, p, NULL)) + { + /* Another thread already installed the value. */ + free (p); + grp_tablename_len = strlen (grp_tablename_val); + } + } + + return NSS_STATUS_SUCCESS; +} + + +static void +internal_endgrent (void) +{ + __nisbind_destroy (&bptr); + memset (&bptr, '\0', sizeof (bptr)); + + nis_free_directory (dir); + dir = NULL; + + nis_free_request (ibreq); + ibreq = NULL; + + xdr_free ((xdrproc_t) xdr_netobj, (char *) &cursor); + memset (&cursor, '\0', sizeof (cursor)); + + free (tablepath); + tableptr = tablepath = NULL; +} + + +static enum nss_status +internal_setgrent (int *errnop) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + if (grp_tablename_val == NULL) + status = _nss_grp_create_tablename (errnop); + + if (status == NSS_STATUS_SUCCESS) + { + ibreq = __create_ib_request (grp_tablename_val, 0); + if (ibreq == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } + + nis_error retcode = __prepare_niscall (grp_tablename_val, &dir, &bptr, 0); + if (retcode != NIS_SUCCESS) + { + nis_free_request (ibreq); + ibreq = NULL; + status = niserr2nss (retcode); + } + } + + return status; +} + + +enum nss_status +_nss_nisplus_setgrent (int stayopen) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + internal_endgrent (); + + // XXX We need to be able to set errno. Pass in new parameter. + int err; + status = internal_setgrent (&err); + + __libc_lock_unlock (lock); + + return status; +} + + +enum nss_status +_nss_nisplus_endgrent (void) +{ + __libc_lock_lock (lock); + + internal_endgrent (); + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + + +static enum nss_status +internal_nisplus_getgrent_r (struct group *gr, char *buffer, size_t buflen, + int *errnop) +{ + int parse_res = -1; + enum nss_status retval = NSS_STATUS_SUCCESS; + + /* Get the next entry until we found a correct one. */ + do + { + nis_error status; + nis_result result; + memset (&result, '\0', sizeof (result)); + + if (cursor.n_bytes == NULL) + { + if (ibreq == NULL) + { + retval = internal_setgrent (errnop); + if (retval != NSS_STATUS_SUCCESS) + return retval; + } + + status = __do_niscall3 (&bptr, NIS_IBFIRST, + (xdrproc_t) _xdr_ib_request, + (caddr_t) ibreq, + (xdrproc_t) _xdr_nis_result, + (caddr_t) &result, + 0, NULL); + } + else + { + ibreq->ibr_cookie.n_bytes = cursor.n_bytes; + ibreq->ibr_cookie.n_len = cursor.n_len; + + status = __do_niscall3 (&bptr, NIS_IBNEXT, + (xdrproc_t) _xdr_ib_request, + (caddr_t) ibreq, + (xdrproc_t) _xdr_nis_result, + (caddr_t) &result, + 0, NULL); + + ibreq->ibr_cookie.n_bytes = NULL; + ibreq->ibr_cookie.n_len = 0; + } + + if (status != NIS_SUCCESS) + return niserr2nss (status); + + if (NIS_RES_STATUS (&result) == NIS_NOTFOUND) + { + /* No more entries on this server. This means we have to go + to the next server on the path. */ + status = __follow_path (&tablepath, &tableptr, ibreq, &bptr); + if (status != NIS_SUCCESS) + return niserr2nss (status); + + directory_obj *newdir = NULL; + dir_binding newbptr; + status = __prepare_niscall (ibreq->ibr_name, &newdir, &newbptr, 0); + if (status != NIS_SUCCESS) + return niserr2nss (status); + + nis_free_directory (dir); + dir = newdir; + __nisbind_destroy (&bptr); + bptr = newbptr; + + xdr_free ((xdrproc_t) xdr_netobj, (char *) &result.cookie); + result.cookie.n_bytes = NULL; + result.cookie.n_len = 0; + parse_res = 0; + goto next; + } + else if (NIS_RES_STATUS (&result) != NIS_SUCCESS) + return niserr2nss (NIS_RES_STATUS (&result)); + + parse_res = _nss_nisplus_parse_grent (&result, gr, + buffer, buflen, errnop); + if (__glibc_unlikely (parse_res == -1)) + { + *errnop = ERANGE; + retval = NSS_STATUS_TRYAGAIN; + goto freeres; + } + + next: + /* Free the old cursor. */ + xdr_free ((xdrproc_t) xdr_netobj, (char *) &cursor); + /* Remember the new one. */ + cursor.n_bytes = result.cookie.n_bytes; + cursor.n_len = result.cookie.n_len; + /* Free the result structure. NB: we do not remove the cookie. */ + result.cookie.n_bytes = NULL; + result.cookie.n_len = 0; + freeres: + xdr_free ((xdrproc_t) _xdr_nis_result, (char *) &result); + memset (&result, '\0', sizeof (result)); + } + while (!parse_res); + + return retval; +} + +enum nss_status +_nss_nisplus_getgrent_r (struct group *result, char *buffer, size_t buflen, + int *errnop) +{ + int status; + + __libc_lock_lock (lock); + + status = internal_nisplus_getgrent_r (result, buffer, buflen, errnop); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nisplus_getgrnam_r (const char *name, struct group *gr, + char *buffer, size_t buflen, int *errnop) +{ + int parse_res; + + if (grp_tablename_val == NULL) + { + enum nss_status status = _nss_grp_create_tablename (errnop); + + if (status != NSS_STATUS_SUCCESS) + return status; + } + + if (name == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_NOTFOUND; + } + + nis_result *result; + char buf[strlen (name) + 9 + grp_tablename_len]; + int olderr = errno; + + snprintf (buf, sizeof (buf), "[name=%s],%s", name, grp_tablename_val); + + result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL); + + if (result == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } + + if (__glibc_unlikely (niserr2nss (result->status) != NSS_STATUS_SUCCESS)) + { + enum nss_status status = niserr2nss (result->status); + + nis_freeresult (result); + return status; + } + + parse_res = _nss_nisplus_parse_grent (result, gr, buffer, buflen, errnop); + nis_freeresult (result); + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + else + { + __set_errno (olderr); + return NSS_STATUS_NOTFOUND; + } + } + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nisplus_getgrgid_r (const gid_t gid, struct group *gr, + char *buffer, size_t buflen, int *errnop) +{ + if (grp_tablename_val == NULL) + { + enum nss_status status = _nss_grp_create_tablename (errnop); + + if (status != NSS_STATUS_SUCCESS) + return status; + } + + int parse_res; + nis_result *result; + char buf[8 + 3 * sizeof (unsigned long int) + grp_tablename_len]; + int olderr = errno; + + snprintf (buf, sizeof (buf), "[gid=%lu],%s", + (unsigned long int) gid, grp_tablename_val); + + result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); + + if (result == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } + + if (__glibc_unlikely (niserr2nss (result->status) != NSS_STATUS_SUCCESS)) + { + enum nss_status status = niserr2nss (result->status); + + __set_errno (olderr); + + nis_freeresult (result); + return status; + } + + parse_res = _nss_nisplus_parse_grent (result, gr, buffer, buflen, errnop); + + nis_freeresult (result); + if (__glibc_unlikely (parse_res < 1)) + { + __set_errno (olderr); + + if (parse_res == -1) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + else + return NSS_STATUS_NOTFOUND; + } + + return NSS_STATUS_SUCCESS; +} diff --git a/REORG.TODO/nis/nss_nisplus/nisplus-hosts.c b/REORG.TODO/nis/nss_nisplus/nisplus-hosts.c new file mode 100644 index 0000000000..31dfd31fbd --- /dev/null +++ b/REORG.TODO/nis/nss_nisplus/nisplus-hosts.c @@ -0,0 +1,619 @@ +/* Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <atomic.h> +#include <ctype.h> +#include <errno.h> +#include <netdb.h> +#include <nss.h> +#include <string.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <rpcsvc/nis.h> +#include <libc-lock.h> + +#include "nss-nisplus.h" + +__libc_lock_define_initialized (static, lock) + +static nis_result *result; +static nis_name tablename_val; +static u_long tablename_len; + +#define NISENTRYVAL(idx, col, res) \ + (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val) + +#define NISENTRYLEN(idx, col, res) \ + (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len) + +/* Get implementation for some internal functions. */ +#include <resolv/resolv-internal.h> +#include <resolv/mapv4v6addr.h> + + +static int +_nss_nisplus_parse_hostent (nis_result *result, int af, struct hostent *host, + char *buffer, size_t buflen, int *errnop, + int flags) +{ + unsigned int i; + char *first_unused = buffer; + size_t room_left = buflen; + + if (result == NULL) + return 0; + + if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) + || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ + || strcmp (NIS_RES_OBJECT (result)[0].EN_data.en_type, "hosts_tbl") != 0 + || NIS_RES_OBJECT (result)[0].EN_data.en_cols.en_cols_len < 4) + return 0; + + char *data = first_unused; + + if (room_left < (af != AF_INET || (flags & AI_V4MAPPED) != 0 + ? IN6ADDRSZ : INADDRSZ)) + { + no_more_room: + *errnop = ERANGE; + return -1; + } + + /* Parse address. */ + if (af != AF_INET6 + && inet_pton (AF_INET, NISENTRYVAL (0, 2, result), data) > 0) + { + assert ((flags & AI_V4MAPPED) == 0 || af != AF_UNSPEC); + if (flags & AI_V4MAPPED) + { + map_v4v6_address (data, data); + host->h_addrtype = AF_INET6; + host->h_length = IN6ADDRSZ; + } + else + { + host->h_addrtype = AF_INET; + host->h_length = INADDRSZ; + } + } + else if (af != AF_INET + && inet_pton (AF_INET6, NISENTRYVAL (0, 2, result), data) > 0) + { + host->h_addrtype = AF_INET6; + host->h_length = IN6ADDRSZ; + } + else + /* Illegal address: ignore line. */ + return 0; + + first_unused += host->h_length; + room_left -= host->h_length; + + if (NISENTRYLEN (0, 0, result) + 1 > room_left) + goto no_more_room; + + host->h_name = first_unused; + first_unused = __stpncpy (first_unused, NISENTRYVAL (0, 0, result), + NISENTRYLEN (0, 0, result)); + *first_unused++ = '\0'; + + room_left -= NISENTRYLEN (0, 0, result) + 1; + char *line = first_unused; + + /* When this is a call to gethostbyname4_r we do not need the aliases. */ + if (af != AF_UNSPEC) + { + /* XXX Rewrite at some point to allocate the array first and then + copy the strings. It is wasteful to first concatenate the strings + to just split them again later. */ + for (i = 0; i < NIS_RES_NUMOBJ (result); ++i) + { + if (strcmp (NISENTRYVAL (i, 1, result), host->h_name) != 0) + { + if (NISENTRYLEN (i, 1, result) + 2 > room_left) + goto no_more_room; + + *first_unused++ = ' '; + first_unused = __stpncpy (first_unused, + NISENTRYVAL (i, 1, result), + NISENTRYLEN (i, 1, result)); + *first_unused = '\0'; + room_left -= NISENTRYLEN (i, 1, result) + 1; + } + } + *first_unused++ = '\0'; + } + + /* Adjust the pointer so it is aligned for + storing pointers. */ + size_t adjust = ((__alignof__ (char *) + - (first_unused - (char *) 0) % __alignof__ (char *)) + % __alignof__ (char *)); + if (room_left < adjust + 3 * sizeof (char *)) + goto no_more_room; + first_unused += adjust; + room_left -= adjust; + host->h_addr_list = (char **) first_unused; + + room_left -= 3 * sizeof (char *); + host->h_addr_list[0] = data; + host->h_addr_list[1] = NULL; + host->h_aliases = &host->h_addr_list[2]; + + /* When this is a call to gethostbyname4_r we do not need the aliases. */ + if (af != AF_UNSPEC) + { + i = 0; + 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 *); + host->h_aliases[i++] = line; + + while (*line != '\0' && *line != ' ') + ++line; + + if (*line == ' ') + *line++ = '\0'; + } + + host->h_aliases[i] = NULL; + } + + return 1; +} + + +static enum nss_status +_nss_create_tablename (int *errnop) +{ + if (tablename_val == NULL) + { + const char *local_dir = nis_local_directory (); + size_t local_dir_len = strlen (local_dir); + static const char prefix[] = "hosts.org_dir."; + + char *p = malloc (sizeof (prefix) + local_dir_len); + if (p == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } + + memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1); + + tablename_len = sizeof (prefix) - 1 + local_dir_len; + + atomic_write_barrier (); + + tablename_val = p; + } + + return NSS_STATUS_SUCCESS; +} + + +enum nss_status +_nss_nisplus_sethostent (int stayopen) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + int err; + + __libc_lock_lock (lock); + + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } + + if (tablename_val == NULL) + status = _nss_create_tablename (&err); + + __libc_lock_unlock (lock); + + return status; +} + + +enum nss_status +_nss_nisplus_endhostent (void) +{ + __libc_lock_lock (lock); + + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + + +static enum nss_status +internal_nisplus_gethostent_r (struct hostent *host, char *buffer, + size_t buflen, int *errnop, int *herrnop) +{ + int parse_res; + + /* Get the next entry until we found a correct one. */ + do + { + nis_result *saved_res; + + if (result == NULL) + { + saved_res = NULL; + if (tablename_val == NULL) + { + enum nss_status status = _nss_create_tablename (errnop); + + if (status != NSS_STATUS_SUCCESS) + return status; + } + + result = nis_first_entry (tablename_val); + if (result == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } + if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) + { + enum nss_status retval = niserr2nss (result->status); + if (retval == NSS_STATUS_TRYAGAIN) + { + *herrnop = NETDB_INTERNAL; + *errnop = errno; + } + return retval; + } + + } + else + { + saved_res = result; + result = nis_next_entry (tablename_val, &result->cookie); + if (result == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } + if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) + { + enum nss_status retval= niserr2nss (result->status); + + nis_freeresult (result); + result = saved_res; + if (retval == NSS_STATUS_TRYAGAIN) + { + *herrnop = NETDB_INTERNAL; + *errnop = errno; + } + return retval; + } + } + + if (res_use_inet6 ()) + parse_res = _nss_nisplus_parse_hostent (result, AF_INET6, host, buffer, + buflen, errnop, AI_V4MAPPED); + else + parse_res = _nss_nisplus_parse_hostent (result, AF_INET, host, buffer, + buflen, errnop, 0); + + if (parse_res == -1) + { + nis_freeresult (result); + result = saved_res; + *herrnop = NETDB_INTERNAL; + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + if (saved_res != NULL) + nis_freeresult (saved_res); + + } while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + + +enum nss_status +_nss_nisplus_gethostent_r (struct hostent *result, char *buffer, + size_t buflen, int *errnop, int *herrnop) +{ + int status; + + __libc_lock_lock (lock); + + status = internal_nisplus_gethostent_r (result, buffer, buflen, errnop, + herrnop); + + __libc_lock_unlock (lock); + + return status; +} + + +static enum nss_status +get_tablename (int *herrnop) +{ + __libc_lock_lock (lock); + + enum nss_status status = _nss_create_tablename (herrnop); + + __libc_lock_unlock (lock); + + if (status != NSS_STATUS_SUCCESS) + *herrnop = NETDB_INTERNAL; + + return status; +} + + +static enum nss_status +internal_gethostbyname2_r (const char *name, int af, struct hostent *host, + char *buffer, size_t buflen, int *errnop, + int *herrnop, int flags) +{ + if (tablename_val == NULL) + { + enum nss_status status = get_tablename (herrnop); + if (status != NSS_STATUS_SUCCESS) + return status; + } + + if (name == NULL) + { + *errnop = EINVAL; + *herrnop = NETDB_INTERNAL; + return NSS_STATUS_NOTFOUND; + } + + char buf[strlen (name) + 10 + tablename_len]; + int olderr = errno; + + /* Search at first in the alias list, and use the correct name + for the next search. */ + snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val); + nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); + + if (result != NULL) + { + /* If we did not find it, try it as original name. But if the + database is correct, we should find it in the first case, too. */ + char *bufptr = buf; + size_t buflen = sizeof (buf); + + if ((result->status == NIS_SUCCESS || result->status == NIS_S_SUCCESS) + && __type_of (result->objects.objects_val) == NIS_ENTRY_OBJ + && strcmp (result->objects.objects_val->EN_data.en_type, + "hosts_tbl") == 0 + && result->objects.objects_val->EN_data.en_cols.en_cols_len >= 3) + { + /* We need to allocate a new buffer since there is no + guarantee the returned alias name has a length limit. */ + name = NISENTRYVAL(0, 0, result); + size_t buflen = strlen (name) + 10 + tablename_len; + bufptr = alloca (buflen); + } + + snprintf (bufptr, buflen, "[cname=%s],%s", name, tablename_val); + + nis_freeresult (result); + result = nis_list (bufptr, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); + } + + if (result == NULL) + { + *errnop = ENOMEM; + *herrnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + + int retval = niserr2nss (result->status); + if (__glibc_unlikely (retval != NSS_STATUS_SUCCESS)) + { + if (retval == NSS_STATUS_TRYAGAIN) + { + *errnop = errno; + *herrnop = TRY_AGAIN; + } + else + { + __set_errno (olderr); + *herrnop = NETDB_INTERNAL; + } + nis_freeresult (result); + return retval; + } + + int parse_res = _nss_nisplus_parse_hostent (result, af, host, buffer, + buflen, errnop, flags); + + nis_freeresult (result); + + if (parse_res > 0) + return NSS_STATUS_SUCCESS; + + *herrnop = NETDB_INTERNAL; + if (parse_res == -1) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + __set_errno (olderr); + return NSS_STATUS_NOTFOUND; +} + + +enum nss_status +_nss_nisplus_gethostbyname2_r (const char *name, int af, struct hostent *host, + char *buffer, size_t buflen, int *errnop, + int *herrnop) +{ + if (af != AF_INET && af != AF_INET6) + { + *herrnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } + + return internal_gethostbyname2_r (name, af, host, buffer, buflen, errnop, + herrnop, + (res_use_inet6 () ? AI_V4MAPPED : 0)); +} + + +enum nss_status +_nss_nisplus_gethostbyname_r (const char *name, struct hostent *host, + char *buffer, size_t buflen, int *errnop, + int *h_errnop) +{ + if (res_use_inet6 ()) + { + enum nss_status status; + + status = internal_gethostbyname2_r (name, AF_INET6, host, buffer, + buflen, errnop, h_errnop, + AI_V4MAPPED); + if (status == NSS_STATUS_SUCCESS) + return status; + } + + return internal_gethostbyname2_r (name, AF_INET, host, buffer, + buflen, errnop, h_errnop, 0); +} + + +enum nss_status +_nss_nisplus_gethostbyaddr_r (const void *addr, socklen_t addrlen, int af, + struct hostent *host, char *buffer, + size_t buflen, int *errnop, int *herrnop) +{ + if (tablename_val == NULL) + { + enum nss_status status = get_tablename (herrnop); + if (status != NSS_STATUS_SUCCESS) + return status; + } + + if (addr == NULL) + return NSS_STATUS_NOTFOUND; + + char buf[24 + tablename_len]; + int retval, parse_res; + int olderr = errno; + + snprintf (buf, sizeof (buf), "[addr=%s],%s", + inet_ntoa (*(const struct in_addr *) addr), tablename_val); + nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); + + if (result == NULL) + { + __set_errno (ENOMEM); + return NSS_STATUS_TRYAGAIN; + } + + retval = niserr2nss (result->status); + if (__glibc_unlikely (retval != NSS_STATUS_SUCCESS)) + { + if (retval == NSS_STATUS_TRYAGAIN) + { + *errnop = errno; + *herrnop = NETDB_INTERNAL; + } + else + __set_errno (olderr); + nis_freeresult (result); + return retval; + } + + parse_res = _nss_nisplus_parse_hostent (result, af, host, + buffer, buflen, errnop, + (res_use_inet6 () + ? AI_V4MAPPED : 0)); + nis_freeresult (result); + + if (parse_res > 0) + return NSS_STATUS_SUCCESS; + + *herrnop = NETDB_INTERNAL; + if (parse_res == -1) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + __set_errno (olderr); + return NSS_STATUS_NOTFOUND; +} + + +enum nss_status +_nss_nisplus_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, + char *buffer, size_t buflen, int *errnop, + int *herrnop, int32_t *ttlp) +{ + struct hostent host; + + enum nss_status status = internal_gethostbyname2_r (name, AF_UNSPEC, &host, + buffer, buflen, + errnop, herrnop, 0); + if (__glibc_likely (status == NSS_STATUS_SUCCESS)) + { + if (*pat == NULL) + { + uintptr_t pad = (-(uintptr_t) buffer + % __alignof__ (struct gaih_addrtuple)); + buffer += pad; + buflen = buflen > pad ? buflen - pad : 0; + + if (__glibc_unlikely (buflen < sizeof (struct gaih_addrtuple))) + { + free (result); + *errnop = ERANGE; + *herrnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + } + + (*pat)->next = NULL; + (*pat)->name = host.h_name; + (*pat)->family = host.h_addrtype; + + memcpy ((*pat)->addr, host.h_addr_list[0], host.h_length); + (*pat)->scopeid = 0; + assert (host.h_addr_list[1] == NULL); + } + + return status; +} diff --git a/REORG.TODO/nis/nss_nisplus/nisplus-initgroups.c b/REORG.TODO/nis/nss_nisplus/nisplus-initgroups.c new file mode 100644 index 0000000000..95ee623b1c --- /dev/null +++ b/REORG.TODO/nis/nss_nisplus/nisplus-initgroups.c @@ -0,0 +1,148 @@ +/* Copyright (C) 1997-2017 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <atomic.h> +#include <nss.h> +#include <grp.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <libc-lock.h> +#include <rpcsvc/nis.h> + +#include "nss-nisplus.h" +#include "nisplus-parser.h" +#include <libnsl.h> +#include <nis_intern.h> +#include <nis_xdr.h> + +#define NISOBJVAL(col, obj) \ + ((obj)->EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val) + +#define NISOBJLEN(col, obj) \ + ((obj)->EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len) + +extern nis_name grp_tablename_val attribute_hidden; +extern size_t grp_tablename_len attribute_hidden; +extern enum nss_status _nss_grp_create_tablename (int *errnop); + + +enum nss_status +_nss_nisplus_initgroups_dyn (const char *user, gid_t group, long int *start, + long int *size, gid_t **groupsp, long int limit, + int *errnop) +{ + if (grp_tablename_val == NULL) + { + enum nss_status status = _nss_grp_create_tablename (errnop); + + if (status != NSS_STATUS_SUCCESS) + return status; + } + + nis_result *result; + char buf[strlen (user) + 12 + grp_tablename_len]; + + snprintf (buf, sizeof (buf), "[members=%s],%s", user, grp_tablename_val); + + result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH | ALL_RESULTS, NULL, NULL); + + if (result == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } + + if (__glibc_unlikely (niserr2nss (result->status) != NSS_STATUS_SUCCESS)) + { + enum nss_status status = niserr2nss (result->status); + + nis_freeresult (result); + return status; + } + + if (NIS_RES_NUMOBJ (result) == 0) + { + errout: + nis_freeresult (result); + return NSS_STATUS_NOTFOUND; + } + + gid_t *groups = *groupsp; + nis_object *obj = NIS_RES_OBJECT (result); + for (unsigned int cnt = 0; cnt < NIS_RES_NUMOBJ (result); ++cnt, ++obj) + { + if (__type_of (obj) != NIS_ENTRY_OBJ + || strcmp (obj->EN_data.en_type, "group_tbl") != 0 + || obj->EN_data.en_cols.en_cols_len < 4) + continue; + + char *numstr = NISOBJVAL (2, obj); + size_t len = NISOBJLEN (2, obj); + if (len == 0 || numstr[0] == '\0') + continue; + + gid_t gid; + char *endp; + if (__glibc_unlikely (numstr[len - 1] != '\0')) + { + char numstrbuf[len + 1]; + memcpy (numstrbuf, numstr, len); + numstrbuf[len] = '\0'; + gid = strtoul (numstrbuf, &endp, 10); + if (*endp) + continue; + } + else + { + gid = strtoul (numstr, &endp, 10); + if (*endp) + continue; + } + + if (gid == group) + continue; + + /* Insert this group. */ + if (*start == *size) + { + /* Need a bigger buffer. */ + long int newsize; + + if (limit > 0 && *size == limit) + /* We reached the maximum. */ + break; + + if (limit <= 0) + newsize = 2 * *size; + else + newsize = MIN (limit, 2 * *size); + + gid_t *newgroups = realloc (groups, newsize * sizeof (*groups)); + if (newgroups == NULL) + goto errout; + *groupsp = groups = newgroups; + *size = newsize; + } + + groups[*start] = gid; + *start += 1; + } + + nis_freeresult (result); + return NSS_STATUS_SUCCESS; +} diff --git a/REORG.TODO/nis/nss_nisplus/nisplus-netgrp.c b/REORG.TODO/nis/nss_nisplus/nisplus-netgrp.c new file mode 100644 index 0000000000..f10a85f0e3 --- /dev/null +++ b/REORG.TODO/nis/nss_nisplus/nisplus-netgrp.c @@ -0,0 +1,191 @@ +/* Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <nss.h> +#include <errno.h> +#include <ctype.h> +#include <netdb.h> +#include <string.h> +#include <netgroup.h> +#include <rpcsvc/nis.h> + +#include "nss-nisplus.h" + +#define NISENTRYVAL(idx, col, res) \ + (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val) + +#define NISENTRYLEN(idx, col, res) \ + (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len) + +enum nss_status +_nss_nisplus_getnetgrent_r (struct __netgrent *result, char *buffer, + size_t buflen, int *errnop) +{ + enum nss_status status; + + /* Some sanity checks. */ + if (result->data == NULL || result->data_size == 0) + return NSS_STATUS_NOTFOUND; + + if (result->position == result->data_size) + return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN; + + unsigned int entrylen + = NISENTRYLEN (result->position, 1, (nis_result *) result->data); + if (entrylen > 0) + { + /* We have a list of other netgroups. */ + + result->type = group_val; + if (entrylen >= buflen) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + strncpy (buffer, NISENTRYVAL (result->position, 1, + (nis_result *) result->data), + entrylen); + buffer[entrylen] = '\0'; + result->val.group = buffer; + ++result->position; + result->first = 0; + + return NSS_STATUS_SUCCESS; + } + + /* Before we can copy the entry to the private buffer we have to make + sure it is big enough. */ + unsigned int hostlen + = NISENTRYLEN (result->position, 2, (nis_result *) result->data); + unsigned int userlen + = NISENTRYLEN (result->position, 3, (nis_result *) result->data); + unsigned int domainlen + = NISENTRYLEN (result->position, 4, (nis_result *) result->data); + if (hostlen + userlen + domainlen + 6 > buflen) + { + *errnop = ERANGE; + status = NSS_STATUS_TRYAGAIN; + } + else + { + char *cp = buffer; + + result->type = triple_val; + + if (hostlen == 0 || + NISENTRYVAL (result->position, 2, + (nis_result *) result->data)[0] == '\0') + result->val.triple.host = NULL; + else + { + result->val.triple.host = cp; + cp = __stpncpy (cp, NISENTRYVAL (result->position, 2, + (nis_result *) result->data), + hostlen); + *cp++ = '\0'; + } + + if (userlen == 0 || + NISENTRYVAL (result->position, 3, + (nis_result *) result->data)[0] == '\0') + result->val.triple.user = NULL; + else + { + result->val.triple.user = cp; + cp = __stpncpy (cp, NISENTRYVAL (result->position, 3, + (nis_result *) result->data), + userlen); + *cp++ = '\0'; + } + + if (domainlen == 0 || + NISENTRYVAL (result->position, 4, + (nis_result *) result->data)[0] == '\0') + result->val.triple.domain = NULL; + else + { + result->val.triple.domain = cp; + cp = __stpncpy (cp, NISENTRYVAL (result->position, 4, + (nis_result *) result->data), + domainlen); + *cp = '\0'; + } + + status = NSS_STATUS_SUCCESS; + + /* Remember where we stopped reading. */ + ++result->position; + + result->first = 0; + } + + return status; +} + +static void +internal_endnetgrent (struct __netgrent *netgrp) +{ + nis_freeresult ((nis_result *) netgrp->data); + netgrp->data = NULL; + netgrp->data_size = 0; + netgrp->position = 0; +} + +enum nss_status +_nss_nisplus_setnetgrent (const char *group, struct __netgrent *netgrp) +{ + char buf[strlen (group) + 25]; + + if (group == NULL || group[0] == '\0') + return NSS_STATUS_UNAVAIL; + + enum nss_status status = NSS_STATUS_SUCCESS; + + snprintf (buf, sizeof (buf), "[name=%s],netgroup.org_dir", group); + + netgrp->data = (char *) nis_list (buf, EXPAND_NAME, NULL, NULL); + + if (netgrp->data == NULL) + { + __set_errno (ENOMEM); + status = NSS_STATUS_TRYAGAIN; + } + else if (niserr2nss (((nis_result *) netgrp->data)->status) + != NSS_STATUS_SUCCESS) + { + status = niserr2nss (((nis_result *) netgrp->data)->status); + + internal_endnetgrent (netgrp); + } + else + { + netgrp->data_size = ((nis_result *) netgrp->data)->objects.objects_len; + netgrp->position = 0; + netgrp->first = 1; + } + + return status; +} + +enum nss_status +_nss_nisplus_endnetgrent (struct __netgrent *netgrp) +{ + internal_endnetgrent (netgrp); + + return NSS_STATUS_SUCCESS; +} diff --git a/REORG.TODO/nis/nss_nisplus/nisplus-network.c b/REORG.TODO/nis/nss_nisplus/nisplus-network.c new file mode 100644 index 0000000000..ad266b9f6d --- /dev/null +++ b/REORG.TODO/nis/nss_nisplus/nisplus-network.c @@ -0,0 +1,494 @@ +/* Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <atomic.h> +#include <ctype.h> +#include <errno.h> +#include <netdb.h> +#include <nss.h> +#include <stdint.h> +#include <string.h> +#include <arpa/inet.h> +#include <rpcsvc/nis.h> +#include <libc-lock.h> + +#include "nss-nisplus.h" + +__libc_lock_define_initialized (static, lock) + +static nis_result *result; +static nis_name tablename_val; +static u_long tablename_len; + +#define NISENTRYVAL(idx, col, res) \ + (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val) + +#define NISENTRYLEN(idx, col, res) \ + (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len) + + +static int +_nss_nisplus_parse_netent (nis_result *result, struct netent *network, + char *buffer, size_t buflen, int *errnop) +{ + char *first_unused = buffer; + size_t room_left = buflen; + + if (result == NULL) + return 0; + + if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) + || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ + || strcmp (NIS_RES_OBJECT (result)[0].EN_data.en_type, + "networks_tbl") != 0 + || NIS_RES_OBJECT (result)[0].EN_data.en_cols.en_cols_len < 3) + return 0; + + if (NISENTRYLEN (0, 0, result) >= room_left) + { + /* The line is too long for our buffer. */ + no_more_room: + *errnop = ERANGE; + return -1; + } + + strncpy (first_unused, NISENTRYVAL (0, 0, result), + NISENTRYLEN (0, 0, result)); + first_unused[NISENTRYLEN (0, 0, result)] = '\0'; + network->n_name = first_unused; + size_t len = strlen (first_unused) + 1; + room_left -= len; + first_unused += len; + + network->n_addrtype = 0; + network->n_net = inet_network (NISENTRYVAL (0, 2, result)); + + /* XXX Rewrite at some point to allocate the array first and then + copy the strings. It wasteful to first concatenate the strings + to just split them again later. */ + char *line = first_unused; + for (unsigned int i = 0; i < NIS_RES_NUMOBJ (result); ++i) + { + if (strcmp (NISENTRYVAL (i, 1, result), network->n_name) != 0) + { + if (NISENTRYLEN (i, 1, result) + 2 > room_left) + goto no_more_room; + + *first_unused++ = ' '; + first_unused = __stpncpy (first_unused, NISENTRYVAL (i, 1, result), + NISENTRYLEN (i, 1, result)); + room_left -= (NISENTRYLEN (i, 1, result) + 1); + } + } + *first_unused++ = '\0'; + + /* Adjust the pointer so it is aligned for + storing pointers. */ + size_t adjust = ((__alignof__ (char *) + - (first_unused - (char *) 0) % __alignof__ (char *)) + % __alignof__ (char *)); + if (room_left < adjust + sizeof (char *)) + goto no_more_room; + first_unused += adjust; + room_left -= adjust; + network->n_aliases = (char **) first_unused; + + /* For the terminating NULL pointer. */ + room_left -= sizeof (char *); + + unsigned int i = 0; + 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 *); + network->n_aliases[i++] = line; + + while (*line != '\0' && *line != ' ') + ++line; + + if (*line == ' ') + *line++ = '\0'; + } + network->n_aliases[i] = NULL; + + return 1; +} + + +static enum nss_status +_nss_create_tablename (int *errnop) +{ + if (tablename_val == NULL) + { + const char *local_dir = nis_local_directory (); + size_t local_dir_len = strlen (local_dir); + static const char prefix[] = "networks.org_dir."; + + char *p = malloc (sizeof (prefix) + local_dir_len); + if (p == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } + + memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1); + + tablename_len = sizeof (prefix) - 1 + local_dir_len; + + atomic_write_barrier (); + + tablename_val = p; + } + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nisplus_setnetent (int stayopen) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + __libc_lock_lock (lock); + + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } + + if (tablename_val == NULL) + { + int err; + status = _nss_create_tablename (&err); + } + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nisplus_endnetent (void) +{ + __libc_lock_lock (lock); + + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_nisplus_getnetent_r (struct netent *network, char *buffer, + size_t buflen, int *errnop, int *herrnop) +{ + int parse_res; + + /* Get the next entry until we found a correct one. */ + do + { + nis_result *saved_res; + + if (result == NULL) + { + saved_res = NULL; + + if (tablename_val == NULL) + { + enum nss_status status = _nss_create_tablename (errnop); + + if (status != NSS_STATUS_SUCCESS) + return status; + } + + result = nis_first_entry (tablename_val); + if (result == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } + if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) + { + int retval = niserr2nss (result->status); + nis_freeresult (result); + result = NULL; + if (retval == NSS_STATUS_TRYAGAIN) + { + *herrnop = NETDB_INTERNAL; + *errnop = errno; + return retval; + } + else + return retval; + } + } + else + { + saved_res = result; + result = nis_next_entry (tablename_val, &result->cookie); + if (result == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } + if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) + { + int retval = niserr2nss (result->status); + nis_freeresult (result); + result = saved_res; + if (retval == NSS_STATUS_TRYAGAIN) + { + *herrnop = NETDB_INTERNAL; + *errnop = errno; + } + return retval; + } + } + + parse_res = _nss_nisplus_parse_netent (result, network, buffer, + buflen, errnop); + if (parse_res == -1) + { + *herrnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nisplus_getnetent_r (struct netent *result, char *buffer, + size_t buflen, int *errnop, int *herrnop) +{ + int status; + + __libc_lock_lock (lock); + + status = internal_nisplus_getnetent_r (result, buffer, buflen, errnop, + herrnop); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nisplus_getnetbyname_r (const char *name, struct netent *network, + char *buffer, size_t buflen, int *errnop, + int *herrnop) +{ + int parse_res, retval; + + if (tablename_val == NULL) + { + __libc_lock_lock (lock); + + enum nss_status status = _nss_create_tablename (errnop); + + __libc_lock_unlock (lock); + + if (status != NSS_STATUS_SUCCESS) + return status; + } + + if (name == NULL) + { + *errnop = EINVAL; + *herrnop = NETDB_INTERNAL; + return NSS_STATUS_UNAVAIL; + } + + nis_result *result; + char buf[strlen (name) + 10 + tablename_len]; + int olderr = errno; + + /* Search at first in the alias list, and use the correct name + for the next search */ + snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val); + result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH | USE_DGRAM, NULL, NULL); + + if (result != NULL) + { + char *bufptr = buf; + + /* If we do not find it, try it as original name. But if the + database is correct, we should find it in the first case, too */ + if ((result->status != NIS_SUCCESS + && result->status != NIS_S_SUCCESS) + || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ + || strcmp (result->objects.objects_val[0].EN_data.en_type, + "networks_tbl") != 0 + || (result->objects.objects_val[0].EN_data.en_cols.en_cols_len + < 3)) + snprintf (buf, sizeof (buf), "[cname=%s],%s", name, tablename_val); + else + { + /* We need to allocate a new buffer since there is no + guarantee the returned name has a length limit. */ + const char *entryval = NISENTRYVAL (0, 0, result); + size_t buflen = strlen (entryval) + 10 + tablename_len; + bufptr = alloca (buflen); + snprintf (bufptr, buflen, "[cname=%s],%s", + entryval, tablename_val); + } + + nis_freeresult (result); + result = nis_list (bufptr, FOLLOW_LINKS | FOLLOW_PATH | USE_DGRAM, + NULL, NULL); + } + + if (result == NULL) + { + __set_errno (ENOMEM); + return NSS_STATUS_TRYAGAIN; + } + + retval = niserr2nss (result->status); + if (__glibc_unlikely (retval != NSS_STATUS_SUCCESS)) + { + if (retval == NSS_STATUS_TRYAGAIN) + { + *errnop = errno; + *herrnop = NETDB_INTERNAL; + } + else + __set_errno (olderr); + nis_freeresult (result); + return retval; + } + + parse_res = _nss_nisplus_parse_netent (result, network, buffer, buflen, + errnop); + + nis_freeresult (result); + + if (parse_res > 0) + return NSS_STATUS_SUCCESS; + + *herrnop = NETDB_INTERNAL; + if (parse_res == -1) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + __set_errno (olderr); + return NSS_STATUS_NOTFOUND; +} + +/* XXX type is ignored, SUN's NIS+ table doesn't support it */ +enum nss_status +_nss_nisplus_getnetbyaddr_r (uint32_t addr, const int type, + struct netent *network, char *buffer, + size_t buflen, int *errnop, int *herrnop) +{ + if (tablename_val == NULL) + { + __libc_lock_lock (lock); + + enum nss_status status = _nss_create_tablename (errnop); + + __libc_lock_unlock (lock); + + if (status != NSS_STATUS_SUCCESS) + return status; + } + + { + char buf[27 + tablename_len]; + char buf2[18]; + int olderr = errno; + + struct in_addr in = { .s_addr = htonl (addr) }; + strcpy (buf2, inet_ntoa (in)); + size_t b2len = strlen (buf2); + + while (1) + { + snprintf (buf, sizeof (buf), "[addr=%s],%s", buf2, tablename_val); + nis_result *result = nis_list (buf, EXPAND_NAME | USE_DGRAM, + NULL, NULL); + + if (result == NULL) + { + __set_errno (ENOMEM); + return NSS_STATUS_TRYAGAIN; + } + enum nss_status retval = niserr2nss (result->status); + if (__glibc_unlikely (retval != NSS_STATUS_SUCCESS)) + { + if (b2len > 2 && buf2[b2len - 2] == '.' && buf2[b2len - 1] == '0') + { + /* Try again, but with trailing dot(s) + removed (one by one) */ + buf2[b2len - 2] = '\0'; + b2len -= 2; + nis_freeresult (result); + continue; + } + + if (retval == NSS_STATUS_TRYAGAIN) + { + *errnop = errno; + *herrnop = NETDB_INTERNAL; + } + else + __set_errno (olderr); + nis_freeresult (result); + return retval; + } + + int parse_res = _nss_nisplus_parse_netent (result, network, buffer, + buflen, errnop); + + nis_freeresult (result); + + if (parse_res > 0) + return NSS_STATUS_SUCCESS; + + *herrnop = NETDB_INTERNAL; + if (parse_res == -1) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + else + { + __set_errno (olderr); + return NSS_STATUS_NOTFOUND; + } + } + } +} diff --git a/REORG.TODO/nis/nss_nisplus/nisplus-parser.c b/REORG.TODO/nis/nss_nisplus/nisplus-parser.c new file mode 100644 index 0000000000..64170ddc1a --- /dev/null +++ b/REORG.TODO/nis/nss_nisplus/nisplus-parser.c @@ -0,0 +1,375 @@ +/* Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <pwd.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <rpcsvc/nis.h> + +#include "nisplus-parser.h" + +#define NISENTRYVAL(idx, col, res) \ + (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val) + +#define NISENTRYLEN(idx, col, res) \ + (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len) + +#define NISOBJVAL(col, obj) \ + ((obj)->EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val) + +#define NISOBJLEN(col, obj) \ + ((obj)->EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len) + + +int +_nss_nisplus_parse_pwent (nis_result *result, struct passwd *pw, + char *buffer, size_t buflen, int *errnop) +{ + if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) + || NIS_RES_NUMOBJ (result) != 1 + || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ + || strcmp (NIS_RES_OBJECT (result)->EN_data.en_type, "passwd_tbl") != 0 + || NIS_RES_OBJECT (result)->EN_data.en_cols.en_cols_len < 7) + return 0; + + nis_object *obj = NIS_RES_OBJECT (result); + char *first_unused = buffer; + size_t room_left = buflen; + size_t len; + + if (NISOBJLEN (0, obj) >= room_left) + { + /* The line is too long for our buffer. */ + no_more_room: + *errnop = ERANGE; + return -1; + } + + strncpy (first_unused, NISOBJVAL (0, obj), NISOBJLEN (0, obj)); + first_unused[NISOBJLEN (0, obj)] = '\0'; + len = strlen (first_unused); + if (len == 0) /* No name ? Should never happen, database is corrupt */ + return 0; + pw->pw_name = first_unused; + room_left -= len + 1; + first_unused += len + 1; + + if (NISOBJLEN (1, obj) >= room_left) + goto no_more_room; + + strncpy (first_unused, NISOBJVAL (1, obj), NISOBJLEN (1, obj)); + first_unused[NISOBJLEN (1, obj)] = '\0'; + pw->pw_passwd = first_unused; + len = strlen (first_unused); + room_left -= len + 1; + first_unused += len + 1; + + char *numstr = NISOBJVAL (2, obj); + len = NISOBJLEN (2, obj); + if (len == 0 && numstr[len - 1] != '\0') + { + if (len >= room_left) + goto no_more_room; + + strncpy (first_unused, numstr, len); + first_unused[len] = '\0'; + numstr = first_unused; + } + if (numstr[0] == '\0') + /* If we don't have a uid, it's an invalid shadow entry. */ + return 0; + pw->pw_uid = strtoul (numstr, NULL, 10); + + numstr = NISOBJVAL (3, obj); + len = NISOBJLEN (3, obj); + if (len == 0 && numstr[len - 1] != '\0') + { + if (len >= room_left) + goto no_more_room; + + strncpy (first_unused, numstr, len); + first_unused[len] = '\0'; + numstr = first_unused; + } + if (numstr[0] == '\0') + /* If we don't have a gid, it's an invalid shadow entry. */ + return 0; + pw->pw_gid = strtoul (numstr, NULL, 10); + + if (NISOBJLEN(4, obj) >= room_left) + goto no_more_room; + + strncpy (first_unused, NISOBJVAL (4, obj), NISOBJLEN (4, obj)); + first_unused[NISOBJLEN (4, obj)] = '\0'; + pw->pw_gecos = first_unused; + len = strlen (first_unused); + room_left -= len + 1; + first_unused += len + 1; + + if (NISOBJLEN (5, obj) >= room_left) + goto no_more_room; + + strncpy (first_unused, NISOBJVAL (5, obj), NISOBJLEN (5, obj)); + first_unused[NISOBJLEN (5, obj)] = '\0'; + pw->pw_dir = first_unused; + len = strlen (first_unused); + room_left -= len + 1; + first_unused += len + 1; + + if (NISOBJLEN (6, obj) >= room_left) + goto no_more_room; + + strncpy (first_unused, NISOBJVAL (6, obj), NISOBJLEN (6, obj)); + first_unused[NISOBJLEN (6, obj)] = '\0'; + pw->pw_shell = first_unused; + len = strlen (first_unused); + room_left -= len + 1; + first_unused += len + 1; + + return 1; +} + + +int +_nss_nisplus_parse_grent (nis_result *result, struct group *gr, + char *buffer, size_t buflen, int *errnop) +{ + if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) + || __type_of(NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ + || strcmp (NIS_RES_OBJECT (result)[0].EN_data.en_type, "group_tbl") != 0 + || NIS_RES_OBJECT (result)[0].EN_data.en_cols.en_cols_len < 4) + return 0; + + nis_object *obj = NIS_RES_OBJECT (result); + char *first_unused = buffer; + size_t room_left = buflen; + char *line; + int count; + size_t len; + + if (NISOBJLEN (0, obj) >= room_left) + { + /* The line is too long for our buffer. */ + no_more_room: + *errnop = ERANGE; + return -1; + } + + strncpy (first_unused, NISOBJVAL (0, obj), NISOBJLEN (0, obj)); + first_unused[NISOBJLEN (0, obj)] = '\0'; + len = strlen (first_unused); + if (len == 0) /* group table is corrupt */ + return 0; + gr->gr_name = first_unused; + room_left -= len + 1; + first_unused += len + 1; + + if (NISOBJLEN (1, obj) >= room_left) + goto no_more_room; + + strncpy (first_unused, NISOBJVAL (1, obj), NISOBJLEN (1, obj)); + first_unused[NISOBJLEN (1, obj)] = '\0'; + gr->gr_passwd = first_unused; + len = strlen (first_unused); + room_left -= len + 1; + first_unused += len + 1; + + char *numstr = NISOBJVAL (2, obj); + len = NISOBJLEN (2, obj); + if (len == 0 || numstr[len - 1] != '\0') + { + if (len >= room_left) + goto no_more_room; + + strncpy (first_unused, numstr, len); + first_unused[len] = '\0'; + numstr = first_unused; + } + if (numstr[0] == '\0') + /* We should always have a gid. */ + return 0; + gr->gr_gid = strtoul (numstr, NULL, 10); + + if (NISOBJLEN (3, obj) >= room_left) + goto no_more_room; + + strncpy (first_unused, NISOBJVAL (3, obj), NISOBJLEN (3, obj)); + first_unused[NISOBJLEN (3, obj)] = '\0'; + line = first_unused; + len = strlen (line); + room_left -= len + 1; + first_unused += len + 1; + /* Adjust the pointer so it is aligned for + storing pointers. */ + size_t adjust = ((__alignof__ (char *) + - (first_unused - (char *) 0) % __alignof__ (char *)) + % __alignof__ (char *)); + if (room_left < adjust) + goto no_more_room; + first_unused += adjust; + room_left -= adjust; + gr->gr_mem = (char **) first_unused; + + count = 0; + 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 *); + gr->gr_mem[count++] = line; + + while (*line != '\0' && *line != ',' && !isspace (*line)) + ++line; + + if (*line == ',' || isspace (*line)) + { + int is = isspace (*line); + + *line++ = '\0'; + if (is) + while (*line != '\0' && (*line == ',' || isspace (*line))) + ++line; + } + } + if (room_left < sizeof (char *)) + goto no_more_room; + room_left -= sizeof (char *); + gr->gr_mem[count] = NULL; + + return 1; +} + + +int +_nss_nisplus_parse_spent (nis_result *result, struct spwd *sp, + char *buffer, size_t buflen, int *errnop) +{ + char *first_unused = buffer; + size_t room_left = buflen; + size_t len; + + if (result == NULL) + return 0; + + if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) + || NIS_RES_NUMOBJ (result) != 1 + || __type_of(NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ + || strcmp (NIS_RES_OBJECT (result)->EN_data.en_type, "passwd_tbl") != 0 + || NIS_RES_OBJECT (result)->EN_data.en_cols.en_cols_len < 8) + return 0; + + if (NISENTRYLEN (0, 0, result) >= room_left) + { + /* The line is too long for our buffer. */ + no_more_room: + *errnop = ERANGE; + return -1; + } + + strncpy (first_unused, NISENTRYVAL (0, 0, result), + NISENTRYLEN (0, 0, result)); + first_unused[NISENTRYLEN (0, 0, result)] = '\0'; + len = strlen (first_unused); + if (len == 0) + return 0; + sp->sp_namp = first_unused; + room_left -= len + 1; + first_unused += len + 1; + + if (NISENTRYLEN (0, 1, result) >= room_left) + goto no_more_room; + + strncpy (first_unused, NISENTRYVAL (0, 1, result), + NISENTRYLEN (0, 1, result)); + first_unused[NISENTRYLEN (0, 1, result)] = '\0'; + sp->sp_pwdp = first_unused; + len = strlen (first_unused); + room_left -= len + 1; + first_unused += len + 1; + + sp->sp_lstchg = sp->sp_min = sp->sp_max = sp->sp_warn = sp->sp_inact = + sp->sp_expire = -1; + sp->sp_flag = ~0ul; + + if (NISENTRYLEN (0, 7, result) > 0) + { + char *line = NISENTRYVAL (0, 7, result); + char *cp = strchr (line, ':'); + if (cp == NULL) + return 1; + *cp++ = '\0'; + if (*line) + sp->sp_lstchg = atol (line); + + line = cp; + cp = strchr (line, ':'); + if (cp == NULL) + return 1; + *cp++ = '\0'; + if (*line) + sp->sp_min = atol (line); + + line = cp; + cp = strchr (line, ':'); + if (cp == NULL) + return 1; + *cp++ = '\0'; + if (*line) + sp->sp_max = atol (line); + + line = cp; + cp = strchr (line, ':'); + if (cp == NULL) + return 1; + *cp++ = '\0'; + if (*line) + sp->sp_warn = atol (line); + + line = cp; + cp = strchr (line, ':'); + if (cp == NULL) + return 1; + *cp++ = '\0'; + if (*line) + sp->sp_inact = atol (line); + + line = cp; + cp = strchr (line, ':'); + if (cp == NULL) + return 1; + *cp++ = '\0'; + if (*line) + sp->sp_expire = atol (line); + + line = cp; + if (line == NULL) + return 1; + if (*line) + sp->sp_flag = atol (line); + } + + return 1; +} diff --git a/REORG.TODO/nis/nss_nisplus/nisplus-proto.c b/REORG.TODO/nis/nss_nisplus/nisplus-proto.c new file mode 100644 index 0000000000..1f4a24fab2 --- /dev/null +++ b/REORG.TODO/nis/nss_nisplus/nisplus-proto.c @@ -0,0 +1,441 @@ +/* Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <atomic.h> +#include <ctype.h> +#include <errno.h> +#include <netdb.h> +#include <nss.h> +#include <string.h> +#include <rpcsvc/nis.h> +#include <libc-lock.h> + +#include "nss-nisplus.h" + +__libc_lock_define_initialized (static, lock) + +static nis_result *result; +static nis_name tablename_val; +static u_long tablename_len; + +#define NISENTRYVAL(idx, col, res) \ + (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val) + +#define NISENTRYLEN(idx, col, res) \ + (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len) + + +static int +_nss_nisplus_parse_protoent (nis_result *result, struct protoent *proto, + char *buffer, size_t buflen, int *errnop) +{ + char *first_unused = buffer; + size_t room_left = buflen; + unsigned int i; + + if (result == NULL) + return 0; + + if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) + || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ + || strcmp (NIS_RES_OBJECT (result)->EN_data.en_type, + "protocols_tbl") != 0 + || NIS_RES_OBJECT (result)->EN_data.en_cols.en_cols_len < 3) + return 0; + + /* Generate the protocols entry format and use the normal parser */ + if (NISENTRYLEN (0, 0, result) + 1 > room_left) + { + no_more_room: + *errnop = ERANGE; + return -1; + } + strncpy (first_unused, NISENTRYVAL (0, 0, result), + NISENTRYLEN (0, 0, result)); + first_unused[NISENTRYLEN (0, 0, result)] = '\0'; + proto->p_name = first_unused; + size_t len = strlen (first_unused) + 1; + room_left -= len; + first_unused += len; + + + proto->p_proto = atoi (NISENTRYVAL (0, 2, result)); + + /* XXX Rewrite at some point to allocate the array first and then + copy the strings. It wasteful to first concatenate the strings + to just split them again later. */ + char *line = first_unused; + for (i = 0; i < NIS_RES_NUMOBJ (result); ++i) + { + if (strcmp (NISENTRYVAL (i, 1, result), proto->p_name) != 0) + { + if (NISENTRYLEN (i, 1, result) + 2 > room_left) + goto no_more_room; + *first_unused++ = ' '; + first_unused = __stpncpy (first_unused, NISENTRYVAL (i, 1, result), + NISENTRYLEN (i, 1, result)); + room_left -= NISENTRYLEN (i, 1, result) + 1; + } + } + *first_unused++ = '\0'; + + /* Adjust the pointer so it is aligned for + storing pointers. */ + size_t adjust = ((__alignof__ (char *) + - (first_unused - (char *) 0) % __alignof__ (char *)) + % __alignof__ (char *)); + if (room_left < adjust + sizeof (char *)) + goto no_more_room; + first_unused += adjust; + room_left -= adjust; + proto->p_aliases = (char **) first_unused; + + /* For the terminating NULL pointer. */ + room_left -= sizeof (char *); + + i = 0; + 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 *); + proto->p_aliases[i++] = line; + + while (*line != '\0' && *line != ' ') + ++line; + + if (*line == ' ') + *line++ = '\0'; + } + proto->p_aliases[i] = NULL; + + return 1; +} + +static enum nss_status +_nss_create_tablename (int *errnop) +{ + if (tablename_val == NULL) + { + const char *local_dir = nis_local_directory (); + size_t local_dir_len = strlen (local_dir); + static const char prefix[] = "protocols.org_dir."; + + char *p = malloc (sizeof (prefix) + local_dir_len); + if (p == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } + + memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1); + + tablename_len = sizeof (prefix) - 1 + local_dir_len; + + atomic_write_barrier (); + + tablename_val = p; + } + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nisplus_setprotoent (int stayopen) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + __libc_lock_lock (lock); + + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } + + if (tablename_val == NULL) + { + int err; + status = _nss_create_tablename (&err); + } + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nisplus_endprotoent (void) +{ + __libc_lock_lock (lock); + + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_nisplus_getprotoent_r (struct protoent *proto, char *buffer, + size_t buflen, int *errnop) +{ + int parse_res; + + /* Get the next entry until we found a correct one. */ + do + { + nis_result *saved_res; + + if (result == NULL) + { + saved_res = NULL; + if (tablename_val == NULL) + { + enum nss_status status = _nss_create_tablename (errnop); + + if (status != NSS_STATUS_SUCCESS) + return status; + } + + result = nis_first_entry (tablename_val); + if (result == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } + if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) + return niserr2nss (result->status); + } + else + { + saved_res = result; + result = nis_next_entry (tablename_val, &result->cookie); + if (result == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } + if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) + { + nis_freeresult (saved_res); + return niserr2nss (result->status); + } + } + + parse_res = _nss_nisplus_parse_protoent (result, proto, buffer, + buflen, errnop); + if (parse_res == -1) + { + nis_freeresult (result); + result = saved_res; + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + else + { + if (saved_res) + nis_freeresult (saved_res); + } + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nisplus_getprotoent_r (struct protoent *result, char *buffer, + size_t buflen, int *errnop) +{ + int status; + + __libc_lock_lock (lock); + + status = internal_nisplus_getprotoent_r (result, buffer, buflen, errnop); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nisplus_getprotobyname_r (const char *name, struct protoent *proto, + char *buffer, size_t buflen, int *errnop) +{ + int parse_res; + + if (tablename_val == NULL) + { + __libc_lock_lock (lock); + + enum nss_status status = _nss_create_tablename (errnop); + + __libc_lock_unlock (lock); + + if (status != NSS_STATUS_SUCCESS) + return status; + } + + if (name == NULL) + return NSS_STATUS_NOTFOUND; + + char buf[strlen (name) + 10 + tablename_len]; + int olderr = errno; + + /* Search at first in the alias list, and use the correct name + for the next search */ + snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val); + nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); + + if (result != NULL) + { + char *bufptr = buf; + + /* If we did not find it, try it as original name. But if the + database is correct, we should find it in the first case, too */ + if ((result->status != NIS_SUCCESS + && result->status != NIS_S_SUCCESS) + || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ + || strcmp (result->objects.objects_val->EN_data.en_type, + "protocols_tbl") != 0 + || result->objects.objects_val->EN_data.en_cols.en_cols_len < 3) + snprintf (buf, sizeof (buf), "[cname=%s],%s", name, tablename_val); + else + { + /* We need to allocate a new buffer since there is no + guarantee the returned name has a length limit. */ + const char *entryval = NISENTRYVAL (0, 0, result); + size_t buflen = strlen (entryval) + 10 + tablename_len; + bufptr = alloca (buflen); + snprintf (bufptr, buflen, "[cname=%s],%s", + entryval, tablename_val); + } + + nis_freeresult (result); + result = nis_list (bufptr, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); + } + + if (result == NULL) + { + __set_errno (ENOMEM); + return NSS_STATUS_TRYAGAIN; + } + + if (__glibc_unlikely (niserr2nss (result->status) != NSS_STATUS_SUCCESS)) + { + enum nss_status status = niserr2nss (result->status); + + __set_errno (olderr); + + nis_freeresult (result); + return status; + } + + parse_res = _nss_nisplus_parse_protoent (result, proto, buffer, buflen, + errnop); + + nis_freeresult (result); + + if (parse_res < 1) + { + if (parse_res == -1) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + else + { + __set_errno (olderr); + return NSS_STATUS_NOTFOUND; + } + } + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nisplus_getprotobynumber_r (const int number, struct protoent *proto, + char *buffer, size_t buflen, int *errnop) +{ + if (tablename_val == NULL) + { + __libc_lock_lock (lock); + + enum nss_status status = _nss_create_tablename (errnop); + + __libc_lock_unlock (lock); + + if (status != NSS_STATUS_SUCCESS) + return status; + } + + char buf[12 + 3 * sizeof (number) + tablename_len]; + int olderr = errno; + + snprintf (buf, sizeof (buf), "[number=%d],%s", number, tablename_val); + + nis_result *result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL); + + if (result == NULL) + { + __set_errno (ENOMEM); + return NSS_STATUS_TRYAGAIN; + } + + if (__glibc_unlikely (niserr2nss (result->status) != NSS_STATUS_SUCCESS)) + { + enum nss_status status = niserr2nss (result->status); + + __set_errno (olderr); + + nis_freeresult (result); + return status; + } + + int parse_res = _nss_nisplus_parse_protoent (result, proto, buffer, buflen, + errnop); + + nis_freeresult (result); + + if (parse_res < 1) + { + if (parse_res == -1) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + else + { + __set_errno (olderr); + return NSS_STATUS_NOTFOUND; + } + } + + return NSS_STATUS_SUCCESS; +} diff --git a/REORG.TODO/nis/nss_nisplus/nisplus-publickey.c b/REORG.TODO/nis/nss_nisplus/nisplus-publickey.c new file mode 100644 index 0000000000..d327936941 --- /dev/null +++ b/REORG.TODO/nis/nss_nisplus/nisplus-publickey.c @@ -0,0 +1,411 @@ +/* Copyright (c) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <nss.h> +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <libintl.h> +#include <syslog.h> +#include <rpc/rpc.h> +#include <rpcsvc/nis.h> +#include <rpc/key_prot.h> +extern int xdecrypt (char *, char *); + +#include <nss-nisplus.h> + +/* If we haven't found the entry, we give a SUCCESS and an empty key back. */ +enum nss_status +_nss_nisplus_getpublickey (const char *netname, char *pkey, int *errnop) +{ + nis_result *res; + enum nss_status retval; + char buf[NIS_MAXNAMELEN + 2]; + size_t slen; + char *domain, *cptr; + int len; + + pkey[0] = 0; + + if (netname == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + domain = strchr (netname, '@'); + if (!domain) + return NSS_STATUS_UNAVAIL; + domain++; + + slen = snprintf (buf, NIS_MAXNAMELEN, + "[auth_name=%s,auth_type=DES],cred.org_dir.%s", + netname, domain); + + if (slen >= NIS_MAXNAMELEN) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + if (buf[slen - 1] != '.') + { + buf[slen++] = '.'; + buf[slen] = '\0'; + } + + res = nis_list (buf, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH, + NULL, NULL); + + if (res == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } + retval = niserr2nss (res->status); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + if (res->status == NIS_NOTFOUND) + retval = NSS_STATUS_SUCCESS; + nis_freeresult (res); + return retval; + } + + if (NIS_RES_NUMOBJ (res) > 1) + { + /* + * More than one principal with same uid? + * something wrong with cred table. Should be unique + * Warn user and continue. + */ + syslog (LOG_ERR, _("DES entry for netname %s not unique\n"), netname); + nis_freeresult (res); + return NSS_STATUS_SUCCESS; + } + + len = ENTRY_LEN (NIS_RES_OBJECT (res), 3); + memcpy (pkey, ENTRY_VAL (NIS_RES_OBJECT (res),3), len); + pkey[len] = 0; + cptr = strchr (pkey, ':'); + if (cptr) + cptr[0] = '\0'; + nis_freeresult (res); + + return NSS_STATUS_SUCCESS; +} + + +enum nss_status +_nss_nisplus_getsecretkey (const char *netname, char *skey, char *passwd, + int *errnop) +{ + nis_result *res; + enum nss_status retval; + char buf[NIS_MAXNAMELEN + 2]; + size_t slen; + char *domain, *cptr; + int len; + + skey[0] = 0; + + if (netname == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + domain = strchr (netname, '@'); + if (!domain) + return NSS_STATUS_UNAVAIL; + domain++; + + slen = snprintf (buf, NIS_MAXNAMELEN, + "[auth_name=%s,auth_type=DES],cred.org_dir.%s", + netname, domain); + + if (slen >= NIS_MAXNAMELEN) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + if (buf[slen - 1] != '.') + { + buf[slen++] = '.'; + buf[slen] = '\0'; + } + + res = nis_list (buf, USE_DGRAM | NO_AUTHINFO | FOLLOW_LINKS | FOLLOW_PATH, + NULL, NULL); + + if (res == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } + retval = niserr2nss (res->status); + + if (retval != NSS_STATUS_SUCCESS) + { + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + nis_freeresult (res); + return retval; + } + + if (NIS_RES_NUMOBJ (res) > 1) + { + /* + * More than one principal with same uid? + * something wrong with cred table. Should be unique + * Warn user and continue. + */ + syslog (LOG_ERR, _("DES entry for netname %s not unique\n"), netname); + nis_freeresult (res); + return NSS_STATUS_SUCCESS; + } + + len = ENTRY_LEN (NIS_RES_OBJECT (res), 4); + memcpy (buf, ENTRY_VAL (NIS_RES_OBJECT (res), 4), len); + buf[len] = '\0'; + cptr = strchr (buf, ':'); + if (cptr) + cptr[0] = '\0'; + nis_freeresult (res); + + if (!xdecrypt (buf, passwd)) + return NSS_STATUS_SUCCESS; + + if (memcmp (buf, &(buf[HEXKEYBYTES]), KEYCHECKSUMSIZE) != 0) + return NSS_STATUS_SUCCESS; + + buf[HEXKEYBYTES] = 0; + strcpy (skey, buf); + + return NSS_STATUS_SUCCESS; +} + + +/* Parse information from the passed string. + The format of the string passed is gid,grp,grp, ... */ +static enum nss_status +parse_grp_str (const char *s, gid_t *gidp, int *gidlenp, gid_t *gidlist, + int *errnop) +{ + char *ep; + int gidlen; + + if (!s || (!isdigit (*s))) + { + syslog (LOG_ERR, _("netname2user: missing group id list in `%s'"), s); + return NSS_STATUS_NOTFOUND; + } + + *gidp = strtoul (s, &ep, 10); + + gidlen = 0; + + /* After strtoul() ep should point to the marker ',', which means + here starts a new value. + + The Sun man pages show that GIDLIST should contain at least NGRPS + elements. Limiting the number written by this value is the best + we can do. */ + while (ep != NULL && *ep == ',' && gidlen < NGRPS) + { + ep++; + s = ep; + gidlist[gidlen++] = strtoul (s, &ep, 10); + } + *gidlenp = gidlen; + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nisplus_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp, + gid_t *gidp, int *gidlenp, gid_t *gidlist, int *errnop) +{ + char *domain; + nis_result *res; + char sname[NIS_MAXNAMELEN + 2]; /* search criteria + table name */ + size_t slen; + char principal[NIS_MAXNAMELEN + 1]; + int len; + + /* 1. Get home domain of user. */ + domain = strchr (netname, '@'); + if (! domain) + return NSS_STATUS_UNAVAIL; + + ++domain; /* skip '@' */ + + /* 2. Get user's nisplus principal name. */ + slen = snprintf (sname, NIS_MAXNAMELEN, + "[auth_name=%s,auth_type=DES],cred.org_dir.%s", + netname, domain); + + if (slen >= NIS_MAXNAMELEN) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + if (sname[slen - 1] != '.') + { + sname[slen++] = '.'; + sname[slen] = '\0'; + } + + /* must use authenticated call here */ + /* XXX but we cant, for now. XXX */ + res = nis_list (sname, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH, + NULL, NULL); + if (res == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } + switch (res->status) + { + case NIS_SUCCESS: + case NIS_S_SUCCESS: + break; /* go and do something useful */ + case NIS_NOTFOUND: + case NIS_PARTIAL: + case NIS_NOSUCHNAME: + case NIS_NOSUCHTABLE: + nis_freeresult (res); + return NSS_STATUS_NOTFOUND; + case NIS_S_NOTFOUND: + case NIS_TRYAGAIN: + syslog (LOG_ERR, _("netname2user: (nis+ lookup): %s\n"), + nis_sperrno (res->status)); + nis_freeresult (res); + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + default: + syslog (LOG_ERR, _("netname2user: (nis+ lookup): %s\n"), + nis_sperrno (res->status)); + nis_freeresult (res); + return NSS_STATUS_UNAVAIL; + } + + if (NIS_RES_NUMOBJ (res) > 1) + /* + * A netname belonging to more than one principal? + * Something wrong with cred table. should be unique. + * Warn user and continue. + */ + syslog (LOG_ALERT, + _("netname2user: DES entry for %s in directory %s not unique"), + netname, domain); + + len = ENTRY_LEN (NIS_RES_OBJECT (res), 0); + strncpy (principal, ENTRY_VAL (NIS_RES_OBJECT (res), 0), len); + principal[len] = '\0'; + nis_freeresult (res); + + if (principal[0] == '\0') + return NSS_STATUS_UNAVAIL; + + /* + * 3. Use principal name to look up uid/gid information in + * LOCAL entry in **local** cred table. + */ + domain = nis_local_directory (); + if (strlen (principal) + strlen (domain) + 45 > (size_t) NIS_MAXNAMELEN) + { + syslog (LOG_ERR, _("netname2user: principal name `%s' too long"), + principal); + return NSS_STATUS_UNAVAIL; + } + + slen = snprintf (sname, sizeof (sname), + "[cname=%s,auth_type=LOCAL],cred.org_dir.%s", + principal, domain); + + if (sname[slen - 1] != '.') + { + sname[slen++] = '.'; + sname[slen] = '\0'; + } + + /* must use authenticated call here */ + /* XXX but we cant, for now. XXX */ + res = nis_list (sname, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH, + NULL, NULL); + if (res == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } + switch(res->status) + { + case NIS_NOTFOUND: + case NIS_PARTIAL: + case NIS_NOSUCHNAME: + case NIS_NOSUCHTABLE: + nis_freeresult (res); + return NSS_STATUS_NOTFOUND; + case NIS_S_NOTFOUND: + case NIS_TRYAGAIN: + syslog (LOG_ERR, _("netname2user: (nis+ lookup): %s\n"), + nis_sperrno (res->status)); + nis_freeresult (res); + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + case NIS_SUCCESS: + case NIS_S_SUCCESS: + break; /* go and do something useful */ + default: + syslog (LOG_ERR, _("netname2user: (nis+ lookup): %s\n"), + nis_sperrno (res->status)); + nis_freeresult (res); + return NSS_STATUS_UNAVAIL; + } + + if (NIS_RES_NUMOBJ (res) > 1) + /* + * A principal can have more than one LOCAL entry? + * Something wrong with cred table. + * Warn user and continue. + */ + syslog (LOG_ALERT, + _("netname2user: LOCAL entry for %s in directory %s not unique"), + netname, domain); + /* Fetch the uid */ + *uidp = strtoul (ENTRY_VAL (NIS_RES_OBJECT (res), 2), NULL, 10); + + if (*uidp == 0) + { + syslog (LOG_ERR, _("netname2user: should not have uid 0")); + nis_freeresult (res); + return NSS_STATUS_NOTFOUND; + } + + parse_grp_str (ENTRY_VAL (NIS_RES_OBJECT (res), 3), + gidp, gidlenp, gidlist, errnop); + + nis_freeresult (res); + return NSS_STATUS_SUCCESS; +} diff --git a/REORG.TODO/nis/nss_nisplus/nisplus-pwd.c b/REORG.TODO/nis/nss_nisplus/nisplus-pwd.c new file mode 100644 index 0000000000..3b5e25ea43 --- /dev/null +++ b/REORG.TODO/nis/nss_nisplus/nisplus-pwd.c @@ -0,0 +1,408 @@ +/* Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <atomic.h> +#include <nss.h> +#include <errno.h> +#include <pwd.h> +#include <string.h> +#include <libc-lock.h> +#include <rpcsvc/nis.h> + +#include "nss-nisplus.h" +#include "nisplus-parser.h" +#include <libnsl.h> +#include <nis_intern.h> +#include <nis_xdr.h> + + +__libc_lock_define_initialized (static, lock) + +/* Connection information. */ +static ib_request *ibreq; +static directory_obj *dir; +static dir_binding bptr; +static char *tablepath; +static char *tableptr; +/* Cursor. */ +static netobj cursor; + + +nis_name pwd_tablename_val attribute_hidden; +size_t pwd_tablename_len attribute_hidden; + +enum nss_status +_nss_pwd_create_tablename (int *errnop) +{ + if (pwd_tablename_val == NULL) + { + const char *local_dir = nis_local_directory (); + size_t local_dir_len = strlen (local_dir); + static const char prefix[] = "passwd.org_dir."; + + char *p = malloc (sizeof (prefix) + local_dir_len); + if (p == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } + + memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1); + + pwd_tablename_len = sizeof (prefix) - 1 + local_dir_len; + + atomic_write_barrier (); + + if (atomic_compare_and_exchange_bool_acq (&pwd_tablename_val, p, NULL)) + { + /* Another thread already installed the value. */ + free (p); + pwd_tablename_len = strlen (pwd_tablename_val); + } + } + + return NSS_STATUS_SUCCESS; +} + + +static void +internal_nisplus_endpwent (void) +{ + __nisbind_destroy (&bptr); + memset (&bptr, '\0', sizeof (bptr)); + + nis_free_directory (dir); + dir = NULL; + + nis_free_request (ibreq); + ibreq = NULL; + + xdr_free ((xdrproc_t) xdr_netobj, (char *) &cursor); + memset (&cursor, '\0', sizeof (cursor)); + + free (tablepath); + tableptr = tablepath = NULL; +} + + +static enum nss_status +internal_nisplus_setpwent (int *errnop) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + if (pwd_tablename_val == NULL) + status = _nss_pwd_create_tablename (errnop); + + if (status == NSS_STATUS_SUCCESS) + { + ibreq = __create_ib_request (pwd_tablename_val, 0); + if (ibreq == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } + + nis_error retcode = __prepare_niscall (pwd_tablename_val, &dir, + &bptr, 0); + if (retcode != NIS_SUCCESS) + { + nis_free_request (ibreq); + ibreq = NULL; + status = niserr2nss (retcode); + } + } + + return status; +} + + +enum nss_status +_nss_nisplus_setpwent (int stayopen) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + internal_nisplus_endpwent (); + + // XXX We need to be able to set errno. Pass in new parameter. + int err; + status = internal_nisplus_setpwent (&err); + + __libc_lock_unlock (lock); + + return status; +} + + +enum nss_status +_nss_nisplus_endpwent (void) +{ + __libc_lock_lock (lock); + + internal_nisplus_endpwent (); + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + + +static enum nss_status +internal_nisplus_getpwent_r (struct passwd *pw, char *buffer, size_t buflen, + int *errnop) +{ + int parse_res = -1; + enum nss_status retval = NSS_STATUS_SUCCESS; + + /* Get the next entry until we found a correct one. */ + do + { + nis_error status; + nis_result result; + memset (&result, '\0', sizeof (result)); + + if (cursor.n_bytes == NULL) + { + if (ibreq == NULL) + { + retval = internal_nisplus_setpwent (errnop); + if (retval != NSS_STATUS_SUCCESS) + return retval; + } + + status = __do_niscall3 (&bptr, NIS_IBFIRST, + (xdrproc_t) _xdr_ib_request, + (caddr_t) ibreq, + (xdrproc_t) _xdr_nis_result, + (caddr_t) &result, + 0, NULL); + } + else + { + ibreq->ibr_cookie.n_bytes = cursor.n_bytes; + ibreq->ibr_cookie.n_len = cursor.n_len; + + status = __do_niscall3 (&bptr, NIS_IBNEXT, + (xdrproc_t) _xdr_ib_request, + (caddr_t) ibreq, + (xdrproc_t) _xdr_nis_result, + (caddr_t) &result, + 0, NULL); + + ibreq->ibr_cookie.n_bytes = NULL; + ibreq->ibr_cookie.n_len = 0; + } + + if (status != NIS_SUCCESS) + return niserr2nss (status); + + if (NIS_RES_STATUS (&result) == NIS_NOTFOUND) + { + /* No more entries on this server. This means we have to go + to the next server on the path. */ + status = __follow_path (&tablepath, &tableptr, ibreq, &bptr); + if (status != NIS_SUCCESS) + return niserr2nss (status); + + directory_obj *newdir = NULL; + dir_binding newbptr; + status = __prepare_niscall (ibreq->ibr_name, &newdir, &newbptr, 0); + if (status != NIS_SUCCESS) + return niserr2nss (status); + + nis_free_directory (dir); + dir = newdir; + __nisbind_destroy (&bptr); + bptr = newbptr; + + xdr_free ((xdrproc_t) xdr_netobj, (char *) &result.cookie); + result.cookie.n_bytes = NULL; + result.cookie.n_len = 0; + parse_res = 0; + goto next; + } + else if (NIS_RES_STATUS (&result) != NIS_SUCCESS) + return niserr2nss (NIS_RES_STATUS (&result)); + + parse_res = _nss_nisplus_parse_pwent (&result, pw, buffer, + buflen, errnop); + + if (__glibc_unlikely (parse_res == -1)) + { + *errnop = ERANGE; + retval = NSS_STATUS_TRYAGAIN; + goto freeres; + } + + next: + /* Free the old cursor. */ + xdr_free ((xdrproc_t) xdr_netobj, (char *) &cursor); + /* Remember the new one. */ + cursor.n_bytes = result.cookie.n_bytes; + cursor.n_len = result.cookie.n_len; + /* Free the result structure. NB: we do not remove the cookie. */ + result.cookie.n_bytes = NULL; + result.cookie.n_len = 0; + freeres: + xdr_free ((xdrproc_t) _xdr_nis_result, (char *) &result); + memset (&result, '\0', sizeof (result)); + } + while (!parse_res); + + return retval; +} + +enum nss_status +_nss_nisplus_getpwent_r (struct passwd *result, char *buffer, size_t buflen, + int *errnop) +{ + int status; + + __libc_lock_lock (lock); + + status = internal_nisplus_getpwent_r (result, buffer, buflen, errnop); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nisplus_getpwnam_r (const char *name, struct passwd *pw, + char *buffer, size_t buflen, int *errnop) +{ + int parse_res; + + if (pwd_tablename_val == NULL) + { + enum nss_status status = _nss_pwd_create_tablename (errnop); + + if (status != NSS_STATUS_SUCCESS) + return status; + } + + if (name == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + nis_result *result; + char buf[strlen (name) + 9 + pwd_tablename_len]; + int olderr = errno; + + snprintf (buf, sizeof (buf), "[name=%s],%s", name, pwd_tablename_val); + + result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, NULL, NULL); + + if (result == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } + + if (__glibc_unlikely (niserr2nss (result->status) != NSS_STATUS_SUCCESS)) + { + enum nss_status status = niserr2nss (result->status); + + __set_errno (olderr); + + nis_freeresult (result); + return status; + } + + parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, buflen, errnop); + + nis_freeresult (result); + + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + else + { + __set_errno (olderr); + return NSS_STATUS_NOTFOUND; + } + } + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nisplus_getpwuid_r (const uid_t uid, struct passwd *pw, + char *buffer, size_t buflen, int *errnop) +{ + if (pwd_tablename_val == NULL) + { + enum nss_status status = _nss_pwd_create_tablename (errnop); + + if (status != NSS_STATUS_SUCCESS) + return status; + } + + int parse_res; + nis_result *result; + char buf[8 + 3 * sizeof (unsigned long int) + pwd_tablename_len]; + int olderr = errno; + + snprintf (buf, sizeof (buf), "[uid=%lu],%s", + (unsigned long int) uid, pwd_tablename_val); + + result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, NULL, NULL); + + if (result == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } + + if (__glibc_unlikely (niserr2nss (result->status) != NSS_STATUS_SUCCESS)) + { + enum nss_status status = niserr2nss (result->status); + + __set_errno (olderr); + + nis_freeresult (result); + return status; + } + + parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, buflen, errnop); + + nis_freeresult (result); + + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + else + { + __set_errno (olderr); + return NSS_STATUS_NOTFOUND; + } + } + + return NSS_STATUS_SUCCESS; +} diff --git a/REORG.TODO/nis/nss_nisplus/nisplus-rpc.c b/REORG.TODO/nis/nss_nisplus/nisplus-rpc.c new file mode 100644 index 0000000000..977d85a574 --- /dev/null +++ b/REORG.TODO/nis/nss_nisplus/nisplus-rpc.c @@ -0,0 +1,444 @@ +/* Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <atomic.h> +#include <ctype.h> +#include <errno.h> +#include <nss.h> +#include <string.h> +#include <rpc/netdb.h> +#include <rpcsvc/nis.h> +#include <libc-lock.h> + +#include "nss-nisplus.h" + +__libc_lock_define_initialized (static, lock) + +static nis_result *result; +static nis_name tablename_val; +static u_long tablename_len; + +#define NISENTRYVAL(idx, col, res) \ + (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val) + +#define NISENTRYLEN(idx, col, res) \ + (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len) + + +static int +_nss_nisplus_parse_rpcent (nis_result *result, struct rpcent *rpc, + char *buffer, size_t buflen, int *errnop) +{ + char *first_unused = buffer; + size_t room_left = buflen; + unsigned int i; + char *line; + + + if (result == NULL) + return 0; + + if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) + || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ + || strcmp (NIS_RES_OBJECT (result)[0].EN_data.en_type, "rpc_tbl") != 0 + || NIS_RES_OBJECT (result)[0].EN_data.en_cols.en_cols_len < 3) + return 0; + + if (NISENTRYLEN (0, 0, result) >= room_left) + { + no_more_room: + *errnop = ERANGE; + return -1; + } + strncpy (first_unused, NISENTRYVAL (0, 0, result), + NISENTRYLEN (0, 0, result)); + first_unused[NISENTRYLEN (0, 0, result)] = '\0'; + rpc->r_name = first_unused; + size_t len = strlen (first_unused) + 1; + room_left -= len; + first_unused += len; + + rpc->r_number = atoi (NISENTRYVAL (0, 2, result)); + + /* XXX Rewrite at some point to allocate the array first and then + copy the strings. It wasteful to first concatenate the strings + to just split them again later. */ + line = first_unused; + for (i = 0; i < NIS_RES_NUMOBJ (result); ++i) + { + if (strcmp (NISENTRYVAL (i, 1, result), rpc->r_name) != 0) + { + if (NISENTRYLEN (i, 1, result) + 2 > room_left) + goto no_more_room; + *first_unused++ = ' '; + first_unused = __stpncpy (first_unused, NISENTRYVAL (i, 1, result), + NISENTRYLEN (i, 1, result)); + room_left -= NISENTRYLEN (i, 1, result) + 1; + } + } + *first_unused++ = '\0'; + + /* Adjust the pointer so it is aligned for + storing pointers. */ + size_t adjust = ((__alignof__ (char *) + - (first_unused - (char *) 0) % __alignof__ (char *)) + % __alignof__ (char *)); + if (room_left < adjust + sizeof (char *)) + goto no_more_room; + first_unused += adjust; + room_left -= adjust; + rpc->r_aliases = (char **) first_unused; + + /* For the terminating NULL pointer. */ + room_left -= sizeof (char *); + + i = 0; + 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 *); + rpc->r_aliases[i++] = line; + + while (*line != '\0' && *line != ' ') + ++line; + + if (*line == ' ') + *line++ = '\0'; + } + rpc->r_aliases[i] = NULL; + + return 1; +} + + +static enum nss_status +_nss_create_tablename (int *errnop) +{ + if (tablename_val == NULL) + { + const char *local_dir = nis_local_directory (); + size_t local_dir_len = strlen (local_dir); + static const char prefix[] = "rpc.org_dir."; + + char *p = malloc (sizeof (prefix) + local_dir_len); + if (p == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } + + memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1); + + tablename_len = sizeof (prefix) - 1 + local_dir_len; + + atomic_write_barrier (); + + tablename_val = p; + } + + return NSS_STATUS_SUCCESS; +} + + +enum nss_status +_nss_nisplus_setrpcent (int stayopen) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + __libc_lock_lock (lock); + + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } + + if (tablename_val == NULL) + { + int err; + status = _nss_create_tablename (&err); + } + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nisplus_endrpcent (void) +{ + __libc_lock_lock (lock); + + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_nisplus_getrpcent_r (struct rpcent *rpc, char *buffer, + size_t buflen, int *errnop) +{ + int parse_res; + + /* Get the next entry until we found a correct one. */ + do + { + nis_result *saved_res; + + if (result == NULL) + { + saved_res = NULL; + if (tablename_val == NULL) + { + enum nss_status status = _nss_create_tablename (errnop); + + if (status != NSS_STATUS_SUCCESS) + return status; + } + + result = nis_first_entry (tablename_val); + if (result == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } + if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) + return niserr2nss (result->status); + } + else + { + saved_res = result; + result = nis_next_entry (tablename_val, &result->cookie); + if (result == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } + if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) + { + nis_freeresult (saved_res); + return niserr2nss (result->status); + } + } + + parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer, + buflen, errnop); + if (parse_res == -1) + { + nis_freeresult (result); + result = saved_res; + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + else + { + if (saved_res) + nis_freeresult (saved_res); + } + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nisplus_getrpcent_r (struct rpcent *result, char *buffer, + size_t buflen, int *errnop) +{ + int status; + + __libc_lock_lock (lock); + + status = internal_nisplus_getrpcent_r (result, buffer, buflen, errnop); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nisplus_getrpcbyname_r (const char *name, struct rpcent *rpc, + char *buffer, size_t buflen, int *errnop) +{ + int parse_res; + + if (tablename_val == NULL) + { + __libc_lock_lock (lock); + + enum nss_status status = _nss_create_tablename (errnop); + + __libc_lock_unlock (lock); + + if (status != NSS_STATUS_SUCCESS) + return status; + } + + if (name == NULL) + return NSS_STATUS_NOTFOUND; + + char buf[strlen (name) + 10 + tablename_len]; + int olderr = errno; + + /* Search at first in the alias list, and use the correct name + for the next search */ + snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val); + nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, + NULL, NULL); + + if (result != NULL) + { + char *bufptr = buf; + + /* If we did not find it, try it as original name. But if the + database is correct, we should find it in the first case, too */ + if ((result->status != NIS_SUCCESS + && result->status != NIS_S_SUCCESS) + || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ + || strcmp (result->objects.objects_val->EN_data.en_type, + "rpc_tbl") != 0 + || result->objects.objects_val->EN_data.en_cols.en_cols_len < 3) + snprintf (buf, sizeof (buf), "[cname=%s],%s", name, tablename_val); + else + { + /* We need to allocate a new buffer since there is no + guarantee the returned name has a length limit. */ + const char *entryval = NISENTRYVAL (0, 0, result); + size_t buflen = strlen (entryval) + 10 + tablename_len; + bufptr = alloca (buflen); + snprintf (bufptr, buflen, "[cname=%s],%s", + entryval, tablename_val); + } + + nis_freeresult (result); + result = nis_list (bufptr, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, + NULL, NULL); + } + + if (result == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } + + if (__glibc_unlikely (niserr2nss (result->status) != NSS_STATUS_SUCCESS)) + { + enum nss_status status = niserr2nss (result->status); + + __set_errno (olderr); + + nis_freeresult (result); + return status; + } + + parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer, buflen, + errnop); + + nis_freeresult (result); + + if (parse_res < 1) + { + if (parse_res == -1) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + __set_errno (olderr); + return NSS_STATUS_NOTFOUND; + } + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nisplus_getrpcbynumber_r (const int number, struct rpcent *rpc, + char *buffer, size_t buflen, int *errnop) +{ + if (tablename_val == NULL) + { + __libc_lock_lock (lock); + + enum nss_status status = _nss_create_tablename (errnop); + + __libc_lock_unlock (lock); + + if (status != NSS_STATUS_SUCCESS) + return status; + } + + char buf[12 + 3 * sizeof (number) + tablename_len]; + int olderr = errno; + + snprintf (buf, sizeof (buf), "[number=%d],%s", number, tablename_val); + + nis_result *result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH | USE_DGRAM, + NULL, NULL); + + if (result == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } + + if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0)) + { + enum nss_status status = niserr2nss (result->status); + + __set_errno (olderr); + + nis_freeresult (result); + return status; + } + + int parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer, buflen, + errnop); + + nis_freeresult (result); + + if (parse_res < 1) + { + if (parse_res == -1) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + else + { + __set_errno (olderr); + return NSS_STATUS_NOTFOUND; + } + } + + return NSS_STATUS_SUCCESS; +} diff --git a/REORG.TODO/nis/nss_nisplus/nisplus-service.c b/REORG.TODO/nis/nss_nisplus/nisplus-service.c new file mode 100644 index 0000000000..302087153f --- /dev/null +++ b/REORG.TODO/nis/nss_nisplus/nisplus-service.c @@ -0,0 +1,461 @@ +/* Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <atomic.h> +#include <ctype.h> +#include <errno.h> +#include <netdb.h> +#include <nss.h> +#include <string.h> +#include <rpcsvc/nis.h> +#include <libc-lock.h> + +#include "nss-nisplus.h" + +__libc_lock_define_initialized (static, lock); + +static nis_result *result; +static nis_name tablename_val; +static u_long tablename_len; + +#define NISENTRYVAL(idx, col, res) \ + (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val) + +#define NISENTRYLEN(idx, col, res) \ + (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len) + + +static int +_nss_nisplus_parse_servent (nis_result *result, struct servent *serv, + char *buffer, size_t buflen, int *errnop) +{ + char *first_unused = buffer; + size_t room_left = buflen; + + if (result == NULL) + return 0; + + if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) + || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ + || strcmp (NIS_RES_OBJECT (result)->EN_data.en_type, "services_tbl") != 0 + || NIS_RES_OBJECT (result)->EN_data.en_cols.en_cols_len < 4) + return 0; + + if (NISENTRYLEN (0, 0, result) >= room_left) + { + no_more_room: + *errnop = ERANGE; + return -1; + } + strncpy (first_unused, NISENTRYVAL (0, 0, result), + NISENTRYLEN (0, 0, result)); + first_unused[NISENTRYLEN (0, 0, result)] = '\0'; + serv->s_name = first_unused; + size_t len = strlen (first_unused) + 1; + room_left -= len; + first_unused += len; + + if (NISENTRYLEN (0, 2, result) >= room_left) + goto no_more_room; + strncpy (first_unused, NISENTRYVAL (0, 2, result), + NISENTRYLEN (0, 2, result)); + first_unused[NISENTRYLEN (0, 2, result)] = '\0'; + serv->s_proto = first_unused; + len = strlen (first_unused) + 1; + room_left -= len; + first_unused += len; + + serv->s_port = htons (atoi (NISENTRYVAL (0, 3, result))); + + /* XXX Rewrite at some point to allocate the array first and then + copy the strings. It wasteful to first concatenate the strings + to just split them again later. */ + char *line = first_unused; + for (unsigned int i = 0; i < NIS_RES_NUMOBJ (result); ++i) + { + if (strcmp (NISENTRYVAL (i, 1, result), serv->s_name) != 0) + { + if (NISENTRYLEN (i, 1, result) + 2 > room_left) + goto no_more_room; + *first_unused++ = ' '; + first_unused = __stpncpy (first_unused, NISENTRYVAL (i, 1, result), + NISENTRYLEN (i, 1, result)); + room_left -= NISENTRYLEN (i, 1, result) + 1; + } + } + *first_unused++ = '\0'; + + /* Adjust the pointer so it is aligned for + storing pointers. */ + size_t adjust = ((__alignof__ (char *) + - (first_unused - (char *) 0) % __alignof__ (char *)) + % __alignof__ (char *)); + if (room_left < adjust + sizeof (char *)) + goto no_more_room; + first_unused += adjust; + room_left -= adjust; + serv->s_aliases = (char **) first_unused; + + /* For the terminating NULL pointer. */ + room_left -= (sizeof (char *)); + + unsigned int i = 0; + 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 *); + serv->s_aliases[i++] = line; + + while (*line != '\0' && *line != ' ') + ++line; + + if (*line == ' ') + *line++ = '\0'; + } + serv->s_aliases[i] = NULL; + + return 1; +} + + +static enum nss_status +_nss_create_tablename (int *errnop) +{ + if (tablename_val == NULL) + { + const char *local_dir = nis_local_directory (); + size_t local_dir_len = strlen (local_dir); + static const char prefix[] = "services.org_dir."; + + char *p = malloc (sizeof (prefix) + local_dir_len); + if (p == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } + + memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1); + + tablename_len = sizeof (prefix) - 1 + local_dir_len; + + atomic_write_barrier (); + + tablename_val = p; + } + + return NSS_STATUS_SUCCESS; +} + + +enum nss_status +_nss_nisplus_setservent (int stayopen) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + int err; + + __libc_lock_lock (lock); + + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } + + if (tablename_val == NULL) + status = _nss_create_tablename (&err); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nisplus_endservent (void) +{ + __libc_lock_lock (lock); + + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_nisplus_getservent_r (struct servent *serv, char *buffer, + size_t buflen, int *errnop) +{ + int parse_res; + + /* Get the next entry until we found a correct one. */ + do + { + nis_result *saved_res; + + if (result == NULL) + { + saved_res = NULL; + if (tablename_val == NULL) + { + enum nss_status status = _nss_create_tablename (errnop); + + if (status != NSS_STATUS_SUCCESS) + return status; + } + + result = nis_first_entry (tablename_val); + if (result == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } + if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) + return niserr2nss (result->status); + } + else + { + saved_res = result; + result = nis_next_entry (tablename_val, &result->cookie); + if (result == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } + if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) + { + nis_freeresult (saved_res); + return niserr2nss (result->status); + } + } + + parse_res = _nss_nisplus_parse_servent (result, serv, buffer, + buflen, errnop); + if (__glibc_unlikely (parse_res == -1)) + { + nis_freeresult (result); + result = saved_res; + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + else + { + if (saved_res) + nis_freeresult (saved_res); + } + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nisplus_getservent_r (struct servent *result, char *buffer, + size_t buflen, int *errnop) +{ + __libc_lock_lock (lock); + + int status = internal_nisplus_getservent_r (result, buffer, buflen, errnop); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nisplus_getservbyname_r (const char *name, const char *protocol, + struct servent *serv, + char *buffer, size_t buflen, int *errnop) +{ + if (tablename_val == NULL) + { + __libc_lock_lock (lock); + + enum nss_status status = _nss_create_tablename (errnop); + + __libc_lock_unlock (lock); + + if (status != NSS_STATUS_SUCCESS) + return status; + } + + if (name == NULL || protocol == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_NOTFOUND; + } + + size_t protocol_len = strlen (protocol); + char buf[strlen (name) + protocol_len + 17 + tablename_len]; + int olderr = errno; + + /* Search at first in the alias list, and use the correct name + for the next search */ + snprintf (buf, sizeof (buf), "[name=%s,proto=%s],%s", name, protocol, + tablename_val); + nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, + NULL, NULL); + + if (result != NULL) + { + char *bufptr = buf; + + /* If we did not find it, try it as original name. But if the + database is correct, we should find it in the first case, too */ + if ((result->status != NIS_SUCCESS + && result->status != NIS_S_SUCCESS) + || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ + || strcmp (NIS_RES_OBJECT (result)->EN_data.en_type, + "services_tbl") != 0 + || NIS_RES_OBJECT (result)->EN_data.en_cols.en_cols_len < 4) + snprintf (buf, sizeof (buf), "[cname=%s,proto=%s],%s", name, protocol, + tablename_val); + else + { + /* We need to allocate a new buffer since there is no + guarantee the returned name has a length limit. */ + const char *entryval = NISENTRYVAL(0, 0, result); + size_t buflen = (strlen (entryval) + protocol_len + 17 + + tablename_len); + bufptr = alloca (buflen); + snprintf (bufptr, buflen, "[cname=%s,proto=%s],%s", + entryval, protocol, tablename_val); + } + + nis_freeresult (result); + result = nis_list (bufptr, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, + NULL, NULL); + } + + if (result == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } + + if (__glibc_unlikely (niserr2nss (result->status) != NSS_STATUS_SUCCESS)) + { + enum nss_status status = niserr2nss (result->status); + + __set_errno (olderr); + + nis_freeresult (result); + return status; + } + + int parse_res = _nss_nisplus_parse_servent (result, serv, buffer, buflen, + errnop); + nis_freeresult (result); + + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + else + { + __set_errno (olderr); + return NSS_STATUS_NOTFOUND; + } + } + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nisplus_getservbyport_r (const int number, const char *protocol, + struct servent *serv, + char *buffer, size_t buflen, int *errnop) +{ + if (tablename_val == NULL) + { + __libc_lock_lock (lock); + + enum nss_status status = _nss_create_tablename (errnop); + + __libc_lock_unlock (lock); + + if (status != NSS_STATUS_SUCCESS) + return status; + } + + if (protocol == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_NOTFOUND; + } + + char buf[17 + 3 * sizeof (int) + strlen (protocol) + tablename_len]; + int olderr = errno; + + snprintf (buf, sizeof (buf), "[port=%d,proto=%s],%s", + number, protocol, tablename_val); + + nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, + NULL, NULL); + + if (result == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } + + if (__glibc_unlikely (niserr2nss (result->status) != NSS_STATUS_SUCCESS)) + { + enum nss_status status = niserr2nss (result->status); + + __set_errno (olderr); + + nis_freeresult (result); + return status; + } + + int parse_res = _nss_nisplus_parse_servent (result, serv, buffer, buflen, + errnop); + nis_freeresult (result); + + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + else + { + __set_errno (olderr); + return NSS_STATUS_NOTFOUND; + } + } + + return NSS_STATUS_SUCCESS; +} diff --git a/REORG.TODO/nis/nss_nisplus/nisplus-spwd.c b/REORG.TODO/nis/nss_nisplus/nisplus-spwd.c new file mode 100644 index 0000000000..e51ba7f969 --- /dev/null +++ b/REORG.TODO/nis/nss_nisplus/nisplus-spwd.c @@ -0,0 +1,220 @@ +/* Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <nss.h> +#include <errno.h> +#include <shadow.h> +#include <string.h> +#include <libc-lock.h> +#include <rpcsvc/nis.h> + +#include "nss-nisplus.h" +#include "nisplus-parser.h" + +__libc_lock_define_initialized (static, lock) + +static nis_result *result; + +/* Defined in nisplus-pwd.c. */ +extern nis_name pwd_tablename_val attribute_hidden; +extern size_t pwd_tablename_len attribute_hidden; +extern enum nss_status _nss_pwd_create_tablename (int *errnop); + + +enum nss_status +_nss_nisplus_setspent (int stayopen) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + int err; + + __libc_lock_lock (lock); + + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } + + if (pwd_tablename_val == NULL) + status = _nss_pwd_create_tablename (&err); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nisplus_endspent (void) +{ + __libc_lock_lock (lock); + + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_nisplus_getspent_r (struct spwd *sp, char *buffer, size_t buflen, + int *errnop) +{ + int parse_res; + + /* Get the next entry until we found a correct one. */ + do + { + nis_result *saved_res; + + if (result == NULL) + { + saved_res = NULL; + + if (pwd_tablename_val == NULL) + { + enum nss_status status = _nss_pwd_create_tablename (errnop); + + if (status != NSS_STATUS_SUCCESS) + return status; + } + + result = nis_first_entry (pwd_tablename_val); + if (result == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } + if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) + return niserr2nss (result->status); + } + else + { + saved_res = result; + result = nis_next_entry (pwd_tablename_val, &result->cookie); + if (result == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } + if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) + { + nis_freeresult (saved_res); + return niserr2nss (result->status); + } + } + + parse_res = _nss_nisplus_parse_spent (result, sp, buffer, + buflen, errnop); + if (__glibc_unlikely (parse_res == -1)) + { + nis_freeresult (result); + result = saved_res; + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + if (saved_res != NULL) + nis_freeresult (saved_res); + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nisplus_getspent_r (struct spwd *result, char *buffer, size_t buflen, + int *errnop) +{ + int status; + + __libc_lock_lock (lock); + + status = internal_nisplus_getspent_r (result, buffer, buflen, errnop); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nisplus_getspnam_r (const char *name, struct spwd *sp, + char *buffer, size_t buflen, int *errnop) +{ + int parse_res; + + if (pwd_tablename_val == NULL) + { + enum nss_status status = _nss_pwd_create_tablename (errnop); + + if (status != NSS_STATUS_SUCCESS) + return status; + } + + if (name == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_NOTFOUND; + } + + nis_result *result; + char buf[strlen (name) + 9 + pwd_tablename_len]; + int olderr = errno; + + snprintf (buf, sizeof (buf), "[name=%s],%s", name, pwd_tablename_val); + + result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, NULL, NULL); + + if (result == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } + + if (__glibc_unlikely (niserr2nss (result->status) != NSS_STATUS_SUCCESS)) + { + enum nss_status status = niserr2nss (result->status); + + __set_errno (olderr); + + nis_freeresult (result); + return status; + } + + parse_res = _nss_nisplus_parse_spent (result, sp, buffer, buflen, errnop); + nis_freeresult (result); + + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + else + { + __set_errno (olderr); + return NSS_STATUS_NOTFOUND; + } + } + + return NSS_STATUS_SUCCESS; +} diff --git a/REORG.TODO/nis/rpcsvc/nis.h b/REORG.TODO/nis/rpcsvc/nis.h new file mode 100644 index 0000000000..933c4d9daf --- /dev/null +++ b/REORG.TODO/nis/rpcsvc/nis.h @@ -0,0 +1,616 @@ +/* + * Copyright (c) 2010, Oracle America, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the "Oracle America, Inc." 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 COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER 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. + */ + +#ifndef _RPCSVC_NIS_H +#define _RPCSVC_NIS_H 1 + +#include <features.h> +#include <rpc/rpc.h> +#include <rpcsvc/nis_tags.h> + +__BEGIN_DECLS + +/* + * nis.h + * + * This file is the main include file for NIS clients. It contains + * both the client library function defines and the various data + * structures used by the NIS service. It includes the file nis_tags.h + * which defines the tag values. This allows the tags to change without + * having to change the nis.x file. + * + * NOTE : THIS FILE IS NOT GENERATED WITH RPCGEN ! SO YOU HAVE TO + * ADD ALL THE CHANGES ON nis_*.x FILES HERE AGAIN ! + * + * I have removed all the Solaris internal structs and variables, + * because they are not supported, Sun changed them between various + * releases and they shouldn't be used in user programs. + * <kukuk@suse.de> + */ + + +#ifndef __nis_object_h +#define __nis_object_h + +#define NIS_MAXSTRINGLEN 255 +#define NIS_MAXNAMELEN 1024 +#define NIS_MAXATTRNAME 32 +#define NIS_MAXATTRVAL 2048 +#define NIS_MAXCOLUMNS 64 +#define NIS_MAXATTR 16 +#define NIS_MAXPATH 1024 +#define NIS_MAXREPLICAS 128 +#define NIS_MAXLINKS 16 +#define NIS_PK_NONE 0 +#define NIS_PK_DH 1 +#define NIS_PK_RSA 2 +#define NIS_PK_KERB 3 +#define NIS_PK_DHEXT 4 + +struct nis_attr { + char *zattr_ndx; + struct { + u_int zattr_val_len; + char *zattr_val_val; + } zattr_val; +}; +typedef struct nis_attr nis_attr; + +typedef char *nis_name; + +enum zotypes { + BOGUS_OBJ = 0, + NO_OBJ = 1, + DIRECTORY_OBJ = 2, + GROUP_OBJ = 3, + TABLE_OBJ = 4, + ENTRY_OBJ = 5, + LINK_OBJ = 6, + PRIVATE_OBJ = 7, + NIS_BOGUS_OBJ = 0, + NIS_NO_OBJ = 1, + NIS_DIRECTORY_OBJ = 2, + NIS_GROUP_OBJ = 3, + NIS_TABLE_OBJ = 4, + NIS_ENTRY_OBJ = 5, + NIS_LINK_OBJ = 6, + NIS_PRIVATE_OBJ = 7 +}; +typedef enum zotypes zotypes; + +enum nstype { + UNKNOWN = 0, + NIS = 1, + SUNYP = 2, + IVY = 3, + DNS = 4, + X500 = 5, + DNANS = 6, + XCHS = 7, + CDS = 8, +}; +typedef enum nstype nstype; + +struct oar_mask { + uint32_t oa_rights; + zotypes oa_otype; +}; +typedef struct oar_mask oar_mask; + +struct endpoint { + char *uaddr; + char *family; + char *proto; +}; +typedef struct endpoint endpoint; + +struct nis_server { + nis_name name; + struct { + u_int ep_len; + endpoint *ep_val; + } ep; + uint32_t key_type; + netobj pkey; +}; +typedef struct nis_server nis_server; + +struct directory_obj { + nis_name do_name; + nstype do_type; + struct { + u_int do_servers_len; + nis_server *do_servers_val; + } do_servers; + uint32_t do_ttl; + struct { + u_int do_armask_len; + oar_mask *do_armask_val; + } do_armask; +}; +typedef struct directory_obj directory_obj; + +#define EN_BINARY 1 +#define EN_CRYPT 2 +#define EN_XDR 4 +#define EN_MODIFIED 8 +#define EN_ASN1 64 + +struct entry_col { + uint32_t ec_flags; + struct { + u_int ec_value_len; + char *ec_value_val; + } ec_value; +}; +typedef struct entry_col entry_col; + +struct entry_obj { + char *en_type; + struct { + u_int en_cols_len; + entry_col *en_cols_val; + } en_cols; +}; +typedef struct entry_obj entry_obj; + +struct group_obj { + uint32_t gr_flags; + struct { + u_int gr_members_len; + nis_name *gr_members_val; + } gr_members; +}; +typedef struct group_obj group_obj; + +struct link_obj { + zotypes li_rtype; + struct { + u_int li_attrs_len; + nis_attr *li_attrs_val; + } li_attrs; + nis_name li_name; +}; +typedef struct link_obj link_obj; + +#define TA_BINARY 1 +#define TA_CRYPT 2 +#define TA_XDR 4 +#define TA_SEARCHABLE 8 +#define TA_CASE 16 +#define TA_MODIFIED 32 +#define TA_ASN1 64 + +struct table_col { + char *tc_name; + uint32_t tc_flags; + uint32_t tc_rights; +}; +typedef struct table_col table_col; + +struct table_obj { + char *ta_type; + int ta_maxcol; + u_char ta_sep; + struct { + u_int ta_cols_len; + table_col *ta_cols_val; + } ta_cols; + char *ta_path; +}; +typedef struct table_obj table_obj; + +struct objdata { + zotypes zo_type; + union { + struct directory_obj di_data; + struct group_obj gr_data; + struct table_obj ta_data; + struct entry_obj en_data; + struct link_obj li_data; + struct { + u_int po_data_len; + char *po_data_val; + } po_data; + } objdata_u; +}; +typedef struct objdata objdata; + +struct nis_oid { + uint32_t ctime; + uint32_t mtime; +}; +typedef struct nis_oid nis_oid; + +struct nis_object { + nis_oid zo_oid; + nis_name zo_name; + nis_name zo_owner; + nis_name zo_group; + nis_name zo_domain; + uint32_t zo_access; + uint32_t zo_ttl; + objdata zo_data; +}; +typedef struct nis_object nis_object; + +#endif /* if __nis_object_h */ + +enum nis_error { + NIS_SUCCESS = 0, + NIS_S_SUCCESS = 1, + NIS_NOTFOUND = 2, + NIS_S_NOTFOUND = 3, + NIS_CACHEEXPIRED = 4, + NIS_NAMEUNREACHABLE = 5, + NIS_UNKNOWNOBJ = 6, + NIS_TRYAGAIN = 7, + NIS_SYSTEMERROR = 8, + NIS_CHAINBROKEN = 9, + NIS_PERMISSION = 10, + NIS_NOTOWNER = 11, + NIS_NOT_ME = 12, + NIS_NOMEMORY = 13, + NIS_NAMEEXISTS = 14, + NIS_NOTMASTER = 15, + NIS_INVALIDOBJ = 16, + NIS_BADNAME = 17, + NIS_NOCALLBACK = 18, + NIS_CBRESULTS = 19, + NIS_NOSUCHNAME = 20, + NIS_NOTUNIQUE = 21, + NIS_IBMODERROR = 22, + NIS_NOSUCHTABLE = 23, + NIS_TYPEMISMATCH = 24, + NIS_LINKNAMEERROR = 25, + NIS_PARTIAL = 26, + NIS_TOOMANYATTRS = 27, + NIS_RPCERROR = 28, + NIS_BADATTRIBUTE = 29, + NIS_NOTSEARCHABLE = 30, + NIS_CBERROR = 31, + NIS_FOREIGNNS = 32, + NIS_BADOBJECT = 33, + NIS_NOTSAMEOBJ = 34, + NIS_MODFAIL = 35, + NIS_BADREQUEST = 36, + NIS_NOTEMPTY = 37, + NIS_COLDSTART_ERR = 38, + NIS_RESYNC = 39, + NIS_FAIL = 40, + NIS_UNAVAIL = 41, + NIS_RES2BIG = 42, + NIS_SRVAUTH = 43, + NIS_CLNTAUTH = 44, + NIS_NOFILESPACE = 45, + NIS_NOPROC = 46, + NIS_DUMPLATER = 47, +}; +typedef enum nis_error nis_error; + +struct nis_result { + nis_error status; + struct { + u_int objects_len; + nis_object *objects_val; + } objects; + netobj cookie; + uint32_t zticks; + uint32_t dticks; + uint32_t aticks; + uint32_t cticks; +}; +typedef struct nis_result nis_result; + +struct ns_request { + nis_name ns_name; + struct { + u_int ns_object_len; + nis_object *ns_object_val; + } ns_object; +}; +typedef struct ns_request ns_request; + +struct ib_request { + nis_name ibr_name; + struct { + u_int ibr_srch_len; + nis_attr *ibr_srch_val; + } ibr_srch; + uint32_t ibr_flags; + struct { + u_int ibr_obj_len; + nis_object *ibr_obj_val; + } ibr_obj; + struct { + u_int ibr_cbhost_len; + nis_server *ibr_cbhost_val; + } ibr_cbhost; + u_int ibr_bufsize; + netobj ibr_cookie; +}; +typedef struct ib_request ib_request; + +struct ping_args { + nis_name dir; + uint32_t stamp; +}; +typedef struct ping_args ping_args; + +enum log_entry_t { + LOG_NOP = 0, + ADD_NAME = 1, + REM_NAME = 2, + MOD_NAME_OLD = 3, + MOD_NAME_NEW = 4, + ADD_IBASE = 5, + REM_IBASE = 6, + MOD_IBASE = 7, + UPD_STAMP = 8, +}; +typedef enum log_entry_t log_entry_t; + +struct log_entry { + uint32_t le_time; + log_entry_t le_type; + nis_name le_princp; + nis_name le_name; + struct { + u_int le_attrs_len; + nis_attr *le_attrs_val; + } le_attrs; + nis_object le_object; +}; +typedef struct log_entry log_entry; + +struct log_result { + nis_error lr_status; + netobj lr_cookie; + struct { + u_int lr_entries_len; + log_entry *lr_entries_val; + } lr_entries; +}; +typedef struct log_result log_result; + +struct cp_result { + nis_error cp_status; + uint32_t cp_zticks; + uint32_t cp_dticks; +}; +typedef struct cp_result cp_result; + +struct nis_tag { + uint32_t tag_type; + char *tag_val; +}; +typedef struct nis_tag nis_tag; + +struct nis_taglist { + struct { + u_int tags_len; + nis_tag *tags_val; + } tags; +}; +typedef struct nis_taglist nis_taglist; + +struct dump_args { + nis_name da_dir; + uint32_t da_time; + struct { + u_int da_cbhost_len; + nis_server *da_cbhost_val; + } da_cbhost; +}; +typedef struct dump_args dump_args; + +struct fd_args { + nis_name dir_name; + nis_name requester; +}; +typedef struct fd_args fd_args; + +struct fd_result { + nis_error status; + nis_name source; + struct { + u_int dir_data_len; + char *dir_data_val; + } dir_data; + struct { + u_int signature_len; + char *signature_val; + } signature; +}; +typedef struct fd_result fd_result; + +/* Generic client creating flags */ +#define ZMH_VC 1 +#define ZMH_DG 2 +#define ZMH_AUTH 4 + +/* Testing Access rights for objects */ + +#define NIS_READ_ACC 1 +#define NIS_MODIFY_ACC 2 +#define NIS_CREATE_ACC 4 +#define NIS_DESTROY_ACC 8 +/* Test macros. a == access rights, m == desired rights. */ +#define NIS_WORLD(a, m) (((a) & (m)) != 0) +#define NIS_GROUP(a, m) (((a) & ((m) << 8)) != 0) +#define NIS_OWNER(a, m) (((a) & ((m) << 16)) != 0) +#define NIS_NOBODY(a, m) (((a) & ((m) << 24)) != 0) +/* + * EOL Alert - The following non-prefixed test macros are + * here for backward compatibility, and will be not be present + * in future releases - use the NIS_*() macros above. + */ +#define WORLD(a, m) (((a) & (m)) != 0) +#define GROUP(a, m) (((a) & ((m) << 8)) != 0) +#define OWNER(a, m) (((a) & ((m) << 16)) != 0) +#define NOBODY(a, m) (((a) & ((m) << 24)) != 0) + +#define OATYPE(d, n) (((d)->do_armask.do_armask_val+n)->oa_otype) +#define OARIGHTS(d, n) (((d)->do_armask.do_armask_val+n)->oa_rights) +#define WORLD_DEFAULT (NIS_READ_ACC) +#define GROUP_DEFAULT (NIS_READ_ACC << 8) +#define OWNER_DEFAULT ((NIS_READ_ACC + NIS_MODIFY_ACC + NIS_CREATE_ACC +\ + NIS_DESTROY_ACC) << 16) +#define DEFAULT_RIGHTS (WORLD_DEFAULT | GROUP_DEFAULT | OWNER_DEFAULT) + +/* Result manipulation defines ... */ +#define NIS_RES_NUMOBJ(x) ((x)->objects.objects_len) +#define NIS_RES_OBJECT(x) ((x)->objects.objects_val) +#define NIS_RES_COOKIE(x) ((x)->cookie) +#define NIS_RES_STATUS(x) ((x)->status) + +/* These defines make getting at the variant part of the object easier. */ +#define TA_data zo_data.objdata_u.ta_data +#define EN_data zo_data.objdata_u.en_data +#define DI_data zo_data.objdata_u.di_data +#define LI_data zo_data.objdata_u.li_data +#define GR_data zo_data.objdata_u.gr_data + +#define __type_of(o) ((o)->zo_data.zo_type) + +/* Declarations for the internal subroutines in nislib.c */ +enum name_pos {SAME_NAME, HIGHER_NAME, LOWER_NAME, NOT_SEQUENTIAL, BAD_NAME}; +typedef enum name_pos name_pos; + +/* + * Defines for getting at column data in entry objects. Because RPCGEN + * generates some rather wordy structures, we create some defines that + * collapse the needed keystrokes to access a particular value using + * these definitions they take an nis_object *, and an int and return + * a u_char * for Value, and an int for length. + */ +#define ENTRY_VAL(obj, col) (obj)->EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val +#define ENTRY_LEN(obj, col) (obj)->EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len + + +/* Prototypes, and extern declarations for the NIS library functions. */ +#include <rpcsvc/nislib.h> +#endif + +/* + * nis_3.h + * + * This file contains definitions that are only of interest to the actual + * service daemon and client stubs. Normal users of NIS will not include + * this file. + * + * NOTE : This include file is automatically created by a combination + * of rpcgen and sed. DO NOT EDIT IT, change the nis.x file instead + * and then remake this file. + */ +#ifndef __nis_3_h +#define __nis_3_h + +#define NIS_PROG 100300 +#define NIS_VERSION 3 + +#define NIS_LOOKUP 1 +extern nis_result * nis_lookup_3 (ns_request *, CLIENT *) __THROW; +extern nis_result * nis_lookup_3_svc (ns_request *, struct svc_req *) __THROW; +#define NIS_ADD 2 +extern nis_result * nis_add_3 (ns_request *, CLIENT *) __THROW; +extern nis_result * nis_add_3_svc (ns_request *, struct svc_req *) __THROW; +#define NIS_MODIFY 3 +extern nis_result * nis_modify_3 (ns_request *, CLIENT *) __THROW; +extern nis_result * nis_modify_3_svc (ns_request *, struct svc_req *) __THROW; +#define NIS_REMOVE 4 +extern nis_result * nis_remove_3 (ns_request *, CLIENT *) __THROW; +extern nis_result * nis_remove_3_svc (ns_request *, struct svc_req *) __THROW; +#define NIS_IBLIST 5 +extern nis_result * nis_iblist_3 (ib_request *, CLIENT *) __THROW; +extern nis_result * nis_iblist_3_svc (ib_request *, struct svc_req *) __THROW; +#define NIS_IBADD 6 +extern nis_result * nis_ibadd_3 (ib_request *, CLIENT *) __THROW; +extern nis_result * nis_ibadd_3_svc (ib_request *, struct svc_req *) __THROW; +#define NIS_IBMODIFY 7 +extern nis_result * nis_ibmodify_3 (ib_request *, CLIENT *) __THROW; +extern nis_result * nis_ibmodify_3_svc (ib_request *, struct svc_req *) + __THROW; +#define NIS_IBREMOVE 8 +extern nis_result * nis_ibremove_3 (ib_request *, CLIENT *) __THROW; +extern nis_result * nis_ibremove_3_svc (ib_request *, struct svc_req *) + __THROW; +#define NIS_IBFIRST 9 +extern nis_result * nis_ibfirst_3 (ib_request *, CLIENT *) __THROW; +extern nis_result * nis_ibfirst_3_svc (ib_request *, struct svc_req *) + __THROW; +#define NIS_IBNEXT 10 +extern nis_result * nis_ibnext_3 (ib_request *, CLIENT *) __THROW; +extern nis_result * nis_ibnext_3_svc (ib_request *, struct svc_req *) __THROW; +#define NIS_FINDDIRECTORY 12 +extern fd_result * nis_finddirectory_3 (fd_args *, CLIENT *) __THROW; +extern fd_result * nis_finddirectory_3_svc (fd_args *, + struct svc_req *) __THROW; +#define NIS_STATUS 14 +extern nis_taglist * nis_status_3 (nis_taglist *, CLIENT *) __THROW; +extern nis_taglist * nis_status_3_svc (nis_taglist *, struct svc_req *) + __THROW; +#define NIS_DUMPLOG 15 +extern log_result * nis_dumplog_3 (dump_args *, CLIENT *) __THROW; +extern log_result * nis_dumplog_3_svc (dump_args *, struct svc_req *) __THROW; +#define NIS_DUMP 16 +extern log_result * nis_dump_3 (dump_args *, CLIENT *) __THROW; +extern log_result * nis_dump_3_svc (dump_args *, struct svc_req *) __THROW; +#define NIS_CALLBACK 17 +extern bool_t * nis_callback_3 (netobj *, CLIENT *) __THROW; +extern bool_t * nis_callback_3_svc (netobj *, struct svc_req *) __THROW; +#define NIS_CPTIME 18 +extern uint32_t * nis_cptime_3 (nis_name *, CLIENT *) __THROW; +extern uint32_t * nis_cptime_3_svc (nis_name *, struct svc_req *) __THROW; +#define NIS_CHECKPOINT 19 +extern cp_result * nis_checkpoint_3 (nis_name *, CLIENT *) __THROW; +extern cp_result * nis_checkpoint_3_svc (nis_name *, struct svc_req *) + __THROW; +#define NIS_PING 20 +extern void * nis_ping_3 (ping_args *, CLIENT *) __THROW; +extern void * nis_ping_3_svc (ping_args *, struct svc_req *) __THROW; +#define NIS_SERVSTATE 21 +extern nis_taglist * nis_servstate_3 (nis_taglist *, CLIENT *) __THROW; +extern nis_taglist * nis_servstate_3_svc (nis_taglist *, + struct svc_req *) __THROW; +#define NIS_MKDIR 22 +extern nis_error * nis_mkdir_3 (nis_name *, CLIENT *) __THROW; +extern nis_error * nis_mkdir_3_svc (nis_name *, struct svc_req *) __THROW; +#define NIS_RMDIR 23 +extern nis_error * nis_rmdir_3 (nis_name *, CLIENT *) __THROW; +extern nis_error * nis_rmdir_3_svc (nis_name *, struct svc_req *) __THROW; +#define NIS_UPDKEYS 24 +extern nis_error * nis_updkeys_3 (nis_name *, CLIENT *) __THROW; +extern nis_error * nis_updkeys_3_svc (nis_name *, struct svc_req *) __THROW; + +__END_DECLS + +#endif /* ! _RPCSVC_NIS_H */ diff --git a/REORG.TODO/nis/rpcsvc/nis.x b/REORG.TODO/nis/rpcsvc/nis.x new file mode 100644 index 0000000000..e318af29a6 --- /dev/null +++ b/REORG.TODO/nis/rpcsvc/nis.x @@ -0,0 +1,474 @@ +%/* +% * Copyright (c) 2010, Oracle America, Inc. +% * +% * Redistribution and use in source and binary forms, with or without +% * modification, are permitted provided that the following conditions are +% * met: +% * +% * * Redistributions of source code must retain the above copyright +% * notice, this list of conditions and the following disclaimer. +% * * 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. +% * * Neither the name of the "Oracle America, Inc." 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 COPYRIGHT HOLDERS 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 +% * COPYRIGHT HOLDER 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. +% */ + +#ifdef RPC_HDR +%/* +% * nis.h +% * +% * This file is the main include file for NIS clients. It contains +% * both the client library function defines and the various data +% * structures used by the NIS service. It includes the file nis_tags.h +% * which defines the tag values. This allows the tags to change without +% * having to change the nis.x file. +% * +% * NOTE : DO NOT EDIT THIS FILE! It is automatically generated when +% * rpcgen is run on the nis.x file. Note that there is a +% * simple sed script to remove some unneeded lines. (See the +% * Makefile target nis.h) +% * +% */ +%#include <rpcsvc/nis_tags.h> +#endif + +/* This gets stuffed into the source files. */ +#if RPC_HDR +%#include <rpc/xdr.h> +#endif + +/* Include the RPC Language description of NIS objects */ +#include "nis_object.x" + +/* Errors that can be returned by the service */ +enum nis_error { + NIS_SUCCESS = 0, /* A-ok, let's rock n roll */ + NIS_S_SUCCESS = 1, /* Name found (maybe) */ + NIS_NOTFOUND = 2, /* Name definitely not found */ + NIS_S_NOTFOUND = 3, /* Name maybe not found */ + NIS_CACHEEXPIRED = 4, /* Name exists but cache out of date */ + NIS_NAMEUNREACHABLE = 5, /* Can't get there from here */ + NIS_UNKNOWNOBJ = 6, /* Object type is bogus */ + NIS_TRYAGAIN = 7, /* I'm busy, call back */ + NIS_SYSTEMERROR = 8, /* Generic system error */ + NIS_CHAINBROKEN = 9, /* First/Next warning */ + NIS_PERMISSION = 10, /* Not enough permission to access */ + NIS_NOTOWNER = 11, /* You don't own it, sorry */ + NIS_NOT_ME = 12, /* I don't serve this name */ + NIS_NOMEMORY = 13, /* Outta VM! Help! */ + NIS_NAMEEXISTS = 14, /* Can't create over another name */ + NIS_NOTMASTER = 15, /* I'm justa secondaray, don't ask me */ + NIS_INVALIDOBJ = 16, /* Object is broken somehow */ + NIS_BADNAME = 17, /* Unparsable name */ + NIS_NOCALLBACK = 18, /* Couldn't talk to call back proc */ + NIS_CBRESULTS = 19, /* Results being called back to you */ + NIS_NOSUCHNAME = 20, /* Name unknown */ + NIS_NOTUNIQUE = 21, /* Value is not uniques (entry) */ + NIS_IBMODERROR = 22, /* Inf. Base. Modify error. */ + NIS_NOSUCHTABLE = 23, /* Name for table was wrong */ + NIS_TYPEMISMATCH = 24, /* Entry and table type mismatch */ + NIS_LINKNAMEERROR = 25, /* Link points to bogus name */ + NIS_PARTIAL = 26, /* Partial success, found table */ + NIS_TOOMANYATTRS = 27, /* Too many attributes */ + NIS_RPCERROR = 28, /* RPC error encountered */ + NIS_BADATTRIBUTE = 29, /* Bad or invalid attribute */ + NIS_NOTSEARCHABLE = 30, /* Non-searchable object searched */ + NIS_CBERROR = 31, /* Error during callback (svc crash) */ + NIS_FOREIGNNS = 32, /* Foreign Namespace */ + NIS_BADOBJECT = 33, /* Malformed object structure */ + NIS_NOTSAMEOBJ = 34, /* Object swapped during deletion */ + NIS_MODFAIL = 35, /* Failure during a Modify. */ + NIS_BADREQUEST = 36, /* Illegal query for table */ + NIS_NOTEMPTY = 37, /* Attempt to remove a non-empty tbl */ + NIS_COLDSTART_ERR = 38, /* Error accesing the cold start file */ + NIS_RESYNC = 39, /* Transaction log too far out of date */ + NIS_FAIL = 40, /* NIS operation failed. */ + NIS_UNAVAIL = 41, /* NIS+ service is unavailable (client) */ + NIS_RES2BIG = 42, /* NIS+ result too big for datagram */ + NIS_SRVAUTH = 43, /* NIS+ server wasn't authenticated. */ + NIS_CLNTAUTH = 44, /* NIS+ Client wasn't authenticated. */ + NIS_NOFILESPACE = 45, /* NIS+ server ran out of disk space */ + NIS_NOPROC = 46, /* NIS+ server couldn't create new proc */ + NIS_DUMPLATER = 47 /* NIS+ server already has dump child */ +}; + + +/* + * Structure definitions for the parameters and results of the actual + * NIS RPC calls. + * + * This is the standard result (in the protocol) of most of the nis + * requests. + */ + +struct nis_result { + nis_error status; /* Status of the response */ + nis_object objects<>; /* objects found */ + netobj cookie; /* Cookie Data */ + uint32_t zticks; /* server ticks */ + uint32_t dticks; /* DBM ticks. */ + uint32_t aticks; /* Cache (accel) ticks */ + uint32_t cticks; /* Client ticks */ +}; + +/* + * A Name Service request + * This request is used to access the name space, ns_name is the name + * of the object within the namespace and the object is it's value, for + * add/modify, a copy of the original for remove. + */ + +struct ns_request { + nis_name ns_name; /* Name in the NIS name space */ + nis_object ns_object<1>; /* Optional Object (add/remove) */ +}; + +/* + * An information base request + * This request includes the NIS name of the table we wish to search, the + * search criteria in the form of attribute/value pairs and an optional + * callback program number. If the callback program number is provided + * the server will send back objects one at a time, otherwise it will + * return them all in the response. + */ + +struct ib_request { + nis_name ibr_name; /* The name of the Table */ + nis_attr ibr_srch<>; /* The search critereia */ + uint32_t ibr_flags; /* Optional flags */ + nis_object ibr_obj<1>; /* optional object (add/modify) */ + nis_server ibr_cbhost<1>; /* Optional callback info */ + u_int ibr_bufsize; /* Optional first/next bufsize */ + netobj ibr_cookie; /* The first/next cookie */ +}; + +/* + * This argument to the PING call notifies the replicas that something in + * a directory has changed and this is it's timestamp. The replica will use + * the timestamp to determine if its resync operation was successful. + */ +struct ping_args { + nis_name dir; /* Directory that had the change */ + uint32_t stamp; /* timestamp of the transaction */ +}; + +/* + * These are the type of entries that are stored in the transaction log, + * note that modifications will appear as two entries, for names, they have + * a "OLD" entry followed by a "NEW" entry. For entries in tables, there + * is a remove followed by an add. It is done this way so that we can read + * the log backwards to back out transactions and forwards to propogate + * updated. + */ +enum log_entry_t { + LOG_NOP = 0, + ADD_NAME = 1, /* Name Added to name space */ + REM_NAME = 2, /* Name removed from name space */ + MOD_NAME_OLD = 3, /* Name was modified in the name space */ + MOD_NAME_NEW = 4, /* Name was modified in the name space */ + ADD_IBASE = 5, /* Entry added to information base */ + REM_IBASE = 6, /* Entry removed from information base */ + MOD_IBASE = 7, /* Entry was modified in information base */ + UPD_STAMP = 8 /* Update timestamp (used as fenceposts) */ +}; + +/* + * This result is returned from the name service when it is requested to + * dump logged entries from its transaction log. Information base updates + * will have the name of the information base in the le_name field and + * a canonical set of attribute/value pairs to fully specify the entry's + * 'name'. + */ +struct log_entry { + uint32_t le_time; /* Time in seconds */ + log_entry_t le_type; /* Type of log entry */ + nis_name le_princp; /* Principal making the change */ + nis_name le_name; /* Name of table/dir involved */ + nis_attr le_attrs<>; /* List of AV pairs. */ + nis_object le_object; /* Actual object value */ +}; + +struct log_result { + nis_error lr_status; /* The status itself */ + netobj lr_cookie; /* Used by the dump callback */ + log_entry lr_entries<>; /* zero or more entries */ +}; + +struct cp_result { + nis_error cp_status; /* Status of the checkpoint */ + uint32_t cp_zticks; /* Service 'ticks' */ + uint32_t cp_dticks; /* Database 'ticks' */ +}; + +/* + * This structure defines a generic NIS tag list. The taglist contains + * zero or tags, each of which is a type and a value. (u_int). + * These are used to report statistics (see tag definitions below) + * and to set or reset state variables. + */ +struct nis_tag { + uint32_t tag_type; /* Statistic tag (may vary) */ + string tag_val<>; /* Statistic value may also vary */ +}; + +struct nis_taglist { + nis_tag tags<>; /* List of tags */ +}; + +struct dump_args { + nis_name da_dir; /* Directory to dump */ + uint32_t da_time; /* From this timestamp */ + nis_server da_cbhost<1>; /* Callback to use. */ +}; + +struct fd_args { + nis_name dir_name; /* The directory we're looking for */ + nis_name requester; /* Host principal name for signature */ +}; + +struct fd_result { + nis_error status; /* Status returned by function */ + nis_name source; /* Source of this answer */ + opaque dir_data<>; /* Directory Data (XDR'ed) */ + opaque signature<>; /* Signature of the source */ +}; + +%/* +% * Structures used for server binding. +% */ +struct nis_bound_endpoint { + endpoint ep; + int generation; + int rank; + uint32_t flags; + int hostnum; + int epnum; + nis_name uaddr; + endpoint cbep; +}; +typedef struct nis_bound_endpoint nis_bound_endpoint; + +struct nis_bound_directory { + int generation; + int min_rank; /* minimum rank of bound endpoints */ + int optimal_rank; /* best possible rank of all endpoints */ + directory_obj dobj; + nis_bound_endpoint BEP<>; +}; +typedef struct nis_bound_directory nis_bound_directory; +%#define bep_len BEP.BEP_len +%#define bep_val BEP.BEP_val + +struct nis_active_endpoint { + endpoint ep; + nis_name hostname; + int rank; + int uaddr_generation; + nis_name uaddr; + int cbep_generation; + endpoint cbep; +}; +typedef struct nis_active_endpoint nis_active_endpoint; + +%/* defines for nis_bound_endpoint.flags */ +%#define NIS_BOUND 0x1 +%#define NIS_TRANSIENT_ERRORS 0x2 + +program NIS_PROG { + + /* RPC Language description of the NIS+ protocol */ + version NIS_VERSION { + /* The name service functions */ + nis_result NIS_LOOKUP(ns_request) = 1; + nis_result NIS_ADD(ns_request) = 2; + nis_result NIS_MODIFY(ns_request) = 3; + nis_result NIS_REMOVE(ns_request) = 4; + + /* The information base functions */ + nis_result NIS_IBLIST(ib_request) = 5; + nis_result NIS_IBADD(ib_request) = 6; + nis_result NIS_IBMODIFY(ib_request) = 7; + nis_result NIS_IBREMOVE(ib_request) = 8; + nis_result NIS_IBFIRST(ib_request) = 9; + nis_result NIS_IBNEXT(ib_request) = 10; + + /* NIS Administrative functions */ + fd_result NIS_FINDDIRECTORY(fd_args) = 12; + + /* If fetch and optionally reset statistics */ + nis_taglist NIS_STATUS(nis_taglist) = 14; + + /* Dump changes to directory since time in da_time */ + log_result NIS_DUMPLOG(dump_args) = 15; + + /* Dump contents of directory named */ + log_result NIS_DUMP(dump_args) = 16; + + /* Check status of callback thread */ + bool NIS_CALLBACK(netobj) = 17; + + /* Return last update time for named dir */ + uint32_t NIS_CPTIME(nis_name) = 18; + + /* Checkpoint directory or table named */ + cp_result NIS_CHECKPOINT(nis_name) = 19; + + /* Send 'status changed' ping to replicates */ + void NIS_PING(ping_args) = 20; + + /* Modify server behaviour (such as debugging) */ + nis_taglist NIS_SERVSTATE(nis_taglist) = 21; + + /* Create a Directory */ + nis_error NIS_MKDIR(nis_name) = 22; + + /* Remove a Directory */ + nis_error NIS_RMDIR(nis_name) = 23; + + /* Update public keys of a directory object */ + nis_error NIS_UPDKEYS(nis_name) = 24; + } = 3; +} = 100300; + +/* + * Included below are the defines that become part of nis.h, + * they are technically not part of the protocol, but do define + * key aspects of the implementation and are therefore useful + * in building a conforming server or client. + */ +#if RPC_HDR +%/* +% * Generic "hash" datastructures, used by all types of hashed data. +% */ +%struct nis_hash_data { +% nis_name name; /* NIS name of hashed item */ +% int keychain; /* It's hash key (for pop) */ +% struct nis_hash_data *next; /* Hash collision pointer */ +% struct nis_hash_data *prv_item; /* A serial, doubly linked list */ +% struct nis_hash_data *nxt_item; /* of items in the hash table */ +%}; +%typedef struct nis_hash_data NIS_HASH_ITEM; +% +%struct nis_hash_table { +% NIS_HASH_ITEM *keys[64]; /* A hash table of items */ +% NIS_HASH_ITEM *first; /* The first "item" in serial list */ +%}; +%typedef struct nis_hash_table NIS_HASH_TABLE; +% +%/* Structure for storing dynamically allocated static data */ +%struct nis_sdata { +% void *buf; /* Memory allocation pointer */ +% u_int size; /* Buffer size */ +%}; +% +%/* Generic client creating flags */ +%#define ZMH_VC 1 +%#define ZMH_DG 2 +%#define ZMH_AUTH 4 +% +%/* Testing Access rights for objects */ +% +%#define NIS_READ_ACC 1 +%#define NIS_MODIFY_ACC 2 +%#define NIS_CREATE_ACC 4 +%#define NIS_DESTROY_ACC 8 +%/* Test macros. a == access rights, m == desired rights. */ +%#define NIS_WORLD(a, m) (((a) & (m)) != 0) +%#define NIS_GROUP(a, m) (((a) & ((m) << 8)) != 0) +%#define NIS_OWNER(a, m) (((a) & ((m) << 16)) != 0) +%#define NIS_NOBODY(a, m) (((a) & ((m) << 24)) != 0) +%/* +% * EOL Alert - The following non-prefixed test macros are +% * here for backward compatability, and will be not be present +% * in future releases - use the NIS_*() macros above. +% */ +%#define WORLD(a, m) (((a) & (m)) != 0) +%#define GROUP(a, m) (((a) & ((m) << 8)) != 0) +%#define OWNER(a, m) (((a) & ((m) << 16)) != 0) +%#define NOBODY(a, m) (((a) & ((m) << 24)) != 0) +% +%#define OATYPE(d, n) (((d)->do_armask.do_armask_val+n)->oa_otype) +%#define OARIGHTS(d, n) (((d)->do_armask.do_armask_val+n)->oa_rights) +%#define WORLD_DEFAULT (NIS_READ_ACC) +%#define GROUP_DEFAULT (NIS_READ_ACC << 8) +%#define OWNER_DEFAULT ((NIS_READ_ACC +\ + NIS_MODIFY_ACC +\ + NIS_CREATE_ACC +\ + NIS_DESTROY_ACC) << 16) +%#define DEFAULT_RIGHTS (WORLD_DEFAULT | GROUP_DEFAULT | OWNER_DEFAULT) +% +%/* Result manipulation defines ... */ +%#define NIS_RES_NUMOBJ(x) ((x)->objects.objects_len) +%#define NIS_RES_OBJECT(x) ((x)->objects.objects_val) +%#define NIS_RES_COOKIE(x) ((x)->cookie) +%#define NIS_RES_STATUS(x) ((x)->status) +% +%/* These defines make getting at the variant part of the object easier. */ +%#define TA_data zo_data.objdata_u.ta_data +%#define EN_data zo_data.objdata_u.en_data +%#define DI_data zo_data.objdata_u.di_data +%#define LI_data zo_data.objdata_u.li_data +%#define GR_data zo_data.objdata_u.gr_data +% +%#define __type_of(o) ((o)->zo_data.zo_type) +% +%/* Declarations for the internal subroutines in nislib.c */ +%enum name_pos {SAME_NAME, HIGHER_NAME, LOWER_NAME, NOT_SEQUENTIAL, BAD_NAME}; +%typedef enum name_pos name_pos; +% +%/* +% * Defines for getting at column data in entry objects. Because RPCGEN +% * generates some rather wordy structures, we create some defines that +% * collapse the needed keystrokes to access a particular value using +% * these definitions they take an nis_object *, and an int and return +% * a u_char * for Value, and an int for length. +% */ +%#define ENTRY_VAL(obj, col) \ +% (obj)->EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val +%#define ENTRY_LEN(obj, col) \ +% (obj)->EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len +% +% +% +%#ifdef __cplusplus +%} +%#endif +% +%/* Prototypes, and extern declarations for the NIS library functions. */ +%#include <rpcsvc/nislib.h> +%#endif /* __NIS_RPCGEN_H */ +%/* EDIT_START */ +% +%/* +% * nis_3.h +% * +% * This file contains definitions that are only of interest to the actual +% * service daemon and client stubs. Normal users of NIS will not include +% * this file. +% * +% * NOTE : This include file is automatically created by a combination +% * of rpcgen and sed. DO NOT EDIT IT, change the nis.x file instead +% * and then remake this file. +% */ +%#ifndef __nis_3_h +%#define __nis_3_h +%#ifdef __cplusplus +%extern "C" { +%#endif +#endif diff --git a/REORG.TODO/nis/rpcsvc/nis_callback.h b/REORG.TODO/nis/rpcsvc/nis_callback.h new file mode 100644 index 0000000000..6f05728e2a --- /dev/null +++ b/REORG.TODO/nis/rpcsvc/nis_callback.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2010, Oracle America, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the "Oracle America, Inc." 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 COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER 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. + */ +#ifndef _RPCSVC_NIS_CALLBACK_H +#define _RPCSVC_NIS_CALLBACK_H 1 + +#include <rpc/rpc.h> +#include <rpcsvc/nis.h> + +__BEGIN_DECLS + +typedef nis_object *obj_p; + +struct cback_data { + struct { + u_int entries_len; + obj_p *entries_val; + } entries; +}; +typedef struct cback_data cback_data; + +#define CB_PROG 100302 +#define CB_VERS 1 + +#define CBPROC_RECEIVE 1 +extern bool_t * cbproc_receive_1 (cback_data *, CLIENT *) __THROW; +extern bool_t * cbproc_receive_1_svc (cback_data *, struct svc_req *) __THROW; + +#define CBPROC_FINISH 2 +extern void * cbproc_finish_1 (void *, CLIENT *) __THROW; +extern void * cbproc_finish_1_svc (void *, struct svc_req *) __THROW; + +#define CBPROC_ERROR 3 +extern void * cbproc_error_1 (nis_error *, CLIENT *) __THROW; +extern void * cbproc_error_1_svc (nis_error *, struct svc_req *) __THROW; +extern int cb_prog_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t) __THROW; + +/* the xdr functions */ + +extern bool_t xdr_obj_p (XDR *, obj_p*) __THROW; +extern bool_t xdr_cback_data (XDR *, cback_data*) __THROW; + +__END_DECLS + +#endif /* !_RPCVSC_NIS_CALLBACK_H */ diff --git a/REORG.TODO/nis/rpcsvc/nis_callback.x b/REORG.TODO/nis/rpcsvc/nis_callback.x new file mode 100644 index 0000000000..0fdca9eeec --- /dev/null +++ b/REORG.TODO/nis/rpcsvc/nis_callback.x @@ -0,0 +1,63 @@ +%/* +% * Copyright (c) 2010, Oracle America, Inc. +% * +% * Redistribution and use in source and binary forms, with or without +% * modification, are permitted provided that the following conditions are +% * met: +% * +% * * Redistributions of source code must retain the above copyright +% * notice, this list of conditions and the following disclaimer. +% * * 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. +% * * Neither the name of the "Oracle America, Inc." 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 COPYRIGHT HOLDERS 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 +% * COPYRIGHT HOLDER 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. +% */ + +/* + * nis_callback.x + */ + +%#pragma ident "@(#)nis_callback.x 1.7 94/05/03" + +/* + * "@(#)zns_cback.x 1.2 90/09/10" + * + * RPCL description of the Callback Service. + */ + +#ifdef RPC_HDR +%#include <rpcsvc/nis.h> +#endif +#ifdef RPC_XDR +%#include "nis_clnt.h" +#endif + +typedef nis_object *obj_p; + +struct cback_data { + obj_p entries<>; /* List of objects */ +}; + +program CB_PROG { + version CB_VERS { + bool CBPROC_RECEIVE(cback_data) = 1; + void CBPROC_FINISH(void) = 2; + void CBPROC_ERROR(nis_error) = 3; + } = 1; +} = 100302; diff --git a/REORG.TODO/nis/rpcsvc/nis_object.x b/REORG.TODO/nis/rpcsvc/nis_object.x new file mode 100644 index 0000000000..774b38fa9c --- /dev/null +++ b/REORG.TODO/nis/rpcsvc/nis_object.x @@ -0,0 +1,328 @@ +/* + * nis_object.x + * + * Copyright (c) 2010, Oracle America, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the "Oracle America, Inc." 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 COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER 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. + */ + +%#pragma ident "@(#)nis_object.x 1.12 97/11/19" + +#if RPC_HDR +% +%#ifndef __nis_object_h +%#define __nis_object_h +% +#endif +/* + * This file defines the format for a NIS object in RPC language. + * It is included by the main .x file and the database access protocol + * file. It is common because both of them need to deal with the same + * type of object. Generating the actual code though is a bit messy because + * the nis.x file and the nis_dba.x file will generate xdr routines to + * encode/decode objects when only one set is needed. Such is life when + * one is using rpcgen. + * + * Note, the protocol doesn't specify any limits on such things as + * maximum name length, number of attributes, etc. These are enforced + * by the database backend. When you hit them you will no. Also see + * the db_getlimits() function for fetching the limit values. + * + */ + +/* Some manifest constants, chosen to maximize flexibility without + * plugging the wire full of data. + */ +const NIS_MAXSTRINGLEN = 255; +const NIS_MAXNAMELEN = 1024; +const NIS_MAXATTRNAME = 32; +const NIS_MAXATTRVAL = 2048; +const NIS_MAXCOLUMNS = 64; +const NIS_MAXATTR = 16; +const NIS_MAXPATH = 1024; +const NIS_MAXREPLICAS = 128; +const NIS_MAXLINKS = 16; + +const NIS_PK_NONE = 0; /* no public key (unix/sys auth) */ +const NIS_PK_DH = 1; /* Public key is Diffie-Hellman type */ +const NIS_PK_RSA = 2; /* Public key if RSA type */ +const NIS_PK_KERB = 3; /* Use kerberos style authentication */ +const NIS_PK_DHEXT = 4; /* Extended Diffie-Hellman for RPC-GSS */ + +/* + * The fundamental name type of NIS. The name may consist of two parts, + * the first being the fully qualified name, and the second being an + * optional set of attribute/value pairs. + */ +struct nis_attr { + string zattr_ndx<>; /* name of the index */ + opaque zattr_val<>; /* Value for the attribute. */ +}; + +typedef string nis_name<>; /* The NIS name itself. */ + +/* NIS object types are defined by the following enumeration. The numbers + * they use are based on the following scheme : + * 0 - 1023 are reserved for Sun, + * 1024 - 2047 are defined to be private to a particular tree. + * 2048 - 4095 are defined to be user defined. + * 4096 - ... are reserved for future use. + * + * EOL Alert - The non-prefixed names are present for backward + * compatability only, and will not exist in future releases. Use + * the NIS_* names for future compatability. + */ + +enum zotypes { + + BOGUS_OBJ = 0, /* Uninitialized object structure */ + NO_OBJ = 1, /* NULL object (no data) */ + DIRECTORY_OBJ = 2, /* Directory object describing domain */ + GROUP_OBJ = 3, /* Group object (a list of names) */ + TABLE_OBJ = 4, /* Table object (a database schema) */ + ENTRY_OBJ = 5, /* Entry object (a database record) */ + LINK_OBJ = 6, /* A name link. */ + PRIVATE_OBJ = 7, /* Private object (all opaque data) */ + + NIS_BOGUS_OBJ = 0, /* Uninitialized object structure */ + NIS_NO_OBJ = 1, /* NULL object (no data) */ + NIS_DIRECTORY_OBJ = 2, /* Directory object describing domain */ + NIS_GROUP_OBJ = 3, /* Group object (a list of names) */ + NIS_TABLE_OBJ = 4, /* Table object (a database schema) */ + NIS_ENTRY_OBJ = 5, /* Entry object (a database record) */ + NIS_LINK_OBJ = 6, /* A name link. */ + NIS_PRIVATE_OBJ = 7 /* Private object (all opaque data) */ +}; + +/* + * The types of Name services NIS knows about. They are enumerated + * here. The Binder code will use this type to determine if it has + * a set of library routines that will access the indicated name service. + */ +enum nstype { + UNKNOWN = 0, + NIS = 1, /* Nis Plus Service */ + SUNYP = 2, /* Old NIS Service */ + IVY = 3, /* Nis Plus Plus Service */ + DNS = 4, /* Domain Name Service */ + X500 = 5, /* ISO/CCCIT X.500 Service */ + DNANS = 6, /* Digital DECNet Name Service */ + XCHS = 7, /* Xerox ClearingHouse Service */ + CDS= 8 +}; + +/* + * DIRECTORY - The name service object. These objects identify other name + * servers that are serving some portion of the name space. Each has a + * type associated with it. The resolver library will note whether or not + * is has the needed routines to access that type of service. + * The oarmask structure defines an access rights mask on a per object + * type basis for the name spaces. The only bits currently used are + * create and destroy. By enabling or disabling these access rights for + * a specific object type for a one of the accessor entities (owner, + * group, world) the administrator can control what types of objects + * may be freely added to the name space and which require the + * administrator's approval. + */ +struct oar_mask { + uint32_t oa_rights; /* Access rights mask */ + zotypes oa_otype; /* Object type */ +}; + +struct endpoint { + string uaddr<>; + string family<>; /* Transport family (INET, OSI, etc) */ + string proto<>; /* Protocol (TCP, UDP, CLNP, etc) */ +}; + +/* + * Note: pkey is a netobj which is limited to 1024 bytes which limits the + * keysize to 8192 bits. This is consider to be a reasonable limit for + * the expected lifetime of this service. + */ +struct nis_server { + nis_name name; /* Principal name of the server */ + endpoint ep<>; /* Universal addr(s) for server */ + uint32_t key_type; /* Public key type */ + netobj pkey; /* server's public key */ +}; + +struct directory_obj { + nis_name do_name; /* Name of the directory being served */ + nstype do_type; /* one of NIS, DNS, IVY, YP, or X.500 */ + nis_server do_servers<>; /* <0> == Primary name server */ + uint32_t do_ttl; /* Time To Live (for caches) */ + oar_mask do_armask<>; /* Create/Destroy rights by object type */ +}; + +/* + * ENTRY - This is one row of data from an information base. + * The type value is used by the client library to convert the entry to + * it's internal structure representation. The Table name is a back pointer + * to the table where the entry is stored. This allows the client library + * to determine where to send a request if the client wishes to change this + * entry but got to it through a LINK rather than directly. + * If the entry is a "standalone" entry then this field is void. + */ +const EN_BINARY = 1; /* Indicates value is binary data */ +const EN_CRYPT = 2; /* Indicates the value is encrypted */ +const EN_XDR = 4; /* Indicates the value is XDR encoded */ +const EN_MODIFIED = 8; /* Indicates entry is modified. */ +const EN_ASN1 = 64; /* Means contents use ASN.1 encoding */ + +struct entry_col { + uint32_t ec_flags; /* Flags for this value */ + opaque ec_value<>; /* It's textual value */ +}; + +struct entry_obj { + string en_type<>; /* Type of entry such as "passwd" */ + entry_col en_cols<>; /* Value for the entry */ +}; + +/* + * GROUP - The group object contains a list of NIS principal names. Groups + * are used to authorize principals. Each object has a set of access rights + * for members of its group. Principal names in groups are in the form + * name.directory and recursive groups are expressed as @groupname.directory + */ +struct group_obj { + uint32_t gr_flags; /* Flags controlling group */ + nis_name gr_members<>; /* List of names in group */ +}; + +/* + * LINK - This is the LINK object. It is quite similar to a symbolic link + * in the UNIX filesystem. The attributes in the main object structure are + * relative to the LINK data and not what it points to (like the file system) + * "modify" privleges here indicate the right to modify what the link points + * at and not to modify that actual object pointed to by the link. + */ +struct link_obj { + zotypes li_rtype; /* Real type of the object */ + nis_attr li_attrs<>; /* Attribute/Values for tables */ + nis_name li_name; /* The object's real NIS name */ +}; + +/* + * TABLE - This is the table object. It implements a simple + * data base that applications and use for configuration or + * administration purposes. The role of the table is to group together + * a set of related entries. Tables are the simple database component + * of NIS. Like many databases, tables are logically divided into columns + * and rows. The columns are labeled with indexes and each ENTRY makes + * up a row. Rows may be addressed within the table by selecting one + * or more indexes, and values for those indexes. Each row which has + * a value for the given index that matches the desired value is returned. + * Within the definition of each column there is a flags variable, this + * variable contains flags which determine whether or not the column is + * searchable, contains binary data, and access rights for the entry objects + * column value. + */ + +const TA_BINARY = 1; /* Means table data is binary */ +const TA_CRYPT = 2; /* Means value should be encrypted */ +const TA_XDR = 4; /* Means value is XDR encoded */ +const TA_SEARCHABLE = 8; /* Means this column is searchable */ +const TA_CASE = 16; /* Means this column is Case Sensitive */ +const TA_MODIFIED = 32; /* Means this columns attrs are modified*/ +const TA_ASN1 = 64; /* Means contents use ASN.1 encoding */ + +struct table_col { + string tc_name<64>; /* Column Name */ + uint32_t tc_flags; /* control flags */ + uint32_t tc_rights; /* Access rights mask */ +}; + +struct table_obj { + string ta_type<64>; /* Table type such as "passwd" */ + int ta_maxcol; /* Total number of columns */ + u_char ta_sep; /* Separator character */ + table_col ta_cols<>; /* The number of table indexes */ + string ta_path<>; /* A search path for this table */ +}; + +/* + * This union joins together all of the currently known objects. + */ +union objdata switch (zotypes zo_type) { + case NIS_DIRECTORY_OBJ : + struct directory_obj di_data; + case NIS_GROUP_OBJ : + struct group_obj gr_data; + case NIS_TABLE_OBJ : + struct table_obj ta_data; + case NIS_ENTRY_OBJ: + struct entry_obj en_data; + case NIS_LINK_OBJ : + struct link_obj li_data; + case NIS_PRIVATE_OBJ : + opaque po_data<>; + case NIS_NO_OBJ : + void; + case NIS_BOGUS_OBJ : + void; + default : + void; +}; + +/* + * This is the basic NIS object data type. It consists of a generic part + * which all objects contain, and a specialized part which varies depending + * on the type of the object. All of the specialized sections have been + * described above. You might have wondered why they all start with an + * integer size, followed by the useful data. The answer is, when the + * server doesn't recognize the type returned it treats it as opaque data. + * And the definition for opaque data is {int size; char *data;}. In this + * way, servers and utility routines that do not understand a given type + * may still pass it around. One has to be careful in setting + * this variable accurately, it must take into account such things as + * XDR padding of structures etc. The best way to set it is to note one's + * position in the XDR encoding stream, encode the structure, look at the + * new position and calculate the size. + */ +struct nis_oid { + uint32_t ctime; /* Time of objects creation */ + uint32_t mtime; /* Time of objects modification */ +}; + +struct nis_object { + nis_oid zo_oid; /* object identity verifier. */ + nis_name zo_name; /* The NIS name for this object */ + nis_name zo_owner; /* NIS name of object owner. */ + nis_name zo_group; /* NIS name of access group. */ + nis_name zo_domain; /* The administrator for the object */ + uint32_t zo_access; /* Access rights (owner, group, world) */ + uint32_t zo_ttl; /* Object's time to live in seconds. */ + objdata zo_data; /* Data structure for this type */ +}; +#if RPC_HDR +% +%#endif /* if __nis_object_h */ +% +#endif diff --git a/REORG.TODO/nis/rpcsvc/nis_tags.h b/REORG.TODO/nis/rpcsvc/nis_tags.h new file mode 100644 index 0000000000..c2dc7fd269 --- /dev/null +++ b/REORG.TODO/nis/rpcsvc/nis_tags.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2010, Oracle America, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the "Oracle America, Inc." 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 COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER 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. + */ + +/* + * nis_tags.h + * + * This file contains the tags and statistics definitions. It is + * automatically included by nis.h + */ + +#ifndef _RPCSVC_NIS_TAGS_H +#define _RPCSVC_NIS_TAGS_H + +#if 0 +#pragma ident "@(#)nis_tags.h 1.16 96/10/25" +#endif +/* from file: zns_tags.h 1.7 */ + +#ifdef __cplusplus +extern "C" { +#endif + + +#define NIS_DIR "data" + +/* Lookup and List function flags */ +#define FOLLOW_LINKS (1<<0) /* Follow link objects */ +#define FOLLOW_PATH (1<<1) /* Follow the path in a table */ +#define HARD_LOOKUP (1<<2) /* Block until successful */ +#define ALL_RESULTS (1<<3) /* Retrieve all results */ +#define NO_CACHE (1<<4) /* Do not return 'cached' results */ +#define MASTER_ONLY (1<<5) /* Get value only from master server */ +#define EXPAND_NAME (1<<6) /* Expand partitially qualified names */ + +/* Semantic modification for table operations flags */ +#define RETURN_RESULT (1<<7) /* Return resulting object to client */ +#define ADD_OVERWRITE (1<<8) /* Allow overwrites on ADD */ +#define REM_MULTIPLE (1<<9) /* Allow wildcard deletes */ +#define MOD_SAMEOBJ (1<<10) /* Check modified object before write */ +#define ADD_RESERVED (1<<11) /* Spare ADD semantic */ +#define REM_RESERVED (1<<12) /* Spare REM semantic */ +#define MOD_EXCLUSIVE (1<<13) /* Modify no overwrite on modified keys */ + +/* Lookup and List function flags (continued) */ +#define SOFT_LOOKUP (1<<14) /* The "old default" return on failure */ + +/* Transport specific modifications to the operation */ +#define USE_DGRAM (1<<16) /* Use a datagram transport */ +#define NO_AUTHINFO (1<<17) /* Don't bother attaching auth info */ + +/* + * Declarations for "standard" NIS+ tags + * State variable tags have values 0 - 2047 + * Statistic tags have values 2048 - 65535 + * User Tags have values >2^16 + */ +#define TAG_DEBUG 1 /* set debug level */ +#define TAG_STATS 2 /* Enable/disable statistics */ +#define TAG_GCACHE 3 /* Flush the Group Cache */ +#define TAG_GCACHE_ALL TAG_GCACHE +#define TAG_DCACHE 4 /* Flush the directory cache */ +#define TAG_DCACHE_ONE TAG_DCACHE +#define TAG_OCACHE 5 /* Flush the Object Cache */ +#define TAG_SECURE 6 /* Set the security level */ +#define TAG_TCACHE_ONE 7 /* Flush the table cache */ +#define TAG_DCACHE_ALL 8 /* Flush entire directory cache */ +#define TAG_TCACHE_ALL 9 /* Flush entire table cache */ +#define TAG_GCACHE_ONE 10 /* Flush one group object */ +#define TAG_DCACHE_ONE_REFRESH 11 /* Flush and refresh one DO */ +#define TAG_READONLY 12 /* Set read only mode */ +#define TAG_READWRITE 14 /* Reset read-write mode */ + +#define TAG_OPSTATS 2048 /* NIS+ operations statistics */ +#define TAG_THREADS 2049 /* Child process/thread status */ +#define TAG_HEAP 2050 /* Heap usage statistics */ +#define TAG_UPDATES 2051 /* Updates to this service */ +#define TAG_VISIBLE 2052 /* First update that isn't replicated */ +#define TAG_S_DCACHE 2053 /* Directory cache statistics */ +#define TAG_S_OCACHE 2054 /* Object cache statistics */ +#define TAG_S_GCACHE 2055 /* Group cache statistics */ +#define TAG_S_STORAGE 2056 /* Group cache statistics */ +#define TAG_UPTIME 2057 /* Time that server has been up */ +#define TAG_DIRLIST 2058 /* Dir served by this server */ +#define TAG_NISCOMPAT 2059 /* Whether supports NIS compat mode */ +#define TAG_DNSFORWARDING 2060 /* Whether DNS forwarding supported */ +#define TAG_SECURITY_LEVEL 2061 /* Security level of the server */ +#define TAG_ROOTSERVER 2062 /* Whether root server */ + +/* + * Declarations for the Group object flags. Currently + * there are only 3. + */ +#define IMPMEM_GROUPS 1 /* Implicit Membership allowed */ +#define RECURS_GROUPS 2 /* Recursive Groups allowed */ +#define NEGMEM_GROUPS 4 /* Negative Groups allowed */ + +#ifdef __cplusplus +} +#endif + +#endif /* _RPCSVC_NIS_TAGS_H */ diff --git a/REORG.TODO/nis/rpcsvc/nislib.h b/REORG.TODO/nis/rpcsvc/nislib.h new file mode 100644 index 0000000000..52fbba4b8f --- /dev/null +++ b/REORG.TODO/nis/rpcsvc/nislib.h @@ -0,0 +1,286 @@ +/* Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef __RPCSVC_NISLIB_H__ +#define __RPCSVC_NISLIB_H__ + +#include <rpcsvc/nis.h> + +__BEGIN_DECLS + +typedef const char *const_nis_name; + +/* nis_names: These functions are used to locate and manipulate all NIS+ + * objects except the NIS+ entry objects. + * + * nis_lookup (name, flags) resolves a NIS+ name and returns a copy of + * that object from a NIS+ server. + * const nis_name name: name of the object to be resolved + * unsigned int flags: logically ORing zero or more flags (FOLLOW_LINKS, + * HARD_LOOKUP, [NO_CACHE], MASTER_ONLY, EXPAND_NAME) + * + * nis_add (name, obj) adds objects to the NIS+ namespace. + * const nis_name name: fully qualified NIS+ name. + * const nis_object *obj: object members zo_name and zo_domain will be + * constructed from name. + * + * nis_remove (name, obj) removes objects from the NIS+ namespace. + * const nis_name name: fully qualified NIS+ name. + * const nis_object *obj: if not NULL, it is assumed to point to a copy + * of the object being removed. In this case, if + * the object on the server does not have the same + * object identifier as the object being passed, + * the operation will fail with the NIS_NOTSAMEOBJ + * error. + * + * nis_modify (name, obj) can change specific attributes of an object + * that already exists in the namespace. + */ +extern nis_result *nis_lookup (const_nis_name name, unsigned int flags) + __THROW; +extern nis_result *nis_add (const_nis_name name, const nis_object *obj) + __THROW; +extern nis_result *nis_remove (const_nis_name name, + const nis_object *obj) __THROW; +extern nis_result *nis_modify (const_nis_name name, + const nis_object *obj) __THROW; + +/* nis_tables: These functions are used to search and modify NIS+ tables. + * + * nis_list (table_name, flags, callback(table_name, obj, userdata), userdata) + * search a table in the NIS+ namespace. + * const nis_name table_name: indexed name ([xx=yy],table.dir) + * unsigned int flags: logically ORing one or more flags (FOLLOW_LINKS, + * [FOLLOW_PATH], HARD_LOOKUP, [ALL_RESULTS], [NO_CACHE], + * MASTER_ONLY, EXPAND_NAME, RETURN_RESULT) + * callback(): callback is an optional pointer to a function that will + * process the ENTRY type objects that are returned from the + * search. If this pointer is NULL, then all entries that match + * the search criteria are returned in the nis_result structure, + * otherwise this function will be called once for each + * entry returned. + * void *userdata: passed to callback function along with the returned + * entry object. + * + * nis_add_entry (table_name, obj, flags) will add the NIS+ object to the + * NIS+ table_name. + * const nis_name table_name + * const nis_object *obj + * unsigned int flags: 0, ADD_OVERWRITE, RETURN_RESULT + * + * nis_modify_entry (name, obj, flags) modifies an object identified by name. + * const nis_name name: object identifier + * const nis_object *obj: should point to an entry with the EN_MODIFIED + * flag set in each column that contains new + * information. + * unsigned int flags: 0, MOD_SAMEOBJ, RETURN_RESULT + * + * nis_remove_entry (table_name, obj, flags) removes a set of entries + * identified by table_name from the table. + * const nis_name table_name: indexed NIS+ name + * const nis_object *obj: if obj is non-null, it is presumed to point to + * a cached copy of the entry. When the removal is + * attempted, and the object that would be removed + * is not the same as the cached object pointed to + * by object then the operation will fail with an + * NIS_NOTSAMEOBJ error + * unsigned int flags: 0, REM_MULTIPLE + * + * nis_first_entry (table_name) fetches entries from a table one at a time. + * const nis_name table_name + * + * nis_next_entry (table_name, cookie) retrieves the "next" entry from a + * table specified by table_name. + * const nis_name table_name: + * const netobj *cookie: The value of cookie from the nis_result structure + * form the previous call. + */ +extern nis_result *nis_list (const_nis_name __name, unsigned int __flags, + int (*__callback)(const_nis_name __table_name, + const nis_object *__obj, + const void *__userdata), + const void *__userdata) __THROW; +extern nis_result *nis_add_entry (const_nis_name __table_name, + const nis_object *__obj, + unsigned int __flags) __THROW; +extern nis_result *nis_modify_entry (const_nis_name __name, + const nis_object *__obj, + unsigned int __flags) __THROW; +extern nis_result *nis_remove_entry (const_nis_name __table_name, + const nis_object *__obj, + unsigned int __flags) __THROW; +extern nis_result *nis_first_entry (const_nis_name __table_name) __THROW; +extern nis_result *nis_next_entry (const_nis_name __table_name, + const netobj *__cookie) __THROW; +/* +** nis_server +*/ +extern nis_error nis_mkdir (const_nis_name __dirname, + const nis_server *__machine) __THROW; +extern nis_error nis_rmdir (const_nis_name __dirname, + const nis_server *__machine) __THROW; +extern nis_error nis_servstate (const nis_server *__machine, + const nis_tag *__tags, int __numtags, + nis_tag **__result) __THROW; +extern nis_error nis_stats (const nis_server *__machine, + const nis_tag *__tags, int __numtags, + nis_tag **__result) __THROW; +extern void nis_freetags (nis_tag *__tags, int __numtags) __THROW; +extern nis_server **nis_getservlist (const_nis_name __dirname) __THROW; +extern void nis_freeservlist (nis_server **__machines) __THROW; + +/* +** nis_subr +*/ +extern nis_name nis_leaf_of (const_nis_name __name) __THROW; +extern nis_name nis_leaf_of_r (const_nis_name __name, char *__buffer, + size_t __buflen) __THROW; +extern nis_name nis_name_of (const_nis_name __name) __THROW; +extern nis_name nis_name_of_r (const_nis_name __name, char *__buffer, + size_t __buflen) __THROW; +extern nis_name nis_domain_of (const_nis_name __name) __THROW; +extern nis_name nis_domain_of_r (const_nis_name __name, char *__buffer, + size_t __buflen) __THROW; +extern nis_name *nis_getnames (const_nis_name __name) __THROW; +extern void nis_freenames (nis_name *__namelist) __THROW; +extern name_pos nis_dir_cmp (const_nis_name __n1, const_nis_name __n2) __THROW; +extern nis_object *nis_clone_object (const nis_object *__src, + nis_object *__dest) __THROW; +extern void nis_destroy_object (nis_object *__obj) __THROW; +extern void nis_print_object (const nis_object *__obj) __THROW; + +/* +** nis_local_names +*/ +extern nis_name nis_local_group (void) __THROW; +extern nis_name nis_local_directory (void) __THROW; +extern nis_name nis_local_principal (void) __THROW; +extern nis_name nis_local_host (void) __THROW; + +/* +** nis_error +*/ +extern const char *nis_sperrno (const nis_error __status) __THROW; +extern void nis_perror (const nis_error __status, const char *__label) __THROW; +extern void nis_lerror (const nis_error __status, const char *__label) __THROW; +extern char *nis_sperror (const nis_error status, const char *__label) __THROW; +extern char *nis_sperror_r (const nis_error __status, const char *__label, + char *__buffer, size_t __buflen) __THROW; +/* +** nis_groups +*/ +extern bool_t nis_ismember (const_nis_name __principal, + const_nis_name __group) __THROW; +extern nis_error nis_addmember (const_nis_name __member, + const_nis_name __group) __THROW; +extern nis_error nis_removemember (const_nis_name __member, + const_nis_name __group) __THROW; +extern nis_error nis_creategroup (const_nis_name __group, + unsigned int __flags) __THROW; +extern nis_error nis_destroygroup (const_nis_name __group) __THROW; +extern void nis_print_group_entry (const_nis_name __group) __THROW; +extern nis_error nis_verifygroup (const_nis_name __group) __THROW; + +/* +** nis_ping +*/ +extern void nis_ping (const_nis_name __dirname, uint32_t __utime, + const nis_object *__dirobj) __THROW; +extern nis_result *nis_checkpoint (const_nis_name __dirname) __THROW; + +/* +** nis_print (XXX INTERNAL FUNCTIONS, SHOULD NOT BE USED !!) +*/ +extern void nis_print_result (const nis_result *__result) __THROW; +extern void nis_print_rights (unsigned int __rights) __THROW; +extern void nis_print_directory (const directory_obj *__dirobj) __THROW; +extern void nis_print_group (const group_obj *__grpobj) __THROW; +extern void nis_print_table (const table_obj *__tblobj) __THROW; +extern void nis_print_link (const link_obj *__lnkobj) __THROW; +extern void nis_print_entry (const entry_obj *__enobj) __THROW; + +/* +** nis_file (XXX INTERNAL FUNCTIONS, SHOULD NOT BE USED !!) +*/ +extern directory_obj *readColdStartFile (void) __THROW; +extern bool_t writeColdStartFile (const directory_obj *__dirobj) __THROW; +extern nis_object *nis_read_obj (const char *__obj) __THROW; +extern bool_t nis_write_obj (const char *__file, const nis_object *__obj) __THROW; + +/* +** nis_clone - (XXX INTERNAL FUNCTIONS, SHOULD NOT BE USED !!) +*/ +extern directory_obj *nis_clone_directory (const directory_obj *__src, + directory_obj *__dest) __THROW; +extern nis_result *nis_clone_result (const nis_result *__src, + nis_result *__dest) __THROW; + +/* nis_free - nis_freeresult */ +extern void nis_freeresult (nis_result *__result) __THROW; +/* (XXX THE FOLLOWING ARE INTERNAL FUNCTIONS, SHOULD NOT BE USED !!) */ +extern void nis_free_request (ib_request *__req) __THROW; +extern void nis_free_directory (directory_obj *__dirobj) __THROW; +extern void nis_free_object (nis_object *__obj) __THROW; + +/* (XXX INTERNAL FUNCTIONS, SHOULD NOT BE USED !!) */ +extern nis_name __nis_default_owner (char *) __THROW; +extern nis_name __nis_default_group (char *) __THROW; +extern uint32_t __nis_default_ttl (char *) __THROW; +extern unsigned int __nis_default_access (char *, unsigned int) __THROW; +extern fd_result *__nis_finddirectory (directory_obj *, const_nis_name) __THROW; +extern void __free_fdresult (fd_result *) __THROW; +extern uint32_t __nis_hash (const void *__keyarg, size_t __len) __THROW; + +/* NIS+ cache locking */ +extern int __nis_lock_cache (void) __THROW; +extern int __nis_unlock_cache (void) __THROW; + +/* (XXX INTERNAL FUNCTIONS, ONLY FOR rpc.nisd AND glibc !!) */ +#if defined (NIS_INTERNAL) || defined (_LIBC) + +struct dir_binding +{ + CLIENT *clnt; /* RPC CLIENT handle */ + nis_server *server_val; /* List of servers */ + unsigned int server_len; /* # of servers */ + unsigned int server_used; /* Which server we are bind in the moment ? */ + unsigned int current_ep; /* Which endpoint of the server are in use? */ + unsigned int trys; /* How many server have we tried ? */ + unsigned int class; /* From which class is server_val ? */ + bool_t master_only; /* Is only binded to the master */ + bool_t use_auth; /* Do we use AUTH ? */ + bool_t use_udp; /* Do we use UDP ? */ + struct sockaddr_in addr; /* Server's IP address */ + int socket; /* Server's local socket */ +}; +typedef struct dir_binding dir_binding; + +extern nis_error __nisbind_create (dir_binding *, const nis_server *, + unsigned int, unsigned int, unsigned int, + unsigned int) __THROW; +extern nis_error __nisbind_connect (dir_binding *) __THROW; +extern nis_error __nisbind_next (dir_binding *) __THROW; +extern void __nisbind_destroy (dir_binding *) __THROW; +extern nis_error __nisfind_server (const_nis_name, int, directory_obj **, + dir_binding *, unsigned int) __THROW; + +#endif + +__END_DECLS + +#endif /* __RPCSVC_NISLIB_H__ */ diff --git a/REORG.TODO/nis/rpcsvc/yp.h b/REORG.TODO/nis/rpcsvc/yp.h new file mode 100644 index 0000000000..968b74c42e --- /dev/null +++ b/REORG.TODO/nis/rpcsvc/yp.h @@ -0,0 +1,339 @@ +/* + * Copyright (c) 2010, Oracle America, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the "Oracle America, Inc." 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 COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER 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. + */ + +#ifndef __RPCSVC_YP_H__ +#define __RPCSVC_YP_H__ + +#include <features.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; + +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; + +typedef char *domainname; +typedef char *mapname; +typedef char *peername; + +typedef struct { + u_int keydat_len; + char *keydat_val; +} keydat; + +typedef struct { + u_int valdat_len; + char *valdat_val; +} valdat; + +struct ypmap_parms { + domainname domain; + mapname map; + u_int ordernum; + peername peer; +}; +typedef struct ypmap_parms ypmap_parms; + +struct ypreq_key { + domainname domain; + mapname map; + keydat key; +}; +typedef struct ypreq_key ypreq_key; + +struct ypreq_nokey { + domainname domain; + mapname map; +}; +typedef struct ypreq_nokey ypreq_nokey; + +struct ypreq_xfr { + ypmap_parms map_parms; + u_int transid; + u_int prog; + u_int port; +}; +typedef struct ypreq_xfr ypreq_xfr; + +struct ypresp_val { + ypstat stat; + valdat val; +}; +typedef struct ypresp_val ypresp_val; + +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; + +struct ypresp_master { + ypstat stat; + peername peer; +}; +typedef struct ypresp_master ypresp_master; + +struct ypresp_order { + ypstat stat; + u_int ordernum; +}; +typedef struct ypresp_order ypresp_order; + +struct ypresp_all { + bool_t more; + union { + ypresp_key_val val; + } ypresp_all_u; +}; +typedef struct ypresp_all ypresp_all; + +struct ypresp_xfr { + u_int transid; + ypxfrstat xfrstat; +}; +typedef struct ypresp_xfr ypresp_xfr; + +struct ypmaplist { + mapname map; + struct ypmaplist *next; +}; +typedef struct ypmaplist ypmaplist; + +struct ypresp_maplist { + ypstat stat; + ypmaplist *maps; +}; +typedef struct ypresp_maplist ypresp_maplist; + +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; + +struct yppushresp_xfr { + u_int transid; + yppush_status status; +}; +typedef struct yppushresp_xfr yppushresp_xfr; + +enum ypbind_resptype { + YPBIND_SUCC_VAL = 1, + YPBIND_FAIL_VAL = 2, +}; +typedef enum ypbind_resptype ypbind_resptype; + +struct ypbind_binding { + char ypbind_binding_addr[4]; + char ypbind_binding_port[2]; +}; +typedef struct ypbind_binding ypbind_binding; + +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; + +#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; + +__BEGIN_DECLS + +#define YPPROG 100004 +#define YPVERS 2 + +#define YPPROC_NULL 0 +extern void *ypproc_null_2 (void *, CLIENT *); +extern void *ypproc_null_2_svc (void *, struct svc_req *); +#define YPPROC_DOMAIN 1 +extern bool_t *ypproc_domain_2 (domainname *, CLIENT *); +extern bool_t *ypproc_domain_2_svc (domainname *, struct svc_req *); +#define YPPROC_DOMAIN_NONACK 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 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 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 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 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 7 +extern void *ypproc_clear_2 (void *, CLIENT *); +extern void *ypproc_clear_2_svc (void *, struct svc_req *); +#define YPPROC_ALL 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 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 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 11 +extern ypresp_maplist *ypproc_maplist_2 (domainname *, CLIENT *); +extern ypresp_maplist *ypproc_maplist_2_svc (domainname *, struct svc_req *); +extern int ypprog_2_freeresult (SVCXPRT *, xdrproc_t, caddr_t); + + +#define YPPUSH_XFRRESPPROG (0x40000000) +#define YPPUSH_XFRRESPVERS 1 + +#define YPPUSHPROC_NULL 0 +extern void *yppushproc_null_1 (void *, CLIENT *); +extern void *yppushproc_null_1_svc (void *, struct svc_req *); +#define YPPUSHPROC_XFRRESP 1 +extern void *yppushproc_xfrresp_1 (yppushresp_xfr *, CLIENT *); +extern void *yppushproc_xfrresp_1_svc (yppushresp_xfr *, struct svc_req *); +extern int yppush_xfrrespprog_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t); + + +#define YPBINDPROG 100007 +#define YPBINDVERS 2 + +#define YPBINDPROC_NULL 0 +extern void *ypbindproc_null_2 (void *, CLIENT *); +extern void *ypbindproc_null_2_svc (void *, struct svc_req *); +#define YPBINDPROC_DOMAIN 1 +extern ypbind_resp *ypbindproc_domain_2 (domainname *, CLIENT *); +extern ypbind_resp *ypbindproc_domain_2_svc (domainname *, struct svc_req *); +#define YPBINDPROC_SETDOM 2 +extern void *ypbindproc_setdom_2 (ypbind_setdom *, CLIENT *); +extern void *ypbindproc_setdom_2_svc (ypbind_setdom *, struct svc_req *); +extern int ypbindprog_2_freeresult (SVCXPRT *, xdrproc_t, caddr_t); + + +extern bool_t xdr_ypstat (XDR *, ypstat*); +extern bool_t xdr_ypxfrstat (XDR *, ypxfrstat*); +extern bool_t xdr_domainname (XDR *, domainname*); +extern bool_t xdr_mapname (XDR *, mapname*); +extern bool_t xdr_peername (XDR *, peername*); +extern bool_t xdr_keydat (XDR *, keydat*); +extern bool_t xdr_valdat (XDR *, valdat*); +extern bool_t xdr_ypmap_parms (XDR *, ypmap_parms*); +extern bool_t xdr_ypreq_key (XDR *, ypreq_key*); +extern bool_t xdr_ypreq_nokey (XDR *, ypreq_nokey*); +extern bool_t xdr_ypreq_xfr (XDR *, ypreq_xfr*); +extern bool_t xdr_ypresp_val (XDR *, ypresp_val*); +extern bool_t xdr_ypresp_key_val (XDR *, ypresp_key_val*); +extern bool_t xdr_ypresp_master (XDR *, ypresp_master*); +extern bool_t xdr_ypresp_order (XDR *, ypresp_order*); +extern bool_t xdr_ypresp_all (XDR *, ypresp_all*); +extern bool_t xdr_ypresp_xfr (XDR *, ypresp_xfr*); +extern bool_t xdr_ypmaplist (XDR *, ypmaplist*); +extern bool_t xdr_ypresp_maplist (XDR *, ypresp_maplist*); +extern bool_t xdr_yppush_status (XDR *, yppush_status*); +extern bool_t xdr_yppushresp_xfr (XDR *, yppushresp_xfr*); +extern bool_t xdr_ypbind_resptype (XDR *, ypbind_resptype*); +extern bool_t xdr_ypbind_binding (XDR *, ypbind_binding*); +extern bool_t xdr_ypbind_resp (XDR *, ypbind_resp*); +extern bool_t xdr_ypbind_setdom (XDR *, ypbind_setdom*); + +__END_DECLS + +#endif /* !__RPCSVC_YP_H__ */ diff --git a/REORG.TODO/nis/rpcsvc/yp.x b/REORG.TODO/nis/rpcsvc/yp.x new file mode 100644 index 0000000000..269ae6f606 --- /dev/null +++ b/REORG.TODO/nis/rpcsvc/yp.x @@ -0,0 +1,311 @@ +/* @(#)yp.x 2.1 88/08/01 4.0 RPCSRC */ + +/* + * Copyright (c) 2010, Oracle America, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the "Oracle America, Inc." 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 COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER 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. + */ + +/* + * Protocol description file for the Yellow Pages Service + */ + +const YPMAXRECORD = 1024; +const YPMAXDOMAIN = 64; +const YPMAXMAP = 64; +const 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 +}; + + +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 string domainname<YPMAXDOMAIN>; +typedef string mapname<YPMAXMAP>; +typedef string peername<YPMAXPEER>; +typedef opaque keydat<YPMAXRECORD>; +typedef opaque valdat<YPMAXRECORD>; + + +struct ypmap_parms { + domainname domain; + mapname map; + unsigned int ordernum; + peername peer; +}; + +struct ypreq_key { + domainname domain; + mapname map; + keydat key; +}; + +struct ypreq_nokey { + domainname domain; + mapname map; +}; + +struct ypreq_xfr { + ypmap_parms map_parms; + unsigned int transid; + unsigned int prog; + unsigned int port; +}; + + +struct ypresp_val { + ypstat stat; + valdat val; +}; + +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 +}; + + +struct ypresp_master { + ypstat stat; + peername peer; +}; + +struct ypresp_order { + ypstat stat; + unsigned int ordernum; +}; + +union ypresp_all switch (bool more) { +case TRUE: + ypresp_key_val val; +case FALSE: + void; +}; + +struct ypresp_xfr { + unsigned int transid; + ypxfrstat xfrstat; +}; + +struct ypmaplist { + mapname map; + ypmaplist *next; +}; + +struct ypresp_maplist { + ypstat stat; + ypmaplist *maps; +}; + +enum yppush_status { + YPPUSH_SUCC = 1, /* Success */ + YPPUSH_AGE = 2, /* Master's version not newer */ + YPPUSH_NOMAP = -1, /* Can't find server for map */ + YPPUSH_NODOM = -2, /* Domain not supported */ + YPPUSH_RSRC = -3, /* Local resource alloc failure */ + YPPUSH_RPC = -4, /* RPC failure talking to server */ + YPPUSH_MADDR = -5, /* Can't get master address */ + YPPUSH_YPERR = -6, /* YP server/map db error */ + YPPUSH_BADARGS = -7, /* Request arguments bad */ + YPPUSH_DBM = -8, /* Local dbm operation failed */ + YPPUSH_FILE = -9, /* Local file I/O operation failed */ + YPPUSH_SKEW = -10, /* Map version skew during transfer */ + YPPUSH_CLEAR = -11, /* Can't send "Clear" req to local ypserv */ + YPPUSH_FORCE = -12, /* No local order number in map use -f flag. */ + YPPUSH_XFRERR = -13, /* ypxfr error */ + YPPUSH_REFUSED = -14 /* Transfer request refused by ypserv */ +}; + +struct yppushresp_xfr { + unsigned transid; + yppush_status status; +}; + +/* + * Response structure and overall result status codes. Success and failure + * represent two separate response message types. + */ + +enum ypbind_resptype { + YPBIND_SUCC_VAL = 1, + YPBIND_FAIL_VAL = 2 +}; + +struct ypbind_binding { + opaque ypbind_binding_addr[4]; /* In network order */ + opaque ypbind_binding_port[2]; /* In network order */ +}; + +union ypbind_resp switch (ypbind_resptype ypbind_status) { +case YPBIND_FAIL_VAL: + unsigned ypbind_error; +case YPBIND_SUCC_VAL: + ypbind_binding ypbind_bindinfo; +}; + +/* Detailed failure reason codes for response field ypbind_error*/ + +const YPBIND_ERR_ERR = 1; /* Internal error */ +const YPBIND_ERR_NOSERV = 2; /* No bound server for passed domain */ +const YPBIND_ERR_RESC = 3; /* System resource allocation failure */ + + +/* + * Request data structure for ypbind "Set domain" procedure. + */ +struct ypbind_setdom { + domainname ypsetdom_domain; + ypbind_binding ypsetdom_binding; + unsigned ypsetdom_vers; +}; + + +/* + * YP access protocol + */ +program YPPROG { + version YPVERS { + void + YPPROC_NULL(void) = 0; + + bool + YPPROC_DOMAIN(domainname) = 1; + + bool + YPPROC_DOMAIN_NONACK(domainname) = 2; + + ypresp_val + YPPROC_MATCH(ypreq_key) = 3; + + ypresp_key_val + YPPROC_FIRST(ypreq_key) = 4; + + ypresp_key_val + YPPROC_NEXT(ypreq_key) = 5; + + ypresp_xfr + YPPROC_XFR(ypreq_xfr) = 6; + + void + YPPROC_CLEAR(void) = 7; + + ypresp_all + YPPROC_ALL(ypreq_nokey) = 8; + + ypresp_master + YPPROC_MASTER(ypreq_nokey) = 9; + + ypresp_order + YPPROC_ORDER(ypreq_nokey) = 10; + + ypresp_maplist + YPPROC_MAPLIST(domainname) = 11; + } = 2; +} = 100004; + + +/* + * YPPUSHPROC_XFRRESP is the callback routine for result of YPPROC_XFR + */ +program YPPUSH_XFRRESPPROG { + version YPPUSH_XFRRESPVERS { + void + YPPUSHPROC_NULL(void) = 0; + +#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. */ + yppushresp_xfr + YPPUSHPROC_XFRRESP(void) = 1; +#else + void + YPPUSHPROC_XFRRESP(yppushresp_xfr) = 1; +#endif + } = 1; +} = 0x40000000; /* transient: could be anything up to 0x5fffffff */ + +/* + * YP binding protocol + */ +program YPBINDPROG { + version YPBINDVERS { + void + YPBINDPROC_NULL(void) = 0; + + ypbind_resp + YPBINDPROC_DOMAIN(domainname) = 1; + + void + YPBINDPROC_SETDOM(ypbind_setdom) = 2; + } = 2; +} = 100007; diff --git a/REORG.TODO/nis/rpcsvc/yp_prot.h b/REORG.TODO/nis/rpcsvc/yp_prot.h new file mode 100644 index 0000000000..ae0db3688e --- /dev/null +++ b/REORG.TODO/nis/rpcsvc/yp_prot.h @@ -0,0 +1,366 @@ +/* + * This file contains symbols and structures defining the rpc protocol + * between the NIS clients and the NIS servers. The servers + * are the NIS database servers, and the NIS binders. + */ + +#ifndef _RPCSVC_YP_PROT_H +#define _RPCSVC_YP_PROT_H + +#include <features.h> + +#include <rpc/rpc.h> +#include <rpcsvc/ypclnt.h> + +__BEGIN_DECLS + +/* + * The following procedures are supported by the protocol: + * + * YPPROC_NULL() returns () takes nothing, returns nothing. This indicates + * that the NIS server is alive. + * + * YPPROC_DOMAIN (char *) returns (bool_t) TRUE. Indicates that the + * responding NIS server does serve the named domain; FALSE indicates no + * support. + * + * YPPROC_DOMAIN_NONACK (char *) returns (TRUE) if the NIS server does serve + * the named domain, otherwise does not return. Used in the broadcast case. + * + * YPPROC_MATCH (struct ypreq_key) returns (struct ypresp_val). Returns the + * right-hand value for a passed left-hand key, within a named map and + * domain. + * + * YPPROC_FIRST (struct ypreq_nokey) returns (struct ypresp_key_val). + * Returns the first key-value pair from a named domain and map. + * + * YPPROC_NEXT (struct ypreq_key) returns (struct ypresp_key_val). Returns + * the key-value pair following a passed key-value pair within a named + * domain and map. + * + * YPPROC_XFR (struct ypreq_xfr) returns nothing. Indicates to a server that + * a map should be updated. + * + * YPPROC_CLEAR takes nothing, returns nothing. Instructs a NIS server to + * close the current map, so that old versions of the disk file don't get + * held open. + * + * YPPROC_ALL (struct ypreq_nokey), returns + * union switch (bool_t more) { + * TRUE: (struct ypresp_key_val); + * FALSE: (struct) {}; + * } + * + * YPPROC_MASTER (struct ypreq_nokey), returns (ypresp_master) + * + * YPPROC_ORDER (struct ypreq_nokey), returns (ypresp_order) + * + * YPPROC_MAPLIST (char *), returns (struct ypmaplist *) + */ + +/* Program and version symbols, magic numbers */ + +#define YPPROG 100004 +#define YPVERS 2 +#define YPVERS_ORIG 1 +#define YPMAXRECORD 1024 +#define YPMAXDOMAIN 64 /* XXX orig. yp_prot.h defines 256 */ +#define YPMAXMAP 64 +#define YPMAXPEER 64 /* XXX orig. yp_prot.h defines 256 */ + +/* byte size of a large NIS packet */ +#define YPMSGSZ 1600 + +typedef struct { + u_int keydat_len; + char *keydat_val; +} keydat_t; + +typedef struct { + u_int valdat_len; + char *valdat_val; +} valdat_t; + +struct ypmap_parms { + char *domain; /* Null string means not available */ + char *map; /* Null string means not available */ + unsigned int ordernum; /* 0 means not available */ + char *owner; /* Null string means not available */ +}; + +/* + * Request parameter structures + */ + +struct ypreq_key { + const char *domain; + const char *map; + keydat_t keydat; +}; + +struct ypreq_nokey { + char *domain; + char *map; +}; + +struct ypreq_xfr { + struct ypmap_parms map_parms; + u_int transid; + u_int proto; + u_int port; +}; + +#define ypxfr_domain map_parms.domain +#define ypxfr_map map_parms.map +#define ypxfr_ordernum map_parms.ordernum +#define ypxfr_owner map_parms.owner + +/* Return status values */ + +enum ypstat { + YP_TRUE = 1, /* General purpose success code */ +#define YP_TRUE YP_TRUE + YP_NOMORE = 2, /* No more entries in map */ +#define YP_NOMORE YP_NOMORE + YP_FALSE = 0, /* General purpose failure code */ +#define YP_FALSE YP_FALSE + YP_NOMAP = -1, /* No such map in domain */ +#define YP_NOMAP YP_NOMAP + YP_NODOM = -2, /* Domain not supported */ +#define YP_NODOM YP_NODOM + YP_NOKEY = -3, /* No such key in map */ +#define YP_NOKEY YP_NOKEY + YP_BADOP = -4, /* Invalid operation */ +#define YP_BADOP YP_BADOP + YP_BADDB = -5, /* Server data base is bad */ +#define YP_BADDB YP_BADDB + YP_YPERR = -6, /* NIS server error */ +#define YP_YPERR YP_YPERR + YP_BADARGS = -7, /* Request arguments bad */ +#define YP_BADARGS YP_BADARGS + YP_VERS = -8, /* NIS server version mismatch - server can't supply + requested service. */ +#define YP_VERS YP_VERS +}; + +/* + * Response parameter structures + */ + +typedef enum ypstat ypstat; + +struct ypresp_val { + ypstat status; + valdat_t valdat; +}; + +struct ypresp_key_val { + ypstat status; +#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_t keydat; + valdat_t valdat; +#else + valdat_t valdat; + keydat_t keydat; +#endif +}; + +struct ypresp_master { + ypstat status; + char *master; +}; + +struct ypresp_order { + ypstat status; + u_int ordernum; +}; + +struct ypmaplist { + char *map; +#define ypml_name map + struct ypmaplist *next; +#define ypml_next next +}; + +struct ypresp_maplist { + ypstat status; + struct ypmaplist *list; +}; + +/* + * Procedure symbols. YPPROC_NULL, YPPROC_DOMAIN, and YPPROC_DOMAIN_NONACK + * must keep the same values (0, 1, and 2) that they had in the first version + * of the protocol. + */ + +#define YPPROC_NULL 0 +#define YPPROC_DOMAIN 1 +#define YPPROC_DOMAIN_NONACK 2 +#define YPPROC_MATCH 3 +#define YPPROC_FIRST 4 +#define YPPROC_NEXT 5 +#define YPPROC_XFR 6 +#define YPPROC_CLEAR 7 +#define YPPROC_ALL 8 +#define YPPROC_MASTER 9 +#define YPPROC_ORDER 10 +#define YPPROC_MAPLIST 11 +#define YPPROC_NEWXFR 12 + +/* + * Protocol between clients and NIS binder servers + */ + +/* + * The following procedures are supported by the protocol: + * + * YPBINDPROC_NULL() returns () + * takes nothing, returns nothing + * + * YPBINDPROC_DOMAIN takes (char *) returns (struct ypbind_resp) + * + * YPBINDPROC_SETDOM takes (struct ypbind_setdom) returns nothing + */ + +/* Program and version symbols, magic numbers */ + +#define YPBINDPROG 100007 +#define YPBINDVERS 2 +#define YPBINDVERS_ORIG 1 + +/* Procedure symbols */ + +#define YPBINDPROC_NULL 0 +#define YPBINDPROC_DOMAIN 1 +#define YPBINDPROC_SETDOM 2 +/* + * Response structure and overall result status codes. Success and failure + * represent two separate response message types. + */ + +enum ypbind_resptype {YPBIND_SUCC_VAL = 1, YPBIND_FAIL_VAL = 2}; + +struct ypbind_binding { + struct in_addr ypbind_binding_addr; /* In network order */ + unsigned short int ypbind_binding_port; /* In network order */ +}; + +struct ypbind_resp { + enum ypbind_resptype ypbind_status; + union { + u_int ypbind_error; + struct ypbind_binding ypbind_bindinfo; + } ypbind_respbody; +}; + + +/* Detailed failure reason codes for response field ypbind_error*/ + +#define YPBIND_ERR_ERR 1 /* Internal error */ +#define YPBIND_ERR_NOSERV 2 /* No bound server for passed domain */ +#define YPBIND_ERR_RESC 3 /* System resource allocation failure */ + +/* + * Request data structure for ypbind "Set domain" procedure. + */ +struct ypbind_setdom { + char *ypsetdom_domain; + struct ypbind_binding ypsetdom_binding; + u_int ypsetdom_vers; +}; +#define ypsetdom_addr ypsetdom_binding.ypbind_binding_addr +#define ypsetdom_port ypsetdom_binding.ypbind_binding_port + +/* + * Protocol between clients (ypxfr, only) and yppush + * yppush speaks a protocol in the transient range, which + * is supplied to ypxfr as a command-line parameter when it + * is activated by ypserv. + */ +#define YPPUSHVERS 1 +#define YPPUSHVERS_ORIG 1 + +/* Procedure symbols */ + +#define YPPUSHPROC_NULL 0 +#define YPPUSHPROC_XFRRESP 1 + +/* Status values for yppushresp_xfr.status */ + +enum yppush_status { + YPPUSH_SUCC = 1, /* Success */ +#define YPPUSH_SUCC YPPUSH_SUCC + YPPUSH_AGE = 2, /* Master's version not newer */ +#define YPPUSH_AGE YPPUSH_AGE + YPPUSH_NOMAP = -1, /* Can't find server for map */ +#define YPPUSH_NOMAP YPPUSH_NOMAP + YPPUSH_NODOM = -2, /* Domain not supported */ +#define YPPUSH_NODOM YPPUSH_NODOM + YPPUSH_RSRC = -3, /* Local resouce alloc failure */ +#define YPPUSH_RSRC YPPUSH_RSRC + YPPUSH_RPC = -4, /* RPC failure talking to server */ +#define YPPUSH_RPC YPPUSH_RPC + YPPUSH_MADDR = -5, /* Can't get master address */ +#define YPPUSH_MADDR YPPUSH_MADDR + YPPUSH_YPERR = -6, /* NIS server/map db error */ +#define YPPUSH_YPERR YPPUSH_YPERR + YPPUSH_BADARGS = -7, /* Request arguments bad */ +#define YPPUSH_BADARGS YPPUSH_BADARGS + YPPUSH_DBM = -8, /* Local dbm operation failed */ +#define YPPUSH_DBM YPPUSH_DBM + YPPUSH_FILE = -9, /* Local file I/O operation failed */ +#define YPPUSH_FILE YPPUSH_FILE + YPPUSH_SKEW = -10, /* Map version skew during transfer */ +#define YPPUSH_SKEW YPPUSH_SKEW + YPPUSH_CLEAR = -11, /* Can't send "Clear" req to local ypserv */ +#define YPPUSH_CLEAR YPPUSH_CLEAR + YPPUSH_FORCE = -12, /* No local order number in map - use -f flag*/ +#define YPPUSH_FORCE YPPUSH_FORCE + YPPUSH_XFRERR = -13, /* ypxfr error */ +#define YPPUSH_XFRERR YPPUSH_XFRERR + YPPUSH_REFUSED = -14, /* Transfer request refused by ypserv */ +#define YPPUSH_REFUSED YPPUSH_REFUSED + YPPUSH_NOALIAS = -15 /* Alias not found for map or domain */ +#define YPPUSH_NOALIAS YPPUSH_NOALIAS +}; +typedef enum yppush_status yppush_status; + +struct yppushresp_xfr { + u_int transid; + yppush_status status; +}; + +struct ypresp_all { + bool_t more; + union { + struct ypresp_key_val val; + } ypresp_all_u; +}; + +extern bool_t xdr_ypreq_key (XDR *__xdrs, struct ypreq_key * __objp); +extern bool_t xdr_ypreq_nokey (XDR *__xdrs, struct ypreq_nokey * __objp); +extern bool_t xdr_ypreq_xfr (XDR *__xdrs, struct ypreq_xfr * __objp); +extern bool_t xdr_ypresp_val (XDR *__xdrs, struct ypresp_val * __objp); +extern bool_t xdr_ypresp_key_val (XDR *__xdrs, struct ypresp_key_val * __objp); +extern bool_t xdr_ypbind_resp (XDR *__xdrs, struct ypbind_resp * __objp); +extern bool_t xdr_ypbind_setdom (XDR *__xdrs, struct ypbind_setdom * __objp); +extern bool_t xdr_ypmap_parms (XDR *__xdrs, struct ypmap_parms * __objp); +extern bool_t xdr_yppushresp_xfr (XDR *__xdrs, struct yppushresp_xfr * __objp); +extern bool_t xdr_ypresp_order (XDR *__xdrs, struct ypresp_order * __objp); +extern bool_t xdr_ypresp_master (XDR *__xdrs, struct ypresp_master * __objp); +extern bool_t xdr_ypall (XDR *__xdrs, struct ypall_callback * __objp); +extern bool_t xdr_ypresp_maplist (XDR *__xdrs, struct ypresp_maplist * __objp); +extern bool_t xdr_ypbind_binding (XDR *__xdrs, struct ypbind_binding * __objp); +extern bool_t xdr_ypbind_resptype (XDR *__xdrs, enum ypbind_resptype * __objp); +extern bool_t xdr_ypstat (XDR *__xdrs, enum ypbind_resptype * __objp); +extern bool_t xdr_ypresp_all (XDR *__xdrs, struct ypresp_all * __objp); +extern bool_t xdr_domainname (XDR *__xdrs, char ** __objp); + +__END_DECLS + +#endif /* _RPCSVC_YP_PROT_H */ diff --git a/REORG.TODO/nis/rpcsvc/ypclnt.h b/REORG.TODO/nis/rpcsvc/ypclnt.h new file mode 100644 index 0000000000..8f59ad4eae --- /dev/null +++ b/REORG.TODO/nis/rpcsvc/ypclnt.h @@ -0,0 +1,88 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + + +#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 int, char *, + int, char *, int) __THROW; +#if 0 +extern int yp_maplist (const char *, struct ypmaplist **) __THROW; +#endif + +/* This functions exists only under BSD and Linux systems. */ +extern int __yp_check (char **) __THROW; + +__END_DECLS + +#endif /* __RPCSVC_YPCLNT_H__ */ diff --git a/REORG.TODO/nis/rpcsvc/ypupd.h b/REORG.TODO/nis/rpcsvc/ypupd.h new file mode 100644 index 0000000000..d07fd4d744 --- /dev/null +++ b/REORG.TODO/nis/rpcsvc/ypupd.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2010, Oracle America, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the "Oracle America, Inc." 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 COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER 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. + */ +/* from @(#)ypupdate_prot.x 1.3 91/03/11 TIRPC 1.0 */ + +#ifndef __RPCSVC_YPUPD_H__ +#define __RPCSVC_YPUPD_H__ + +#include <features.h> + +#include <rpc/rpc.h> + +#define MAXMAPNAMELEN 255 +#define MAXYPDATALEN 1023 +#define MAXERRMSGLEN 255 + +__BEGIN_DECLS + +typedef struct { + u_int yp_buf_len; + char *yp_buf_val; +} yp_buf; + +extern bool_t xdr_yp_buf (XDR *, yp_buf*); + +struct ypupdate_args { + char *mapname; + yp_buf key; + yp_buf datum; +}; +typedef struct ypupdate_args ypupdate_args; + +extern bool_t xdr_ypupdate_args (XDR *, ypupdate_args*); + +struct ypdelete_args { + char *mapname; + yp_buf key; +}; +typedef struct ypdelete_args ypdelete_args; + +extern bool_t xdr_ypdelete_args (XDR *, ypdelete_args*); + +#define YPU_PROG 100028 +#define YPU_VERS 1 + +#define YPU_CHANGE 1 +extern u_int * ypu_change_1 (ypupdate_args *, CLIENT *); +extern u_int * ypu_change_1_svc (ypupdate_args *, struct svc_req *); +#define YPU_INSERT 2 +extern u_int * ypu_insert_1 (ypupdate_args *, CLIENT *); +extern u_int * ypu_insert_1_svc (ypupdate_args *, struct svc_req *); +#define YPU_DELETE 3 +extern u_int * ypu_delete_1 (ypdelete_args *, CLIENT *); +extern u_int * ypu_delete_1_svc (ypdelete_args *, struct svc_req *); +#define YPU_STORE 4 +extern u_int * ypu_store_1 (ypupdate_args *, CLIENT *); +extern u_int * ypu_store_1_svc (ypupdate_args *, struct svc_req *); + +__END_DECLS + +#endif /* !__RPCSVC_YPUPD_H__ */ diff --git a/REORG.TODO/nis/yp_xdr.c b/REORG.TODO/nis/yp_xdr.c new file mode 100644 index 0000000000..0081b4c926 --- /dev/null +++ b/REORG.TODO/nis/yp_xdr.c @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2010, Oracle America, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the "Oracle America, Inc." 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 COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER 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 <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> +#include <shlib-compat.h> + +/* The NIS v2 protocol suggests 1024 bytes as a maximum length of all fields. + Current Linux systems don't use this limit. To remain compatible with + recent Linux systems we choose limits large enough to load large key and + data values, but small enough to not pose a DoS threat. */ + +#define XDRMAXNAME 1024 +#define XDRMAXRECORD (16 * 1024 * 1024) + +bool_t +xdr_ypstat (XDR *xdrs, ypstat *objp) +{ + return xdr_enum (xdrs, (enum_t *) objp); +} +libnsl_hidden_nolink_def (xdr_ypstat, GLIBC_2_0) + +bool_t +xdr_ypxfrstat (XDR *xdrs, ypxfrstat *objp) +{ + return xdr_enum (xdrs, (enum_t *) objp); +} +libnsl_hidden_nolink_def (xdr_ypxfrstat, GLIBC_2_0) + +bool_t +xdr_domainname (XDR *xdrs, domainname *objp) +{ + return xdr_string (xdrs, objp, XDRMAXNAME); +} +libnsl_hidden_nolink_def (xdr_domainname, GLIBC_2_0) + +bool_t +xdr_mapname (XDR *xdrs, mapname *objp) +{ + return xdr_string (xdrs, objp, XDRMAXNAME); +} +libnsl_hidden_nolink_def (xdr_mapname, GLIBC_2_0) + +bool_t +xdr_peername (XDR *xdrs, peername *objp) +{ + return xdr_string (xdrs, objp, XDRMAXNAME); +} +libnsl_hidden_nolink_def (xdr_peername, GLIBC_2_0) + +bool_t +xdr_keydat (XDR *xdrs, keydat *objp) +{ + return xdr_bytes (xdrs, (char **) &objp->keydat_val, + (u_int *) &objp->keydat_len, XDRMAXRECORD); +} +libnsl_hidden_nolink_def (xdr_keydat, GLIBC_2_0) + +bool_t +xdr_valdat (XDR *xdrs, valdat *objp) +{ + return xdr_bytes (xdrs, (char **) &objp->valdat_val, + (u_int *) &objp->valdat_len, XDRMAXRECORD); +} +libnsl_hidden_nolink_def (xdr_valdat, GLIBC_2_0) + +bool_t +xdr_ypmap_parms (XDR *xdrs, ypmap_parms *objp) +{ + if (!xdr_domainname (xdrs, &objp->domain)) + return FALSE; + if (!xdr_mapname (xdrs, &objp->map)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->ordernum)) + return FALSE; + return xdr_peername (xdrs, &objp->peer); +} +libnsl_hidden_nolink_def (xdr_ypmap_parms, GLIBC_2_0) + +bool_t +xdr_ypreq_key (XDR *xdrs, ypreq_key *objp) +{ + if (!xdr_domainname (xdrs, &objp->domain)) + return FALSE; + if (!xdr_mapname (xdrs, &objp->map)) + return FALSE; + return xdr_keydat (xdrs, &objp->key); +} +libnsl_hidden_nolink_def (xdr_ypreq_key, GLIBC_2_0) + +bool_t +xdr_ypreq_nokey (XDR *xdrs, ypreq_nokey *objp) +{ + if (!xdr_domainname (xdrs, &objp->domain)) + return FALSE; + return xdr_mapname (xdrs, &objp->map); +} +libnsl_hidden_nolink_def (xdr_ypreq_nokey, GLIBC_2_0) + +bool_t +xdr_ypreq_xfr (XDR *xdrs, ypreq_xfr *objp) +{ + if (!xdr_ypmap_parms (xdrs, &objp->map_parms)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->transid)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->prog)) + return FALSE; + return xdr_u_int (xdrs, &objp->port); +} +libnsl_hidden_nolink_def (xdr_ypreq_xfr, GLIBC_2_0) + +bool_t +xdr_ypresp_val (XDR *xdrs, ypresp_val *objp) +{ + if (!xdr_ypstat (xdrs, &objp->stat)) + return FALSE; + return xdr_valdat (xdrs, &objp->val); +} +libnsl_hidden_nolink_def (xdr_ypresp_val, GLIBC_2_0) + +bool_t +xdr_ypresp_key_val (XDR *xdrs, ypresp_key_val *objp) +{ + if (!xdr_ypstat (xdrs, &objp->stat)) + return FALSE; + if (!xdr_valdat (xdrs, &objp->val)) + return FALSE; + return xdr_keydat (xdrs, &objp->key); +} +libnsl_hidden_nolink_def (xdr_ypresp_key_val, GLIBC_2_0) + +bool_t +xdr_ypresp_master (XDR *xdrs, ypresp_master *objp) +{ + if (!xdr_ypstat (xdrs, &objp->stat)) + return FALSE; + return xdr_peername (xdrs, &objp->peer); +} +libnsl_hidden_nolink_def (xdr_ypresp_master, GLIBC_2_0) + +bool_t +xdr_ypresp_order (XDR *xdrs, ypresp_order *objp) +{ + if (!xdr_ypstat (xdrs, &objp->stat)) + return FALSE; + return xdr_u_int (xdrs, &objp->ordernum); +} +libnsl_hidden_nolink_def (xdr_ypresp_order, GLIBC_2_0) + +bool_t +xdr_ypresp_all (XDR *xdrs, ypresp_all *objp) +{ + if (!xdr_bool (xdrs, &objp->more)) + return FALSE; + switch (objp->more) + { + case TRUE: + return xdr_ypresp_key_val (xdrs, &objp->ypresp_all_u.val); + case FALSE: + break; + default: + return FALSE; + } + return TRUE; +} +libnsl_hidden_nolink_def (xdr_ypresp_all, GLIBC_2_0) + +bool_t +xdr_ypresp_xfr (XDR *xdrs, ypresp_xfr *objp) +{ + if (!xdr_u_int (xdrs, &objp->transid)) + return FALSE; + return xdr_ypxfrstat (xdrs, &objp->xfrstat); +} +libnsl_hidden_nolink_def (xdr_ypresp_xfr, GLIBC_2_0) + +bool_t +xdr_ypmaplist (XDR *xdrs, ypmaplist *objp) +{ + if (!xdr_mapname (xdrs, &objp->map)) + return FALSE; + /* Prevent gcc warning about alias violation. */ + char **tp = (void *) &objp->next; + return xdr_pointer (xdrs, tp, sizeof (ypmaplist), (xdrproc_t) xdr_ypmaplist); +} +libnsl_hidden_nolink_def (xdr_ypmaplist, GLIBC_2_0) + +bool_t +xdr_ypresp_maplist (XDR *xdrs, ypresp_maplist *objp) +{ + if (!xdr_ypstat (xdrs, &objp->stat)) + return FALSE; + /* Prevent gcc warning about alias violation. */ + char **tp = (void *) &objp->maps; + return xdr_pointer (xdrs, tp, sizeof (ypmaplist), (xdrproc_t) xdr_ypmaplist); +} +libnsl_hidden_nolink_def (xdr_ypresp_maplist, GLIBC_2_0) + +bool_t +xdr_yppush_status (XDR *xdrs, yppush_status *objp) +{ + return xdr_enum (xdrs, (enum_t *) objp); +} +libnsl_hidden_nolink_def (xdr_yppush_status, GLIBC_2_0) + +bool_t +xdr_yppushresp_xfr (XDR *xdrs, yppushresp_xfr *objp) +{ + if (!xdr_u_int (xdrs, &objp->transid)) + return FALSE; + return xdr_yppush_status (xdrs, &objp->status); +} +libnsl_hidden_nolink_def (xdr_yppushresp_xfr, GLIBC_2_0) + +bool_t +xdr_ypbind_resptype (XDR *xdrs, ypbind_resptype *objp) +{ + return xdr_enum (xdrs, (enum_t *) objp); +} +libnsl_hidden_nolink_def (xdr_ypbind_resptype, GLIBC_2_0) + +bool_t +xdr_ypbind_binding (XDR *xdrs, ypbind_binding *objp) +{ + if (!xdr_opaque (xdrs, objp->ypbind_binding_addr, 4)) + return FALSE; + return xdr_opaque (xdrs, objp->ypbind_binding_port, 2); +} +libnsl_hidden_nolink_def (xdr_ypbind_binding, GLIBC_2_0) + +bool_t +xdr_ypbind_resp (XDR *xdrs, ypbind_resp *objp) +{ + if (!xdr_ypbind_resptype (xdrs, &objp->ypbind_status)) + return FALSE; + switch (objp->ypbind_status) + { + case YPBIND_FAIL_VAL: + return xdr_u_int (xdrs, &objp->ypbind_resp_u.ypbind_error); + case YPBIND_SUCC_VAL: + return xdr_ypbind_binding (xdrs, &objp->ypbind_resp_u.ypbind_bindinfo); + } + return FALSE; +} +libnsl_hidden_nolink_def (xdr_ypbind_resp, GLIBC_2_0) + +bool_t +xdr_ypbind_setdom (XDR *xdrs, ypbind_setdom *objp) +{ + if (!xdr_domainname (xdrs, &objp->ypsetdom_domain)) + return FALSE; + if (!xdr_ypbind_binding (xdrs, &objp->ypsetdom_binding)) + return FALSE; + return xdr_u_int (xdrs, &objp->ypsetdom_vers); +} +libnsl_hidden_nolink_def (xdr_ypbind_setdom, GLIBC_2_0) + +bool_t +xdr_ypall(XDR *xdrs, struct ypall_callback *incallback) +{ + struct ypresp_key_val out; + char key[YPMAXRECORD], val[YPMAXRECORD]; + + /* + * Set up key/val struct to be used during the transaction. + */ + memset(&out, 0, sizeof out); + out.key.keydat_val = key; + out.key.keydat_len = sizeof(key); + out.val.valdat_val = val; + out.val.valdat_len = sizeof(val); + + for (;;) { + bool_t more, status; + + /* Values pending? */ + if (!xdr_bool(xdrs, &more)) + return FALSE; /* can't tell! */ + if (!more) + return TRUE; /* no more */ + + /* Transfer key/value pair. */ + status = xdr_ypresp_key_val(xdrs, &out); + + /* + * If we succeeded, call the callback function. + * The callback will return TRUE when it wants + * no more values. If we fail, indicate the + * error. + */ + if (status) { + if ((*incallback->foreach)(out.stat, + (char *)out.key.keydat_val, out.key.keydat_len, + (char *)out.val.valdat_val, out.val.valdat_len, + incallback->data)) + return TRUE; + } else + return FALSE; + } +} +/* XXX libnsl_hidden_nolink_def(xdr_ypall, GLIBC_2_2) */ diff --git a/REORG.TODO/nis/ypclnt.c b/REORG.TODO/nis/ypclnt.c new file mode 100644 index 0000000000..a03e347685 --- /dev/null +++ b/REORG.TODO/nis/ypclnt.c @@ -0,0 +1,1030 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> +#include <libintl.h> +#include <rpc/rpc.h> +#include <rpcsvc/nis.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> +#include <rpcsvc/ypupd.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <libc-lock.h> +#include <shlib-compat.h> + +/* This should only be defined on systems with a BSD compatible ypbind */ +#ifndef BINDINGDIR +# define BINDINGDIR "/var/yp/binding" +#endif + +struct dom_binding + { + struct dom_binding *dom_pnext; + char dom_domain[YPMAXDOMAIN + 1]; + struct sockaddr_in dom_server_addr; + int dom_socket; + CLIENT *dom_client; + }; +typedef struct dom_binding dom_binding; + +static const struct timeval RPCTIMEOUT = {25, 0}; +static const struct timeval UDPTIMEOUT = {5, 0}; +static int const MAXTRIES = 2; +static char ypdomainname[NIS_MAXNAMELEN + 1]; +__libc_lock_define_initialized (static, ypbindlist_lock) +static dom_binding *ypbindlist = NULL; + + +static void +yp_bind_client_create (const char *domain, dom_binding *ysd, + struct ypbind_resp *ypbr) +{ + ysd->dom_server_addr.sin_family = AF_INET; + memcpy (&ysd->dom_server_addr.sin_port, + ypbr->ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port, + sizeof (ysd->dom_server_addr.sin_port)); + memcpy (&ysd->dom_server_addr.sin_addr.s_addr, + ypbr->ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr, + sizeof (ysd->dom_server_addr.sin_addr.s_addr)); + strncpy (ysd->dom_domain, domain, YPMAXDOMAIN); + ysd->dom_domain[YPMAXDOMAIN] = '\0'; + + ysd->dom_socket = RPC_ANYSOCK; + ysd->dom_client = __libc_clntudp_bufcreate (&ysd->dom_server_addr, YPPROG, + YPVERS, UDPTIMEOUT, + &ysd->dom_socket, + UDPMSGSIZE, UDPMSGSIZE, + SOCK_CLOEXEC); +} + +#if USE_BINDINGDIR +static void +yp_bind_file (const char *domain, dom_binding *ysd) +{ + char path[sizeof (BINDINGDIR) + strlen (domain) + 3 * sizeof (unsigned) + 3]; + + snprintf (path, sizeof (path), "%s/%s.%u", BINDINGDIR, domain, YPBINDVERS); + int fd = open (path, O_RDONLY); + if (fd >= 0) + { + /* We have a binding file and could save a RPC call. The file + contains a port number and the YPBIND_RESP record. The port + number (16 bits) can be ignored. */ + struct ypbind_resp ypbr; + + if (pread (fd, &ypbr, sizeof (ypbr), 2) == sizeof (ypbr)) + yp_bind_client_create (domain, ysd, &ypbr); + + close (fd); + } +} +#endif + +static int +yp_bind_ypbindprog (const char *domain, dom_binding *ysd) +{ + struct sockaddr_in clnt_saddr; + struct ypbind_resp ypbr; + int clnt_sock; + CLIENT *client; + + clnt_saddr.sin_family = AF_INET; + clnt_saddr.sin_port = 0; + clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + clnt_sock = RPC_ANYSOCK; + client = clnttcp_create (&clnt_saddr, YPBINDPROG, YPBINDVERS, + &clnt_sock, 0, 0); + if (client == NULL) + return YPERR_YPBIND; + + /* Check the port number -- should be < IPPORT_RESERVED. + If not, it's possible someone has registered a bogus + ypbind with the portmapper and is trying to trick us. */ + if (ntohs (clnt_saddr.sin_port) >= IPPORT_RESERVED) + { + clnt_destroy (client); + return YPERR_YPBIND; + } + + if (clnt_call (client, YPBINDPROC_DOMAIN, + (xdrproc_t) xdr_domainname, (caddr_t) &domain, + (xdrproc_t) xdr_ypbind_resp, + (caddr_t) &ypbr, RPCTIMEOUT) != RPC_SUCCESS) + { + clnt_destroy (client); + return YPERR_YPBIND; + } + + clnt_destroy (client); + + if (ypbr.ypbind_status != YPBIND_SUCC_VAL) + { + fprintf (stderr, "YPBINDPROC_DOMAIN: %s\n", + ypbinderr_string (ypbr.ypbind_resp_u.ypbind_error)); + return YPERR_DOMAIN; + } + memset (&ysd->dom_server_addr, '\0', sizeof ysd->dom_server_addr); + + yp_bind_client_create (domain, ysd, &ypbr); + + return YPERR_SUCCESS; +} + +static int +__yp_bind (const char *domain, dom_binding **ypdb) +{ + dom_binding *ysd = NULL; + int is_new = 0; + + if (domain == NULL || domain[0] == '\0') + return YPERR_BADARGS; + + ysd = *ypdb; + while (ysd != NULL) + { + if (strcmp (domain, ysd->dom_domain) == 0) + break; + ysd = ysd->dom_pnext; + } + + if (ysd == NULL) + { + is_new = 1; + ysd = (dom_binding *) calloc (1, sizeof *ysd); + if (__glibc_unlikely (ysd == NULL)) + return YPERR_RESRC; + } + +#if USE_BINDINGDIR + /* Try binding dir at first if we have no binding */ + if (ysd->dom_client == NULL) + yp_bind_file (domain, ysd); +#endif /* USE_BINDINGDIR */ + + if (ysd->dom_client == NULL) + { + int retval = yp_bind_ypbindprog (domain, ysd); + if (retval != YPERR_SUCCESS) + { + if (is_new) + free (ysd); + return retval; + } + } + + if (ysd->dom_client == NULL) + { + if (is_new) + free (ysd); + return YPERR_YPSERV; + } + + if (is_new) + { + ysd->dom_pnext = *ypdb; + *ypdb = ysd; + } + + return YPERR_SUCCESS; +} + +static void +__yp_unbind (dom_binding *ydb) +{ + clnt_destroy (ydb->dom_client); + free (ydb); +} + +int +yp_bind (const char *indomain) +{ + int status; + + __libc_lock_lock (ypbindlist_lock); + + status = __yp_bind (indomain, &ypbindlist); + + __libc_lock_unlock (ypbindlist_lock); + + return status; +} +libnsl_hidden_nolink_def (yp_bind, GLIBC_2_0) + +static void +yp_unbind_locked (const char *indomain) +{ + dom_binding *ydbptr, *ydbptr2; + + ydbptr2 = NULL; + ydbptr = ypbindlist; + + while (ydbptr != NULL) + { + if (strcmp (ydbptr->dom_domain, indomain) == 0) + { + dom_binding *work; + + work = ydbptr; + if (ydbptr2 == NULL) + ypbindlist = ypbindlist->dom_pnext; + else + ydbptr2 = ydbptr->dom_pnext; + __yp_unbind (work); + break; + } + ydbptr2 = ydbptr; + ydbptr = ydbptr->dom_pnext; + } +} + +void +yp_unbind (const char *indomain) +{ + __libc_lock_lock (ypbindlist_lock); + + yp_unbind_locked (indomain); + + __libc_lock_unlock (ypbindlist_lock); + + return; +} +libnsl_hidden_nolink_def(yp_unbind, GLIBC_2_0) + +static int +__ypclnt_call (const char *domain, u_long prog, xdrproc_t xargs, + caddr_t req, xdrproc_t xres, caddr_t resp, dom_binding **ydb, + int print_error) +{ + enum clnt_stat result; + + result = clnt_call ((*ydb)->dom_client, prog, + xargs, req, xres, resp, RPCTIMEOUT); + + if (result != RPC_SUCCESS) + { + /* We don't print an error message, if we try our old, + cached data. Only print this for data, which should work. */ + if (print_error) + clnt_perror ((*ydb)->dom_client, "do_ypcall: clnt_call"); + + return YPERR_RPC; + } + + return YPERR_SUCCESS; +} + +static int +do_ypcall (const char *domain, u_long prog, xdrproc_t xargs, + caddr_t req, xdrproc_t xres, caddr_t resp) +{ + dom_binding *ydb; + int status; + int saved_errno = errno; + + status = YPERR_YPERR; + + __libc_lock_lock (ypbindlist_lock); + ydb = ypbindlist; + while (ydb != NULL) + { + if (strcmp (domain, ydb->dom_domain) == 0) + { + if (__yp_bind (domain, &ydb) == 0) + { + /* Call server, print no error message, do not unbind. */ + status = __ypclnt_call (domain, prog, xargs, req, xres, + resp, &ydb, 0); + if (status == YPERR_SUCCESS) + { + __libc_lock_unlock (ypbindlist_lock); + __set_errno (saved_errno); + return status; + } + } + /* We use ypbindlist, and the old cached data is + invalid. unbind now and create a new binding */ + yp_unbind_locked (domain); + + break; + } + ydb = ydb->dom_pnext; + } + __libc_lock_unlock (ypbindlist_lock); + + /* First try with cached data failed. Now try to get + current data from the system. */ + ydb = NULL; + if (__yp_bind (domain, &ydb) == 0) + { + status = __ypclnt_call (domain, prog, xargs, req, xres, + resp, &ydb, 1); + __yp_unbind (ydb); + } + +#if USE_BINDINGDIR + /* If we support binding dir data, we have a third chance: + Ask ypbind. */ + if (status != YPERR_SUCCESS) + { + ydb = calloc (1, sizeof (dom_binding)); + if (ydb != NULL && yp_bind_ypbindprog (domain, ydb) == YPERR_SUCCESS) + { + status = __ypclnt_call (domain, prog, xargs, req, xres, + resp, &ydb, 1); + __yp_unbind (ydb); + } + else + free (ydb); + } +#endif + + __set_errno (saved_errno); + + return status; +} + +/* Like do_ypcall, but translate the status value if necessary. */ +static int +do_ypcall_tr (const char *domain, u_long prog, xdrproc_t xargs, + caddr_t req, xdrproc_t xres, caddr_t resp) +{ + int status = do_ypcall (domain, prog, xargs, req, xres, resp); + if (status == YPERR_SUCCESS) + /* We cast to ypresp_val although the pointer could also be of + type ypresp_key_val or ypresp_master or ypresp_order or + ypresp_maplist. But the stat element is in a common prefix so + this does not matter. */ + status = ypprot_err (((struct ypresp_val *) resp)->stat); + return status; +} + + +__libc_lock_define_initialized (static, domainname_lock) + +int +yp_get_default_domain (char **outdomain) +{ + int result = YPERR_SUCCESS;; + *outdomain = NULL; + + __libc_lock_lock (domainname_lock); + + if (ypdomainname[0] == '\0') + { + if (getdomainname (ypdomainname, NIS_MAXNAMELEN)) + result = YPERR_NODOM; + else if (strcmp (ypdomainname, "(none)") == 0) + { + /* If domainname is not set, some systems will return "(none)" */ + ypdomainname[0] = '\0'; + result = YPERR_NODOM; + } + else + *outdomain = ypdomainname; + } + else + *outdomain = ypdomainname; + + __libc_lock_unlock (domainname_lock); + + return result; +} +libnsl_hidden_nolink_def (yp_get_default_domain, GLIBC_2_0) + +int +__yp_check (char **domain) +{ + char *unused; + + if (ypdomainname[0] == '\0') + if (yp_get_default_domain (&unused)) + return 0; + + if (domain) + *domain = ypdomainname; + + if (yp_bind (ypdomainname) == 0) + return 1; + return 0; +} +libnsl_hidden_nolink_def(__yp_check, GLIBC_2_0) + +int +yp_match (const char *indomain, const char *inmap, const char *inkey, + const int inkeylen, char **outval, int *outvallen) +{ + ypreq_key req; + ypresp_val resp; + enum clnt_stat result; + + if (indomain == NULL || indomain[0] == '\0' || + inmap == NULL || inmap[0] == '\0' || + inkey == NULL || inkey[0] == '\0' || inkeylen <= 0) + return YPERR_BADARGS; + + req.domain = (char *) indomain; + req.map = (char *) inmap; + req.key.keydat_val = (char *) inkey; + req.key.keydat_len = inkeylen; + + *outval = NULL; + *outvallen = 0; + memset (&resp, '\0', sizeof (resp)); + + result = do_ypcall_tr (indomain, YPPROC_MATCH, (xdrproc_t) xdr_ypreq_key, + (caddr_t) &req, (xdrproc_t) xdr_ypresp_val, + (caddr_t) &resp); + + if (result != YPERR_SUCCESS) + return result; + + *outvallen = resp.val.valdat_len; + *outval = malloc (*outvallen + 1); + int status = YPERR_RESRC; + if (__glibc_likely (*outval != NULL)) + { + memcpy (*outval, resp.val.valdat_val, *outvallen); + (*outval)[*outvallen] = '\0'; + status = YPERR_SUCCESS; + } + + xdr_free ((xdrproc_t) xdr_ypresp_val, (char *) &resp); + + return status; +} +libnsl_hidden_nolink_def(yp_match, GLIBC_2_0) + +int +yp_first (const char *indomain, const char *inmap, char **outkey, + int *outkeylen, char **outval, int *outvallen) +{ + ypreq_nokey req; + ypresp_key_val resp; + enum clnt_stat result; + + if (indomain == NULL || indomain[0] == '\0' || + inmap == NULL || inmap[0] == '\0') + return YPERR_BADARGS; + + req.domain = (char *) indomain; + req.map = (char *) inmap; + + *outkey = *outval = NULL; + *outkeylen = *outvallen = 0; + memset (&resp, '\0', sizeof (resp)); + + result = do_ypcall (indomain, YPPROC_FIRST, (xdrproc_t) xdr_ypreq_nokey, + (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val, + (caddr_t) &resp); + + if (result != RPC_SUCCESS) + return YPERR_RPC; + if (resp.stat != YP_TRUE) + return ypprot_err (resp.stat); + + int status; + if (__builtin_expect ((*outkey = malloc (resp.key.keydat_len + 1)) != NULL + && (*outval = malloc (resp.val.valdat_len + + 1)) != NULL, 1)) + { + *outkeylen = resp.key.keydat_len; + memcpy (*outkey, resp.key.keydat_val, *outkeylen); + (*outkey)[*outkeylen] = '\0'; + + *outvallen = resp.val.valdat_len; + memcpy (*outval, resp.val.valdat_val, *outvallen); + (*outval)[*outvallen] = '\0'; + + status = YPERR_SUCCESS; + } + else + { + free (*outkey); + status = YPERR_RESRC; + } + + xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp); + + return status; +} +libnsl_hidden_nolink_def(yp_first, GLIBC_2_0) + +int +yp_next (const char *indomain, const char *inmap, const char *inkey, + const int inkeylen, char **outkey, int *outkeylen, char **outval, + int *outvallen) +{ + ypreq_key req; + ypresp_key_val resp; + enum clnt_stat result; + + if (indomain == NULL || indomain[0] == '\0' || + inmap == NULL || inmap[0] == '\0' || + inkeylen <= 0 || inkey == NULL || inkey[0] == '\0') + return YPERR_BADARGS; + + req.domain = (char *) indomain; + req.map = (char *) inmap; + req.key.keydat_val = (char *) inkey; + req.key.keydat_len = inkeylen; + + *outkey = *outval = NULL; + *outkeylen = *outvallen = 0; + memset (&resp, '\0', sizeof (resp)); + + result = do_ypcall_tr (indomain, YPPROC_NEXT, (xdrproc_t) xdr_ypreq_key, + (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val, + (caddr_t) &resp); + + if (result != YPERR_SUCCESS) + return result; + + int status; + if (__builtin_expect ((*outkey = malloc (resp.key.keydat_len + 1)) != NULL + && (*outval = malloc (resp.val.valdat_len + + 1)) != NULL, 1)) + { + *outkeylen = resp.key.keydat_len; + memcpy (*outkey, resp.key.keydat_val, *outkeylen); + (*outkey)[*outkeylen] = '\0'; + + *outvallen = resp.val.valdat_len; + memcpy (*outval, resp.val.valdat_val, *outvallen); + (*outval)[*outvallen] = '\0'; + + status = YPERR_SUCCESS; + } + else + { + free (*outkey); + status = YPERR_RESRC; + } + + xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp); + + return status; +} +libnsl_hidden_nolink_def(yp_next, GLIBC_2_0) + +int +yp_master (const char *indomain, const char *inmap, char **outname) +{ + ypreq_nokey req; + ypresp_master resp; + enum clnt_stat result; + + if (indomain == NULL || indomain[0] == '\0' || + inmap == NULL || inmap[0] == '\0') + return YPERR_BADARGS; + + req.domain = (char *) indomain; + req.map = (char *) inmap; + + memset (&resp, '\0', sizeof (ypresp_master)); + + result = do_ypcall_tr (indomain, YPPROC_MASTER, (xdrproc_t) xdr_ypreq_nokey, + (caddr_t) &req, (xdrproc_t) xdr_ypresp_master, + (caddr_t) &resp); + + if (result != YPERR_SUCCESS) + return result; + + *outname = strdup (resp.peer); + xdr_free ((xdrproc_t) xdr_ypresp_master, (char *) &resp); + + return *outname == NULL ? YPERR_YPERR : YPERR_SUCCESS; +} +libnsl_hidden_nolink_def (yp_master, GLIBC_2_0) + +int +yp_order (const char *indomain, const char *inmap, unsigned int *outorder) +{ + struct ypreq_nokey req; + struct ypresp_order resp; + enum clnt_stat result; + + if (indomain == NULL || indomain[0] == '\0' || + inmap == NULL || inmap[0] == '\0') + return YPERR_BADARGS; + + req.domain = (char *) indomain; + req.map = (char *) inmap; + + memset (&resp, '\0', sizeof (resp)); + + result = do_ypcall_tr (indomain, YPPROC_ORDER, (xdrproc_t) xdr_ypreq_nokey, + (caddr_t) &req, (xdrproc_t) xdr_ypresp_order, + (caddr_t) &resp); + + if (result != YPERR_SUCCESS) + return result; + + *outorder = resp.ordernum; + xdr_free ((xdrproc_t) xdr_ypresp_order, (char *) &resp); + + return result; +} +libnsl_hidden_nolink_def(yp_order, GLIBC_2_0) + +struct ypresp_all_data +{ + unsigned long status; + void *data; + int (*foreach) (int status, char *key, int keylen, + char *val, int vallen, char *data); +}; + +static bool_t +__xdr_ypresp_all (XDR *xdrs, struct ypresp_all_data *objp) +{ + while (1) + { + struct ypresp_all resp; + + memset (&resp, '\0', sizeof (struct ypresp_all)); + if (!xdr_ypresp_all (xdrs, &resp)) + { + xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp); + objp->status = YP_YPERR; + return FALSE; + } + if (resp.more == 0) + { + xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp); + objp->status = YP_NOMORE; + return TRUE; + } + + switch (resp.ypresp_all_u.val.stat) + { + case YP_TRUE: + { + char key[resp.ypresp_all_u.val.key.keydat_len + 1]; + char val[resp.ypresp_all_u.val.val.valdat_len + 1]; + int keylen = resp.ypresp_all_u.val.key.keydat_len; + int vallen = resp.ypresp_all_u.val.val.valdat_len; + + /* We are not allowed to modify the key and val data. + But we are allowed to add data behind the buffer, + if we don't modify the length. So add an extra NUL + character to avoid trouble with broken code. */ + objp->status = YP_TRUE; + *((char *) __mempcpy (key, resp.ypresp_all_u.val.key.keydat_val, + keylen)) = '\0'; + *((char *) __mempcpy (val, resp.ypresp_all_u.val.val.valdat_val, + vallen)) = '\0'; + xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp); + if ((*objp->foreach) (objp->status, key, keylen, + val, vallen, objp->data)) + return TRUE; + } + break; + default: + objp->status = resp.ypresp_all_u.val.stat; + xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp); + /* Sun says we don't need to make this call, but must return + immediately. Since Solaris makes this call, we will call + the callback function, too. */ + (*objp->foreach) (objp->status, NULL, 0, NULL, 0, objp->data); + return TRUE; + } + } +} + +int +yp_all (const char *indomain, const char *inmap, + const struct ypall_callback *incallback) +{ + struct ypreq_nokey req; + dom_binding *ydb = NULL; + int try, res; + enum clnt_stat result; + struct sockaddr_in clnt_sin; + CLIENT *clnt; + struct ypresp_all_data data; + int clnt_sock; + int saved_errno = errno; + + if (indomain == NULL || indomain[0] == '\0' + || inmap == NULL || inmap[0] == '\0') + return YPERR_BADARGS; + + try = 0; + res = YPERR_YPERR; + + while (try < MAXTRIES && res != YPERR_SUCCESS) + { + if (__yp_bind (indomain, &ydb) != 0) + { + __set_errno (saved_errno); + return YPERR_DOMAIN; + } + + clnt_sock = RPC_ANYSOCK; + clnt_sin = ydb->dom_server_addr; + clnt_sin.sin_port = 0; + + /* We don't need the UDP connection anymore. */ + __yp_unbind (ydb); + ydb = NULL; + + clnt = clnttcp_create (&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0); + if (clnt == NULL) + { + __set_errno (saved_errno); + return YPERR_PMAP; + } + req.domain = (char *) indomain; + req.map = (char *) inmap; + + data.foreach = incallback->foreach; + data.data = (void *) incallback->data; + + result = clnt_call (clnt, YPPROC_ALL, (xdrproc_t) xdr_ypreq_nokey, + (caddr_t) &req, (xdrproc_t) __xdr_ypresp_all, + (caddr_t) &data, RPCTIMEOUT); + + if (__glibc_unlikely (result != RPC_SUCCESS)) + { + /* Print the error message only on the last try. */ + if (try == MAXTRIES - 1) + clnt_perror (clnt, "yp_all: clnt_call"); + res = YPERR_RPC; + } + else + res = YPERR_SUCCESS; + + clnt_destroy (clnt); + + if (res == YPERR_SUCCESS && data.status != YP_NOMORE) + { + __set_errno (saved_errno); + return ypprot_err (data.status); + } + ++try; + } + + __set_errno (saved_errno); + + return res; +} +libnsl_hidden_nolink_def (yp_all, GLIBC_2_0) + +int +yp_maplist (const char *indomain, struct ypmaplist **outmaplist) +{ + struct ypresp_maplist resp; + enum clnt_stat result; + + if (indomain == NULL || indomain[0] == '\0') + return YPERR_BADARGS; + + memset (&resp, '\0', sizeof (resp)); + + result = do_ypcall_tr (indomain, YPPROC_MAPLIST, (xdrproc_t) xdr_domainname, + (caddr_t) &indomain, (xdrproc_t) xdr_ypresp_maplist, + (caddr_t) &resp); + + if (__glibc_likely (result == YPERR_SUCCESS)) + { + *outmaplist = resp.maps; + /* We don't free the list, this will be done by ypserv + xdr_free((xdrproc_t)xdr_ypresp_maplist, (char *)&resp); */ + } + + return result; +} + +const char * +yperr_string (const int error) +{ + const char *str; + switch (error) + { + case YPERR_SUCCESS: + str = N_("Success"); + break; + case YPERR_BADARGS: + str = N_("Request arguments bad"); + break; + case YPERR_RPC: + str = N_("RPC failure on NIS operation"); + break; + case YPERR_DOMAIN: + str = N_("Can't bind to server which serves this domain"); + break; + case YPERR_MAP: + str = N_("No such map in server's domain"); + break; + case YPERR_KEY: + str = N_("No such key in map"); + break; + case YPERR_YPERR: + str = N_("Internal NIS error"); + break; + case YPERR_RESRC: + str = N_("Local resource allocation failure"); + break; + case YPERR_NOMORE: + str = N_("No more records in map database"); + break; + case YPERR_PMAP: + str = N_("Can't communicate with portmapper"); + break; + case YPERR_YPBIND: + str = N_("Can't communicate with ypbind"); + break; + case YPERR_YPSERV: + str = N_("Can't communicate with ypserv"); + break; + case YPERR_NODOM: + str = N_("Local domain name not set"); + break; + case YPERR_BADDB: + str = N_("NIS map database is bad"); + break; + case YPERR_VERS: + str = N_("NIS client/server version mismatch - can't supply service"); + break; + case YPERR_ACCESS: + str = N_("Permission denied"); + break; + case YPERR_BUSY: + str = N_("Database is busy"); + break; + default: + str = N_("Unknown NIS error code"); + break; + } + return _(str); +} +libnsl_hidden_nolink_def(yperr_string, GLIBC_2_0) + +static const int8_t yp_2_yperr[] = + { +#define YP2YPERR(yp, yperr) [YP_##yp - YP_VERS] = YPERR_##yperr + YP2YPERR (TRUE, SUCCESS), + YP2YPERR (NOMORE, NOMORE), + YP2YPERR (FALSE, YPERR), + YP2YPERR (NOMAP, MAP), + YP2YPERR (NODOM, DOMAIN), + YP2YPERR (NOKEY, KEY), + YP2YPERR (BADOP, YPERR), + YP2YPERR (BADDB, BADDB), + YP2YPERR (YPERR, YPERR), + YP2YPERR (BADARGS, BADARGS), + YP2YPERR (VERS, VERS) + }; +int +ypprot_err (const int code) +{ + if (code < YP_VERS || code > YP_NOMORE) + return YPERR_YPERR; + return yp_2_yperr[code - YP_VERS]; +} +libnsl_hidden_nolink_def (ypprot_err, GLIBC_2_0) + +const char * +ypbinderr_string (const int error) +{ + const char *str; + switch (error) + { + case 0: + str = N_("Success"); + break; + case YPBIND_ERR_ERR: + str = N_("Internal ypbind error"); + break; + case YPBIND_ERR_NOSERV: + str = N_("Domain not bound"); + break; + case YPBIND_ERR_RESC: + str = N_("System resource allocation failure"); + break; + default: + str = N_("Unknown ypbind error"); + break; + } + return _(str); +} +libnsl_hidden_nolink_def (ypbinderr_string, GLIBC_2_0) + +#define WINDOW 60 + +int +yp_update (char *domain, char *map, unsigned ypop, + char *key, int keylen, char *data, int datalen) +{ + union + { + ypupdate_args update_args; + ypdelete_args delete_args; + } + args; + xdrproc_t xdr_argument; + unsigned res = 0; + CLIENT *clnt; + char *master; + struct sockaddr saddr; + char servername[MAXNETNAMELEN + 1]; + int r; + + if (!domain || !map || !key || (ypop != YPOP_DELETE && !data)) + return YPERR_BADARGS; + + args.update_args.mapname = map; + args.update_args.key.yp_buf_len = keylen; + args.update_args.key.yp_buf_val = key; + args.update_args.datum.yp_buf_len = datalen; + args.update_args.datum.yp_buf_val = data; + + if ((r = yp_master (domain, map, &master)) != YPERR_SUCCESS) + return r; + + if (!host2netname (servername, master, domain)) + { + fputs (_("yp_update: cannot convert host to netname\n"), stderr); + free (master); + return YPERR_YPERR; + } + + clnt = clnt_create (master, YPU_PROG, YPU_VERS, "tcp"); + + /* We do not need the string anymore. */ + free (master); + + if (clnt == NULL) + { + clnt_pcreateerror ("yp_update: clnt_create"); + return YPERR_RPC; + } + + if (!clnt_control (clnt, CLGET_SERVER_ADDR, (char *) &saddr)) + { + fputs (_("yp_update: cannot get server address\n"), stderr); + return YPERR_RPC; + } + + switch (ypop) + { + case YPOP_CHANGE: + case YPOP_INSERT: + case YPOP_STORE: + xdr_argument = (xdrproc_t) xdr_ypupdate_args; + break; + case YPOP_DELETE: + xdr_argument = (xdrproc_t) xdr_ypdelete_args; + break; + default: + return YPERR_BADARGS; + break; + } + + clnt->cl_auth = authdes_create (servername, WINDOW, &saddr, NULL); + + if (clnt->cl_auth == NULL) + clnt->cl_auth = authunix_create_default (); + +again: + r = clnt_call (clnt, ypop, xdr_argument, (caddr_t) &args, + (xdrproc_t) xdr_u_int, (caddr_t) &res, RPCTIMEOUT); + + if (r == RPC_AUTHERROR) + { + if (clnt->cl_auth->ah_cred.oa_flavor == AUTH_DES) + { + auth_destroy (clnt->cl_auth); + clnt->cl_auth = authunix_create_default (); + goto again; + } + else + return YPERR_ACCESS; + } + if (r != RPC_SUCCESS) + { + clnt_perror (clnt, "yp_update: clnt_call"); + return YPERR_RPC; + } + return res; +} +libnsl_hidden_nolink_def(yp_update, GLIBC_2_0) diff --git a/REORG.TODO/nis/ypupdate_xdr.c b/REORG.TODO/nis/ypupdate_xdr.c new file mode 100644 index 0000000000..bbfb2fb683 --- /dev/null +++ b/REORG.TODO/nis/ypupdate_xdr.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2010, Oracle America, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the "Oracle America, Inc." 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 COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER 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 <rpcsvc/ypupd.h> +#include <shlib-compat.h> + +bool_t +xdr_yp_buf (XDR *xdrs, yp_buf *objp) +{ + return xdr_bytes (xdrs, (char **) &objp->yp_buf_val, + (u_int *) &objp->yp_buf_len, ~0); +} +libnsl_hidden_nolink_def (xdr_yp_buf, GLIBC_2_0) + +bool_t +xdr_ypupdate_args (XDR *xdrs, ypupdate_args *objp) +{ + if (!xdr_string (xdrs, &objp->mapname, ~0)) + return FALSE; + if (!xdr_yp_buf (xdrs, &objp->key)) + return FALSE; + return xdr_yp_buf (xdrs, &objp->datum); +} +libnsl_hidden_nolink_def (xdr_ypupdate_args, GLIBC_2_0) + +bool_t +xdr_ypdelete_args (XDR *xdrs, ypdelete_args *objp) +{ + if (!xdr_string (xdrs, &objp->mapname, ~0)) + return FALSE; + return xdr_yp_buf (xdrs, &objp->key); +} +libnsl_hidden_nolink_def (xdr_ypdelete_args, GLIBC_2_0) |