mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-03-08 20:58:20 +03:00
Merge pull request #18982 from keszybz/test-nss-users
Add a new test for user/group resolution in nss modules
This commit is contained in:
commit
4c31bfdf55
@ -198,11 +198,6 @@ All tools:
|
|||||||
prefixed with `:` in which case the kernel command line option takes
|
prefixed with `:` in which case the kernel command line option takes
|
||||||
precedence, if it is specified as well.
|
precedence, if it is specified as well.
|
||||||
|
|
||||||
installed systemd tests:
|
|
||||||
|
|
||||||
* `$SYSTEMD_TEST_DATA` — override the location of test data. This is useful if
|
|
||||||
a test executable is moved to an arbitrary location.
|
|
||||||
|
|
||||||
`nss-systemd`:
|
`nss-systemd`:
|
||||||
|
|
||||||
* `$SYSTEMD_NSS_BYPASS_SYNTHETIC=1` — if set, `nss-systemd` won't synthesize
|
* `$SYSTEMD_NSS_BYPASS_SYNTHETIC=1` — if set, `nss-systemd` won't synthesize
|
||||||
@ -302,6 +297,14 @@ installed systemd tests:
|
|||||||
* `$SYSTEMD_SYSVRCND_PATH` — Controls where `systemd-sysv-generator` looks for
|
* `$SYSTEMD_SYSVRCND_PATH` — Controls where `systemd-sysv-generator` looks for
|
||||||
SysV init script runlevel link farms.
|
SysV init script runlevel link farms.
|
||||||
|
|
||||||
|
systemd tests:
|
||||||
|
|
||||||
|
* `$SYSTEMD_TEST_DATA` — override the location of test data. This is useful if
|
||||||
|
a test executable is moved to an arbitrary location.
|
||||||
|
|
||||||
|
* `$SYSTEMD_TEST_NSS_BUFSIZE` — size of scratch buffers for "reentrant"
|
||||||
|
functions exported by the nss modules.
|
||||||
|
|
||||||
fuzzers:
|
fuzzers:
|
||||||
|
|
||||||
* `$SYSTEMD_FUZZ_OUTPUT` — A boolean that specifies whether to write output to
|
* `$SYSTEMD_FUZZ_OUTPUT` — A boolean that specifies whether to write output to
|
||||||
|
@ -213,3 +213,25 @@ typedef enum nss_status (*_nss_gethostbyaddr_r_t)(
|
|||||||
struct hostent *host,
|
struct hostent *host,
|
||||||
char *buffer, size_t buflen,
|
char *buffer, size_t buflen,
|
||||||
int *errnop, int *h_errnop);
|
int *errnop, int *h_errnop);
|
||||||
|
|
||||||
|
typedef enum nss_status (*_nss_getpwnam_r_t)(
|
||||||
|
const char *name,
|
||||||
|
struct passwd *pwd,
|
||||||
|
char *buffer, size_t buflen,
|
||||||
|
int *errnop);
|
||||||
|
typedef enum nss_status (*_nss_getpwuid_r_t)(
|
||||||
|
uid_t uid,
|
||||||
|
struct passwd *pwd,
|
||||||
|
char *buffer, size_t buflen,
|
||||||
|
int *errnop);
|
||||||
|
|
||||||
|
typedef enum nss_status (*_nss_getgrnam_r_t)(
|
||||||
|
const char *name,
|
||||||
|
struct group *gr,
|
||||||
|
char *buffer, size_t buflen,
|
||||||
|
int *errnop);
|
||||||
|
typedef enum nss_status (*_nss_getgrgid_r_t)(
|
||||||
|
gid_t gid,
|
||||||
|
struct group *gr,
|
||||||
|
char *buffer, size_t buflen,
|
||||||
|
int *errnop);
|
||||||
|
@ -540,7 +540,16 @@ tests += [
|
|||||||
[['src/test/test-gcrypt-util.c'],
|
[['src/test/test-gcrypt-util.c'],
|
||||||
[], [], [], 'HAVE_GCRYPT'],
|
[], [], [], 'HAVE_GCRYPT'],
|
||||||
|
|
||||||
[['src/test/test-nss.c'],
|
[['src/test/test-nss-hosts.c',
|
||||||
|
'src/test/nss-test-util.c',
|
||||||
|
'src/test/nss-test-util.h'],
|
||||||
|
[],
|
||||||
|
[libdl],
|
||||||
|
[], 'ENABLE_NSS', 'manual'],
|
||||||
|
|
||||||
|
[['src/test/test-nss-users.c',
|
||||||
|
'src/test/nss-test-util.c',
|
||||||
|
'src/test/nss-test-util.h'],
|
||||||
[],
|
[],
|
||||||
[libdl],
|
[libdl],
|
||||||
[], 'ENABLE_NSS', 'manual'],
|
[], 'ENABLE_NSS', 'manual'],
|
||||||
|
42
src/test/nss-test-util.c
Normal file
42
src/test/nss-test-util.c
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "nss-test-util.h"
|
||||||
|
#include "string-util.h"
|
||||||
|
|
||||||
|
const char* nss_status_to_string(enum nss_status status, char *buf, size_t buf_len) {
|
||||||
|
switch (status) {
|
||||||
|
case NSS_STATUS_TRYAGAIN:
|
||||||
|
return "NSS_STATUS_TRYAGAIN";
|
||||||
|
case NSS_STATUS_UNAVAIL:
|
||||||
|
return "NSS_STATUS_UNAVAIL";
|
||||||
|
case NSS_STATUS_NOTFOUND:
|
||||||
|
return "NSS_STATUS_NOTFOUND";
|
||||||
|
case NSS_STATUS_SUCCESS:
|
||||||
|
return "NSS_STATUS_SUCCESS";
|
||||||
|
case NSS_STATUS_RETURN:
|
||||||
|
return "NSS_STATUS_RETURN";
|
||||||
|
default:
|
||||||
|
snprintf(buf, buf_len, "%i", status);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void* nss_open_handle(const char *dir, const char *module, int flags) {
|
||||||
|
const char *path = NULL;
|
||||||
|
void *handle;
|
||||||
|
|
||||||
|
if (dir)
|
||||||
|
path = strjoina(dir, "/libnss_", module, ".so.2");
|
||||||
|
if (!path || access(path, F_OK) < 0)
|
||||||
|
path = strjoina("libnss_", module, ".so.2");
|
||||||
|
|
||||||
|
log_debug("Using %s", path);
|
||||||
|
handle = dlopen(path, flags);
|
||||||
|
if (!handle)
|
||||||
|
log_error("Failed to load module %s: %s", module, dlerror());
|
||||||
|
return handle;
|
||||||
|
}
|
8
src/test/nss-test-util.h
Normal file
8
src/test/nss-test-util.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <nss.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
const char* nss_status_to_string(enum nss_status status, char *buf, size_t buf_len);
|
||||||
|
void* nss_open_handle(const char *dir, const char *module, int flags);
|
@ -1,12 +1,12 @@
|
|||||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "af-list.h"
|
#include "af-list.h"
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
|
#include "dlfcn-util.h"
|
||||||
#include "errno-list.h"
|
#include "errno-list.h"
|
||||||
#include "format-util.h"
|
#include "format-util.h"
|
||||||
#include "hexdecoct.h"
|
#include "hexdecoct.h"
|
||||||
@ -15,30 +15,16 @@
|
|||||||
#include "local-addresses.h"
|
#include "local-addresses.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "main-func.h"
|
#include "main-func.h"
|
||||||
|
#include "nss-test-util.h"
|
||||||
#include "nss-util.h"
|
#include "nss-util.h"
|
||||||
|
#include "parse-util.h"
|
||||||
#include "path-util.h"
|
#include "path-util.h"
|
||||||
#include "stdio-util.h"
|
#include "stdio-util.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
|
|
||||||
static const char* nss_status_to_string(enum nss_status status, char *buf, size_t buf_len) {
|
static size_t arg_bufsize = 1024;
|
||||||
switch (status) {
|
|
||||||
case NSS_STATUS_TRYAGAIN:
|
|
||||||
return "NSS_STATUS_TRYAGAIN";
|
|
||||||
case NSS_STATUS_UNAVAIL:
|
|
||||||
return "NSS_STATUS_UNAVAIL";
|
|
||||||
case NSS_STATUS_NOTFOUND:
|
|
||||||
return "NSS_STATUS_NOTFOUND";
|
|
||||||
case NSS_STATUS_SUCCESS:
|
|
||||||
return "NSS_STATUS_SUCCESS";
|
|
||||||
case NSS_STATUS_RETURN:
|
|
||||||
return "NSS_STATUS_RETURN";
|
|
||||||
default:
|
|
||||||
snprintf(buf, buf_len, "%i", status);
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char* af_to_string(int family, char *buf, size_t buf_len) {
|
static const char* af_to_string(int family, char *buf, size_t buf_len) {
|
||||||
const char *name;
|
const char *name;
|
||||||
@ -54,22 +40,6 @@ static const char* af_to_string(int family, char *buf, size_t buf_len) {
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void* open_handle(const char *dir, const char *module, int flags) {
|
|
||||||
const char *path = NULL;
|
|
||||||
void *handle;
|
|
||||||
|
|
||||||
if (dir)
|
|
||||||
path = strjoina(dir, "/libnss_", module, ".so.2");
|
|
||||||
if (!path || access(path, F_OK) < 0)
|
|
||||||
path = strjoina("libnss_", module, ".so.2");
|
|
||||||
|
|
||||||
log_debug("Using %s", path);
|
|
||||||
handle = dlopen(path, flags);
|
|
||||||
if (!handle)
|
|
||||||
log_error("Failed to load module %s: %s", module, dlerror());
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int print_gaih_addrtuples(const struct gaih_addrtuple *tuples) {
|
static int print_gaih_addrtuples(const struct gaih_addrtuple *tuples) {
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
|
||||||
@ -132,7 +102,7 @@ static void print_struct_hostent(struct hostent *host, const char *canon) {
|
|||||||
static void test_gethostbyname4_r(void *handle, const char *module, const char *name) {
|
static void test_gethostbyname4_r(void *handle, const char *module, const char *name) {
|
||||||
const char *fname;
|
const char *fname;
|
||||||
_nss_gethostbyname4_r_t f;
|
_nss_gethostbyname4_r_t f;
|
||||||
char buffer[2000];
|
char buffer[arg_bufsize];
|
||||||
struct gaih_addrtuple *pat = NULL;
|
struct gaih_addrtuple *pat = NULL;
|
||||||
int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
|
int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
|
||||||
int32_t ttl = INT32_MAX; /* nss-dns wants to return the lowest ttl,
|
int32_t ttl = INT32_MAX; /* nss-dns wants to return the lowest ttl,
|
||||||
@ -184,7 +154,7 @@ static void test_gethostbyname4_r(void *handle, const char *module, const char *
|
|||||||
static void test_gethostbyname3_r(void *handle, const char *module, const char *name, int af) {
|
static void test_gethostbyname3_r(void *handle, const char *module, const char *name, int af) {
|
||||||
const char *fname;
|
const char *fname;
|
||||||
_nss_gethostbyname3_r_t f;
|
_nss_gethostbyname3_r_t f;
|
||||||
char buffer[2000];
|
char buffer[arg_bufsize];
|
||||||
int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
|
int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
|
||||||
int32_t ttl = INT32_MAX; /* nss-dns wants to return the lowest ttl,
|
int32_t ttl = INT32_MAX; /* nss-dns wants to return the lowest ttl,
|
||||||
and will access this variable through *ttlp,
|
and will access this variable through *ttlp,
|
||||||
@ -219,7 +189,7 @@ static void test_gethostbyname3_r(void *handle, const char *module, const char *
|
|||||||
static void test_gethostbyname2_r(void *handle, const char *module, const char *name, int af) {
|
static void test_gethostbyname2_r(void *handle, const char *module, const char *name, int af) {
|
||||||
const char *fname;
|
const char *fname;
|
||||||
_nss_gethostbyname2_r_t f;
|
_nss_gethostbyname2_r_t f;
|
||||||
char buffer[2000];
|
char buffer[arg_bufsize];
|
||||||
int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
|
int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
|
||||||
enum nss_status status;
|
enum nss_status status;
|
||||||
char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
|
char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
|
||||||
@ -247,7 +217,7 @@ static void test_gethostbyname2_r(void *handle, const char *module, const char *
|
|||||||
static void test_gethostbyname_r(void *handle, const char *module, const char *name) {
|
static void test_gethostbyname_r(void *handle, const char *module, const char *name) {
|
||||||
const char *fname;
|
const char *fname;
|
||||||
_nss_gethostbyname_r_t f;
|
_nss_gethostbyname_r_t f;
|
||||||
char buffer[2000];
|
char buffer[arg_bufsize];
|
||||||
int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
|
int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
|
||||||
enum nss_status status;
|
enum nss_status status;
|
||||||
char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
|
char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
|
||||||
@ -278,7 +248,7 @@ static void test_gethostbyaddr2_r(void *handle,
|
|||||||
|
|
||||||
const char *fname;
|
const char *fname;
|
||||||
_nss_gethostbyaddr2_r_t f;
|
_nss_gethostbyaddr2_r_t f;
|
||||||
char buffer[2000];
|
char buffer[arg_bufsize];
|
||||||
int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
|
int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
|
||||||
enum nss_status status;
|
enum nss_status status;
|
||||||
char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
|
char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
|
||||||
@ -316,7 +286,7 @@ static void test_gethostbyaddr_r(void *handle,
|
|||||||
|
|
||||||
const char *fname;
|
const char *fname;
|
||||||
_nss_gethostbyaddr_r_t f;
|
_nss_gethostbyaddr_r_t f;
|
||||||
char buffer[2000];
|
char buffer[arg_bufsize];
|
||||||
int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
|
int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
|
||||||
enum nss_status status;
|
enum nss_status status;
|
||||||
char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
|
char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
|
||||||
@ -392,8 +362,7 @@ static int make_addresses(struct local_address **addresses) {
|
|||||||
log_info_errno(n, "Failed to query local addresses: %m");
|
log_info_errno(n, "Failed to query local addresses: %m");
|
||||||
|
|
||||||
n_alloc = n; /* we _can_ do that */
|
n_alloc = n; /* we _can_ do that */
|
||||||
if (!GREEDY_REALLOC(addrs, n_alloc, n + 3))
|
assert_se(GREEDY_REALLOC(addrs, n_alloc, n + 3));
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
addrs[n++] = (struct local_address) { .family = AF_INET,
|
addrs[n++] = (struct local_address) { .family = AF_INET,
|
||||||
.address.in = { htobe32(0x7F000001) } };
|
.address.in = { htobe32(0x7F000001) } };
|
||||||
@ -409,15 +378,14 @@ static int test_one_module(const char *dir,
|
|||||||
char **names,
|
char **names,
|
||||||
struct local_address *addresses,
|
struct local_address *addresses,
|
||||||
int n_addresses) {
|
int n_addresses) {
|
||||||
void *handle;
|
|
||||||
char **name;
|
|
||||||
|
|
||||||
log_info("======== %s ========", module);
|
log_info("======== %s ========", module);
|
||||||
|
|
||||||
handle = open_handle(dir, module, RTLD_LAZY|RTLD_NODELETE);
|
_cleanup_(dlclosep) void *handle = nss_open_handle(dir, module, RTLD_LAZY|RTLD_NODELETE);
|
||||||
if (!handle)
|
if (!handle)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
char **name;
|
||||||
STRV_FOREACH(name, names)
|
STRV_FOREACH(name, names)
|
||||||
test_byname(handle, module, *name);
|
test_byname(handle, module, *name);
|
||||||
|
|
||||||
@ -428,7 +396,6 @@ static int test_one_module(const char *dir,
|
|||||||
addresses[i].family);
|
addresses[i].family);
|
||||||
|
|
||||||
log_info(" ");
|
log_info(" ");
|
||||||
dlclose(handle);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -437,10 +404,18 @@ static int parse_argv(int argc, char **argv,
|
|||||||
char ***the_names,
|
char ***the_names,
|
||||||
struct local_address **the_addresses, int *n_addresses) {
|
struct local_address **the_addresses, int *n_addresses) {
|
||||||
|
|
||||||
int r, n = 0;
|
|
||||||
_cleanup_strv_free_ char **modules = NULL, **names = NULL;
|
_cleanup_strv_free_ char **modules = NULL, **names = NULL;
|
||||||
_cleanup_free_ struct local_address *addrs = NULL;
|
_cleanup_free_ struct local_address *addrs = NULL;
|
||||||
size_t n_allocated = 0;
|
size_t n_allocated = 0;
|
||||||
|
const char *p;
|
||||||
|
int r, n = 0;
|
||||||
|
|
||||||
|
p = getenv("SYSTEMD_TEST_NSS_BUFSIZE");
|
||||||
|
if (p) {
|
||||||
|
r = safe_atozu(p, &arg_bufsize);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to parse $SYSTEMD_TEST_NSS_BUFSIZE");
|
||||||
|
}
|
||||||
|
|
||||||
if (argc > 1)
|
if (argc > 1)
|
||||||
modules = strv_new(argv[1]);
|
modules = strv_new(argv[1]);
|
||||||
@ -456,8 +431,7 @@ static int parse_argv(int argc, char **argv,
|
|||||||
"mymachines",
|
"mymachines",
|
||||||
#endif
|
#endif
|
||||||
"dns");
|
"dns");
|
||||||
if (!modules)
|
assert_se(modules);
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
if (argc > 2) {
|
if (argc > 2) {
|
||||||
char **name;
|
char **name;
|
||||||
@ -472,8 +446,7 @@ static int parse_argv(int argc, char **argv,
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
} else {
|
} else {
|
||||||
if (!GREEDY_REALLOC0(addrs, n_allocated, n + 1))
|
assert_se(GREEDY_REALLOC0(addrs, n_allocated, n + 1));
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
addrs[n++] = (struct local_address) { .family = family,
|
addrs[n++] = (struct local_address) { .family = family,
|
||||||
.address = address };
|
.address = address };
|
||||||
@ -481,26 +454,18 @@ static int parse_argv(int argc, char **argv,
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_cleanup_free_ char *hostname;
|
_cleanup_free_ char *hostname;
|
||||||
|
assert_se(hostname = gethostname_malloc());
|
||||||
|
|
||||||
hostname = gethostname_malloc();
|
assert_se(names = strv_new("localhost", "_gateway", "foo_no_such_host", hostname));
|
||||||
if (!hostname)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
names = strv_new("localhost", "_gateway", "foo_no_such_host", hostname);
|
|
||||||
if (!names)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
n = make_addresses(&addrs);
|
n = make_addresses(&addrs);
|
||||||
if (n < 0)
|
assert_se(n >= 0);
|
||||||
return n;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*the_modules = modules;
|
*the_modules = TAKE_PTR(modules);
|
||||||
*the_names = names;
|
*the_names = TAKE_PTR(names);
|
||||||
modules = names = NULL;
|
*the_addresses = TAKE_PTR(addrs);
|
||||||
*the_addresses = addrs;
|
|
||||||
*n_addresses = n;
|
*n_addresses = n;
|
||||||
addrs = NULL;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -515,14 +480,10 @@ static int run(int argc, char **argv) {
|
|||||||
test_setup_logging(LOG_INFO);
|
test_setup_logging(LOG_INFO);
|
||||||
|
|
||||||
r = parse_argv(argc, argv, &modules, &names, &addresses, &n_addresses);
|
r = parse_argv(argc, argv, &modules, &names, &addresses, &n_addresses);
|
||||||
if (r < 0) {
|
if (r < 0)
|
||||||
log_error_errno(r, "Failed to parse arguments: %m");
|
return log_error_errno(r, "Failed to parse arguments: %m");
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
dir = dirname_malloc(argv[0]);
|
assert_se(path_extract_directory(argv[0], &dir) >= 0);
|
||||||
if (!dir)
|
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
STRV_FOREACH(module, modules) {
|
STRV_FOREACH(module, modules) {
|
||||||
r = test_one_module(dir, *module, names, addresses, n_addresses);
|
r = test_one_module(dir, *module, names, addresses, n_addresses);
|
258
src/test/test-nss-users.c
Normal file
258
src/test/test-nss-users.c
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "alloc-util.h"
|
||||||
|
#include "dlfcn-util.h"
|
||||||
|
#include "errno-list.h"
|
||||||
|
#include "format-util.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "main-func.h"
|
||||||
|
#include "nss-test-util.h"
|
||||||
|
#include "nss-util.h"
|
||||||
|
#include "path-util.h"
|
||||||
|
#include "parse-util.h"
|
||||||
|
#include "stdio-util.h"
|
||||||
|
#include "string-util.h"
|
||||||
|
#include "strv.h"
|
||||||
|
#include "tests.h"
|
||||||
|
#include "user-util.h"
|
||||||
|
|
||||||
|
static size_t arg_bufsize = 1024;
|
||||||
|
|
||||||
|
static void print_struct_passwd(const struct passwd *pwd) {
|
||||||
|
log_info(" \"%s\" / "UID_FMT":"GID_FMT,
|
||||||
|
pwd->pw_name, pwd->pw_uid, pwd->pw_gid);
|
||||||
|
log_info(" passwd=\"%s\"", pwd->pw_passwd);
|
||||||
|
log_info(" gecos=\"%s\"", pwd->pw_gecos);
|
||||||
|
log_info(" dir=\"%s\"", pwd->pw_dir);
|
||||||
|
log_info(" shell=\"%s\"", pwd->pw_shell);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_struct_group(const struct group *gr) {
|
||||||
|
_cleanup_free_ char *members = NULL;
|
||||||
|
|
||||||
|
log_info(" \"%s\" / "GID_FMT,
|
||||||
|
gr->gr_name, gr->gr_gid);
|
||||||
|
log_info(" passwd=\"%s\"", gr->gr_passwd);
|
||||||
|
|
||||||
|
assert_se(members = strv_join(gr->gr_mem, ", "));
|
||||||
|
// FIXME: use shell_maybe_quote(SHELL_ESCAPE_EMPTY) when it becomes available
|
||||||
|
log_info(" members=%s", members);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_getpwnam_r(void *handle, const char *module, const char *name) {
|
||||||
|
const char *fname;
|
||||||
|
_nss_getpwnam_r_t f;
|
||||||
|
char buffer[arg_bufsize];
|
||||||
|
int errno1 = 999; /* nss-dns doesn't set those */
|
||||||
|
enum nss_status status;
|
||||||
|
char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
|
||||||
|
struct passwd pwd;
|
||||||
|
|
||||||
|
fname = strjoina("_nss_", module, "_getpwnam_r");
|
||||||
|
f = dlsym(handle, fname);
|
||||||
|
log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f);
|
||||||
|
if (!f) {
|
||||||
|
log_info("%s not defined", fname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = f(name, &pwd, buffer, sizeof buffer, &errno1);
|
||||||
|
log_info("%s(\"%s\") → status=%s%-20serrno=%d/%s",
|
||||||
|
fname, name,
|
||||||
|
nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
|
||||||
|
errno1, errno_to_name(errno1) ?: "---");
|
||||||
|
if (status == NSS_STATUS_SUCCESS)
|
||||||
|
print_struct_passwd(&pwd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_getgrnam_r(void *handle, const char *module, const char *name) {
|
||||||
|
const char *fname;
|
||||||
|
_nss_getgrnam_r_t f;
|
||||||
|
char buffer[arg_bufsize];
|
||||||
|
int errno1 = 999; /* nss-dns doesn't set those */
|
||||||
|
enum nss_status status;
|
||||||
|
char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
|
||||||
|
struct group gr;
|
||||||
|
|
||||||
|
fname = strjoina("_nss_", module, "_getgrnam_r");
|
||||||
|
f = dlsym(handle, fname);
|
||||||
|
log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f);
|
||||||
|
if (!f) {
|
||||||
|
log_info("%s not defined", fname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = f(name, &gr, buffer, sizeof buffer, &errno1);
|
||||||
|
log_info("%s(\"%s\") → status=%s%-20serrno=%d/%s",
|
||||||
|
fname, name,
|
||||||
|
nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
|
||||||
|
errno1, errno_to_name(errno1) ?: "---");
|
||||||
|
if (status == NSS_STATUS_SUCCESS)
|
||||||
|
print_struct_group(&gr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_getpwuid_r(void *handle, const char *module, uid_t uid) {
|
||||||
|
const char *fname;
|
||||||
|
_nss_getpwuid_r_t f;
|
||||||
|
char buffer[arg_bufsize];
|
||||||
|
int errno1 = 999; /* nss-dns doesn't set those */
|
||||||
|
enum nss_status status;
|
||||||
|
char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
|
||||||
|
struct passwd pwd;
|
||||||
|
|
||||||
|
fname = strjoina("_nss_", module, "_getpwuid_r");
|
||||||
|
f = dlsym(handle, fname);
|
||||||
|
log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f);
|
||||||
|
if (!f) {
|
||||||
|
log_info("%s not defined", fname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = f(uid, &pwd, buffer, sizeof buffer, &errno1);
|
||||||
|
log_info("%s("UID_FMT") → status=%s%-20serrno=%d/%s",
|
||||||
|
fname, uid,
|
||||||
|
nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
|
||||||
|
errno1, errno_to_name(errno1) ?: "---");
|
||||||
|
if (status == NSS_STATUS_SUCCESS)
|
||||||
|
print_struct_passwd(&pwd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_getgrgid_r(void *handle, const char *module, gid_t gid) {
|
||||||
|
const char *fname;
|
||||||
|
_nss_getgrgid_r_t f;
|
||||||
|
char buffer[arg_bufsize];
|
||||||
|
int errno1 = 999; /* nss-dns doesn't set those */
|
||||||
|
enum nss_status status;
|
||||||
|
char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
|
||||||
|
struct group gr;
|
||||||
|
|
||||||
|
fname = strjoina("_nss_", module, "_getgrgid_r");
|
||||||
|
f = dlsym(handle, fname);
|
||||||
|
log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f);
|
||||||
|
if (!f) {
|
||||||
|
log_info("%s not defined", fname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = f(gid, &gr, buffer, sizeof buffer, &errno1);
|
||||||
|
log_info("%s("GID_FMT") → status=%s%-20serrno=%d/%s",
|
||||||
|
fname, gid,
|
||||||
|
nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
|
||||||
|
errno1, errno_to_name(errno1) ?: "---");
|
||||||
|
if (status == NSS_STATUS_SUCCESS)
|
||||||
|
print_struct_group(&gr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_byname(void *handle, const char *module, const char *name) {
|
||||||
|
test_getpwnam_r(handle, module, name);
|
||||||
|
test_getgrnam_r(handle, module, name);
|
||||||
|
puts("");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_byuid(void *handle, const char *module, uid_t uid) {
|
||||||
|
test_getpwuid_r(handle, module, uid);
|
||||||
|
test_getgrgid_r(handle, module, uid);
|
||||||
|
puts("");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int test_one_module(const char *dir,
|
||||||
|
const char *module,
|
||||||
|
char **names) {
|
||||||
|
|
||||||
|
log_info("======== %s ========", module);
|
||||||
|
|
||||||
|
_cleanup_(dlclosep) void *handle = nss_open_handle(dir, module, RTLD_LAZY|RTLD_NODELETE);
|
||||||
|
if (!handle)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
char **name;
|
||||||
|
STRV_FOREACH(name, names)
|
||||||
|
test_byname(handle, module, *name);
|
||||||
|
|
||||||
|
STRV_FOREACH(name, names) {
|
||||||
|
uid_t uid;
|
||||||
|
|
||||||
|
assert_cc(sizeof(uid_t) == sizeof(uint32_t));
|
||||||
|
/* We use safe_atou32 because we don't want to refuse invalid uids. */
|
||||||
|
if (safe_atou32(*name, &uid) < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
test_byuid(handle, module, uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info(" ");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_argv(int argc, char **argv,
|
||||||
|
char ***the_modules,
|
||||||
|
char ***the_names) {
|
||||||
|
|
||||||
|
_cleanup_strv_free_ char **modules = NULL, **names = NULL;
|
||||||
|
const char *p;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
p = getenv("SYSTEMD_TEST_NSS_BUFSIZE");
|
||||||
|
if (p) {
|
||||||
|
r = safe_atozu(p, &arg_bufsize);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to parse $SYSTEMD_TEST_NSS_BUFSIZE");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc > 1)
|
||||||
|
modules = strv_new(argv[1]);
|
||||||
|
else
|
||||||
|
modules = strv_new(
|
||||||
|
#if ENABLE_NSS_SYSTEMD
|
||||||
|
"systemd",
|
||||||
|
#endif
|
||||||
|
#if ENABLE_NSS_MYMACHINES
|
||||||
|
"mymachines",
|
||||||
|
#endif
|
||||||
|
"files");
|
||||||
|
assert_se(modules);
|
||||||
|
|
||||||
|
if (argc > 2)
|
||||||
|
names = strv_copy(strv_skip(argv, 2));
|
||||||
|
else
|
||||||
|
names = strv_new("root",
|
||||||
|
NOBODY_USER_NAME,
|
||||||
|
"foo_no_such_user",
|
||||||
|
"0",
|
||||||
|
"65534");
|
||||||
|
assert_se(names);
|
||||||
|
|
||||||
|
*the_modules = TAKE_PTR(modules);
|
||||||
|
*the_names = TAKE_PTR(names);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int run(int argc, char **argv) {
|
||||||
|
_cleanup_free_ char *dir = NULL;
|
||||||
|
_cleanup_strv_free_ char **modules = NULL, **names = NULL;
|
||||||
|
char **module;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
test_setup_logging(LOG_INFO);
|
||||||
|
|
||||||
|
r = parse_argv(argc, argv, &modules, &names);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to parse arguments: %m");
|
||||||
|
|
||||||
|
assert_se(path_extract_directory(argv[0], &dir) >= 0);
|
||||||
|
|
||||||
|
STRV_FOREACH(module, modules) {
|
||||||
|
r = test_one_module(dir, *module, names);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_MAIN_FUNCTION(run);
|
Loading…
x
Reference in New Issue
Block a user