From 899d423eaf3f66e59ffffefe40b2ba2137bd0050 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Fri, 19 Jun 1998 13:01:35 +0000 Subject: Update. 1998-06-10 Thorsten Kukuk * nis/Makefile: Add nis-initgroups and compat-initgroups. * nis/libnss_compat.map: Add _nss_compat_initgroups. * nis/libnss_nis.map: Add _nss_nis_initgroups. * nis/nss_compat/compat-initgroups.c: New, faster then getgrent(). * nis/nss_nis/nis-initgroups.c: Likewise. * libc-work/nss/nsswitch.c: Rename nss_lookup_function to __nss_lookup_function and make it public. * grp/initgroups.c: Rewrite, to use initgroups function from NSS module if exists, else use old method. 1998-06-19 Ulrich Drepper * nss/getXXbyYY_r.c (lookup_function): Correct return in type definition. * nss/getXXent_r.c (set_function, end_function, get_function): Likewise. Reported by Thorsten Kukuk. * sysdeps/unix/sysv/linux/sigstack.c: Mark sigstack as dangerous. 1998-06-19 Andreas Jaeger * sysdeps/unix/sysv/linux/sparc/Dist: Follow change from 1998-06-16 and distribute kernel_termios.h. * nis/Makefile (distribute): Add nis_xdr.h. 1998-06-19 Andreas Jaeger * sysdeps/unix/sysv/linux/sigstack.c (sigstack): Disable for kernels that don't have sigaltstack. --- ChangeLog | 33 ++ grp/initgroups.c | 184 +++++++--- nis/Makefile | 7 +- nis/libnss_compat.map | 4 +- nis/libnss_nis.map | 10 +- nis/nss_compat/compat-initgroups.c | 687 +++++++++++++++++++++++++++++++++++++ nis/nss_nis/nis-initgroups.c | 204 +++++++++++ nss/getXXbyYY_r.c | 4 +- nss/getXXent_r.c | 8 +- nss/nsswitch.c | 13 +- nss/nsswitch.h | 3 + sysdeps/unix/sysv/linux/sigstack.c | 7 + sysdeps/unix/sysv/linux/sparc/Dist | 2 +- 13 files changed, 1087 insertions(+), 79 deletions(-) create mode 100644 nis/nss_compat/compat-initgroups.c create mode 100644 nis/nss_nis/nis-initgroups.c diff --git a/ChangeLog b/ChangeLog index 09d59f456c..4da69ffed8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,36 @@ +1998-06-10 Thorsten Kukuk + + * nis/Makefile: Add nis-initgroups and compat-initgroups. + * nis/libnss_compat.map: Add _nss_compat_initgroups. + * nis/libnss_nis.map: Add _nss_nis_initgroups. + * nis/nss_compat/compat-initgroups.c: New, faster then getgrent(). + * nis/nss_nis/nis-initgroups.c: Likewise. + * libc-work/nss/nsswitch.c: Rename nss_lookup_function to + __nss_lookup_function and make it public. + * grp/initgroups.c: Rewrite, to use initgroups function from NSS + module if exists, else use old method. + +1998-06-19 Ulrich Drepper + + * nss/getXXbyYY_r.c (lookup_function): Correct return in type + definition. + * nss/getXXent_r.c (set_function, end_function, get_function): + Likewise. Reported by Thorsten Kukuk. + + * sysdeps/unix/sysv/linux/sigstack.c: Mark sigstack as dangerous. + +1998-06-19 Andreas Jaeger + + * sysdeps/unix/sysv/linux/sparc/Dist: Follow change from + 1998-06-16 and distribute kernel_termios.h. + + * nis/Makefile (distribute): Add nis_xdr.h. + +1998-06-19 Andreas Jaeger + + * sysdeps/unix/sysv/linux/sigstack.c (sigstack): Disable for + kernels that don't have sigaltstack. + 1998-06-19 Ulrich Drepper * sysdeps/generic/bits/sem.h: Don't define union semun. diff --git a/grp/initgroups.c b/grp/initgroups.c index 2ca90ab18d..2150fa968c 100644 --- a/grp/initgroups.c +++ b/grp/initgroups.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1989, 1991, 1993, 1996, 1997 Free Software Foundation, Inc. +/* Copyright (C) 1989, 91, 93, 96, 97, 98 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -23,8 +23,102 @@ #include #include #include +#include +/* Type of the lookup function. */ +typedef enum nss_status (*initgroups_function) (const char *, gid_t, + long int *, long int *, + gid_t *, long int, int *); +/* Prototype for the setgrent functions we use here. */ +typedef enum nss_status (*set_function) (void); + +/* Prototype for the endgrent functions we use here. */ +typedef enum nss_status (*end_function) (void); + +/* Prototype for the setgrent functions we use here. */ +typedef enum nss_status (*get_function) (struct group *, char *, + size_t, int *); + +/* The lookup function for the first entry of this service. */ +extern int __nss_group_lookup (service_user **nip, const char *name, + void **fctp); +extern void *__nss_lookup_function (service_user *ni, const char *fct_name); + +extern service_user *__nss_group_database; + +static enum nss_status +compat_call (service_user *nip, const char *user, gid_t group, long int *start, + long int *size, gid_t *groups, long int limit, int *errnop) +{ + struct group grpbuf, *g; + size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX); + char *tmpbuf; + enum nss_status status; + set_function setgrent_fct; + get_function getgrent_fct; + end_function endgrent_fct; + + setgrent_fct = __nss_lookup_function (nip, "setgrent"); + status = (*setgrent_fct) (); + if (status != NSS_STATUS_SUCCESS) + return status; + + getgrent_fct = __nss_lookup_function (nip, "getgrent_r"); + endgrent_fct = __nss_lookup_function (nip, "endgrent"); + + tmpbuf = __alloca (buflen); + + do + { + while ((status = + (*getgrent_fct) (&grpbuf, tmpbuf, buflen, errnop)) == + NSS_STATUS_TRYAGAIN && *errnop == ERANGE) + { + buflen *= 2; + tmpbuf = __alloca (buflen); + } + + if (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 && limit <= 0) + { + /* Need a bigger buffer. */ + groups = realloc (groups, *size * sizeof (*groups)); + if (groups == NULL) + goto done; + *size *= 2; + } + + groups[*start] = g->gr_gid; + *start += 1; + + if (*start == limit) + /* Can't take any more groups; stop searching. */ + goto done; + + break; + } + } + } + while (status == NSS_STATUS_SUCCESS); + + done: + (*endgrent_fct) (); + + return NSS_STATUS_SUCCESS; +} + /* Initialize the group set for the current user by reading the group database and using all groups of which USER is a member. Also include GROUP. */ @@ -40,76 +134,58 @@ initgroups (user, group) #else - struct group grpbuf, *g; - size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX); - char *tmpbuf; - size_t n; - size_t ngroups; + service_user *nip = NULL; + initgroups_function fct; + enum nss_status status = NSS_STATUS_UNAVAIL; + int no_more; + /* Start is one, because we have the first group as parameter. */ + long int start = 1; + long int size; gid_t *groups; - int status; #ifdef NGROUPS_MAX # define limit NGROUPS_MAX - ngroups = limit; + size = limit; #else long int limit = sysconf (_SC_NGROUPS_MAX); if (limit > 0) - ngroups = limit; + size = limit; else /* No fixed limit on groups. Pick a starting buffer size. */ - ngroups = 16; + size = 16; #endif - groups = __alloca (ngroups * sizeof *groups); - tmpbuf = __alloca (buflen); - - setgrent (); + groups = malloc (size * sizeof (gid_t *)); - n = 0; - groups[n++] = group; + groups[0] = group; - do + if (__nss_group_database != NULL) { - while ((status = __getgrent_r (&grpbuf, tmpbuf, buflen, &g)) != 0 - && errno == ERANGE) - { - buflen *= 2; - tmpbuf = __alloca (buflen); - } - - if (status == 0 && 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 (n == ngroups && limit <= 0) - { - /* Need a bigger buffer. */ - gid_t *newgrp; - newgrp = __alloca (ngroups * 2 * sizeof *groups); - groups = memcpy (newgrp, groups, ngroups * sizeof *groups); - ngroups *= 2; - } - - groups[n++] = g->gr_gid; - - if (n == limit) - /* Can't take any more groups; stop searching. */ - goto done; - - break; - } - } + no_more = 0; + nip = __nss_group_database; } - while (status == 0); + else + no_more = __nss_database_lookup ("group", NULL, + "compat [NOTFOUND=return] files", &nip); -done: - endgrent (); + while (! no_more) + { + fct = __nss_lookup_function (nip, "initgroups"); + + if (fct == NULL) + status = compat_call (nip, user, group, &start, &size, groups, + limit, &errno); + else + status = (*fct) (user, group, &start, &size, groups, limit, + &errno); + + if (nip->next == NULL) + no_more = -1; + else + nip = nip->next; + } - return setgroups (n, groups); + return setgroups (start, groups); #endif } diff --git a/nis/Makefile b/nis/Makefile index f91121bc11..30d356dcb2 100644 --- a/nis/Makefile +++ b/nis/Makefile @@ -23,7 +23,7 @@ subdir := nis headers := $(wildcard rpcsvc/*.[hx]) distribute := nss-nis.h nss-nisplus.h nis_intern.h Banner \ - nisplus-parser.h nis_cache2.h + nisplus-parser.h nis_cache2.h nis_xdr.h # These are the databases available for the nis (and perhaps later nisplus) # service. This must be a superset of the services in nss. @@ -55,10 +55,11 @@ libnsl-routines = yp_xdr ypclnt ypupdate_xdr \ nis_clone_res libnsl-map = libnsl.map -libnss_compat-routines := $(addprefix compat-,grp pwd spwd) nisplus-parser +libnss_compat-routines := $(addprefix compat-,grp pwd spwd initgroups) \ + nisplus-parser libnss_compat-inhibit-o = $(filter-out .os,$(object-suffixes)) -libnss_nis-routines := $(addprefix nis-,$(databases)) +libnss_nis-routines := $(addprefix nis-,$(databases)) nis-initgroups libnss_nis-inhibit-o = $(filter-out .os,$(object-suffixes)) libnss_nisplus-routines := $(addprefix nisplus-,$(databases)) nisplus-parser diff --git a/nis/libnss_compat.map b/nis/libnss_compat.map index cff0ef2c15..6178bb903a 100644 --- a/nis/libnss_compat.map +++ b/nis/libnss_compat.map @@ -3,8 +3,8 @@ GLIBC_2.0 { _nss_compat_endgrent; _nss_compat_endpwent; _nss_compat_endspent; _nss_compat_getgrent_r; _nss_compat_getgrgid_r; _nss_compat_getgrnam_r; _nss_compat_getpwent_r; _nss_compat_getpwnam_r; _nss_compat_getpwuid_r; - _nss_compat_getspent_r; _nss_compat_getspnam_r; _nss_compat_setgrent; - _nss_compat_setpwent; _nss_compat_setspent; + _nss_compat_getspent_r; _nss_compat_getspnam_r; _nss_compat_initgroups; + _nss_compat_setgrent; _nss_compat_setpwent; _nss_compat_setspent; local: *; diff --git a/nis/libnss_nis.map b/nis/libnss_nis.map index 2773fca29b..5d84fdcc6d 100644 --- a/nis/libnss_nis.map +++ b/nis/libnss_nis.map @@ -14,11 +14,11 @@ GLIBC_2.0 { _nss_nis_getpwnam_r; _nss_nis_getpwuid_r; _nss_nis_getrpcbyname_r; _nss_nis_getrpcbynumber_r; _nss_nis_getrpcent_r; _nss_nis_getsecretkey; _nss_nis_getservbyname_r; _nss_nis_getservbyport_r; _nss_nis_getservent_r; - _nss_nis_getspent_r; _nss_nis_getspnam_r; _nss_nis_netname2user; - _nss_nis_setaliasent; _nss_nis_setetherent; _nss_nis_setgrent; - _nss_nis_sethostent; _nss_nis_setnetent; _nss_nis_setnetgrent; - _nss_nis_setprotoent; _nss_nis_setpwent; _nss_nis_setrpcent; - _nss_nis_setservent; _nss_nis_setspent; + _nss_nis_getspent_r; _nss_nis_getspnam_r; _nss_nis_initgroups; + _nss_nis_netname2user; _nss_nis_setaliasent; _nss_nis_setetherent; + _nss_nis_setgrent; _nss_nis_sethostent; _nss_nis_setnetent; + _nss_nis_setnetgrent; _nss_nis_setprotoent; _nss_nis_setpwent; + _nss_nis_setrpcent; _nss_nis_setservent; _nss_nis_setspent; local: *; diff --git a/nis/nss_compat/compat-initgroups.c b/nis/nss_compat/compat-initgroups.c new file mode 100644 index 0000000000..9def98ba52 --- /dev/null +++ b/nis/nss_compat/compat-initgroups.c @@ -0,0 +1,687 @@ +/* Copyright (C) 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk , 1998. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nss-nisplus.h" +#include "nisplus-parser.h" + +static service_user *ni = NULL; +static bool_t use_nisplus = FALSE; /* default: group_compat: nis */ +static nis_name grptable = NULL; /* Name of the group table */ +static size_t grptablelen = 0; + +/* Get the declaration of the parser function. */ +#define ENTNAME grent +#define STRUCTURE group +#define EXTERN_PARSER +#include + +/* Structure for remembering -group members ... */ +#define BLACKLIST_INITIAL_SIZE 512 +#define BLACKLIST_INCREMENT 256 +struct blacklist_t + { + char *data; + int current; + int size; + }; + +struct ent_t + { + bool_t nis; + bool_t nis_first; + char *oldkey; + int oldkeylen; + nis_result *result; + FILE *stream; + struct blacklist_t blacklist; +}; +typedef struct ent_t ent_t; + + +/* Prototypes for local functions. */ +static void blacklist_store_name (const char *, ent_t *); +static int in_blacklist (const char *, int, ent_t *); + +static enum nss_status +_nss_first_init (void) +{ + if (ni == NULL) + { + __nss_database_lookup ("group_compat", NULL, "nis", &ni); + use_nisplus = (strcmp (ni->name, "nisplus") == 0); + } + + if (grptable == NULL) + { + static const char key[] = "group.org_dir."; + const char *local_dir = nis_local_directory (); + size_t len_local_dir = strlen (local_dir); + + grptable = malloc (sizeof (key) + len_local_dir); + if (grptable == NULL) + return NSS_STATUS_TRYAGAIN; + + grptablelen = ((char *) mempcpy (mempcpy (grptable, + key, sizeof (key) - 1), + local_dir, len_local_dir + 1) + - grptable) - 1; + } + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +internal_setgrent (ent_t *ent) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + ent->nis = ent->nis_first = 0; + + if (_nss_first_init () != NSS_STATUS_SUCCESS) + return NSS_STATUS_UNAVAIL; + + if (ent->oldkey != NULL) + { + free (ent->oldkey); + ent->oldkey = NULL; + ent->oldkeylen = 0; + } + + if (ent->result != NULL) + { + nis_freeresult (ent->result); + ent->result = NULL; + } + + if (ent->blacklist.data != NULL) + { + ent->blacklist.current = 1; + ent->blacklist.data[0] = '|'; + ent->blacklist.data[1] = '\0'; + } + else + ent->blacklist.current = 0; + + if (ent->stream == NULL) + { + ent->stream = fopen ("/etc/group", "r"); + + if (ent->stream == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + else + { + /* We have to make sure the file is `closed on exec'. */ + int result, flags; + + result = flags = fcntl (fileno (ent->stream), F_GETFD, 0); + if (result >= 0) + { + flags |= FD_CLOEXEC; + result = fcntl (fileno (ent->stream), F_SETFD, flags); + } + if (result < 0) + { + /* Something went wrong. Close the stream and return a + failure. */ + fclose (ent->stream); + ent->stream = NULL; + status = NSS_STATUS_UNAVAIL; + } + } + } + else + rewind (ent->stream); + + return status; +} + + +static enum nss_status +internal_endgrent (ent_t *ent) +{ + if (ent->stream != NULL) + { + fclose (ent->stream); + ent->stream = NULL; + } + + ent->nis = ent->nis_first = 0; + + if (ent->oldkey != NULL) + { + free (ent->oldkey); + ent->oldkey = NULL; + ent->oldkeylen = 0; + } + + if (ent->result != NULL) + { + nis_freeresult (ent->result); + ent->result = NULL; + } + + if (ent->blacklist.data != NULL) + { + ent->blacklist.current = 1; + ent->blacklist.data[0] = '|'; + ent->blacklist.data[1] = '\0'; + } + else + ent->blacklist.current = 0; + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +getgrent_next_nis (struct group *result, ent_t *ent, char *buffer, + size_t buflen, int *errnop) +{ + struct parser_data *data = (void *) buffer; + char *domain; + char *outkey, *outval; + int outkeylen, outvallen, parse_res; + char *p; + + if (yp_get_default_domain (&domain) != YPERR_SUCCESS) + { + ent->nis = 0; + return NSS_STATUS_NOTFOUND; + } + + do + { + char *save_oldkey; + int save_oldlen; + bool_t save_nis_first; + + if (ent->nis_first) + { + if (yp_first (domain, "group.byname", &outkey, &outkeylen, + &outval, &outvallen) != YPERR_SUCCESS) + { + ent->nis = 0; + return NSS_STATUS_UNAVAIL; + } + + if ( buflen < ((size_t) outvallen + 1)) + { + free (outval); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + save_oldkey = ent->oldkey; + save_oldlen = ent->oldkeylen; + save_nis_first = TRUE; + ent->oldkey = outkey; + ent->oldkeylen = outkeylen; + ent->nis_first = FALSE; + } + else + { + if (yp_next (domain, "group.byname", ent->oldkey, ent->oldkeylen, + &outkey, &outkeylen, &outval, &outvallen) + != YPERR_SUCCESS) + { + ent->nis = 0; + return NSS_STATUS_NOTFOUND; + } + + if ( buflen < ((size_t) outvallen + 1)) + { + free (outval); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + save_oldkey = ent->oldkey; + save_oldlen = ent->oldkeylen; + save_nis_first = FALSE; + ent->oldkey = outkey; + ent->oldkeylen = outkeylen; + } + + /* Copy the found data to our buffer... */ + p = strncpy (buffer, outval, buflen); + + /* ...and free the data. */ + free (outval); + + while (isspace (*p)) + ++p; + + parse_res = _nss_files_parse_grent (p, result, data, buflen, errnop); + if (parse_res == -1) + { + free (ent->oldkey); + ent->oldkey = save_oldkey; + ent->oldkeylen = save_oldlen; + ent->nis_first = save_nis_first; + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + else + { + if (!save_nis_first) + free (save_oldkey); + } + + if (parse_res && + in_blacklist (result->gr_name, strlen (result->gr_name), ent)) + parse_res = 0; /* if result->gr_name in blacklist,search next entry */ + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +getgrent_next_nisplus (struct group *result, ent_t *ent, char *buffer, + size_t buflen, int *errnop) +{ + int parse_res; + + do + { + nis_result *save_oldres; + bool_t save_nis_first; + + if (ent->nis_first) + { + save_oldres = ent->result; + save_nis_first = TRUE; + ent->result = nis_first_entry(grptable); + if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS) + { + ent->nis = 0; + return niserr2nss (ent->result->status); + } + ent->nis_first = FALSE; + } + else + { + nis_result *res; + + save_oldres = ent->result; + save_nis_first = FALSE; + res = nis_next_entry(grptable, &ent->result->cookie); + ent->result = res; + if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS) + { + ent->nis = 0; + return niserr2nss (ent->result->status); + } + } + parse_res = _nss_nisplus_parse_grent (ent->result, 0, result, + buffer, buflen, errnop); + if (parse_res == -1) + { + nis_freeresult (ent->result); + ent->result = save_oldres; + ent->nis_first = save_nis_first; + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + else + { + if (!save_nis_first) + nis_freeresult (save_oldres); + } + + if (parse_res && + in_blacklist (result->gr_name, strlen (result->gr_name), ent)) + parse_res = 0; /* if result->gr_name in blacklist,search next entry */ + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +/* This function handle the +group entrys in /etc/group */ +static enum nss_status +getgrnam_plusgroup (const char *name, struct group *result, char *buffer, + size_t buflen, int *errnop) +{ + struct parser_data *data = (void *) buffer; + int parse_res; + + if (use_nisplus) /* Do the NIS+ query here */ + { + nis_result *res; + char buf[strlen (name) + 24 + grptablelen]; + + sprintf(buf, "[name=%s],%s", name, grptable); + res = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); + if (niserr2nss (res->status) != NSS_STATUS_SUCCESS) + { + enum nss_status status = niserr2nss (res->status); + + nis_freeresult (res); + return status; + } + parse_res = _nss_nisplus_parse_grent (res, 0, result, buffer, buflen, + errnop); + if (parse_res == -1) + { + nis_freeresult (res); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + nis_freeresult (res); + } + else /* Use NIS */ + { + char *domain, *outval, *p; + int outvallen; + + if (yp_get_default_domain (&domain) != YPERR_SUCCESS) + return NSS_STATUS_NOTFOUND; + + if (yp_match (domain, "group.byname", name, strlen (name), + &outval, &outvallen) != YPERR_SUCCESS) + return NSS_STATUS_NOTFOUND; + + if (buflen < ((size_t) outvallen + 1)) + { + free (outval); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + /* Copy the found data to our buffer... */ + p = strncpy (buffer, outval, buflen); + + /* ... and free the data. */ + free (outval); + while (isspace (*p)) + ++p; + parse_res = _nss_files_parse_grent (p, result, data, buflen, errnop); + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + } + + if (parse_res) + /* We found the entry. */ + return NSS_STATUS_SUCCESS; + else + return NSS_STATUS_RETURN; +} + +static enum nss_status +getgrent_next_file (struct group *result, ent_t *ent, + char *buffer, size_t buflen, int *errnop) +{ + struct parser_data *data = (void *) buffer; + while (1) + { + fpos_t pos; + int parse_res = 0; + char *p; + + do + { + fgetpos (ent->stream, &pos); + buffer[buflen - 1] = '\xff'; + p = fgets (buffer, buflen, ent->stream); + if (p == NULL && feof (ent->stream)) + return NSS_STATUS_NOTFOUND; + if (p == NULL || buffer[buflen - 1] != '\xff') + { + fsetpos (ent->stream, &pos); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + /* Terminate the line for any case. */ + buffer[buflen - 1] = '\0'; + + /* Skip leading blanks. */ + while (isspace (*p)) + ++p; + } + while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ + /* Parse the line. If it is invalid, loop to + get the next line of the file to parse. */ + !(parse_res = _nss_files_parse_grent (p, result, data, buflen, + errnop))); + + if (parse_res == -1) + { + /* The parser ran out of space. */ + fsetpos (ent->stream, &pos); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + if (result->gr_name[0] != '+' && result->gr_name[0] != '-') + /* This is a real entry. */ + break; + + /* -group */ + if (result->gr_name[0] == '-' && result->gr_name[1] != '\0' + && result->gr_name[1] != '@') + { + blacklist_store_name (&result->gr_name[1], ent); + continue; + } + + /* +group */ + if (result->gr_name[0] == '+' && result->gr_name[1] != '\0' + && result->gr_name[1] != '@') + { + enum nss_status status; + + /* Store the group in the blacklist for the "+" at the end of + /etc/group */ + blacklist_store_name (&result->gr_name[1], ent); + status = getgrnam_plusgroup (&result->gr_name[1], result, buffer, + buflen, errnop); + if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ + break; + else + if (status == NSS_STATUS_RETURN /* We couldn't parse the entry */ + || status == NSS_STATUS_NOTFOUND) /* No group in NIS */ + continue; + else + { + if (status == NSS_STATUS_TRYAGAIN) + { + /* The parser ran out of space. */ + fsetpos (ent->stream, &pos); + *errnop = ERANGE; + } + return status; + } + } + + /* +:... */ + if (result->gr_name[0] == '+' && result->gr_name[1] == '\0') + { + ent->nis = TRUE; + ent->nis_first = TRUE; + + if (use_nisplus) + return getgrent_next_nisplus (result, ent, buffer, buflen, errnop); + else + return getgrent_next_nis (result, ent, buffer, buflen, errnop); + } + } + + return NSS_STATUS_SUCCESS; +} + + +static enum nss_status +internal_getgrent_r (struct group *gr, ent_t *ent, char *buffer, + size_t buflen, int *errnop) +{ + if (ent->nis) + { + if (use_nisplus) + return getgrent_next_nisplus (gr, ent, buffer, buflen, errnop); + else + return getgrent_next_nis (gr, ent, buffer, buflen, errnop); + } + else + return getgrent_next_file (gr, ent, buffer, buflen, errnop); +} + +enum nss_status +_nss_compat_initgroups (const char *user, gid_t group, long int *start, + long int *size, gid_t *groups, long int limit, + int *errnop) +{ + struct group grpbuf, *g; + size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX); + char *tmpbuf; + enum nss_status status; + ent_t intern = {0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0}}; + + status = internal_setgrent (&intern); + if (status != NSS_STATUS_SUCCESS) + return status; + + tmpbuf = __alloca (buflen); + + do + { + while ((status = + internal_getgrent_r (&grpbuf, &intern, tmpbuf, buflen, + errnop)) == NSS_STATUS_TRYAGAIN + && *errnop == ERANGE) + { + buflen *= 2; + tmpbuf = __alloca (buflen); + } + + if (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 && limit <= 0) + { + /* Need a bigger buffer. */ + groups = realloc (groups, *size * sizeof (*groups)); + if (groups == NULL) + goto done; + *size *= 2; + } + + groups[*start] = g->gr_gid; + *start += 1; + + if (*start == limit) + /* Can't take any more groups; stop searching. */ + goto done; + + break; + } + } + } + while (status == NSS_STATUS_SUCCESS); + +done: + internal_endgrent (&intern); + + return NSS_STATUS_SUCCESS; +} + + +/* Support routines for remembering -@netgroup and -user entries. + The names are stored in a single string with `|' as separator. */ +static void +blacklist_store_name (const char *name, ent_t *ent) +{ + int namelen = strlen (name); + char *tmp; + + /* first call, setup cache */ + if (ent->blacklist.size == 0) + { + ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen); + ent->blacklist.data = malloc (ent->blacklist.size); + if (ent->blacklist.data == NULL) + return; + ent->blacklist.data[0] = '|'; + ent->blacklist.data[1] = '\0'; + ent->blacklist.current = 1; + } + else + { + if (in_blacklist (name, namelen, ent)) + return; /* no duplicates */ + + if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size) + { + ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen); + tmp = realloc (ent->blacklist.data, ent->blacklist.size); + if (tmp == NULL) + { + free (ent->blacklist.data); + ent->blacklist.size = 0; + return; + } + ent->blacklist.data = tmp; + } + } + + tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name); + *tmp++ = '|'; + *tmp = '\0'; + ent->blacklist.current += namelen + 1; + + return; +} + +/* returns TRUE if ent->blacklist contains name, else FALSE */ +static bool_t +in_blacklist (const char *name, int namelen, ent_t *ent) +{ + char buf[namelen + 3]; + char *cp; + + if (ent->blacklist.data == NULL) + return FALSE; + + buf[0] = '|'; + cp = stpcpy (&buf[1], name); + *cp++= '|'; + *cp = '\0'; + return strstr (ent->blacklist.data, buf) != NULL; +} diff --git a/nis/nss_nis/nis-initgroups.c b/nis/nss_nis/nis-initgroups.c new file mode 100644 index 0000000000..5960c80502 --- /dev/null +++ b/nis/nss_nis/nis-initgroups.c @@ -0,0 +1,204 @@ +/* Copyright (C) 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk , 1998. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nss-nis.h" + +/* Get the declaration of the parser function. */ +#define ENTNAME grent +#define STRUCTURE group +#define EXTERN_PARSER +#include + +struct response_t +{ + char *val; + struct response_t *next; +}; + +struct intern_t +{ + struct response_t *start; + struct response_t *next; +}; +typedef struct intern_t intern_t; + +static int +saveit (int instatus, char *inkey, int inkeylen, char *inval, + int invallen, char *indata) +{ + intern_t *intern = (intern_t *) indata; + + if (instatus != YP_TRUE) + return instatus; + + if (inkey && inkeylen > 0 && inval && invallen > 0) + { + if (intern->start == NULL) + { + intern->start = malloc (sizeof (struct response_t)); + intern->next = intern->start; + } + else + { + intern->next->next = malloc (sizeof (struct response_t)); + intern->next = intern->next->next; + } + intern->next->next = NULL; + intern->next->val = malloc (invallen + 1); + strncpy (intern->next->val, inval, invallen); + intern->next->val[invallen] = '\0'; + } + + return 0; +} + +static enum nss_status +internal_setgrent (intern_t *intern) +{ + char *domainname; + struct ypall_callback ypcb; + enum nss_status status; + + if (yp_get_default_domain (&domainname)) + return NSS_STATUS_UNAVAIL; + + intern->start = NULL; + + ypcb.foreach = saveit; + ypcb.data = (char *) intern; + status = yperr2nss (yp_all (domainname, "group.byname", &ypcb)); + intern->next = intern->start; + + return status; +} + +static enum nss_status +internal_getgrent_r (struct group *grp, char *buffer, size_t buflen, + int *errnop, intern_t *intern) +{ + struct parser_data *data = (void *) buffer; + int parse_res; + char *p; + + if (intern->start == NULL) + internal_setgrent (intern); + + /* Get the next entry until we found a correct one. */ + do + { + if (intern->next == NULL) + return NSS_STATUS_NOTFOUND; + p = strncpy (buffer, intern->next->val, buflen); + while (isspace (*p)) + ++p; + + parse_res = _nss_files_parse_grent (p, grp, data, buflen, errnop); + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + intern->next = intern->next->next; + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_nis_initgroups (const char *user, gid_t group, long int *start, + long int *size, gid_t *groups, long int limit, + int *errnop) +{ + struct group grpbuf, *g; + size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX); + char *tmpbuf; + enum nss_status status; + intern_t intern = { NULL, NULL }; + + status = internal_setgrent (&intern); + if (status != NSS_STATUS_SUCCESS) + return status; + + tmpbuf = __alloca (buflen); + + do + { + while ((status = + internal_getgrent_r (&grpbuf, tmpbuf, buflen, errnop, + &intern)) == NSS_STATUS_TRYAGAIN + && *errnop == ERANGE) + { + buflen *= 2; + tmpbuf = __alloca (buflen); + } + + if (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 && limit <= 0) + { + /* Need a bigger buffer. */ + groups = realloc (groups, *size * sizeof (*groups)); + if (groups == NULL) + goto done; + *size *= 2; + } + + groups[*start] = g->gr_gid; + *start += 1; + + if (*start == limit) + /* Can't take any more groups; stop searching. */ + goto done; + + break; + } + } + } + while (status == NSS_STATUS_SUCCESS); + +done: + while (intern.start != NULL) + { + if (intern.start->val != NULL) + free (intern.start->val); + intern.next = intern.start; + intern.start = intern.start->next; + free (intern.next); + } + + return NSS_STATUS_SUCCESS; +} diff --git a/nss/getXXbyYY_r.c b/nss/getXXbyYY_r.c index c8d6b08009..0f1206762b 100644 --- a/nss/getXXbyYY_r.c +++ b/nss/getXXbyYY_r.c @@ -82,8 +82,8 @@ /* Type of the lookup function we need here. */ -typedef int (*lookup_function) (ADD_PARAMS, LOOKUP_TYPE *, char *, size_t, - int * H_ERRNO_PARM); +typedef enum nss_status (*lookup_function) (ADD_PARAMS, LOOKUP_TYPE *, char *, + size_t, int * H_ERRNO_PARM); /* Some usages of this file might use this variable. */ extern struct __res_state _res; diff --git a/nss/getXXent_r.c b/nss/getXXent_r.c index 02a723d6bc..4e2902d2ca 100644 --- a/nss/getXXent_r.c +++ b/nss/getXXent_r.c @@ -85,14 +85,14 @@ #endif /* Prototype for the setXXXent functions we use here. */ -typedef int (*set_function) (STAYOPEN); +typedef enum nss_status (*set_function) (STAYOPEN); /* Prototype for the endXXXent functions we use here. */ -typedef int (*end_function) (void); +typedef enum nss_status (*end_function) (void); /* Prototype for the setXXXent functions we use here. */ -typedef int (*get_function) (LOOKUP_TYPE *, char *, size_t, int * - H_ERRNO_PARM); +typedef enum nss_status (*get_function) (LOOKUP_TYPE *, char *, size_t, int * + H_ERRNO_PARM); /* This handle for the NSS data base is shared between all diff --git a/nss/nsswitch.c b/nss/nsswitch.c index c968502cdf..f010d2755c 100644 --- a/nss/nsswitch.c +++ b/nss/nsswitch.c @@ -35,8 +35,6 @@ #include "nsswitch.h" /* Prototypes for the local functions. */ -static void *nss_lookup_function (service_user *ni, const char *fct_name) - internal_function; static name_database *nss_parse_file (const char *fname) internal_function; static name_database_entry *nss_getline (char *line) internal_function; static service_user *nss_parse_service_list (const char *line) @@ -140,7 +138,7 @@ __nss_database_lookup (const char *database, const char *alternate_name, int __nss_lookup (service_user **ni, const char *fct_name, void **fctp) { - *fctp = nss_lookup_function (*ni, fct_name); + *fctp = __nss_lookup_function (*ni, fct_name); while (*fctp == NULL && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_CONTINUE @@ -148,7 +146,7 @@ __nss_lookup (service_user **ni, const char *fct_name, void **fctp) { *ni = (*ni)->next; - *fctp = nss_lookup_function (*ni, fct_name); + *fctp = __nss_lookup_function (*ni, fct_name); } return *fctp != NULL ? 0 : (*ni)->next == NULL ? 1 : -1; @@ -187,7 +185,7 @@ __nss_next (service_user **ni, const char *fct_name, void **fctp, int status, { *ni = (*ni)->next; - *fctp = nss_lookup_function (*ni, fct_name); + *fctp = __nss_lookup_function (*ni, fct_name); } while (*fctp == NULL && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_CONTINUE @@ -310,9 +308,8 @@ known_compare (const void *p1, const void *p2) } -static void * -internal_function -nss_lookup_function (service_user *ni, const char *fct_name) +void * +__nss_lookup_function (service_user *ni, const char *fct_name) { void **found, *result; diff --git a/nss/nsswitch.h b/nss/nsswitch.h index 412936976a..cb16fe1542 100644 --- a/nss/nsswitch.h +++ b/nss/nsswitch.h @@ -127,5 +127,8 @@ int __nss_lookup (service_user **ni, const char *fct_name, void **fctp); int __nss_next (service_user **ni, const char *fct_name, void **fctp, int status, int all_values); +/* Search for the service described in NI for a function named FCT_NAME + and return a pointer to this function if successful. */ +void *__nss_lookup_function (service_user *ni, const char *fct_name); #endif /* nsswitch.h */ diff --git a/sysdeps/unix/sysv/linux/sigstack.c b/sysdeps/unix/sysv/linux/sigstack.c index bca7dc634e..cbae972048 100644 --- a/sysdeps/unix/sysv/linux/sigstack.c +++ b/sysdeps/unix/sysv/linux/sigstack.c @@ -19,8 +19,10 @@ Boston, MA 02111-1307, USA. */ #include +#include +#ifdef __NR_sigaltstack int sigstack (ss, oss) const struct sigstack *ss; @@ -59,3 +61,8 @@ sigstack (ss, oss) return result; } + +link_warning (sigstack, "the `sigstack' function is dangerous. `sigaltstack' should be used instead.") +#else +# include +#endif diff --git a/sysdeps/unix/sysv/linux/sparc/Dist b/sysdeps/unix/sysv/linux/sparc/Dist index e7569d1ad3..20d6bfa712 100644 --- a/sysdeps/unix/sysv/linux/sparc/Dist +++ b/sysdeps/unix/sysv/linux/sparc/Dist @@ -1,2 +1,2 @@ -sys/kernel_termios.h +kernel_termios.h sys/trap.h -- cgit v1.2.3