diff options
Diffstat (limited to 'nss/nss_files')
-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 |
3 files changed, 513 insertions, 73 deletions
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 |