diff options
Diffstat (limited to 'REORG.TODO/nis/nss_nis')
-rw-r--r-- | REORG.TODO/nis/nss_nis/nis-alias.c | 281 | ||||
-rw-r--r-- | REORG.TODO/nis/nss_nis/nis-ethers.c | 292 | ||||
-rw-r--r-- | REORG.TODO/nis/nss_nis/nis-grp.c | 359 | ||||
-rw-r--r-- | REORG.TODO/nis/nss_nis/nis-hosts.c | 567 | ||||
-rw-r--r-- | REORG.TODO/nis/nss_nis/nis-initgroups.c | 336 | ||||
-rw-r--r-- | REORG.TODO/nis/nss_nis/nis-netgrp.c | 98 | ||||
-rw-r--r-- | REORG.TODO/nis/nss_nis/nis-network.c | 315 | ||||
-rw-r--r-- | REORG.TODO/nis/nss_nis/nis-proto.c | 278 | ||||
-rw-r--r-- | REORG.TODO/nis/nss_nis/nis-publickey.c | 234 | ||||
-rw-r--r-- | REORG.TODO/nis/nss_nis/nis-pwd.c | 581 | ||||
-rw-r--r-- | REORG.TODO/nis/nss_nis/nis-rpc.c | 279 | ||||
-rw-r--r-- | REORG.TODO/nis/nss_nis/nis-service.c | 438 | ||||
-rw-r--r-- | REORG.TODO/nis/nss_nis/nis-spwd.c | 235 |
13 files changed, 4293 insertions, 0 deletions
diff --git a/REORG.TODO/nis/nss_nis/nis-alias.c b/REORG.TODO/nis/nss_nis/nis-alias.c new file mode 100644 index 0000000000..c9c89db6ce --- /dev/null +++ b/REORG.TODO/nis/nss_nis/nis-alias.c @@ -0,0 +1,281 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <nss.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <aliases.h> +#include <libc-lock.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> + +#include "nss-nis.h" + +__libc_lock_define_initialized (static, lock) + +static bool_t new_start = 1; +static char *oldkey; +static int oldkeylen; + +static int +_nss_nis_parse_aliasent (const char *key, char *alias, struct aliasent *result, + char *buffer, size_t buflen, int *errnop) +{ + char *first_unused = buffer + strlen (alias) + 1; + size_t room_left = + buflen - (buflen % __alignof__ (char *)) - strlen (alias) - 2; + char *line; + char *cp; + + result->alias_members_len = 0; + *first_unused = '\0'; + first_unused++; + strcpy (first_unused, key); + + if (first_unused[room_left - 1] != '\0') + { + /* The line is too long for our buffer. */ + no_more_room: + *errnop = ERANGE; + return -1; + } + + result->alias_name = first_unused; + + /* Terminate the line for any case. */ + cp = strpbrk (alias, "#\n"); + if (cp != NULL) + *cp = '\0'; + + first_unused += strlen (result->alias_name) + 1; + /* Adjust the pointer so it is aligned for + storing pointers. */ + first_unused += __alignof__ (char *) - 1; + first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *)); + result->alias_members = (char **) first_unused; + + line = alias; + + while (*line != '\0') + { + /* Skip leading blanks. */ + while (isspace (*line)) + line++; + + if (*line == '\0') + break; + + if (room_left < sizeof (char *)) + goto no_more_room; + room_left -= sizeof (char *); + result->alias_members[result->alias_members_len] = line; + + while (*line != '\0' && *line != ',') + line++; + + if (line != result->alias_members[result->alias_members_len]) + { + *line = '\0'; + line++; + result->alias_members_len++; + } + } + return result->alias_members_len == 0 ? 0 : 1; +} + +enum nss_status +_nss_nis_setaliasent (void) +{ + __libc_lock_lock (lock); + + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} +/* The 'endaliasent' function is identical. */ +strong_alias (_nss_nis_setaliasent, _nss_nis_endaliasent) + +static enum nss_status +internal_nis_getaliasent_r (struct aliasent *alias, char *buffer, + size_t buflen, int *errnop) +{ + char *domain; + + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + alias->alias_local = 0; + + /* Get the next entry until we found a correct one. */ + int parse_res; + do + { + char *result; + int len; + char *outkey; + int keylen; + int yperr; + + if (new_start) + yperr = yp_first (domain, "mail.aliases", &outkey, &keylen, &result, + &len); + else + yperr = yp_next (domain, "mail.aliases", oldkey, oldkeylen, &outkey, + &keylen, &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + char *p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_nis_parse_aliasent (outkey, p, alias, buffer, + buflen, errnop); + if (__glibc_unlikely (parse_res == -1)) + { + free (outkey); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + free (oldkey); + oldkey = outkey; + oldkeylen = keylen; + new_start = 0; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getaliasent_r (struct aliasent *alias, char *buffer, size_t buflen, + int *errnop) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_getaliasent_r (alias, buffer, buflen, errnop); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_getaliasbyname_r (const char *name, struct aliasent *alias, + char *buffer, size_t buflen, int *errnop) +{ + if (name == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + size_t namlen = strlen (name); + char *name2; + int use_alloca = __libc_use_alloca (namlen + 1); + if (use_alloca) + name2 = __alloca (namlen + 1); + else + { + name2 = malloc (namlen + 1); + if (name2 == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } + } + + /* Convert name to lowercase. */ + size_t i; + for (i = 0; i < namlen; ++i) + name2[i] = _tolower (name[i]); + name2[i] = '\0'; + + char *result; + int len; + int yperr = yp_match (domain, "mail.aliases", name2, namlen, &result, &len); + + if (!use_alloca) + free (name2); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + alias->alias_local = 0; + int parse_res = _nss_nis_parse_aliasent (name, p, alias, buffer, buflen, + errnop); + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + + return NSS_STATUS_SUCCESS; +} diff --git a/REORG.TODO/nis/nss_nis/nis-ethers.c b/REORG.TODO/nis/nss_nis/nis-ethers.c new file mode 100644 index 0000000000..2a466626e8 --- /dev/null +++ b/REORG.TODO/nis/nss_nis/nis-ethers.c @@ -0,0 +1,292 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <nss.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <libc-lock.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> +#include <netinet/ether.h> +#include <netinet/if_ether.h> + +#include "nss-nis.h" + +/* Protect global state against multiple changers */ +__libc_lock_define_initialized (static, lock) + +/* Get the declaration of the parser function. */ +#define ENTNAME etherent +#define STRUCTURE etherent +#define EXTERN_PARSER +#include <nss/nss_files/files-parse.c> + +struct response +{ + struct response *next; + char val[0]; +}; + +static struct response *start; +static struct response *next; + +static int +saveit (int instatus, char *inkey, int inkeylen, char *inval, + int invallen, char *indata) +{ + if (instatus != YP_TRUE) + return 1; + + if (inkey && inkeylen > 0 && inval && invallen > 0) + { + struct response *newp = malloc (sizeof (struct response) + invallen + 1); + if (newp == NULL) + return 1; /* We have no error code for out of memory */ + + if (start == NULL) + start = newp; + else + next->next = newp; + next = newp; + + newp->next = NULL; + *((char *) mempcpy (newp->val, inval, invallen)) = '\0'; + } + + return 0; +} + +static void +internal_nis_endetherent (void) +{ + while (start != NULL) + { + next = start; + start = start->next; + free (next); + } +} + +enum nss_status +_nss_nis_endetherent (void) +{ + __libc_lock_lock (lock); + + internal_nis_endetherent (); + next = NULL; + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_nis_setetherent (void) +{ + char *domainname; + struct ypall_callback ypcb; + enum nss_status status; + + yp_get_default_domain (&domainname); + + internal_nis_endetherent (); + + ypcb.foreach = saveit; + ypcb.data = NULL; + status = yperr2nss (yp_all (domainname, "ethers.byname", &ypcb)); + next = start; + + return status; +} + +enum nss_status +_nss_nis_setetherent (int stayopen) +{ + enum nss_status result; + + __libc_lock_lock (lock); + + result = internal_nis_setetherent (); + + __libc_lock_unlock (lock); + + return result; +} + +static enum nss_status +internal_nis_getetherent_r (struct etherent *eth, char *buffer, size_t buflen, + int *errnop) +{ + struct parser_data *data = (void *) buffer; + int parse_res; + + if (start == NULL) + internal_nis_setetherent (); + + /* Get the next entry until we found a correct one. */ + do + { + char *p; + + if (next == NULL) + return NSS_STATUS_NOTFOUND; + + p = strncpy (buffer, next->val, buflen); + + while (isspace (*p)) + ++p; + + parse_res = _nss_files_parse_etherent (p, eth, data, buflen, errnop); + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + next = next->next; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getetherent_r (struct etherent *result, char *buffer, size_t buflen, + int *errnop) +{ + int status; + + __libc_lock_lock (lock); + + status = internal_nis_getetherent_r (result, buffer, buflen, errnop); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_gethostton_r (const char *name, struct etherent *eth, + char *buffer, size_t buflen, int *errnop) +{ + if (name == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + char *result; + int len; + int yperr = yp_match (domain, "ethers.byname", name, strlen (name), &result, + &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + int parse_res = _nss_files_parse_etherent (p, eth, (void *) buffer, buflen, + errnop); + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getntohost_r (const struct ether_addr *addr, struct etherent *eth, + char *buffer, size_t buflen, int *errnop) +{ + if (addr == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + char buf[33]; + int nlen = snprintf (buf, sizeof (buf), "%x:%x:%x:%x:%x:%x", + (int) addr->ether_addr_octet[0], + (int) addr->ether_addr_octet[1], + (int) addr->ether_addr_octet[2], + (int) addr->ether_addr_octet[3], + (int) addr->ether_addr_octet[4], + (int) addr->ether_addr_octet[5]); + + char *result; + int len; + int yperr = yp_match (domain, "ethers.byaddr", buf, nlen, &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + int parse_res = _nss_files_parse_etherent (p, eth, (void *) buffer, buflen, + errnop); + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + return NSS_STATUS_SUCCESS; +} diff --git a/REORG.TODO/nis/nss_nis/nis-grp.c b/REORG.TODO/nis/nss_nis/nis-grp.c new file mode 100644 index 0000000000..05b33920fc --- /dev/null +++ b/REORG.TODO/nis/nss_nis/nis-grp.c @@ -0,0 +1,359 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <ctype.h> +#include <errno.h> +#include <grp.h> +#include <nss.h> +#include <string.h> +#include <libc-lock.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> + +#include "nss-nis.h" +#include <libnsl.h> + +/* Get the declaration of the parser function. */ +#define ENTNAME grent +#define STRUCTURE group +#define EXTERN_PARSER +#include <nss/nss_files/files-parse.c> + +/* Protect global state against multiple changers */ +__libc_lock_define_initialized (static, lock) + +static bool_t new_start = 1; +static char *oldkey; +static int oldkeylen; +static intern_t intern; + + +static void +internal_nis_endgrent (void) +{ + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + struct response_t *curr = intern.start; + + while (curr != NULL) + { + struct response_t *last = curr; + curr = curr->next; + free (last); + } + + intern.next = intern.start = NULL; +} + + +enum nss_status +_nss_nis_endgrent (void) +{ + __libc_lock_lock (lock); + + internal_nis_endgrent (); + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + + +enum nss_status +internal_nis_setgrent (void) +{ + /* We have to read all the data now. */ + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + struct ypall_callback ypcb; + + ypcb.foreach = _nis_saveit; + ypcb.data = (char *) &intern; + enum nss_status status = yperr2nss (yp_all (domain, "group.byname", &ypcb)); + + + /* Mark the last buffer as full. */ + if (intern.next != NULL) + intern.next->size = intern.offset; + + intern.next = intern.start; + intern.offset = 0; + + return status; +} + + +enum nss_status +_nss_nis_setgrent (int stayopen) +{ + enum nss_status result = NSS_STATUS_SUCCESS; + + __libc_lock_lock (lock); + + internal_nis_endgrent (); + + if (_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ) + result = internal_nis_setgrent (); + + __libc_lock_unlock (lock); + + return result; +} + + +static enum nss_status +internal_nis_getgrent_r (struct group *grp, char *buffer, size_t buflen, + int *errnop) +{ + /* If we read the entire database at setpwent time we just iterate + over the data we have in memory. */ + bool batch_read = intern.start != NULL; + + char *domain = NULL; + if (!batch_read && __builtin_expect (yp_get_default_domain (&domain), 0)) + return NSS_STATUS_UNAVAIL; + + /* Get the next entry until we found a correct one. */ + int parse_res; + do + { + char *result; + char *outkey; + int len; + int keylen; + + if (batch_read) + { + struct response_t *bucket; + + handle_batch_read: + bucket = intern.next; + + if (__glibc_unlikely (intern.offset >= bucket->size)) + { + if (bucket->next == NULL) + return NSS_STATUS_NOTFOUND; + + /* We look at all the content in the current bucket. Go on + to the next. */ + bucket = intern.next = bucket->next; + intern.offset = 0; + } + + for (result = &bucket->mem[intern.offset]; isspace (*result); + ++result) + ++intern.offset; + + len = strlen (result); + } + else + { + int yperr; + + if (new_start) + { + /* Maybe we should read the database in one piece. */ + if ((_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ) + && internal_nis_setgrent () == NSS_STATUS_SUCCESS + && intern.start != NULL) + { + batch_read = true; + goto handle_batch_read; + } + + yperr = yp_first (domain, "group.byname", &outkey, &keylen, + &result, &len); + } + else + yperr = yp_next (domain, "group.byname", oldkey, oldkeylen, + &outkey, &keylen, &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + } + + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + if (!batch_read) + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + if (!batch_read) + free (result); + + parse_res = _nss_files_parse_grent (p, grp, (void *) buffer, buflen, + errnop); + if (__glibc_unlikely (parse_res == -1)) + { + if (!batch_read) + free (outkey); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + if (batch_read) + intern.offset += len + 1; + else + { + free (oldkey); + oldkey = outkey; + oldkeylen = keylen; + new_start = 0; + } + } + while (parse_res < 1); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getgrent_r (struct group *result, char *buffer, size_t buflen, + int *errnop) +{ + int status; + + __libc_lock_lock (lock); + + status = internal_nis_getgrent_r (result, buffer, buflen, errnop); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_getgrnam_r (const char *name, struct group *grp, + char *buffer, size_t buflen, int *errnop) +{ + if (name == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + char *result; + int len; + int yperr = yp_match (domain, "group.byname", name, strlen (name), &result, + &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + int parse_res = _nss_files_parse_grent (p, grp, (void *) buffer, buflen, + errnop); + if (__builtin_expect (parse_res < 1, 0)) + { + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getgrgid_r (gid_t gid, struct group *grp, + char *buffer, size_t buflen, int *errnop) +{ + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + char buf[32]; + int nlen = sprintf (buf, "%lu", (unsigned long int) gid); + + char *result; + int len; + int yperr = yp_match (domain, "group.bygid", buf, nlen, &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + int parse_res = _nss_files_parse_grent (p, grp, (void *) buffer, buflen, + errnop); + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + return NSS_STATUS_SUCCESS; +} diff --git a/REORG.TODO/nis/nss_nis/nis-hosts.c b/REORG.TODO/nis/nss_nis/nis-hosts.c new file mode 100644 index 0000000000..f64dbdaecb --- /dev/null +++ b/REORG.TODO/nis/nss_nis/nis-hosts.c @@ -0,0 +1,567 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <nss.h> +#include <ctype.h> +/* The following is an ugly trick to avoid a prototype declaration for + _nss_nis_endgrent. */ +#define _nss_nis_endhostent _nss_nis_endhostent_XXX +#include <netdb.h> +#undef _nss_nis_endhostent +#include <string.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <resolv/resolv-internal.h> +#include <libc-lock.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> + +#include "nss-nis.h" + +/* Get implementation for some internal functions. */ +#include <resolv/mapv4v6addr.h> + +#define ENTNAME hostent +#define DATABASE "hosts" +#define NEED_H_ERRNO + +#define EXTRA_ARGS , af, flags +#define EXTRA_ARGS_DECL , int af, int flags + +#define ENTDATA hostent_data +struct hostent_data + { + unsigned char host_addr[16]; /* IPv4 or IPv6 address. */ + char *h_addr_ptrs[2]; /* Points to that and null terminator. */ + }; + +#define TRAILING_LIST_MEMBER h_aliases +#define TRAILING_LIST_SEPARATOR_P isspace +#include <nss/nss_files/files-parse.c> +LINE_PARSER +("#", + { + char *addr; + + STRING_FIELD (addr, isspace, 1); + + assert (af == AF_INET || af == AF_INET6 || af == AF_UNSPEC); + + /* Parse address. */ + if (af != AF_INET6 && inet_pton (AF_INET, addr, entdata->host_addr) > 0) + { + assert ((flags & AI_V4MAPPED) == 0 || af != AF_UNSPEC); + if (flags & AI_V4MAPPED) + { + map_v4v6_address ((char *) entdata->host_addr, + (char *) entdata->host_addr); + result->h_addrtype = AF_INET6; + result->h_length = IN6ADDRSZ; + } + else + { + result->h_addrtype = AF_INET; + result->h_length = INADDRSZ; + } + } + else if (af != AF_INET + && inet_pton (AF_INET6, addr, entdata->host_addr) > 0) + { + result->h_addrtype = AF_INET6; + result->h_length = IN6ADDRSZ; + } + else + /* Illegal address: ignore line. */ + return 0; + + /* Store a pointer to the address in the expected form. */ + entdata->h_addr_ptrs[0] = (char *) entdata->host_addr; + entdata->h_addr_ptrs[1] = NULL; + result->h_addr_list = entdata->h_addr_ptrs; + + STRING_FIELD (result->h_name, isspace, 1); + }) + + +__libc_lock_define_initialized (static, lock) + +static bool_t new_start = 1; +static char *oldkey = NULL; +static int oldkeylen = 0; + + +enum nss_status +_nss_nis_sethostent (int stayopen) +{ + __libc_lock_lock (lock); + + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} +/* Make _nss_nis_endhostent an alias of _nss_nis_sethostent. We do this + even though the prototypes don't match. The argument of sethostent + is used so this makes no difference. */ +strong_alias (_nss_nis_sethostent, _nss_nis_endhostent) + + +/* The calling function always need to get a lock first. */ +static enum nss_status +internal_nis_gethostent_r (struct hostent *host, char *buffer, + size_t buflen, int *errnop, int *h_errnop, + int af, int flags) +{ + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct parser_data); + buffer += pad; + + struct parser_data *data = (void *) buffer; + if (__glibc_unlikely (buflen < sizeof *data + 1 + pad)) + { + *errnop = ERANGE; + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + buflen -= pad; + + /* Get the next entry until we found a correct one. */ + const size_t linebuflen = buffer + buflen - data->linebuffer; + int parse_res; + do + { + char *result; + int len; + char *outkey; + int keylen; + int yperr; + if (new_start) + yperr = yp_first (domain, "hosts.byname", &outkey, &keylen, &result, + &len); + else + yperr = yp_next (domain, "hosts.byname", oldkey, oldkeylen, &outkey, + &keylen, &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + switch (retval) + { + case NSS_STATUS_TRYAGAIN: + *errnop = errno; + *h_errnop = TRY_AGAIN; + break; + case NSS_STATUS_NOTFOUND: + *h_errnop = HOST_NOT_FOUND; + break; + default: + *h_errnop = NO_RECOVERY; + break; + } + return retval; + } + + if (__glibc_unlikely ((size_t) (len + 1) > linebuflen)) + { + free (result); + *h_errnop = NETDB_INTERNAL; + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (data->linebuffer, result, len); + data->linebuffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = parse_line (p, host, data, buflen, errnop, af, flags); + if (__glibc_unlikely (parse_res == -1)) + { + free (outkey); + *h_errnop = NETDB_INTERNAL; + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + free (oldkey); + oldkey = outkey; + oldkeylen = keylen; + new_start = 0; + } + while (!parse_res); + + *h_errnop = NETDB_SUCCESS; + return NSS_STATUS_SUCCESS; +} + + +enum nss_status +_nss_nis_gethostent_r (struct hostent *host, char *buffer, size_t buflen, + int *errnop, int *h_errnop) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_gethostent_r (host, buffer, buflen, errnop, h_errnop, + (res_use_inet6 () ? AF_INET6 : AF_INET), + (res_use_inet6 () ? AI_V4MAPPED : 0 )); + + __libc_lock_unlock (lock); + + return status; +} + + +static enum nss_status +internal_gethostbyname2_r (const char *name, int af, struct hostent *host, + char *buffer, size_t buflen, int *errnop, + int *h_errnop, int flags) +{ + uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct parser_data); + buffer += pad; + + struct parser_data *data = (void *) buffer; + + if (name == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + char *domain; + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + if (buflen < sizeof *data + 1 + pad) + { + *h_errnop = NETDB_INTERNAL; + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + buflen -= pad; + + /* Convert name to lowercase. */ + size_t namlen = strlen (name); + /* Limit name length to the maximum size of an RPC packet. */ + if (namlen > UDPMSGSIZE) + { + *errnop = ERANGE; + return NSS_STATUS_UNAVAIL; + } + + char name2[namlen + 1]; + size_t i; + + for (i = 0; i < namlen; ++i) + name2[i] = tolower (name[i]); + name2[i] = '\0'; + + char *result; + int len; + int yperr = yp_match (domain, "hosts.byname", name2, namlen, &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + { + *h_errnop = TRY_AGAIN; + *errnop = errno; + } + if (retval == NSS_STATUS_NOTFOUND) + *h_errnop = HOST_NOT_FOUND; + return retval; + } + + const size_t linebuflen = buffer + buflen - data->linebuffer; + if (__glibc_unlikely ((size_t) (len + 1) > linebuflen)) + { + free (result); + *h_errnop = NETDB_INTERNAL; + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (data->linebuffer, result, len); + data->linebuffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + int parse_res = parse_line (p, host, data, buflen, errnop, af, flags); + + if (__glibc_unlikely (parse_res < 1 || host->h_addrtype != af)) + { + if (parse_res == -1) + { + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + else + { + *h_errnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } + } + + *h_errnop = NETDB_SUCCESS; + return NSS_STATUS_SUCCESS; +} + + +enum nss_status +_nss_nis_gethostbyname2_r (const char *name, int af, struct hostent *host, + char *buffer, size_t buflen, int *errnop, + int *h_errnop) +{ + if (af != AF_INET && af != AF_INET6) + { + *h_errnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } + + return internal_gethostbyname2_r (name, af, host, buffer, buflen, errnop, + h_errnop, + (res_use_inet6 () ? AI_V4MAPPED : 0)); +} + + +enum nss_status +_nss_nis_gethostbyname_r (const char *name, struct hostent *host, char *buffer, + size_t buflen, int *errnop, int *h_errnop) +{ + if (res_use_inet6 ()) + { + enum nss_status status; + + status = internal_gethostbyname2_r (name, AF_INET6, host, buffer, buflen, + errnop, h_errnop, AI_V4MAPPED); + if (status == NSS_STATUS_SUCCESS) + return status; + } + + return internal_gethostbyname2_r (name, AF_INET, host, buffer, buflen, + errnop, h_errnop, 0); +} + + +enum nss_status +_nss_nis_gethostbyaddr_r (const void *addr, socklen_t addrlen, int af, + struct hostent *host, char *buffer, size_t buflen, + int *errnop, int *h_errnop) +{ + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct parser_data); + buffer += pad; + + struct parser_data *data = (void *) buffer; + if (__glibc_unlikely (buflen < sizeof *data + 1 + pad)) + { + *errnop = ERANGE; + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + buflen -= pad; + + char *buf = inet_ntoa (*(const struct in_addr *) addr); + + char *result; + int len; + int yperr = yp_match (domain, "hosts.byaddr", buf, strlen (buf), &result, + &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + { + *h_errnop = TRY_AGAIN; + *errnop = errno; + } + else if (retval == NSS_STATUS_NOTFOUND) + *h_errnop = HOST_NOT_FOUND; + + return retval; + } + + const size_t linebuflen = buffer + buflen - data->linebuffer; + if (__glibc_unlikely ((size_t) (len + 1) > linebuflen)) + { + free (result); + *errnop = ERANGE; + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (data->linebuffer, result, len); + data->linebuffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + int parse_res = parse_line (p, host, data, buflen, errnop, af, + (res_use_inet6 () ? AI_V4MAPPED : 0)); + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + { + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + else + { + *h_errnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } + } + + *h_errnop = NETDB_SUCCESS; + return NSS_STATUS_SUCCESS; +} + + +enum nss_status +_nss_nis_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, + char *buffer, size_t buflen, int *errnop, + int *herrnop, int32_t *ttlp) +{ + char *domain; + if (yp_get_default_domain (&domain)) + { + *herrnop = NO_DATA; + return NSS_STATUS_UNAVAIL; + } + + /* Convert name to lowercase. */ + size_t namlen = strlen (name); + /* Limit name length to the maximum size of an RPC packet. */ + if (namlen > UDPMSGSIZE) + { + *errnop = ERANGE; + return NSS_STATUS_UNAVAIL; + } + + char name2[namlen + 1]; + size_t i; + + for (i = 0; i < namlen; ++i) + name2[i] = tolower (name[i]); + name2[i] = '\0'; + + char *result; + int len; + int yperr = yp_match (domain, "hosts.byname", name2, namlen, &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + { + *herrnop = TRY_AGAIN; + *errnop = errno; + } + if (retval == NSS_STATUS_NOTFOUND) + *herrnop = HOST_NOT_FOUND; + return retval; + } + + if (*pat == NULL) + { + uintptr_t pad = (-(uintptr_t) buffer + % __alignof__ (struct gaih_addrtuple)); + buffer += pad; + buflen = buflen > pad ? buflen - pad : 0; + + if (__glibc_unlikely (buflen < sizeof (struct gaih_addrtuple))) + { + erange: + free (result); + *errnop = ERANGE; + *herrnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + + *pat = (struct gaih_addrtuple *) buffer; + buffer += sizeof (struct gaih_addrtuple); + buflen -= sizeof (struct gaih_addrtuple); + } + + uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct parser_data); + buffer += pad; + + struct parser_data *data = (void *) buffer; + + if (__glibc_unlikely (buflen < sizeof *data + 1 + pad)) + goto erange; + buflen -= pad; + + struct hostent host; + int parse_res = parse_line (result, &host, data, buflen, errnop, AF_UNSPEC, + 0); + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + { + *herrnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + else + { + *herrnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } + } + + (*pat)->next = NULL; + (*pat)->family = host.h_addrtype; + memcpy ((*pat)->addr, host.h_addr_list[0], host.h_length); + (*pat)->scopeid = 0; + assert (host.h_addr_list[1] == NULL); + + /* Undo the alignment for parser_data. */ + buffer -= pad; + buflen += pad; + + size_t h_name_len = strlen (host.h_name) + 1; + if (h_name_len >= buflen) + goto erange; + (*pat)->name = memcpy (buffer, host.h_name, h_name_len); + + free (result); + + return NSS_STATUS_SUCCESS; +} diff --git a/REORG.TODO/nis/nss_nis/nis-initgroups.c b/REORG.TODO/nis/nss_nis/nis-initgroups.c new file mode 100644 index 0000000000..3784c101f7 --- /dev/null +++ b/REORG.TODO/nis/nss_nis/nis-initgroups.c @@ -0,0 +1,336 @@ +/* Copyright (C) 1998-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <alloca.h> +#include <ctype.h> +#include <errno.h> +#include <grp.h> +#include <nss.h> +#include <pwd.h> +#include <string.h> +#include <unistd.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> +#include <sys/param.h> + +#include "nss-nis.h" +#include <libnsl.h> + +/* Get the declaration of the parser function. */ +#define ENTNAME grent +#define STRUCTURE group +#define EXTERN_PARSER +#include <nss/nss_files/files-parse.c> + + +static enum nss_status +internal_setgrent (char *domainname, intern_t *intern) +{ + struct ypall_callback ypcb; + enum nss_status status; + + ypcb.foreach = _nis_saveit; + ypcb.data = (char *) intern; + status = yperr2nss (yp_all (domainname, "group.byname", &ypcb)); + + /* Mark the last buffer as full. */ + if (intern->next != NULL) + intern->next->size = intern->offset; + + intern->next = intern->start; + intern->offset = 0; + + return status; +} + + +static enum nss_status +internal_getgrent_r (struct group *grp, char *buffer, size_t buflen, + int *errnop, intern_t *intern) +{ + if (intern->start == NULL) + return NSS_STATUS_NOTFOUND; + + /* Get the next entry until we found a correct one. */ + int parse_res; + do + { + struct response_t *bucket = intern->next; + + if (__glibc_unlikely (intern->offset >= bucket->size)) + { + if (bucket->next == NULL) + return NSS_STATUS_NOTFOUND; + + /* We look at all the content in the current bucket. Go on + to the next. */ + bucket = intern->next = bucket->next; + intern->offset = 0; + } + + char *p; + for (p = &bucket->mem[intern->offset]; isspace (*p); ++p) + ++intern->offset; + + size_t len = strlen (p) + 1; + if (__glibc_unlikely (len > buflen)) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + /* We unfortunately have to copy the data in the user-provided + buffer because that buffer might be around for a very long + time and the servent structure must remain valid. If we would + rely on the BUCKET memory the next 'setservent' or 'endservent' + call would destroy it. + + The important thing is that it is a single NUL-terminated + string. This is what the parsing routine expects. */ + p = memcpy (buffer, &bucket->mem[intern->offset], len); + + parse_res = _nss_files_parse_grent (p, grp, (void *) buffer, buflen, + errnop); + if (__glibc_unlikely (parse_res == -1)) + return NSS_STATUS_TRYAGAIN; + + intern->offset += len; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + + +static int +get_uid (const char *user, uid_t *uidp) +{ + size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX); + char *buf = (char *) alloca (buflen); + + while (1) + { + struct passwd result; + struct passwd *resp; + + int r = getpwnam_r (user, &result, buf, buflen, &resp); + if (r == 0 && resp != NULL) + { + *uidp = resp->pw_uid; + return 0; + } + + if (r != ERANGE) + break; + + buf = extend_alloca (buf, buflen, 2 * buflen); + } + + return 1; +} + + +static enum nss_status +initgroups_netid (uid_t uid, gid_t group, long int *start, long int *size, + gid_t **groupsp, long int limit, int *errnop, + const char *domainname) +{ + /* Limit domainname length to the maximum size of an RPC packet. */ + if (strlen (domainname) > UDPMSGSIZE) + { + *errnop = ERANGE; + return NSS_STATUS_UNAVAIL; + } + + /* Prepare the key. The form is "unix.UID@DOMAIN" with the UID and + DOMAIN field filled in appropriately. */ + char key[sizeof ("unix.@") + sizeof (uid_t) * 3 + strlen (domainname)]; + ssize_t keylen = snprintf (key, sizeof (key), "unix.%lu@%s", + (unsigned long int) uid, domainname); + + char *result; + int reslen; + int yperr = yp_match (domainname, "netid.byname", key, keylen, &result, + &reslen); + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + return yperr2nss (yperr); + + /* Parse the result: following the colon is a comma separated list of + group IDs. */ + char *cp = strchr (result, ':'); + if (cp == NULL) + { + errout: + free (result); + return NSS_STATUS_NOTFOUND; + } + /* Skip the colon. */ + ++cp; + + gid_t *groups = *groupsp; + while (*cp != '\0') + { + char *endp; + unsigned long int gid = strtoul (cp, &endp, 0); + if (cp == endp) + goto errout; + if (*endp == ',') + ++endp; + else if (*endp != '\0') + goto errout; + cp = endp; + + if (gid == group) + /* We do not need this group again. */ + continue; + + /* Insert this group. */ + if (*start == *size) + { + /* Need a bigger buffer. */ + long int newsize; + + if (limit > 0 && *size == limit) + /* We reached the maximum. */ + break; + + if (limit <= 0) + newsize = 2 * *size; + else + newsize = MIN (limit, 2 * *size); + + gid_t *newgroups = realloc (groups, newsize * sizeof (*groups)); + if (newgroups == NULL) + goto errout; + *groupsp = groups = newgroups; + *size = newsize; + } + + groups[*start] = gid; + *start += 1; + } + + free (result); + + return NSS_STATUS_SUCCESS; +} + + +enum nss_status +_nss_nis_initgroups_dyn (const char *user, gid_t group, long int *start, + long int *size, gid_t **groupsp, long int limit, + int *errnop) +{ + /* We always need the domain name. */ + char *domainname; + if (yp_get_default_domain (&domainname)) + return NSS_STATUS_UNAVAIL; + + /* Check whether we are supposed to use the netid.byname map. */ + if (_nsl_default_nss () & NSS_FLAG_NETID_AUTHORITATIVE) + { + /* We need the user ID. */ + uid_t uid; + + if (get_uid (user, &uid) == 0 + && initgroups_netid (uid, group, start, size, groupsp, limit, + errnop, domainname) == NSS_STATUS_SUCCESS) + return NSS_STATUS_SUCCESS; + } + + struct group grpbuf, *g; + size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX); + char *tmpbuf; + enum nss_status status; + intern_t intern = { NULL, NULL, 0 }; + gid_t *groups = *groupsp; + + status = internal_setgrent (domainname, &intern); + if (status != NSS_STATUS_SUCCESS) + return status; + + tmpbuf = __alloca (buflen); + + while (1) + { + while ((status = + internal_getgrent_r (&grpbuf, tmpbuf, buflen, errnop, + &intern)) == NSS_STATUS_TRYAGAIN + && *errnop == ERANGE) + tmpbuf = extend_alloca (tmpbuf, buflen, 2 * buflen); + + if (status != NSS_STATUS_SUCCESS) + { + if (status == NSS_STATUS_NOTFOUND) + status = NSS_STATUS_SUCCESS; + goto done; + } + + g = &grpbuf; + if (g->gr_gid != group) + { + char **m; + + for (m = g->gr_mem; *m != NULL; ++m) + if (strcmp (*m, user) == 0) + { + /* Matches user. Insert this group. */ + if (*start == *size) + { + /* Need a bigger buffer. */ + gid_t *newgroups; + long int newsize; + + if (limit > 0 && *size == limit) + /* We reached the maximum. */ + goto done; + + if (limit <= 0) + newsize = 2 * *size; + else + newsize = MIN (limit, 2 * *size); + + newgroups = realloc (groups, newsize * sizeof (*groups)); + if (newgroups == NULL) + { + status = NSS_STATUS_TRYAGAIN; + *errnop = errno; + goto done; + } + *groupsp = groups = newgroups; + *size = newsize; + } + + groups[*start] = g->gr_gid; + *start += 1; + + break; + } + } + } + +done: + while (intern.start != NULL) + { + intern.next = intern.start; + intern.start = intern.start->next; + free (intern.next); + } + + return status; +} diff --git a/REORG.TODO/nis/nss_nis/nis-netgrp.c b/REORG.TODO/nis/nss_nis/nis-netgrp.c new file mode 100644 index 0000000000..ab3835fffa --- /dev/null +++ b/REORG.TODO/nis/nss_nis/nis-netgrp.c @@ -0,0 +1,98 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <ctype.h> +#include <errno.h> +#include <malloc.h> +#include <netdb.h> +#include <nss.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <netgroup.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> + +#include "nss-nis.h" + +extern enum nss_status +_nss_netgroup_parseline (char **cursor, struct __netgrent *netgrp, + char *buffer, size_t buflen, int *errnop); + + +static void +internal_nis_endnetgrent (struct __netgrent *netgrp) +{ + free (netgrp->data); + netgrp->data = NULL; + netgrp->data_size = 0; + netgrp->cursor = NULL; +} + + +enum nss_status +_nss_nis_setnetgrent (const char *group, struct __netgrent *netgrp) +{ + int len; + enum nss_status status; + + status = NSS_STATUS_SUCCESS; + + if (__glibc_unlikely (group == NULL || group[0] == '\0')) + return NSS_STATUS_UNAVAIL; + + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + status = yperr2nss (yp_match (domain, "netgroup", group, strlen (group), + &netgrp->data, &len)); + if (__glibc_likely (status == NSS_STATUS_SUCCESS)) + { + /* Our implementation of yp_match already allocates a buffer + which is one byte larger than the value in LEN specifies + and the last byte is filled with NUL. So we can simply + use that buffer. */ + assert (len >= 0); + assert (netgrp->data[len] == '\0'); + + netgrp->data_size = len; + netgrp->cursor = netgrp->data; + } + + return status; +} + + +enum nss_status +_nss_nis_endnetgrent (struct __netgrent *netgrp) +{ + internal_nis_endnetgrent (netgrp); + + return NSS_STATUS_SUCCESS; +} + + +enum nss_status +_nss_nis_getnetgrent_r (struct __netgrent *result, char *buffer, size_t buflen, + int *errnop) +{ + return _nss_netgroup_parseline (&result->cursor, result, buffer, buflen, + errnop); +} diff --git a/REORG.TODO/nis/nss_nis/nis-network.c b/REORG.TODO/nis/nss_nis/nis-network.c new file mode 100644 index 0000000000..baf0ce4b8a --- /dev/null +++ b/REORG.TODO/nis/nss_nis/nis-network.c @@ -0,0 +1,315 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <nss.h> +/* The following is an ugly trick to avoid a prototype declaration for + _nss_nis_endgrent. */ +#define _nss_nis_endnetent _nss_nis_endnetent_XXX +#include <netdb.h> +#undef _nss_nis_endnetent +#include <ctype.h> +#include <errno.h> +#include <stdint.h> +#include <string.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <libc-lock.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> + +#include "nss-nis.h" + +/* Get the declaration of the parser function. */ +#define ENTNAME netent +#define EXTERN_PARSER +#include <nss/nss_files/files-parse.c> + +__libc_lock_define_initialized (static, lock) + +static bool_t new_start = 1; +static char *oldkey; +static int oldkeylen; + +enum nss_status +_nss_nis_setnetent (int stayopen) +{ + __libc_lock_lock (lock); + + new_start = 1; + if (oldkey != NULL) + { + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + } + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} +/* Make _nss_nis_endnetent an alias of _nss_nis_setnetent. We do this + even though the prototypes don't match. The argument of setnetent + is not used so this makes no difference. */ +strong_alias (_nss_nis_setnetent, _nss_nis_endnetent) + +static enum nss_status +internal_nis_getnetent_r (struct netent *net, char *buffer, size_t buflen, + int *errnop, int *herrnop) +{ + struct parser_data *data = (void *) buffer; + + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + /* Get the next entry until we found a correct one. */ + int parse_res; + do + { + char *result; + char *outkey; + int len; + int keylen; + int yperr; + + if (new_start) + yperr = yp_first (domain, "networks.byname", &outkey, &keylen, &result, + &len); + else + yperr = yp_next (domain, "networks.byname", oldkey, oldkeylen, &outkey, + &keylen, &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + { + *herrnop = NETDB_INTERNAL; + *errnop = errno; + } + return retval; + } + + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + *herrnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_netent (p, net, data, buflen, errnop); + if (__glibc_unlikely (parse_res == -1)) + { + free (outkey); + *herrnop = NETDB_INTERNAL; + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + free (oldkey); + oldkey = outkey; + oldkeylen = keylen; + new_start = 0; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getnetent_r (struct netent *net, char *buffer, size_t buflen, + int *errnop, int *herrnop) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_getnetent_r (net, buffer, buflen, errnop, herrnop); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_getnetbyname_r (const char *name, struct netent *net, char *buffer, + size_t buflen, int *errnop, int *herrnop) +{ + if (name == NULL) + { + *errnop = EINVAL; + *herrnop = NETDB_INTERNAL; + return NSS_STATUS_UNAVAIL; + } + + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + struct parser_data *data = (void *) buffer; + if (buflen < sizeof *data + 1) + { + *herrnop = NETDB_INTERNAL; + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + /* Convert name to lowercase. */ + size_t namlen = strlen (name); + /* Limit name length to the maximum size of an RPC packet. */ + if (namlen > UDPMSGSIZE) + { + *errnop = ERANGE; + return NSS_STATUS_UNAVAIL; + } + + char name2[namlen + 1]; + size_t i; + + for (i = 0; i < namlen; ++i) + name2[i] = _tolower (name[i]); + name2[i] = '\0'; + + char *result; + int len; + int yperr = yp_match (domain, "networks.byname", name2, namlen, &result, + &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + { + *errnop = errno; + *herrnop = NETDB_INTERNAL; + } + return retval; + } + + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + *herrnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + int parse_res = _nss_files_parse_netent (p, net, data, buflen, errnop); + + if (__glibc_unlikely (parse_res < 1)) + { + *herrnop = NETDB_INTERNAL; + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + else + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getnetbyaddr_r (uint32_t addr, int type, struct netent *net, + char *buffer, size_t buflen, int *errnop, + int *herrnop) +{ + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + struct in_addr in = { .s_addr = htonl (addr) }; + char *buf = inet_ntoa (in); + size_t blen = strlen (buf); + + while (1) + { + char *result; + int len; + + int yperr = yp_match (domain, "networks.byaddr", buf, blen, &result, + &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_NOTFOUND) + { + if (buf[blen - 2] == '.' && buf[blen - 1] == '0') + { + /* Try again, but with trailing dot(s) + removed (one by one) */ + buf[blen - 2] = '\0'; + blen -= 2; + continue; + } + else + return NSS_STATUS_NOTFOUND; + } + else + { + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + } + + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + *herrnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + int parse_res = _nss_files_parse_netent (p, net, (void *) buffer, + buflen, errnop); + + if (__glibc_unlikely (parse_res < 1)) + { + *herrnop = NETDB_INTERNAL; + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + else + return NSS_STATUS_SUCCESS; + } +} diff --git a/REORG.TODO/nis/nss_nis/nis-proto.c b/REORG.TODO/nis/nss_nis/nis-proto.c new file mode 100644 index 0000000000..df0739aaad --- /dev/null +++ b/REORG.TODO/nis/nss_nis/nis-proto.c @@ -0,0 +1,278 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <nss.h> +#include <netdb.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <libc-lock.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> + +#include "nss-nis.h" + +/* Get the declaration of the parser function. */ +#define ENTNAME protoent +#define EXTERN_PARSER +#include <nss/nss_files/files-parse.c> + +__libc_lock_define_initialized (static, lock) + +struct response +{ + struct response *next; + char val[0]; +}; + +static struct response *start; +static struct response *next; + +static int +saveit (int instatus, char *inkey, int inkeylen, char *inval, + int invallen, char *indata) +{ + if (instatus != YP_TRUE) + return 1; + + if (inkey && inkeylen > 0 && inval && invallen > 0) + { + struct response *newp = malloc (sizeof (struct response) + invallen + 1); + if (newp == NULL) + return 1; /* We have no error code for out of memory */ + + if (start == NULL) + start = newp; + else + next->next = newp; + next = newp; + + newp->next = NULL; + *((char *) mempcpy (newp->val, inval, invallen)) = '\0'; + } + + return 0; +} + +static void +internal_nis_endprotoent (void) +{ + while (start != NULL) + { + next = start; + start = start->next; + free (next); + } +} + +static enum nss_status +internal_nis_setprotoent (void) +{ + char *domainname; + struct ypall_callback ypcb; + enum nss_status status; + + yp_get_default_domain (&domainname); + + internal_nis_endprotoent (); + + ypcb.foreach = saveit; + ypcb.data = NULL; + status = yperr2nss (yp_all (domainname, "protocols.bynumber", &ypcb)); + next = start; + + return status; +} + +enum nss_status +_nss_nis_setprotoent (int stayopen) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_setprotoent (); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_endprotoent (void) +{ + __libc_lock_lock (lock); + + internal_nis_endprotoent (); + next = NULL; + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_nis_getprotoent_r (struct protoent *proto, + char *buffer, size_t buflen, int *errnop) +{ + struct parser_data *data = (void *) buffer; + int parse_res; + + if (start == NULL) + internal_nis_setprotoent (); + + /* Get the next entry until we found a correct one. */ + do + { + char *p; + + if (next == NULL) + return NSS_STATUS_NOTFOUND; + + p = strncpy (buffer, next->val, buflen); + + while (isspace (*p)) + ++p; + + parse_res = _nss_files_parse_protoent (p, proto, data, buflen, errnop); + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + next = next->next; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getprotoent_r (struct protoent *proto, char *buffer, size_t buflen, + int *errnop) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_getprotoent_r (proto, buffer, buflen, errnop); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_getprotobyname_r (const char *name, struct protoent *proto, + char *buffer, size_t buflen, int *errnop) +{ + if (name == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + char *result; + int len; + int yperr = yp_match (domain, "protocols.byname", name, strlen (name), + &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + int parse_res = _nss_files_parse_protoent (p, proto, (void *) buffer, buflen, + errnop); + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getprotobynumber_r (int number, struct protoent *proto, + char *buffer, size_t buflen, int *errnop) +{ + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + char buf[32]; + int nlen = snprintf (buf, sizeof (buf), "%d", number); + + char *result; + int len; + int yperr = yp_match (domain, "protocols.bynumber", buf, nlen, &result, + &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + int parse_res = _nss_files_parse_protoent (p, proto, (void *) buffer, buflen, + errnop); + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + return NSS_STATUS_SUCCESS; +} diff --git a/REORG.TODO/nis/nss_nis/nis-publickey.c b/REORG.TODO/nis/nss_nis/nis-publickey.c new file mode 100644 index 0000000000..188e80cd5d --- /dev/null +++ b/REORG.TODO/nis/nss_nis/nis-publickey.c @@ -0,0 +1,234 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <nss.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <syslog.h> +#include <rpc/rpc.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> +#include <rpc/key_prot.h> +#include <rpc/des_crypt.h> + +#include "nss-nis.h" + +/* If we haven't found the entry, we give a SUCCESS and an empty key back. + Solaris docu says: sizeof (pkey) == HEXKEYBYTES + 1. +*/ +enum nss_status +_nss_nis_getpublickey (const char *netname, char *pkey, int *errnop) +{ + pkey[0] = 0; + + if (netname == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + char *domain = strchr (netname, '@'); + if (domain == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + ++domain; + + char *result; + int len; + int yperr = yp_match (domain, "publickey.byname", netname, strlen (netname), + &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + + if (result != NULL) + { + char *p = strchr (result, ':'); + if (p != NULL) + *p = 0; + strncpy (pkey, result, HEXKEYBYTES + 1); + pkey[HEXKEYBYTES] = '\0'; + free (result); + } + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getsecretkey (const char *netname, char *skey, char *passwd, + int *errnop) +{ + skey[0] = 0; + + if (netname == NULL || passwd == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + char *domain = strchr (netname, '@'); + if (domain == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + ++domain; + + char *result; + int len; + int yperr = yp_match (domain, "publickey.byname", netname, strlen (netname), + &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + + if (result != NULL) + { + char *p = strchr (result, ':'); + if (p != NULL) + { + char buf[2 * (HEXKEYBYTES + 1)]; + + ++p; + strncpy (buf, p, 2 * (HEXKEYBYTES + 1)); + buf[2 * HEXKEYBYTES + 1] = '\0'; + if (xdecrypt (buf, passwd) + && memcmp (buf, &(buf[HEXKEYBYTES]), KEYCHECKSUMSIZE) == 0) + { + buf[HEXKEYBYTES] = '\0'; + strcpy (skey, buf); + } + } + + free (result); + } + return NSS_STATUS_SUCCESS; +} + +/* Parse uid and group information from the passed string. + The format of the string passed is uid:gid,grp,grp, ... */ +static enum nss_status +parse_netid_str (const char *s, uid_t *uidp, gid_t *gidp, int *gidlenp, + gid_t *gidlist) +{ + char *p, *ep; + int gidlen; + + if (!s || !isdigit (*s)) + { + syslog (LOG_ERR, "netname2user: expecting uid '%s'", s); + return NSS_STATUS_NOTFOUND; /* XXX need a better error */ + } + + /* Fetch the uid */ + *uidp = strtoul (s, NULL, 10); + + if (*uidp == 0) + { + syslog (LOG_ERR, "netname2user: should not have uid 0"); + return NSS_STATUS_NOTFOUND; + } + + /* Now get the group list */ + p = strchr (s, ':'); + if (!p) + { + syslog (LOG_ERR, "netname2user: missing group id list in '%s'", s); + return NSS_STATUS_NOTFOUND; + } + ++p; /* skip ':' */ + if (!p || (!isdigit (*p))) + { + syslog (LOG_ERR, "netname2user: missing group id list in '%s'.", p); + return NSS_STATUS_NOTFOUND; + } + + *gidp = strtoul (p, &ep, 10); + + gidlen = 0; + + /* After strtoul() ep should point to the first invalid character. + This is the marker "," we search for the next value. */ + while (ep != NULL && *ep == ',') + { + ep++; + p = ep; + gidlist[gidlen++] = strtoul (p, &ep, 10); + } + + *gidlenp = gidlen; + + return NSS_STATUS_SUCCESS; +} + + +enum nss_status +_nss_nis_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp, + gid_t *gidp, int *gidlenp, gid_t *gidlist, int *errnop) +{ + char *domain = strchr (netname, '@'); + if (domain == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + /* Point past the '@' character */ + ++domain; + char *lookup = NULL; + int len; + int yperr = yp_match (domain, "netid.byname", netname, strlen (netname), + &lookup, &len); + switch (yperr) + { + case YPERR_SUCCESS: + break; /* the successful case */ + case YPERR_DOMAIN: + case YPERR_KEY: + return NSS_STATUS_NOTFOUND; + case YPERR_MAP: + default: + return NSS_STATUS_UNAVAIL; + } + + if (lookup == NULL) + return NSS_STATUS_NOTFOUND; + + + lookup[len] = '\0'; + + enum nss_status err = parse_netid_str (lookup, uidp, gidp, gidlenp, gidlist); + + free (lookup); + + return err; +} diff --git a/REORG.TODO/nis/nss_nis/nis-pwd.c b/REORG.TODO/nis/nss_nis/nis-pwd.c new file mode 100644 index 0000000000..6a759eeaec --- /dev/null +++ b/REORG.TODO/nis/nss_nis/nis-pwd.c @@ -0,0 +1,581 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <ctype.h> +#include <errno.h> +#include <nss.h> +#include <pwd.h> +#include <string.h> +#include <libc-lock.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> + +#include "nss-nis.h" +#include <libnsl.h> + +/* Get the declaration of the parser function. */ +#define ENTNAME pwent +#define STRUCTURE passwd +#define EXTERN_PARSER +#include <nss/nss_files/files-parse.c> + +/* Protect global state against multiple changers */ +__libc_lock_define_initialized (static, lock) + +static bool new_start = true; +static char *oldkey; +static int oldkeylen; +static intern_t intern; + + +int +_nis_saveit (int instatus, char *inkey, int inkeylen, char *inval, + int invallen, char *indata) +{ + intern_t *intern = (intern_t *) indata; + + if (instatus != YP_TRUE) + return 1; + + if (inkey && inkeylen > 0 && inval && invallen > 0) + { + struct response_t *bucket = intern->next; + + if (__glibc_unlikely (bucket == NULL)) + { +#define MINSIZE 4096 - 4 * sizeof (void *) + const size_t minsize = MAX (MINSIZE, 2 * (invallen + 1)); + bucket = malloc (sizeof (struct response_t) + minsize); + if (bucket == NULL) + /* We have no error code for out of memory. */ + return 1; + + bucket->next = NULL; + bucket->size = minsize; + intern->start = intern->next = bucket; + intern->offset = 0; + } + else if (__builtin_expect (invallen + 1 > bucket->size - intern->offset, + 0)) + { + /* We need a new (larger) buffer. */ + const size_t newsize = 2 * MAX (bucket->size, invallen + 1); + struct response_t *newp = malloc (sizeof (struct response_t) + + newsize); + if (newp == NULL) + /* We have no error code for out of memory. */ + return 1; + + /* Mark the old bucket as full. */ + bucket->size = intern->offset; + + newp->next = NULL; + newp->size = newsize; + bucket = intern->next = bucket->next = newp; + intern->offset = 0; + } + + char *p = mempcpy (&bucket->mem[intern->offset], inval, invallen); + if (__glibc_unlikely (p[-1] != '\0')) + { + *p = '\0'; + ++invallen; + } + intern->offset += invallen; + } + + return 0; +} + + +static void +internal_nis_endpwent (void) +{ + new_start = true; + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + + struct response_t *curr = intern.start; + + while (curr != NULL) + { + struct response_t *last = curr; + curr = curr->next; + free (last); + } + + intern.next = intern.start = NULL; +} + + +enum nss_status +_nss_nis_endpwent (void) +{ + __libc_lock_lock (lock); + + internal_nis_endpwent (); + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + + +enum nss_status +internal_nis_setpwent (void) +{ + /* We have to read all the data now. */ + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + struct ypall_callback ypcb; + + ypcb.foreach = _nis_saveit; + ypcb.data = (char *) &intern; + enum nss_status status = yperr2nss (yp_all (domain, "passwd.byname", &ypcb)); + + + /* Mark the last buffer as full. */ + if (intern.next != NULL) + intern.next->size = intern.offset; + + intern.next = intern.start; + intern.offset = 0; + + return status; +} + + +enum nss_status +_nss_nis_setpwent (int stayopen) +{ + enum nss_status result = NSS_STATUS_SUCCESS; + + __libc_lock_lock (lock); + + internal_nis_endpwent (); + + if (_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ) + result = internal_nis_setpwent (); + + __libc_lock_unlock (lock); + + return result; +} + + +static enum nss_status +internal_nis_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen, + int *errnop) +{ + /* If we read the entire database at setpwent time we just iterate + over the data we have in memory. */ + bool batch_read = intern.start != NULL; + + char *domain = NULL; + if (!batch_read && __builtin_expect (yp_get_default_domain (&domain), 0)) + return NSS_STATUS_UNAVAIL; + + /* Get the next entry until we found a correct one. */ + int parse_res; + do + { + char *result; + char *outkey; + int len; + int keylen; + + if (batch_read) + { + struct response_t *bucket; + + handle_batch_read: + bucket = intern.next; + + if (__glibc_unlikely (intern.offset >= bucket->size)) + { + if (bucket->next == NULL) + return NSS_STATUS_NOTFOUND; + + /* We look at all the content in the current bucket. Go on + to the next. */ + bucket = intern.next = bucket->next; + intern.offset = 0; + } + + for (result = &bucket->mem[intern.offset]; isspace (*result); + ++result) + ++intern.offset; + + len = strlen (result); + } + else + { + int yperr; + + if (new_start) + { + /* Maybe we should read the database in one piece. */ + if ((_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ) + && internal_nis_setpwent () == NSS_STATUS_SUCCESS + && intern.start != NULL) + { + batch_read = true; + goto handle_batch_read; + } + + yperr = yp_first (domain, "passwd.byname", &outkey, &keylen, + &result, &len); + } + else + yperr = yp_next (domain, "passwd.byname", oldkey, oldkeylen, + &outkey, &keylen, &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + } + + /* Check for adjunct style secret passwords. They can be + recognized by a password starting with "##". We do not use + it if the passwd.adjunct.byname table is supposed to be used + as a shadow.byname replacement. */ + char *p = strchr (result, ':'); + size_t namelen; + char *result2; + int len2; + if ((_nsl_default_nss () & NSS_FLAG_ADJUNCT_AS_SHADOW) == 0 + && p != NULL /* This better should be true in all cases. */ + && p[1] == '#' && p[2] == '#' + && (namelen = p - result, + yp_match (domain, "passwd.adjunct.byname", result, namelen, + &result2, &len2)) == YPERR_SUCCESS) + { + /* We found a passwd.adjunct.byname entry. Merge encrypted + password therein into original result. */ + char *encrypted = strchr (result2, ':'); + char *endp; + size_t restlen; + + if (encrypted == NULL + || (endp = strchr (++encrypted, ':')) == NULL + || (p = strchr (p + 1, ':')) == NULL) + { + /* Invalid format of the entry. This never should happen + unless the data from which the NIS table is generated is + wrong. We simply ignore it. */ + free (result2); + goto non_adjunct; + } + + restlen = len - (p - result); + if (__builtin_expect ((size_t) (namelen + (endp - encrypted) + + restlen + 2) > buflen, 0)) + { + free (result2); + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + mempcpy (mempcpy (mempcpy (mempcpy (buffer, result, namelen), + ":", 1), + encrypted, endp - encrypted), + p, restlen + 1); + p = buffer; + + free (result2); + } + else + { + non_adjunct: + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + p = buffer; + *((char *) mempcpy (buffer, result, len)) = '\0'; + } + + while (isspace (*p)) + ++p; + if (!batch_read) + free (result); + + parse_res = _nss_files_parse_pwent (p, pwd, (void *) buffer, buflen, + errnop); + if (__glibc_unlikely (parse_res == -1)) + { + if (!batch_read) + free (outkey); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + if (batch_read) + intern.offset += len + 1; + else + { + free (oldkey); + oldkey = outkey; + oldkeylen = keylen; + new_start = false; + } + } + while (parse_res < 1); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getpwent_r (struct passwd *result, char *buffer, size_t buflen, + int *errnop) +{ + int status; + + __libc_lock_lock (lock); + + status = internal_nis_getpwent_r (result, buffer, buflen, errnop); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_getpwnam_r (const char *name, struct passwd *pwd, + char *buffer, size_t buflen, int *errnop) +{ + if (name == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + size_t namelen = strlen (name); + + char *result; + int len; + int yperr = yp_match (domain, "passwd.byname", name, namelen, &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + + /* Check for adjunct style secret passwords. They can be recognized + by a password starting with "##". We do not use it if the + passwd.adjunct.byname table is supposed to be used as a shadow.byname + replacement. */ + char *result2; + int len2; + char *p = strchr (result, ':'); + if ((_nsl_default_nss () & NSS_FLAG_ADJUNCT_AS_SHADOW) == 0 + && p != NULL /* This better should be true in all cases. */ + && p[1] == '#' && p[2] == '#' + && yp_match (domain, "passwd.adjunct.byname", name, namelen, + &result2, &len2) == YPERR_SUCCESS) + { + /* We found a passwd.adjunct.byname entry. Merge encrypted password + therein into original result. */ + char *encrypted = strchr (result2, ':'); + char *endp; + + if (encrypted == NULL + || (endp = strchr (++encrypted, ':')) == NULL + || (p = strchr (p + 1, ':')) == NULL) + { + /* Invalid format of the entry. This never should happen + unless the data from which the NIS table is generated is + wrong. We simply ignore it. */ + free (result2); + goto non_adjunct; + } + + size_t restlen = len - (p - result); + if (__builtin_expect ((size_t) (namelen + (endp - encrypted) + + restlen + 2) > buflen, 0)) + { + free (result2); + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + __mempcpy (__mempcpy (__mempcpy (__mempcpy (buffer, name, namelen), + ":", 1), + encrypted, endp - encrypted), + p, restlen + 1); + p = buffer; + + free (result2); + } + else + { + non_adjunct: + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + } + + while (isspace (*p)) + ++p; + free (result); + + int parse_res = _nss_files_parse_pwent (p, pwd, (void *) buffer, buflen, + errnop); + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + else + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getpwuid_r (uid_t uid, struct passwd *pwd, + char *buffer, size_t buflen, int *errnop) +{ + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + char buf[32]; + int nlen = snprintf (buf, sizeof (buf), "%lu", (unsigned long int) uid); + + char *result; + int len; + int yperr = yp_match (domain, "passwd.byuid", buf, nlen, &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + + /* Check for adjunct style secret passwords. They can be recognized + by a password starting with "##". We do not use it if the + passwd.adjunct.byname table is supposed to be used as a shadow.byname + replacement. */ + char *result2; + int len2; + size_t namelen; + char *p = strchr (result, ':'); + if ((_nsl_default_nss () & NSS_FLAG_ADJUNCT_AS_SHADOW) == 0 + && p != NULL /* This better should be true in all cases. */ + && p[1] == '#' && p[2] == '#' + && (namelen = p - result, + yp_match (domain, "passwd.adjunct.byname", result, namelen, + &result2, &len2)) == YPERR_SUCCESS) + { + /* We found a passwd.adjunct.byname entry. Merge encrypted password + therein into original result. */ + char *encrypted = strchr (result2, ':'); + char *endp; + size_t restlen; + + if (encrypted == NULL + || (endp = strchr (++encrypted, ':')) == NULL + || (p = strchr (p + 1, ':')) == NULL) + { + /* Invalid format of the entry. This never should happen + unless the data from which the NIS table is generated is + wrong. We simply ignore it. */ + free (result2); + goto non_adjunct; + } + + restlen = len - (p - result); + if (__builtin_expect ((size_t) (namelen + (endp - encrypted) + + restlen + 2) > buflen, 0)) + { + free (result2); + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + __mempcpy (__mempcpy (__mempcpy (__mempcpy (buffer, result, namelen), + ":", 1), + encrypted, endp - encrypted), + p, restlen + 1); + p = buffer; + + free (result2); + } + else + { + non_adjunct: + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + } + + while (isspace (*p)) + ++p; + free (result); + + int parse_res = _nss_files_parse_pwent (p, pwd, (void *) buffer, buflen, + errnop); + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + else + return NSS_STATUS_SUCCESS; +} diff --git a/REORG.TODO/nis/nss_nis/nis-rpc.c b/REORG.TODO/nis/nss_nis/nis-rpc.c new file mode 100644 index 0000000000..24e47e9884 --- /dev/null +++ b/REORG.TODO/nis/nss_nis/nis-rpc.c @@ -0,0 +1,279 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <nss.h> +#include <netdb.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <libc-lock.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> + +#include "nss-nis.h" + +/* Get the declaration of the parser function. */ +#define ENTNAME rpcent +#define EXTERN_PARSER +#include <nss/nss_files/files-parse.c> + +__libc_lock_define_initialized (static, lock) + +static intern_t intern; + + +static void +internal_nis_endrpcent (intern_t *intern) +{ + struct response_t *curr = intern->next; + + while (curr != NULL) + { + struct response_t *last = curr; + curr = curr->next; + free (last); + } + + intern->next = intern->start = NULL; +} + +static enum nss_status +internal_nis_setrpcent (intern_t *intern) +{ + char *domainname; + struct ypall_callback ypcb; + enum nss_status status; + + if (yp_get_default_domain (&domainname)) + return NSS_STATUS_UNAVAIL; + + internal_nis_endrpcent (intern); + + ypcb.foreach = _nis_saveit; + ypcb.data = (char *) intern; + status = yperr2nss (yp_all (domainname, "rpc.bynumber", &ypcb)); + + /* Mark the last buffer as full. */ + if (intern->next != NULL) + intern->next->size = intern->offset; + + intern->next = intern->start; + intern->offset = 0; + + return status; +} + +enum nss_status +_nss_nis_setrpcent (int stayopen) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_setrpcent (&intern); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_endrpcent (void) +{ + __libc_lock_lock (lock); + + internal_nis_endrpcent (&intern); + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_nis_getrpcent_r (struct rpcent *rpc, char *buffer, size_t buflen, + int *errnop, intern_t *intern) +{ + struct parser_data *pdata = (void *) buffer; + int parse_res; + char *p; + + if (intern->start == NULL) + internal_nis_setrpcent (intern); + + if (intern->next == NULL) + /* Not one entry in the map. */ + return NSS_STATUS_NOTFOUND; + + /* Get the next entry until we found a correct one. */ + do + { + struct response_t *bucket = intern->next; + + if (__glibc_unlikely (intern->offset >= bucket->size)) + { + if (bucket->next == NULL) + return NSS_STATUS_NOTFOUND; + + /* We look at all the content in the current bucket. Go on + to the next. */ + bucket = intern->next = bucket->next; + intern->offset = 0; + } + + for (p = &bucket->mem[intern->offset]; isspace (*p); ++p) + ++intern->offset; + + size_t len = strlen (p) + 1; + if (__glibc_unlikely (len > buflen)) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + /* We unfortunately have to copy the data in the user-provided + buffer because that buffer might be around for a very long + time and the servent structure must remain valid. If we would + rely on the BUCKET memory the next 'setservent' or 'endservent' + call would destroy it. + + The important thing is that it is a single NUL-terminated + string. This is what the parsing routine expects. */ + p = memcpy (buffer, &bucket->mem[intern->offset], len); + + parse_res = _nss_files_parse_rpcent (p, rpc, pdata, buflen, errnop); + if (__glibc_unlikely (parse_res == -1)) + return NSS_STATUS_TRYAGAIN; + + intern->offset += len; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getrpcent_r (struct rpcent *rpc, char *buffer, size_t buflen, + int *errnop) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_getrpcent_r (rpc, buffer, buflen, errnop, &intern); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_getrpcbyname_r (const char *name, struct rpcent *rpc, + char *buffer, size_t buflen, int *errnop) +{ + if (name == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + intern_t data = { NULL, NULL, 0 }; + enum nss_status status = internal_nis_setrpcent (&data); + if (__glibc_unlikely (status != NSS_STATUS_SUCCESS)) + return status; + + int found = 0; + while (!found && + ((status = internal_nis_getrpcent_r (rpc, buffer, buflen, errnop, + &data)) == NSS_STATUS_SUCCESS)) + { + if (strcmp (rpc->r_name, name) == 0) + found = 1; + else + { + int i = 0; + + while (rpc->r_aliases[i] != NULL) + { + if (strcmp (rpc->r_aliases[i], name) == 0) + { + found = 1; + break; + } + else + ++i; + } + } + } + + internal_nis_endrpcent (&data); + + if (__glibc_unlikely (!found && status == NSS_STATUS_SUCCESS)) + return NSS_STATUS_NOTFOUND; + + return status; +} + +enum nss_status +_nss_nis_getrpcbynumber_r (int number, struct rpcent *rpc, + char *buffer, size_t buflen, int *errnop) +{ + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + char buf[32]; + int nlen = snprintf (buf, sizeof (buf), "%d", number); + + char *result; + int len; + int yperr = yp_match (domain, "rpc.bynumber", buf, nlen, &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + int parse_res = _nss_files_parse_rpcent (p, rpc, (void *) buffer, buflen, + errnop); + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + else + return NSS_STATUS_SUCCESS; +} diff --git a/REORG.TODO/nis/nss_nis/nis-service.c b/REORG.TODO/nis/nss_nis/nis-service.c new file mode 100644 index 0000000000..fe628aa139 --- /dev/null +++ b/REORG.TODO/nis/nss_nis/nis-service.c @@ -0,0 +1,438 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <nss.h> +#include <netdb.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <libc-lock.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> + +#include "nss-nis.h" +#include <libnsl.h> + + +/* Get the declaration of the parser function. */ +#define ENTNAME servent +#define EXTERN_PARSER +#include <nss/nss_files/files-parse.c> + +__libc_lock_define_initialized (static, lock) + +static intern_t intern; + +struct search_t +{ + const char *name; + const char *proto; + int port; + enum nss_status status; + struct servent *serv; + char *buffer; + size_t buflen; + int *errnop; +}; + +static int +dosearch (int instatus, char *inkey, int inkeylen, char *inval, + int invallen, char *indata) +{ + struct search_t *req = (struct search_t *) indata; + + if (__glibc_unlikely (instatus != YP_TRUE)) + return 1; + + if (inkey && inkeylen > 0 && inval && invallen > 0) + { + if (__glibc_unlikely ((size_t) (invallen + 1) > req->buflen)) + { + *req->errnop = ERANGE; + req->status = NSS_STATUS_TRYAGAIN; + return 1; + } + + char *p = strncpy (req->buffer, inval, invallen); + req->buffer[invallen] = '\0'; + while (isspace (*p)) + ++p; + + int parse_res = _nss_files_parse_servent (p, req->serv, + (void *) req->buffer, + req->buflen, req->errnop); + if (parse_res == -1) + { + req->status = NSS_STATUS_TRYAGAIN; + return 1; + } + + if (!parse_res) + return 0; + + if (req->proto != NULL && strcmp (req->serv->s_proto, req->proto) != 0) + return 0; + + if (req->port != -1 && req->serv->s_port != req->port) + return 0; + + if (req->name != NULL && strcmp (req->serv->s_name, req->name) != 0) + { + char **cp; + for (cp = req->serv->s_aliases; *cp; cp++) + if (strcmp (req->name, *cp) == 0) + break; + + if (*cp == NULL) + return 0; + } + + req->status = NSS_STATUS_SUCCESS; + return 1; + } + + return 0; +} + +static void +internal_nis_endservent (void) +{ + struct response_t *curr = intern.next; + + while (curr != NULL) + { + struct response_t *last = curr; + curr = curr->next; + free (last); + } + + intern.next = intern.start = NULL; +} + +enum nss_status +_nss_nis_endservent (void) +{ + __libc_lock_lock (lock); + + internal_nis_endservent (); + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_nis_setservent (void) +{ + char *domainname; + struct ypall_callback ypcb; + enum nss_status status; + + if (yp_get_default_domain (&domainname)) + return NSS_STATUS_UNAVAIL; + + internal_nis_endservent (); + + ypcb.foreach = _nis_saveit; + ypcb.data = (char *) &intern; + status = yperr2nss (yp_all (domainname, "services.byname", &ypcb)); + + /* Mark the last buffer as full. */ + if (intern.next != NULL) + intern.next->size = intern.offset; + + intern.next = intern.start; + intern.offset = 0; + + return status; +} + +enum nss_status +_nss_nis_setservent (int stayopen) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_setservent (); + + __libc_lock_unlock (lock); + + return status; +} + +static enum nss_status +internal_nis_getservent_r (struct servent *serv, char *buffer, + size_t buflen, int *errnop) +{ + struct parser_data *pdata = (void *) buffer; + int parse_res; + char *p; + + if (intern.start == NULL) + internal_nis_setservent (); + + if (intern.next == NULL) + /* Not one entry in the map. */ + return NSS_STATUS_NOTFOUND; + + /* Get the next entry until we found a correct one. */ + do + { + struct response_t *bucket = intern.next; + + if (__glibc_unlikely (intern.offset >= bucket->size)) + { + if (bucket->next == NULL) + return NSS_STATUS_NOTFOUND; + + /* We look at all the content in the current bucket. Go on + to the next. */ + bucket = intern.next = bucket->next; + intern.offset = 0; + } + + for (p = &bucket->mem[intern.offset]; isspace (*p); ++p) + ++intern.offset; + + size_t len = strlen (p) + 1; + if (__glibc_unlikely (len > buflen)) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + /* We unfortunately have to copy the data in the user-provided + buffer because that buffer might be around for a very long + time and the servent structure must remain valid. If we would + rely on the BUCKET memory the next 'setservent' or 'endservent' + call would destroy it. + + The important thing is that it is a single NUL-terminated + string. This is what the parsing routine expects. */ + p = memcpy (buffer, &bucket->mem[intern.offset], len); + + parse_res = _nss_files_parse_servent (p, serv, pdata, buflen, errnop); + if (__glibc_unlikely (parse_res == -1)) + return NSS_STATUS_TRYAGAIN; + + intern.offset += len; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getservent_r (struct servent *serv, char *buffer, size_t buflen, + int *errnop) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_nis_getservent_r (serv, buffer, buflen, errnop); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_getservbyname_r (const char *name, const char *protocol, + struct servent *serv, char *buffer, size_t buflen, + int *errnop) +{ + if (name == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + /* If the protocol is given, we could try if our NIS server knows + about services.byservicename map. If yes, we only need one query. */ + size_t keylen = strlen (name) + (protocol ? 1 + strlen (protocol) : 0); + /* Limit key length to the maximum size of an RPC packet. */ + if (keylen > UDPMSGSIZE) + { + *errnop = ERANGE; + return NSS_STATUS_UNAVAIL; + } + + char key[keylen + 1]; + + /* key is: "name/proto" */ + char *cp = stpcpy (key, name); + if (protocol != NULL) + { + *cp++ = '/'; + strcpy (cp, protocol); + } + + char *result; + int int_len; + int status = yp_match (domain, "services.byservicename", key, + keylen, &result, &int_len); + size_t len = int_len; + + /* If we found the key, it's ok and parse the result. If not, + fall through and parse the complete table. */ + if (__glibc_likely (status == YPERR_SUCCESS)) + { + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + int parse_res = _nss_files_parse_servent (p, serv, (void *) buffer, + buflen, errnop); + if (__glibc_unlikely (parse_res < 0)) + { + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + else + return NSS_STATUS_SUCCESS; + } + + /* Check if it is safe to rely on services.byservicename. */ + if (_nsl_default_nss () & NSS_FLAG_SERVICES_AUTHORITATIVE) + return yperr2nss (status); + + struct ypall_callback ypcb; + struct search_t req; + + ypcb.foreach = dosearch; + ypcb.data = (char *) &req; + req.name = name; + req.proto = protocol; + req.port = -1; + req.serv = serv; + req.buffer = buffer; + req.buflen = buflen; + req.errnop = errnop; + req.status = NSS_STATUS_NOTFOUND; + status = yp_all (domain, "services.byname", &ypcb); + + if (__glibc_unlikely (status != YPERR_SUCCESS)) + return yperr2nss (status); + + return req.status; +} + +enum nss_status +_nss_nis_getservbyport_r (int port, const char *protocol, + struct servent *serv, char *buffer, + size_t buflen, int *errnop) +{ + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + /* If the protocol is given, we only need one query. + Otherwise try first port/tcp, then port/udp and then fallback + to sequential scanning of services.byname. */ + const char *proto = protocol != NULL ? protocol : "tcp"; + /* Limit protocol name length to the maximum size of an RPC packet. */ + if (strlen (proto) > UDPMSGSIZE) + { + *errnop = ERANGE; + return NSS_STATUS_UNAVAIL; + } + + do + { + /* key is: "port/proto" */ + char key[sizeof (int) * 3 + strlen (proto) + 2]; + size_t keylen = snprintf (key, sizeof (key), "%d/%s", ntohs (port), + proto); + + char *result; + int int_len; + int status = yp_match (domain, "services.byname", key, keylen, &result, + &int_len); + size_t len = int_len; + + /* If we found the key, it's ok and parse the result. If not, + fall through and parse the complete table. */ + if (__glibc_likely (status == YPERR_SUCCESS)) + { + if (__glibc_unlikely ((size_t) (len + 1) > buflen)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + int parse_res = _nss_files_parse_servent (p, serv, (void *) buffer, + buflen, errnop); + if (__glibc_unlikely (parse_res < 0)) + { + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + + return NSS_STATUS_SUCCESS; + } + } + while (protocol == NULL && (proto[0] == 't' ? (proto = "udp") : NULL)); + + if (port == -1) + return NSS_STATUS_NOTFOUND; + + struct ypall_callback ypcb; + struct search_t req; + + ypcb.foreach = dosearch; + ypcb.data = (char *) &req; + req.name = NULL; + req.proto = protocol; + req.port = port; + req.serv = serv; + req.buffer = buffer; + req.buflen = buflen; + req.errnop = errnop; + req.status = NSS_STATUS_NOTFOUND; + int status = yp_all (domain, "services.byname", &ypcb); + + if (__glibc_unlikely (status != YPERR_SUCCESS)) + return yperr2nss (status); + + return req.status; +} diff --git a/REORG.TODO/nis/nss_nis/nis-spwd.c b/REORG.TODO/nis/nss_nis/nis-spwd.c new file mode 100644 index 0000000000..45e9d964d2 --- /dev/null +++ b/REORG.TODO/nis/nss_nis/nis-spwd.c @@ -0,0 +1,235 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <nss.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +/* The following is an ugly trick to avoid a prototype declaration for + _nss_nis_endspent. */ +#define _nss_nis_endspent _nss_nis_endspent_XXX +#include <shadow.h> +#undef _nss_nis_endspent +#include <libc-lock.h> +#include <rpcsvc/yp.h> +#include <rpcsvc/ypclnt.h> + +#include "nss-nis.h" +#include <libnsl.h> + +/* Get the declaration of the parser function. */ +#define ENTNAME spent +#define STRUCTURE spwd +#define EXTERN_PARSER +#include <nss/nss_files/files-parse.c> + +/* Protect global state against multiple changers */ +__libc_lock_define_initialized (static, lock) + +static bool new_start = true; +static bool ent_adjunct_used; +static char *oldkey; +static int oldkeylen; + +enum nss_status +_nss_nis_setspent (int stayopen) +{ + __libc_lock_lock (lock); + + new_start = true; + ent_adjunct_used = false; + free (oldkey); + oldkey = NULL; + oldkeylen = 0; + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} +/* Make _nss_nis_endspent an alias of _nss_nis_setspent. We do this + even though the prototypes don't match. The argument of setspent + is not used so this makes no difference. */ +strong_alias (_nss_nis_setspent, _nss_nis_endspent) + +static enum nss_status +internal_nis_getspent_r (struct spwd *sp, char *buffer, size_t buflen, + int *errnop) +{ + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + /* Get the next entry until we found a correct one. */ + int parse_res; + do + { + char *result; + char *outkey; + int len; + int keylen; + int yperr; + + if (new_start) + { + yperr = yp_first (domain, "shadow.byname", &outkey, &keylen, &result, + &len); + if (__builtin_expect (yperr == YPERR_MAP, 0) + && (_nsl_default_nss () & NSS_FLAG_ADJUNCT_AS_SHADOW)) + { + free (result); + yperr = yp_first (domain, "passwd.adjunct.byname", &outkey, + &keylen, &result, &len); + ent_adjunct_used = true; + } + } + else + yperr = yp_next (domain, (ent_adjunct_used + ? "passwd.adjunct.byname" : "shadow.byname"), + oldkey, oldkeylen, &outkey, &keylen, &result, &len); + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + + if (__builtin_expect ((size_t) (len + (ent_adjunct_used ? 3 : 1)) + > buflen, 0)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + if (ent_adjunct_used) + /* This is an ugly trick. The format of passwd.adjunct.byname almost + matches the shadow.byname format except that the last two fields + are missing. Synthesize them by marking them empty. */ + strcpy (&buffer[len], "::"); + else + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + parse_res = _nss_files_parse_spent (p, sp, (void *) buffer, buflen, + errnop); + if (__builtin_expect (parse_res == -1, 0)) + { + free (outkey); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + free (oldkey); + oldkey = outkey; + oldkeylen = keylen; + new_start = false; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_getspent_r (struct spwd *result, char *buffer, size_t buflen, + int *errnop) +{ + int status; + + __libc_lock_lock (lock); + + status = internal_nis_getspent_r (result, buffer, buflen, errnop); + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_nis_getspnam_r (const char *name, struct spwd *sp, + char *buffer, size_t buflen, int *errnop) +{ + if (name == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; + } + const size_t name_len = strlen (name); + + char *domain; + if (__glibc_unlikely (yp_get_default_domain (&domain))) + return NSS_STATUS_UNAVAIL; + + bool adjunct_used = false; + char *result; + int len; + int yperr = yp_match (domain, "shadow.byname", name, name_len, &result, + &len); + if (__builtin_expect (yperr == YPERR_MAP, 0) + && (_nsl_default_nss () & NSS_FLAG_ADJUNCT_AS_SHADOW)) + { + free (result); + yperr = yp_match (domain, "passwd.adjunct.byname", name, name_len, + &result, &len); + adjunct_used = true; + } + + if (__glibc_unlikely (yperr != YPERR_SUCCESS)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + + if (__glibc_unlikely ((size_t) (len + (adjunct_used ? 3 : 1)) > buflen)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + char *p = strncpy (buffer, result, len); + if (__builtin_expect (adjunct_used, false)) + /* This is an ugly trick. The format of passwd.adjunct.byname almost + matches the shadow.byname format except that the last two fields + are missing. Synthesize them by marking them empty. */ + strcpy (&buffer[len], "::"); + else + buffer[len] = '\0'; + while (isspace (*p)) + ++p; + free (result); + + int parse_res = _nss_files_parse_spent (p, sp, (void *) buffer, buflen, + errnop); + if (__glibc_unlikely (parse_res < 1)) + { + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; + } + return NSS_STATUS_SUCCESS; +} |