diff options
Diffstat (limited to 'nss')
-rw-r--r-- | nss/Makefile | 24 | ||||
-rw-r--r-- | nss/Versions | 8 | ||||
-rw-r--r-- | nss/fgetpwent.c | 87 | ||||
-rw-r--r-- | nss/fgetpwent_r.c | 79 | ||||
-rw-r--r-- | nss/getpw.c | 62 | ||||
-rw-r--r-- | nss/getpwent.c | 28 | ||||
-rw-r--r-- | nss/getpwent_r.c | 28 | ||||
-rw-r--r-- | nss/getpwnam.c | 28 | ||||
-rw-r--r-- | nss/getpwnam_r.c | 28 | ||||
-rw-r--r-- | nss/getpwuid.c | 28 | ||||
-rw-r--r-- | nss/getpwuid_r.c | 28 | ||||
-rw-r--r-- | nss/putpwent.c | 65 | ||||
-rw-r--r-- | nss/pwd.h | 193 | ||||
-rw-r--r-- | nss/tst-getpw.c | 114 | ||||
-rw-r--r-- | nss/tst-putpwent.c | 168 |
15 files changed, 968 insertions, 0 deletions
diff --git a/nss/Makefile b/nss/Makefile index 5256b90..28648ea 100644 --- a/nss/Makefile +++ b/nss/Makefile @@ -26,6 +26,7 @@ headers := \ grp.h \ gshadow.h \ nss.h \ + pwd.h \ # headers # This is the trivial part which goes into libc itself. @@ -103,6 +104,27 @@ CFLAGS-getsgnam.c += -fexceptions CFLAGS-getsgnam_r.c += -fexceptions endif +# pwd routines: +routines += \ + fgetpwent \ + fgetpwent_r \ + getpw \ + getpwent \ + getpwent_r \ + getpwnam \ + getpwnam_r \ + getpwuid \ + getpwuid_r \ + putpwent \ + # routines + +ifeq ($(have-thread-library),yes) +CFLAGS-fgetpwent_r.c += $(libio-mtsafe) +CFLAGS-getpw.c += -fexceptions +CFLAGS-getpwent.c += -fexceptions +CFLAGS-getpwent_r.c += -fexceptions +endif + # These are the databases that go through nss dispatch. # Caution: if you add a database here, you must add its real name # in databases.def, too. @@ -143,6 +165,7 @@ tests := \ test-netdb \ testgrp \ tst-fgetsgent_r \ + tst-getpw \ tst-gshadow \ tst-nss-getpwent \ tst-nss-hash \ @@ -152,6 +175,7 @@ tests := \ tst-nss-test5 \ tst-nss-test_errno \ tst-putgrent \ + tst-putpwent \ tst-putsgent \ tst-sgetsgent \ # tests diff --git a/nss/Versions b/nss/Versions index 6204ac0..58ca73c 100644 --- a/nss/Versions +++ b/nss/Versions @@ -8,19 +8,26 @@ libc { # e* endgrent; + endpwent; # f* fgetgrent; fgetgrent_r; + fgetpwent; fgetpwent_r; # g* getgrent; getgrent_r; getgrgid; getgrgid_r; getgrnam; getgrnam_r; getgroups; + getpw; getpwent; getpwent_r; getpwnam; getpwnam_r; getpwuid; getpwuid_r; # i* initgroups; + # p* + putpwent; + # s* setgrent; + setpwent; } GLIBC_2.1 { # p* @@ -29,6 +36,7 @@ libc { GLIBC_2.1.2 { # g* getgrent_r; getgrgid_r; getgrnam_r; + getpwent_r; getpwuid_r; getpwnam_r; } GLIBC_2.2.2 { __nss_hostname_digits_dots; diff --git a/nss/fgetpwent.c b/nss/fgetpwent.c new file mode 100644 index 0000000..b7864d2 --- /dev/null +++ b/nss/fgetpwent.c @@ -0,0 +1,87 @@ +/* Copyright (C) 1991-2023 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <libc-lock.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <set-freeres.h> + + +/* We need to protect the dynamic buffer handling. */ +__libc_lock_define_initialized (static, lock); + +static char *buffer; + +/* Read one entry from the given stream. */ +struct passwd * +fgetpwent (FILE *stream) +{ + static size_t buffer_size; + static struct passwd resbuf; + fpos_t pos; + struct passwd *result; + int save; + + if (fgetpos (stream, &pos) != 0) + return NULL; + + /* Get lock. */ + __libc_lock_lock (lock); + + /* Allocate buffer if not yet available. */ + if (buffer == NULL) + { + buffer_size = NSS_BUFLEN_PASSWD; + buffer = malloc (buffer_size); + } + + while (buffer != NULL + && (__fgetpwent_r (stream, &resbuf, buffer, buffer_size, &result) + == ERANGE)) + { + char *new_buf; + buffer_size += NSS_BUFLEN_PASSWD; + 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. */ + save = errno; + free (buffer); + __set_errno (save); + } + buffer = new_buf; + + /* Reset the stream. */ + if (fsetpos (stream, &pos) != 0) + buffer = NULL; + } + + if (buffer == NULL) + result = NULL; + + /* Release lock. Preserve error value. */ + save = errno; + __libc_lock_unlock (lock); + __set_errno (save); + + return result; +} + +weak_alias (buffer, __libc_fgetpwent_freemem_ptr) diff --git a/nss/fgetpwent_r.c b/nss/fgetpwent_r.c new file mode 100644 index 0000000..5427447 --- /dev/null +++ b/nss/fgetpwent_r.c @@ -0,0 +1,79 @@ +/* Copyright (C) 1991-2023 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <pwd.h> + +/* Define a line parsing function using the common code + used in the nss_files module. */ + +#define STRUCTURE passwd +#define ENTNAME pwent +struct pwent_data {}; + +#include <nss/nss_files/files-parse.c> +LINE_PARSER +(, + STRING_FIELD (result->pw_name, ISCOLON, 0); + if (line[0] == '\0' + && (result->pw_name[0] == '+' || result->pw_name[0] == '-')) + { + /* This a special case. We allow lines containing only a `+' sign + since this is used for nss_compat. All other services will + reject this entry later. Initialize all other fields now. */ + result->pw_passwd = NULL; + result->pw_uid = 0; + result->pw_gid = 0; + result->pw_gecos = NULL; + result->pw_dir = NULL; + result->pw_shell = NULL; + } + else + { + STRING_FIELD (result->pw_passwd, ISCOLON, 0); + if (result->pw_name[0] == '+' || result->pw_name[0] == '-') + { + INT_FIELD_MAYBE_NULL (result->pw_uid, ISCOLON, 0, 10, , 0) + INT_FIELD_MAYBE_NULL (result->pw_gid, ISCOLON, 0, 10, , 0) + } + else + { + INT_FIELD (result->pw_uid, ISCOLON, 0, 10,) + INT_FIELD (result->pw_gid, ISCOLON, 0, 10,) + } + STRING_FIELD (result->pw_gecos, ISCOLON, 0); + STRING_FIELD (result->pw_dir, ISCOLON, 0); + result->pw_shell = line; + } + ) + + +/* Read one entry from the given stream. */ +int +__fgetpwent_r (FILE *stream, struct passwd *resbuf, char *buffer, + size_t buflen, struct passwd **result) +{ + int ret = __nss_fgetent_r (stream, resbuf, buffer, buflen, parse_line); + if (ret == 0) + *result = resbuf; + else + *result = NULL; + return ret; +} +weak_alias (__fgetpwent_r, fgetpwent_r) diff --git a/nss/getpw.c b/nss/getpw.c new file mode 100644 index 0000000..cf74737 --- /dev/null +++ b/nss/getpw.c @@ -0,0 +1,62 @@ +/* Copyright (C) 1991-2023 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <alloca.h> +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <pwd.h> + + +/* Re-construct the password-file line for the given uid + in the given buffer. This knows the format that the caller + will expect, but this need not be the format of the password file. */ + +int __getpw (__uid_t uid, char *buf); + +int +__getpw (__uid_t uid, char *buf) +{ + size_t buflen; + char *tmpbuf; + struct passwd resbuf, *p; + + if (buf == NULL) + { + __set_errno (EINVAL); + return -1; + } + + buflen = __sysconf (_SC_GETPW_R_SIZE_MAX); + tmpbuf = alloca (buflen); + + if (__getpwuid_r (uid, &resbuf, tmpbuf, buflen, &p) != 0) + return -1; + + if (p == NULL) + return -1; + + if (sprintf (buf, "%s:%s:%lu:%lu:%s:%s:%s", p->pw_name, p->pw_passwd, + (unsigned long int) p->pw_uid, (unsigned long int) p->pw_gid, + p->pw_gecos, p->pw_dir, p->pw_shell) < 0) + return -1; + + return 0; +} +weak_alias (__getpw, getpw) + +link_warning (getpw, "the `getpw' function is dangerous and should not be used.") diff --git a/nss/getpwent.c b/nss/getpwent.c new file mode 100644 index 0000000..eb65bdc --- /dev/null +++ b/nss/getpwent.c @@ -0,0 +1,28 @@ +/* Copyright (C) 1996-2023 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <pwd.h> + + +#define LOOKUP_TYPE struct passwd +#define SETFUNC_NAME setpwent +#define GETFUNC_NAME getpwent +#define ENDFUNC_NAME endpwent +#define DATABASE_NAME passwd +#define BUFLEN NSS_BUFLEN_PASSWD + +#include "../nss/getXXent.c" diff --git a/nss/getpwent_r.c b/nss/getpwent_r.c new file mode 100644 index 0000000..f26bf89 --- /dev/null +++ b/nss/getpwent_r.c @@ -0,0 +1,28 @@ +/* Copyright (C) 1996-2023 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <pwd.h> + + +#define LOOKUP_TYPE struct passwd +#define SETFUNC_NAME setpwent +#define GETFUNC_NAME getpwent +#define ENDFUNC_NAME endpwent +#define DATABASE_NAME passwd +#define BUFLEN NSS_BUFLEN_PASSWD + +#include "../nss/getXXent_r.c" diff --git a/nss/getpwnam.c b/nss/getpwnam.c new file mode 100644 index 0000000..9a28d53 --- /dev/null +++ b/nss/getpwnam.c @@ -0,0 +1,28 @@ +/* Copyright (C) 1996-2023 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <pwd.h> + + +#define LOOKUP_TYPE struct passwd +#define FUNCTION_NAME getpwnam +#define DATABASE_NAME passwd +#define ADD_PARAMS const char *name +#define ADD_VARIABLES name +#define BUFLEN NSS_BUFLEN_PASSWD + +#include "../nss/getXXbyYY.c" diff --git a/nss/getpwnam_r.c b/nss/getpwnam_r.c new file mode 100644 index 0000000..e910670 --- /dev/null +++ b/nss/getpwnam_r.c @@ -0,0 +1,28 @@ +/* Copyright (C) 1996-2023 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <pwd.h> + + +#define LOOKUP_TYPE struct passwd +#define FUNCTION_NAME getpwnam +#define DATABASE_NAME passwd +#define ADD_PARAMS const char *name +#define ADD_VARIABLES name +#define BUFLEN NSS_BUFLEN_PASSWD + +#include <nss/getXXbyYY_r.c> diff --git a/nss/getpwuid.c b/nss/getpwuid.c new file mode 100644 index 0000000..d92fb22 --- /dev/null +++ b/nss/getpwuid.c @@ -0,0 +1,28 @@ +/* Copyright (C) 1996-2023 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <pwd.h> + + +#define LOOKUP_TYPE struct passwd +#define FUNCTION_NAME getpwuid +#define DATABASE_NAME passwd +#define ADD_PARAMS uid_t uid +#define ADD_VARIABLES uid +#define BUFLEN NSS_BUFLEN_PASSWD + +#include "../nss/getXXbyYY.c" diff --git a/nss/getpwuid_r.c b/nss/getpwuid_r.c new file mode 100644 index 0000000..763fad5 --- /dev/null +++ b/nss/getpwuid_r.c @@ -0,0 +1,28 @@ +/* Copyright (C) 1996-2023 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <pwd.h> + + +#define LOOKUP_TYPE struct passwd +#define FUNCTION_NAME getpwuid +#define DATABASE_NAME passwd +#define ADD_PARAMS uid_t uid +#define ADD_VARIABLES uid +#define BUFLEN NSS_BUFLEN_PASSWD + +#include <nss/getXXbyYY_r.c> diff --git a/nss/putpwent.c b/nss/putpwent.c new file mode 100644 index 0000000..335e20a --- /dev/null +++ b/nss/putpwent.c @@ -0,0 +1,65 @@ +/* Copyright (C) 1991-2023 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stdio.h> +#include <pwd.h> +#include <stdlib.h> +#include <nss.h> + +#define _S(x) x ?: "" + +/* Write an entry to the given stream. This must know the format of + the password file. If the input contains invalid characters, + return EINVAL, or replace them with spaces (if they are contained + in the GECOS field). */ +int +putpwent (const struct passwd *p, FILE *stream) +{ + if (p == NULL || stream == NULL + || p->pw_name == NULL || !__nss_valid_field (p->pw_name) + || !__nss_valid_field (p->pw_passwd) + || !__nss_valid_field (p->pw_dir) + || !__nss_valid_field (p->pw_shell)) + { + __set_errno (EINVAL); + return -1; + } + + int ret; + char *gecos_alloc; + const char *gecos = __nss_rewrite_field (p->pw_gecos, &gecos_alloc); + + if (gecos == NULL) + return -1; + + if (p->pw_name[0] == '+' || p->pw_name[0] == '-') + ret = fprintf (stream, "%s:%s:::%s:%s:%s\n", + p->pw_name, _S (p->pw_passwd), + gecos, _S (p->pw_dir), _S (p->pw_shell)); + else + ret = fprintf (stream, "%s:%s:%lu:%lu:%s:%s:%s\n", + p->pw_name, _S (p->pw_passwd), + (unsigned long int) p->pw_uid, + (unsigned long int) p->pw_gid, + gecos, _S (p->pw_dir), _S (p->pw_shell)); + + free (gecos_alloc); + if (ret >= 0) + ret = 0; + return ret; +} diff --git a/nss/pwd.h b/nss/pwd.h new file mode 100644 index 0000000..d96f153 --- /dev/null +++ b/nss/pwd.h @@ -0,0 +1,193 @@ +/* Copyright (C) 1991-2023 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +/* + * POSIX Standard: 9.2.2 User Database Access <pwd.h> + */ + +#ifndef _PWD_H +#define _PWD_H 1 + +#include <features.h> + +__BEGIN_DECLS + +#include <bits/types.h> + +#define __need_size_t +#include <stddef.h> + +#if defined __USE_XOPEN || defined __USE_XOPEN2K +/* The Single Unix specification says that some more types are + available here. */ +# ifndef __gid_t_defined +typedef __gid_t gid_t; +# define __gid_t_defined +# endif + +# ifndef __uid_t_defined +typedef __uid_t uid_t; +# define __uid_t_defined +# endif +#endif + +/* A record in the user database. */ +struct passwd +{ + char *pw_name; /* Username. */ + char *pw_passwd; /* Hashed passphrase, if shadow database + not in use (see shadow.h). */ + __uid_t pw_uid; /* User ID. */ + __gid_t pw_gid; /* Group ID. */ + char *pw_gecos; /* Real name. */ + char *pw_dir; /* Home directory. */ + char *pw_shell; /* Shell program. */ +}; + + +#ifdef __USE_MISC +# include <bits/types/FILE.h> +#endif + + +#if defined __USE_MISC || defined __USE_XOPEN_EXTENDED +/* Rewind the user database stream. + + This function is a possible cancellation point and therefore not + marked with __THROW. */ +extern void setpwent (void); + +/* Close the user database stream. + + This function is a possible cancellation point and therefore not + marked with __THROW. */ +extern void endpwent (void); + +/* Read an entry from the user database stream, opening it if necessary. + + This function is a possible cancellation point and therefore not + marked with __THROW. */ +extern struct passwd *getpwent (void); +#endif + +#ifdef __USE_MISC +/* Read a user database entry from STREAM. + + This function is not part of POSIX and therefore no official + cancellation point. But due to similarity with an POSIX interface + or due to the implementation it is a cancellation point and + therefore not marked with __THROW. */ +extern struct passwd *fgetpwent (FILE *__stream) __nonnull ((1)); + +/* Write a given user database entry onto the given stream. + + This function is not part of POSIX and therefore no official + cancellation point. But due to similarity with an POSIX interface + or due to the implementation it is a cancellation point and + therefore not marked with __THROW. */ +extern int putpwent (const struct passwd *__restrict __p, + FILE *__restrict __f); +#endif + +/* Retrieve the user database entry for the given user ID. + + This function is a possible cancellation point and therefore not + marked with __THROW. */ +extern struct passwd *getpwuid (__uid_t __uid); + +/* Retrieve the user database entry for the given username. + + This function is a possible cancellation point and therefore not + marked with __THROW. */ +extern struct passwd *getpwnam (const char *__name) __nonnull ((1)); + +#ifdef __USE_POSIX + +# ifdef __USE_MISC +/* Reasonable value for the buffer sized used in the reentrant + functions below. But better use `sysconf'. */ +# define NSS_BUFLEN_PASSWD 1024 +# endif + +/* Reentrant versions of some of the functions above. + + PLEASE NOTE: the `getpwent_r' function is not (yet) standardized. + The interface may change in later versions of this library. But + the interface is designed following the principals used for the + other reentrant functions so the chances are good this is what the + POSIX people would choose. */ + +# ifdef __USE_MISC +/* This function is not part of POSIX and therefore no official + cancellation point. But due to similarity with an POSIX interface + or due to the implementation it is a cancellation point and + therefore not marked with __THROW. */ +extern int getpwent_r (struct passwd *__restrict __resultbuf, + char *__restrict __buffer, size_t __buflen, + struct passwd **__restrict __result) + __nonnull ((1, 2, 4)) + __attr_access ((__write_only__, 2, 3)); +# endif + +extern int getpwuid_r (__uid_t __uid, + struct passwd *__restrict __resultbuf, + char *__restrict __buffer, size_t __buflen, + struct passwd **__restrict __result) + __nonnull ((2, 3, 5)) + __attr_access ((__write_only__, 3, 4)); + +extern int getpwnam_r (const char *__restrict __name, + struct passwd *__restrict __resultbuf, + char *__restrict __buffer, size_t __buflen, + struct passwd **__restrict __result) + __nonnull ((1, 2, 3, 5)) + __attr_access ((__write_only__, 3, 4)); + + +# ifdef __USE_MISC +/* Read a user database entry from STREAM. This function is not + standardized and probably never will. + + This function is not part of POSIX and therefore no official + cancellation point. But due to similarity with an POSIX interface + or due to the implementation it is a cancellation point and + therefore not marked with __THROW. */ +extern int fgetpwent_r (FILE *__restrict __stream, + struct passwd *__restrict __resultbuf, + char *__restrict __buffer, size_t __buflen, + struct passwd **__restrict __result) + __nonnull ((1, 2, 3, 5)) + __attr_access ((__write_only__, 3, 4)); +# endif + +#endif /* POSIX or reentrant */ + +#ifdef __USE_GNU +/* Write a traditional /etc/passwd line, based on the user database + entry for the given UID, to BUFFER; space for BUFFER must be + allocated by the caller. + + This function is not part of POSIX and therefore no official + cancellation point. But due to similarity with an POSIX interface + or due to the implementation it is a cancellation point and + therefore not marked with __THROW. */ +extern int getpw (__uid_t __uid, char *__buffer); +#endif + +__END_DECLS + +#endif /* pwd.h */ diff --git a/nss/tst-getpw.c b/nss/tst-getpw.c new file mode 100644 index 0000000..30d4740 --- /dev/null +++ b/nss/tst-getpw.c @@ -0,0 +1,114 @@ +/* Copyright (C) 1999-2023 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <stdio.h> +#include <pwd.h> +#include <errno.h> +#include <stdbool.h> + +/* We want to test getpw by calling it with a uid that does + exist and one that doesn't exist. We track if we've met those + conditions and exit. We also track if we've failed due to lack + of memory. That constitutes all of the standard failure cases. */ +bool seen_hit; +bool seen_miss; +bool seen_oom; + +/* How many errors we've had while running the test. */ +int errors; + +static void +check (uid_t uid) +{ + int ret; + char buf[1024]; + + ret = getpw (uid, buf); + + /* Successfully read a password line. */ + if (ret == 0 && !seen_hit) + { + printf ("PASS: Read a password line given a uid.\n"); + seen_hit = true; + } + + /* Failed to read a password line. Why? */ + if (ret == -1) + { + /* No entry? Technically the errno could be any number + of values including ESRCH, EBADP or EPERM depending + on the quality of the nss module that implements the + underlying lookup. It should be 0 for getpw.*/ + if (errno == 0 && !seen_miss) + { + printf ("PASS: Found an invalid uid.\n"); + seen_miss = true; + return; + } + + /* Out of memory? */ + if (errno == ENOMEM && !seen_oom) + { + printf ("FAIL: Failed with ENOMEM.\n"); + seen_oom = true; + errors++; + } + + /* We don't expect any other values for errno. */ + if (errno != ENOMEM && errno != 0) + errors++; + } +} + +static int +do_test (void) +{ + int ret; + uid_t uid; + + /* Should return -1 and set errnot to EINVAL. */ + ret = getpw (0, NULL); + if (ret == -1 && errno == EINVAL) + { + printf ("PASS: NULL buffer returns -1 and sets errno to EINVAL.\n"); + } + else + { + printf ("FAIL: NULL buffer did not return -1 or set errno to EINVAL.\n"); + errors++; + } + + /* Look for one matching uid, one non-found uid and then stop. + Set an upper limit at the 16-bit UID mark; no need to go farther. */ + for (uid = 0; uid < ((uid_t) 65535); ++uid) + { + check (uid); + if (seen_miss && seen_hit) + break; + } + + if (!seen_hit) + printf ("FAIL: Did not read even one password line given a uid.\n"); + + if (!seen_miss) + printf ("FAIL: Did not find even one invalid uid.\n"); + + return errors; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/nss/tst-putpwent.c b/nss/tst-putpwent.c new file mode 100644 index 0000000..3014e0a --- /dev/null +++ b/nss/tst-putpwent.c @@ -0,0 +1,168 @@ +/* Test for processing of invalid passwd entries. [BZ #18724] + Copyright (C) 2015-2023 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <pwd.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +static bool errors; + +static void +check (struct passwd p, const char *expected) +{ + char *buf; + size_t buf_size; + FILE *f = open_memstream (&buf, &buf_size); + + if (f == NULL) + { + printf ("open_memstream: %m\n"); + errors = true; + return; + } + + int ret = putpwent (&p, f); + + if (expected == NULL) + { + if (ret == -1) + { + if (errno != EINVAL) + { + printf ("putpwent: unexpected error code: %m\n"); + errors = true; + } + } + else + { + printf ("putpwent: unexpected success (\"%s\")\n", p.pw_name); + errors = true; + } + } + else + { + /* Expect success. */ + size_t expected_length = strlen (expected); + if (ret == 0) + { + long written = ftell (f); + + if (written <= 0 || fflush (f) < 0) + { + printf ("stream error: %m\n"); + errors = true; + } + else if (buf[written - 1] != '\n') + { + printf ("FAILED: \"%s\" without newline\n", expected); + errors = true; + } + else if (strncmp (buf, expected, written - 1) != 0 + || written - 1 != expected_length) + { + printf ("FAILED: \"%s\" (%ld), expected \"%s\" (%zu)\n", + buf, written - 1, expected, expected_length); + errors = true; + } + } + else + { + printf ("FAILED: putpwent (expected \"%s\"): %m\n", expected); + errors = true; + } + } + + fclose (f); + free (buf); +} + +static int +do_test (void) +{ + check ((struct passwd) { + .pw_name = (char *) "root", + }, + "root::0:0:::"); + check ((struct passwd) { + .pw_name = (char *) "root", + .pw_passwd = (char *) "password", + }, + "root:password:0:0:::"); + check ((struct passwd) { + .pw_name = (char *) "root", + .pw_passwd = (char *) "password", + .pw_uid = 12, + .pw_gid = 34, + .pw_gecos = (char *) "gecos", + .pw_dir = (char *) "home", + .pw_shell = (char *) "shell", + }, + "root:password:12:34:gecos:home:shell"); + check ((struct passwd) { + .pw_name = (char *) "root", + .pw_passwd = (char *) "password", + .pw_uid = 12, + .pw_gid = 34, + .pw_gecos = (char *) ":ge\n:cos\n", + .pw_dir = (char *) "home", + .pw_shell = (char *) "shell", + }, + "root:password:12:34: ge cos :home:shell"); + + /* Bad values. */ + { + static const char *const bad_strings[] = { + ":", + "\n", + ":bad", + "\nbad", + "b:ad", + "b\nad", + "bad:", + "bad\n", + "b:a\nd", + NULL + }; + for (const char *const *bad = bad_strings; *bad != NULL; ++bad) + { + check ((struct passwd) { + .pw_name = (char *) *bad, + }, NULL); + check ((struct passwd) { + .pw_name = (char *) "root", + .pw_passwd = (char *) *bad, + }, NULL); + check ((struct passwd) { + .pw_name = (char *) "root", + .pw_dir = (char *) *bad, + }, NULL); + check ((struct passwd) { + .pw_name = (char *) "root", + .pw_shell = (char *) *bad, + }, NULL); + } + } + + return errors > 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" |