aboutsummaryrefslogtreecommitdiff
path: root/nss/nss_files
diff options
context:
space:
mode:
Diffstat (limited to 'nss/nss_files')
-rw-r--r--nss/nss_files/files-XXX.c120
-rw-r--r--nss/nss_files/files-alias.c424
-rw-r--r--nss/nss_files/files-parse.c42
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