diff options
Diffstat (limited to 'nss')
-rw-r--r-- | nss/Makefile | 8 | ||||
-rw-r--r-- | nss/alias-lookup.c | 22 | ||||
-rw-r--r-- | nss/databases.def | 32 | ||||
-rw-r--r-- | nss/getXXbyYY.c | 72 | ||||
-rw-r--r-- | nss/getXXbyYY_r.c | 2 | ||||
-rw-r--r-- | nss/getXXent.c | 71 | ||||
-rw-r--r-- | nss/getXXent_r.c | 2 | ||||
-rw-r--r-- | nss/nss_db/db-XXX.c | 32 | ||||
-rw-r--r-- | nss/nss_db/db-alias.c | 235 | ||||
-rw-r--r-- | nss/nss_files/files-XXX.c | 120 | ||||
-rw-r--r-- | nss/nss_files/files-alias.c | 424 | ||||
-rw-r--r-- | nss/nss_files/files-parse.c | 42 |
12 files changed, 914 insertions, 148 deletions
diff --git a/nss/Makefile b/nss/Makefile index 93ffbaee34..9193cf2214 100644 --- a/nss/Makefile +++ b/nss/Makefile @@ -12,9 +12,9 @@ # 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. +# 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. # # Makefile for name service switch. @@ -33,7 +33,7 @@ routines = nsswitch $(addsuffix -lookup,$(databases)) # Caution: if you add a database here, you must add its real name # in databases.def, too. databases = proto service hosts network grp pwd rpc ethers \ - spwd netgrp key + spwd netgrp key alias # Specify rules for the nss_* modules. We have some services. services := files dns db diff --git a/nss/alias-lookup.c b/nss/alias-lookup.c new file mode 100644 index 0000000000..6a1244eea7 --- /dev/null +++ b/nss/alias-lookup.c @@ -0,0 +1,22 @@ +/* Copyright (C) 1996 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#define DATABASE_NAME aliases + +#include "XXX-lookup.c" diff --git a/nss/databases.def b/nss/databases.def index 8a5ede2a58..2ab892258d 100644 --- a/nss/databases.def +++ b/nss/databases.def @@ -1,25 +1,26 @@ /* List of all databases defined for the NSS in GNU C Library. -Copyright (C) 1996 Free Software Foundation, Inc. -This file is part of the GNU C Library. -Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996. + Copyright (C) 1996 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996. -The GNU C Library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. + The GNU C Library is 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. + 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. */ + 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. */ /* This list must be kept sorted!!! */ +DEFINE_DATABASE (aliases) DEFINE_DATABASE (ethers) DEFINE_DATABASE (group) DEFINE_DATABASE (hosts) @@ -27,6 +28,7 @@ DEFINE_DATABASE (netgroup) DEFINE_DATABASE (networks) DEFINE_DATABASE (passwd) DEFINE_DATABASE (protocols) +DEFINE_DATABASE (publickey) DEFINE_DATABASE (rpc) DEFINE_DATABASE (services) DEFINE_DATABASE (shadow) diff --git a/nss/getXXbyYY.c b/nss/getXXbyYY.c index c300117b8c..2a84db974a 100644 --- a/nss/getXXbyYY.c +++ b/nss/getXXbyYY.c @@ -1,22 +1,26 @@ /* Copyright (C) 1996 Free Software Foundation, Inc. -This file is part of the GNU C Library. + This file is part of the GNU C Library. -The GNU C Library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. + The GNU C Library is 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. + 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. */ + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ -#include "../nss/nsswitch.h" +#include <errno.h> +#include <libc-lock.h> +#include <stdlib.h> + +#include "nsswitch.h" /*******************************************************************\ |* Here we assume several symbols to be defined: *| @@ -64,17 +68,47 @@ extern int INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer, size_t buflen, LOOKUP_TYPE **result H_ERRNO_PARM); +/* We need to protect the dynamic buffer handling. */ +__libc_lock_define_initialized (static, lock); + + LOOKUP_TYPE * FUNCTION_NAME (ADD_PARAMS) { - static char buffer[BUFLEN]; + static char *buffer; + static size_t buffer_size; static LOOKUP_TYPE resbuf; LOOKUP_TYPE *result; + int save; + + /* Get lock. */ + __libc_lock_lock (lock); + + if (buffer == NULL) + { + buffer_size = BUFLEN; + buffer = malloc (buffer_size); + } + + while (buffer != NULL + && INTERNAL (REENTRANT_NAME) (ADD_VARIABLES, &resbuf, buffer, + buffer_size, &result H_ERRNO_VAR) != 0 + && errno == ERANGE) + { + char *new_buf; + buffer_size += BUFLEN; + new_buf = realloc (buffer, buffer_size); + if (new_buf == NULL) + /* We are out of memory. Free the current buffer so that the + process gets a chance for a normal termination. */ + free (buffer); + buffer = new_buf; + } - if (INTERNAL (REENTRANT_NAME) (ADD_VARIABLES, &resbuf, buffer, - BUFLEN, &result H_ERRNO_VAR) != 0) - /* Error occured. */ - return NULL; + /* Release lock. Preserve error value. */ + save = errno; + __libc_lock_unlock (lock); + __set_errno (save); return result; } diff --git a/nss/getXXbyYY_r.c b/nss/getXXbyYY_r.c index 1295772819..f12907c244 100644 --- a/nss/getXXbyYY_r.c +++ b/nss/getXXbyYY_r.c @@ -71,7 +71,7 @@ /* Type of the lookup function we need here. */ -typedef int (*lookup_function) (ADD_PARAMS, LOOKUP_TYPE *, char *, int +typedef int (*lookup_function) (ADD_PARAMS, LOOKUP_TYPE *, char *, size_t H_ERRNO_PARM); /* Some usages of this file might use this variable. */ diff --git a/nss/getXXent.c b/nss/getXXent.c index 7e291e6298..2d6d1c32e6 100644 --- a/nss/getXXent.c +++ b/nss/getXXent.c @@ -1,20 +1,24 @@ /* Copyright (C) 1996 Free Software Foundation, Inc. -This file is part of the GNU C Library. + This file is part of the GNU C Library. -The GNU C Library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. + The GNU C Library is 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. + 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. */ + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <libc-lock.h> +#include <stdlib.h> #include "nsswitch.h" @@ -55,18 +59,47 @@ extern int INTERNAL (REENTRANT_GETNAME) (LOOKUP_TYPE *resbuf, char *buffer, size_t buflen, LOOKUP_TYPE **result H_ERRNO_PARM); +/* We need to protect the dynamic buffer handling. */ +__libc_lock_define_initialized (static, lock); + LOOKUP_TYPE * GETFUNC_NAME (void) { - static char buffer[BUFLEN]; + static char *buffer; + static size_t buffer_size; static LOOKUP_TYPE resbuf; - LOOKUP_TYPE *result; + LOOKUP_TYPE *result = NULL; + int save; + + /* Get lock. */ + __libc_lock_lock (lock); + + if (buffer == NULL) + { + buffer_size = BUFLEN; + buffer = malloc (buffer_size); + } + + while (buffer != NULL + && INTERNAL (REENTRANT_GETNAME) (&resbuf, buffer, buffer_size, &result + H_ERRNO_VAR) != 0 + && errno == ERANGE) + { + char *new_buf; + buffer_size += BUFLEN; + new_buf = realloc (buffer, buffer_size); + if (new_buf == NULL) + /* We are out of memory. Free the current buffer so that the + process gets a chance for a normal termination. */ + free (buffer); + buffer = new_buf; + } - if (INTERNAL (REENTRANT_GETNAME) (&resbuf, buffer, BUFLEN, &result - H_ERRNO_VAR) != 0) - /* Errors occured. */ - return NULL; + /* Release lock. Preserve error value. */ + save = errno; + __libc_lock_unlock (lock); + __set_errno (save); return result; } diff --git a/nss/getXXent_r.c b/nss/getXXent_r.c index 0db0a8bf28..cc47537129 100644 --- a/nss/getXXent_r.c +++ b/nss/getXXent_r.c @@ -90,7 +90,7 @@ typedef int (*set_function) (STAYOPEN); typedef int (*end_function) (void); /* Prototype for the setXXXent functions we use here. */ -typedef int (*get_function) (LOOKUP_TYPE *, char *, int H_ERRNO_PARM); +typedef int (*get_function) (LOOKUP_TYPE *, char *, size_t H_ERRNO_PARM); /* This handle for the NSS data base is shared between all diff --git a/nss/nss_db/db-XXX.c b/nss/nss_db/db-XXX.c index 0c41761d67..1596be560a 100644 --- a/nss/nss_db/db-XXX.c +++ b/nss/nss_db/db-XXX.c @@ -1,21 +1,21 @@ /* Common code for DB-based databases in nss_db module. -Copyright (C) 1996 Free Software Foundation, Inc. -This file is part of the GNU C Library. + Copyright (C) 1996 Free Software Foundation, Inc. + This file is part of the GNU C Library. -The GNU C Library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. + The GNU C Library is 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. + 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., 675 Mass Ave, -Cambridge, MA 02139, USA. */ + 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 <db.h> #include <fcntl.h> @@ -168,7 +168,7 @@ lookup (const DBT *key, struct STRUCTURE *result, enum nss_status \ _nss_db_get##name##_r (proto, \ struct STRUCTURE *result, \ - char *buffer, int buflen H_ERRNO_PROTO) \ + char *buffer, size_t buflen H_ERRNO_PROTO) \ { \ DBT key; \ enum nss_status status; \ @@ -189,7 +189,7 @@ _nss_db_get##name##_r (proto, \ /* Return the next entry from the database file, doing locking. */ enum nss_status CONCAT(_nss_db_get,ENTNAME_r) (struct STRUCTURE *result, - char *buffer, int buflen H_ERRNO_PROTO) + char *buffer, size_t buflen H_ERRNO_PROTO) { /* Return next entry in host file. */ enum nss_status status; diff --git a/nss/nss_db/db-alias.c b/nss/nss_db/db-alias.c new file mode 100644 index 0000000000..2c44f4df79 --- /dev/null +++ b/nss/nss_db/db-alias.c @@ -0,0 +1,235 @@ +/* Mail alias file parser in nss_db module. + Copyright (C) 1996 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <aliases.h> +#include <alloca.h> +#include <ctype.h> +#include <db.h> +#include <errno.h> +#include <fcntl.h> +#include <libc-lock.h> +#include <paths.h> +#include <string.h> + +#include "nsswitch.h" + +/* Locks the static variables in this file. */ +__libc_lock_define_initialized (static, lock) + +/* Maintenance of the shared handle open on the database. */ + +static DB *db; +static int keep_db; +static unsigned int entidx; /* Index for `getaliasent_r'. */ + +/* Open database file if not already opened. */ +static enum nss_status +internal_setent (int stayopen) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + if (db == NULL) + { + db = dbopen (_PATH_VARDB "aliases.db", O_RDONLY, 0, DB_BTREE, NULL); + + if (db == NULL) + status = NSS_STATUS_UNAVAIL; + } + + /* Remember STAYOPEN flag. */ + if (db != NULL) + keep_db |= stayopen; + + return status; +} + + +/* Thread-safe, exported version of that. */ +enum nss_status +_nss_db_setaliasent (int stayopen) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_setent (stayopen); + + /* Reset the sequential index. */ + entidx = 0; + + __libc_lock_unlock (lock); + + return status; +} + + +/* Close the database file. */ +static void +internal_endent (void) +{ + if (db != NULL) + { + (*db->close) (db); + db = NULL; + } +} + + +/* Thread-safe, exported version of that. */ +enum nss_status +_nss_db_endaliasent (void) +{ + __libc_lock_lock (lock); + + internal_endent (); + + /* Reset STAYOPEN flag. */ + keep_db = 0; + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +/* We provide the parse function here. The parser in libnss_files + cannot be used. The generation of the db file already resolved all + :include: statements so we simply have to parse the list and store + the result. */ +static enum nss_status +lookup (const DBT *key, struct aliasent *result, char *buffer, + size_t buflen) +{ + enum nss_status status; + DBT value; + + /* Open the database. */ + status = internal_setent (keep_db); + if (status != NSS_STATUS_SUCCESS) + return status; + + if ((*db->get) (db, key, &value, 0) == 0) + { + const char *src = value.data; + + result->alias_members_len = 0; + + /* We now have to fill the BUFFER with all the information. */ + if (buflen < key->size + 1) + { + no_more_room: + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + + if (status == NSS_STATUS_SUCCESS) + { + char *cp; + size_t cnt; + + buffer = stpncpy (buffer, key->data, key->size) + 1; + buflen -= key->size + 1; + + while (*src != '\0') + { + const char *end, *upto; + while (isspace (*src)) + ++src; + + end = strchr (src, ','); + if (end == NULL) + end = strchr (src, '\0'); + for (upto = end; upto > src && isspace (upto[-1]); --upto); + + if (upto != src) + { + if ((upto - src) + __alignof__ (char *) > buflen) + goto no_more_room; + buffer = stpncpy (buffer, src, upto - src) + 1; + buflen -= (upto - src) + __alignof (char *); + ++result->alias_members_len; + } + src = end + (*end != '\0'); + } + + /* Now prepare the return. Provide string pointers for the + currently selected aliases. */ + + /* Adjust the pointer so it is aligned for storing pointers. */ + buffer += __alignof__ (char *) - 1; + buffer -= ((buffer - (char *) 0) % __alignof__ (char *)); + result->alias_members = (char **) buffer; + + /* Compute addresses of alias entry strings. */ + cp = result->alias_name; + for (cnt = 0; cnt < result->alias_members_len; ++cnt) + { + cp = strchr (cp, '\0') + 1; + result->alias_members[cnt] = cp; + } + + status = (result->alias_members_len == 0 + ? NSS_STATUS_RETURN : NSS_STATUS_SUCCESS); + } + } + else + status = NSS_STATUS_NOTFOUND; + + if (! keep_db) + internal_endent (); + + return status; +} + +enum nss_status +_nss_db_getaliasent_r (struct aliasent *result, char *buffer, size_t buflen) +{ + /* Return next entry in host file. */ + enum nss_status status; + char buf[20]; + DBT key; + + __libc_lock_lock (lock); + key.size = 1 + snprintf (key.data = buf, sizeof buf, "0%u", entidx++); + status = lookup (&key, result, buffer, buflen); + __libc_lock_unlock (lock); + + return status; +} + + +enum nss_status +_nss_db_getaliasbyname_r (const char *name, struct aliasent *result, + char *buffer, size_t buflen) +{ + DBT key; + enum nss_status status; + + key.size = 1 + strlen (name); + + key.data = __alloca (key.size); + ((char *) key.data)[0] = '.'; + memcpy (&((char *) key.data)[1], name, key.size - 1); + + __libc_lock_lock (lock); + status = lookup (&key, result, buffer, buflen); + __libc_lock_unlock (lock); + + return status; +} diff --git a/nss/nss_files/files-XXX.c b/nss/nss_files/files-XXX.c index b6702b0366..c741ab6f48 100644 --- a/nss/nss_files/files-XXX.c +++ b/nss/nss_files/files-XXX.c @@ -20,6 +20,7 @@ #include <stdio.h> #include <ctype.h> #include <assert.h> +#include <errno.h> #include <libc-lock.h> #include "nsswitch.h" @@ -39,13 +40,13 @@ #define DATAFILE "/etc/" DATABASE #ifdef NEED_H_ERRNO -#define H_ERRNO_PROTO , int *herrnop -#define H_ERRNO_ARG , herrnop -#define H_ERRNO_SET(val) (*herrnop = (val)) +# define H_ERRNO_PROTO , int *herrnop +# define H_ERRNO_ARG , herrnop +# define H_ERRNO_SET(val) (*herrnop = (val)) #else -#define H_ERRNO_PROTO -#define H_ERRNO_ARG -#define H_ERRNO_SET(val) ((void) 0) +# define H_ERRNO_PROTO +# define H_ERRNO_ARG +# define H_ERRNO_SET(val) ((void) 0) #endif /* Locks the static variables in this file. */ @@ -59,10 +60,10 @@ static enum { none, getent, getby } last_use; static int keep_stream; /* Open database file if not already opened. */ -static int +static enum nss_status internal_setent (int stayopen) { - int status = NSS_STATUS_SUCCESS; + enum nss_status status = NSS_STATUS_SUCCESS; if (stream == NULL) { @@ -83,10 +84,10 @@ internal_setent (int stayopen) /* Thread-safe, exported version of that. */ -int +enum nss_status CONCAT(_nss_files_set,ENTNAME) (int stayopen) { - int status; + enum nss_status status; __libc_lock_lock (lock); @@ -120,7 +121,7 @@ internal_endent (void) /* Thread-safe, exported version of that. */ -int +enum nss_status CONCAT(_nss_files_end,ENTNAME) (void) { __libc_lock_lock (lock); @@ -145,16 +146,6 @@ internal_getent (struct STRUCTURE *result, struct parser_data *data = (void *) buffer; int linebuflen = buffer + buflen - data->linebuffer; - /* Be prepared that the set*ent function was not called before. */ - if (stream == NULL) - { - enum nss_status status; - - status = internal_setent (0); - if (status != NSS_STATUS_SUCCESS) - return status; - } - if (buflen < (int) sizeof *data + 1) { __set_errno (ERANGE); @@ -163,6 +154,9 @@ internal_getent (struct STRUCTURE *result, do { + /* Terminate the line so that we can test for overflow. */ + data->linebuffer[linebuflen - 1] = '\0'; + p = fgets (data->linebuffer, linebuflen, stream); if (p == NULL) { @@ -170,17 +164,23 @@ internal_getent (struct STRUCTURE *result, H_ERRNO_SET (HOST_NOT_FOUND); return NSS_STATUS_NOTFOUND; } - - /* Terminate the line for any case. */ - data->linebuffer[linebuflen - 1] = '\0'; + else if (data->linebuffer[linebuflen - 1] != '\0') + { + /* The line is too long. Give the user the opportunity to + enlarge the buffer. */ + __set_errno (ERANGE); + H_ERRNO_SET (NETDB_INTERNAL); + return NSS_STATUS_TRYAGAIN; + } /* Skip leading blanks. */ while (isspace (*p)) ++p; - } while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ - /* Parse the line. If it is invalid, loop to - get the next line of the file to parse. */ - ! parse_line (p, result, data, buflen)); + } + 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_line (p, result, data, buflen)); /* Filled in RESULT with the next entry from the database file. */ return NSS_STATUS_SUCCESS; @@ -188,29 +188,42 @@ internal_getent (struct STRUCTURE *result, /* Return the next entry from the database file, doing locking. */ -int +enum nss_status CONCAT(_nss_files_get,ENTNAME_r) (struct STRUCTURE *result, - char *buffer, int buflen H_ERRNO_PROTO) + char *buffer, size_t buflen H_ERRNO_PROTO) { /* Return next entry in host file. */ - int status = NSS_STATUS_SUCCESS; + enum nss_status status = NSS_STATUS_SUCCESS; __libc_lock_lock (lock); - /* If the last use was not by the getent function we need the - position the stream. */ - if (last_use != getent) - if (fsetpos (stream, &position) < 0) - status = NSS_STATUS_UNAVAIL; - else - last_use = getent; + /* Be prepared that the set*ent function was not called before. */ + if (stream == NULL) + status = internal_setent (0); - if (status == NSS_STATUS_SUCCESS) + if (status != NSS_STATUS_SUCCESS) { - status = internal_getent (result, buffer, buflen H_ERRNO_ARG); - - /* Remember this position. */ - fgetpos (stream, &position); + /* If the last use was not by the getent function we need the + position the stream. */ + if (last_use != getent) + if (fsetpos (stream, &position) < 0) + status = NSS_STATUS_UNAVAIL; + else + last_use = getent; + + if (status == NSS_STATUS_SUCCESS) + { + status = internal_getent (result, buffer, buflen H_ERRNO_ARG); + + /* Remember this position if we were successful. If the + operation failed we give the user a chance to repeat the + operation (perhaps the buffer was too small). */ + if (status == NSS_STATUS_SUCCESS) + fgetpos (stream, &position); + else + /* We must make sure we reposition the stream the next call. */ + last_use = none; + } } __libc_lock_unlock (lock); @@ -234,24 +247,27 @@ CONCAT(_nss_files_get,ENTNAME_r) (struct STRUCTURE *result, enum nss_status \ _nss_files_get##name##_r (proto, \ struct STRUCTURE *result, \ - char *buffer, int buflen H_ERRNO_PROTO) \ + char *buffer, size_t buflen H_ERRNO_PROTO) \ { \ enum nss_status status; \ \ __libc_lock_lock (lock); \ \ /* Reset file pointer to beginning or open file. */ \ - internal_setent (keep_stream); \ + status = internal_setent (keep_stream); \ \ - /* Tell getent function that we have repositioned the file pointer. */ \ - last_use = getby; \ + if (status == NSS_STATUS_SUCCESS) \ + { \ + /* Tell getent function that we have repositioned the file pointer. */ \ + last_use = getby; \ \ - while ((status = internal_getent (result, buffer, buflen H_ERRNO_ARG)) \ - == NSS_STATUS_SUCCESS) \ - { break_if_match } \ + while ((status = internal_getent (result, buffer, buflen H_ERRNO_ARG)) \ + == NSS_STATUS_SUCCESS) \ + { break_if_match } \ \ - if (! keep_stream) \ - internal_endent (); \ + if (! keep_stream) \ + internal_endent (); \ + } \ \ __libc_lock_unlock (lock); \ \ diff --git a/nss/nss_files/files-alias.c b/nss/nss_files/files-alias.c new file mode 100644 index 0000000000..c6ef49c621 --- /dev/null +++ b/nss/nss_files/files-alias.c @@ -0,0 +1,424 @@ +/* Mail alias file parser in nss_files module. + Copyright (C) 1996 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <aliases.h> +#include <ctype.h> +#include <libc-lock.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "nsswitch.h" + +/* Locks the static variables in this file. */ +__libc_lock_define_initialized (static, lock) + +/* Maintenance of the shared stream open on the database file. */ + +static FILE *stream; +static fpos_t position; +static enum { none, getent, getby } last_use; + + +static enum nss_status +internal_setent (void) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + if (stream == NULL) + { + stream = fopen ("/etc/aliases", "r"); + + if (stream == NULL) + status = NSS_STATUS_UNAVAIL; + } + else + rewind (stream); + + return status; +} + + +/* Thread-safe, exported version of that. */ +enum nss_status +_nss_files_setaliasent (void) +{ + enum nss_status status; + + __libc_lock_lock (lock); + + status = internal_setent (); + + if (status == NSS_STATUS_SUCCESS && fgetpos (stream, &position) < 0) + { + fclose (stream); + stream = NULL; + status = NSS_STATUS_UNAVAIL; + } + + last_use = getent; + + __libc_lock_unlock (lock); + + return status; +} + + +/* Close the database file. */ +static void +internal_endent (void) +{ + if (stream != NULL) + { + fclose (stream); + stream = NULL; + } +} + + +/* Thread-safe, exported version of that. */ +enum nss_status +_nss_files_endaliasent (void) +{ + __libc_lock_lock (lock); + + internal_endent (); + + __libc_lock_unlock (lock); + + return NSS_STATUS_SUCCESS; +} + +/* Parsing the database file into `struct aliasent' data structures. */ +static enum nss_status +get_next_alias (const char *match, struct aliasent *result, + char *buffer, size_t buflen) +{ + enum nss_status status = NSS_STATUS_NOTFOUND; + int ignore = 0; + + result->alias_members_len = 0; + + while (1) + { + /* Now we are ready to process the input. We have to read a + line and all its continuations and construct the array of + string pointers. This pointers and the names itself have to + be placed in BUFFER. */ + char *first_unused = buffer; + size_t room_left = buflen - (buflen % __alignof__ (char *)); + char *line; + + /* Read the first line. It must contain the alias name and + possibly some alias names. */ + first_unused[room_left - 1] = '\0'; + line = fgets (first_unused, room_left, stream); + if (line == NULL) + /* Nothing to read. */ + break; + else if (first_unused[room_left - 1] != '\0') + { + /* The line is too long for our buffer. */ + no_more_room: + __set_errno (ERANGE); + status = NSS_STATUS_TRYAGAIN; + break; + } + else + { + char *cp; + + /* If we are in IGNORE mode and the first character in the + line is a white space we ignore the line and start + reading the next. */ + if (ignore && isspace (first_unused)) + continue; + + /* Terminate the line for any case. */ + cp = strpbrk (first_unused, "#\n"); + if (cp != NULL) + *cp = '\0'; + + /* Skip leading blanks. */ + while (isspace (*line)) + ++line; + + result->alias_name = first_unused; + while (*line != '\0' && *line != ':') + *first_unused++ = *line++; + if (*line == '\0' || result->alias_name == first_unused) + /* No valid name. Ignore the line. */ + continue; + + *first_unused++ = '\0'; + if (room_left < (size_t) (first_unused - result->alias_name)) + goto no_more_room; + room_left -= first_unused - result->alias_name; + ++line; + + /* When we search for a specific alias we can avoid all the + difficult parts and compare now with the name we are + looking for. If it does not match we simply ignore all + lines until the next line containing the start of a new + alias is found. */ + ignore = match != NULL && strcmp (result->alias_name, match) == 0; + + while (! ignore) + { + while (isspace (*line)) + ++line; + + cp = first_unused; + while (*line != '\0' && *line != ',') + *first_unused++ = *line++; + + if (first_unused != cp) + { + if (*line != '\0') + { + /* OK, we can have a regular entry or an include + request. */ + *first_unused++ = '\0'; + ++line; + } + else + ++first_unused; + + + if (strncmp (cp, ":include:", 9) != 0) + { + if (room_left < (first_unused - cp) + sizeof (char *)) + goto no_more_room; + room_left -= (first_unused - cp) + sizeof (char *); + + ++result->alias_members_len; + } + else + { + /* Oh well, we have to read the addressed file. */ + FILE *listfile; + char *old_line = NULL; + + first_unused = cp; + + listfile = fopen (&cp[9], "r"); + /* If the file does not exist we simply ignore + the statement. */ + if (listfile != NULL + && (old_line = strdup (line)) != NULL) + { + while (! feof (listfile)) + { + first_unused[room_left - 1] = '\0'; + line = fgets (first_unused, room_left, listfile); + if (line == NULL) + break; + if (first_unused[room_left - 1] != '\0') + { + free (old_line); + goto no_more_room; + } + + /* Parse the line. */ + cp = strpbrk (line, "#\n"); + if (cp != NULL) + *cp = '\0'; + + do + { + while (isspace (*line)) + ++line; + + cp = first_unused; + while (*line != '\0' && *line != ',') + *first_unused++ = *line++; + + if (*line != '\0') + ++line; + + if (first_unused != cp) + { + *first_unused++ = '\0'; + if (room_left < ((first_unused - cp) + + __alignof__ (char *))) + { + free (old_line); + goto no_more_room; + } + room_left -= ((first_unused - cp) + + __alignof__ (char *)); + ++result->alias_members_len; + } + } + while (*line != '\0'); + } + fclose (listfile); + + first_unused[room_left - 1] = '\0'; + strncpy (first_unused, old_line, room_left); + + if (old_line != NULL) + free (old_line); + + if (first_unused[room_left - 1] != '\0') + goto no_more_room; + } + } + } + + if (*line == '\0') + { + /* Get the next line. But we must be careful. We + must not read the whole line at once since it + might belong to the current alias. Simply read + the first character. If it is a white space we + have a continuation line. Otherwise it is the + beginning of a new alias and we can push back the + just read character. */ + int ch; + + first_unused[room_left - 1] = '\0'; + line = first_unused; + ch = fgetc (stream); + if (ch == EOF || !isspace (ch)) + { + size_t cnt; + + /* Now prepare the return. Provide string + pointers for the currently selected aliases. */ + if (ch != EOF) + ungetc (ch, stream); + + /* Adjust the pointer so it is aligned for + storing pointers. */ + first_unused += __alignof__ (char *) - 1; + first_unused -= ((first_unused - (char *) 0) + % __alignof__ (char *)); + result->alias_members = (char **) first_unused; + + /* Compute addresses of alias entry strings. */ + cp = result->alias_name; + for (cnt = 0; cnt < result->alias_members_len; ++cnt) + { + cp = strchr (cp, '\0') + 1; + result->alias_members[cnt] = cp; + } + + status = (result->alias_members_len == 0 + ? NSS_STATUS_RETURN : NSS_STATUS_SUCCESS); + break; + } + + /* The just read character is a white space and so + can be ignored. */ + cp = strpbrk (line, "#\n"); + if (cp != NULL) + *cp = '\0'; + } + } + } + + if (status != NSS_STATUS_NOTFOUND) + /* We read something. In any case break here. */ + break; + } + + return status; +} + + +enum nss_status +_nss_files_getaliasent_r (struct aliasent *result, char *buffer, size_t buflen) +{ + /* Return next entry in host file. */ + enum nss_status status = NSS_STATUS_SUCCESS; + + __libc_lock_lock (lock); + + /* Be prepared that the set*ent function was not called before. */ + if (stream == NULL) + status = internal_setent (); + + if (status == NSS_STATUS_SUCCESS) + { + /* If the last use was not by the getent function we need the + position the stream. */ + if (last_use != getent) + if (fsetpos (stream, &position) < 0) + status = NSS_STATUS_UNAVAIL; + else + last_use = getent; + + if (status == NSS_STATUS_SUCCESS) + { + result->alias_local = 1; + + /* Read lines until we get a definite result. */ + do + status = get_next_alias (NULL, result, buffer, buflen); + while (status == NSS_STATUS_RETURN); + + /* If we successfully read an entry remember this position. */ + if (status == NSS_STATUS_SUCCESS) + fgetpos (stream, &position); + else + last_use = none; + } + } + + __libc_lock_unlock (lock); + + return status; +} + + +enum nss_status +_nss_files_getaliasbyname_r (const char *name, struct aliasent *result, + char *buffer, size_t buflen) +{ + /* Return next entry in host file. */ + enum nss_status status = NSS_STATUS_SUCCESS; + + if (name == NULL) + { + __set_errno (EINVAL); + return NSS_STATUS_UNAVAIL; + } + + __libc_lock_lock (lock); + + /* Open the stream or rest it. */ + status = internal_setent (); + last_use = getby; + + if (status == NSS_STATUS_SUCCESS) + { + result->alias_local = 1; + + /* Read lines until we get a definite result. */ + do + status = get_next_alias (name, result, buffer, buflen); + while (status == NSS_STATUS_RETURN); + } + + __libc_lock_unlock (lock); + + return status; +} diff --git a/nss/nss_files/files-parse.c b/nss/nss_files/files-parse.c index 1250bb9572..83a80f35c0 100644 --- a/nss/nss_files/files-parse.c +++ b/nss/nss_files/files-parse.c @@ -39,7 +39,7 @@ #define CONCAT1(a,b) a##b #ifndef STRUCTURE -#define STRUCTURE ENTNAME +# define STRUCTURE ENTNAME #endif @@ -47,9 +47,9 @@ struct parser_data { #ifdef ENTDATA struct ENTDATA entdata; -#define ENTDATA_DECL(data) struct ENTDATA *const entdata = &data->entdata; +# define ENTDATA_DECL(data) struct ENTDATA *const entdata = &data->entdata; #else -#define ENTDATA_DECL(data) +# define ENTDATA_DECL(data) #endif char linebuffer[0]; }; @@ -57,11 +57,11 @@ struct parser_data #ifdef ENTDATA /* The function can't be exported, because the entdata structure is defined only in files-foo.c. */ -#define parser_stclass static inline +# define parser_stclass static inline #else /* Export the line parser function so it can be used in nss_db. */ -#define parser_stclass /* Global */ -#define parse_line CONCAT(_nss_files_parse_,ENTNAME) +# define parser_stclass /* Global */ +# define parse_line CONCAT(_nss_files_parse_,ENTNAME) #endif @@ -71,20 +71,20 @@ struct parser_data extern int parse_line (char *line, struct STRUCTURE *result, struct parser_data *data, int datalen); -#define LINE_PARSER(EOLSET, BODY) /* Do nothing */ +# define LINE_PARSER(EOLSET, BODY) /* Do nothing */ #else /* Define a line parsing function. */ -#define LINE_PARSER(EOLSET, BODY) \ +# define LINE_PARSER(EOLSET, BODY) \ parser_stclass int \ parse_line (char *line, struct STRUCTURE *result, \ struct parser_data *data, int datalen) \ { \ ENTDATA_DECL (data) \ char *p = strpbrk (line, EOLSET "\n"); \ - if (p) \ + if (p != NULL) \ *p = '\0'; \ BODY; \ TRAILING_LIST_PARSER; \ @@ -92,7 +92,7 @@ parse_line (char *line, struct STRUCTURE *result, \ } -#define STRING_FIELD(variable, terminator_p, swallow) \ +# define STRING_FIELD(variable, terminator_p, swallow) \ { \ variable = line; \ while (*line != '\0' && !terminator_p (*line)) \ @@ -106,7 +106,7 @@ parse_line (char *line, struct STRUCTURE *result, \ } \ } -#define INT_FIELD(variable, terminator_p, swallow, base, convert) \ +# define INT_FIELD(variable, terminator_p, swallow, base, convert) \ { \ char *endp; \ variable = convert (strtol (line, &endp, base)); \ @@ -121,7 +121,7 @@ parse_line (char *line, struct STRUCTURE *result, \ line = endp; \ } -#define INT_FIELD_MAYBE_NULL(variable, terminator_p, swallow, base, convert, default) \ +# define INT_FIELD_MAYBE_NULL(variable, terminator_p, swallow, base, convert, default) \ { \ char *endp; \ if (*line == '\0') \ @@ -139,14 +139,14 @@ parse_line (char *line, struct STRUCTURE *result, \ line = endp; \ } -#define ISCOLON(c) ((c) == ':') +# define ISCOLON(c) ((c) == ':') -#ifndef TRAILING_LIST_MEMBER -#define TRAILING_LIST_PARSER /* Nothing to do. */ -#else +# ifndef TRAILING_LIST_MEMBER +# define TRAILING_LIST_PARSER /* Nothing to do. */ +# else -#define TRAILING_LIST_PARSER \ +# define TRAILING_LIST_PARSER \ { \ char **list = parse_list (line, data, datalen); \ if (list) \ @@ -198,10 +198,10 @@ parse_list (char *line, struct parser_data *data, int datalen) *line = '\0'; do ++line; - while (TRAILING_LIST_SEPARATOR_P (*line)); + while (isspace (*line)); elt = line; } - else if (*line == '\0' || *line == '\n') + else if (*line == '\0') { /* End of the line. */ if (line > elt) @@ -219,7 +219,7 @@ parse_list (char *line, struct parser_data *data, int datalen) return list; } -#endif /* TRAILING_LIST_MEMBER */ +# endif /* TRAILING_LIST_MEMBER */ #endif /* EXTERN_PARSER */ @@ -238,5 +238,5 @@ parse_list (char *line, struct parser_data *data, int datalen) /* This is defined by db-*.c to include "../nss_db/db-XXX.c" instead. */ #ifndef GENERIC -#define GENERIC "files-XXX.c" +# define GENERIC "files-XXX.c" #endif |