diff options
Diffstat (limited to 'REORG.TODO/nis/nss_nisplus')
-rw-r--r-- | REORG.TODO/nis/nss_nisplus/nisplus-alias.c | 337 | ||||
-rw-r--r-- | REORG.TODO/nis/nss_nisplus/nisplus-ethers.c | 356 | ||||
-rw-r--r-- | REORG.TODO/nis/nss_nisplus/nisplus-grp.c | 401 | ||||
-rw-r--r-- | REORG.TODO/nis/nss_nisplus/nisplus-hosts.c | 619 | ||||
-rw-r--r-- | REORG.TODO/nis/nss_nisplus/nisplus-initgroups.c | 148 | ||||
-rw-r--r-- | REORG.TODO/nis/nss_nisplus/nisplus-netgrp.c | 191 | ||||
-rw-r--r-- | REORG.TODO/nis/nss_nisplus/nisplus-network.c | 494 | ||||
-rw-r--r-- | REORG.TODO/nis/nss_nisplus/nisplus-parser.c | 375 | ||||
-rw-r--r-- | REORG.TODO/nis/nss_nisplus/nisplus-proto.c | 441 | ||||
-rw-r--r-- | REORG.TODO/nis/nss_nisplus/nisplus-publickey.c | 411 | ||||
-rw-r--r-- | REORG.TODO/nis/nss_nisplus/nisplus-pwd.c | 408 | ||||
-rw-r--r-- | REORG.TODO/nis/nss_nisplus/nisplus-rpc.c | 444 | ||||
-rw-r--r-- | REORG.TODO/nis/nss_nisplus/nisplus-service.c | 461 | ||||
-rw-r--r-- | REORG.TODO/nis/nss_nisplus/nisplus-spwd.c | 220 |
14 files changed, 5306 insertions, 0 deletions
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; +} |