1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
/*
* testpam_preload.c
*
* Fake test environment to run PAM tests unprivileged.
*/
#include "config.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <dlfcn.h>
#include <pwd.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#ifdef __APPLE__
# define _PATH_LIBC "libc.dylib"
#elif defined(__linux__)
# define _PATH_LIBC "libc.so.6"
#else
# define _PATH_LIBC "libc.so"
#endif
static void _preload_init(void) __attribute((constructor));
int (*_sys_open)(const char *pathname, int flags, ...);
int (*_sys_open64)(const char *pathname, int flags, ...);
FILE *(*_sys_fopen)(const char *filename, const char *mode);
FILE *(*_sys_fopen64)(const char *filename, const char *mode);
char *(*_sys_inet_ntoa)(struct in_addr in);
void modify_gecos(const char *username, struct passwd *pass);
static void
_fatal(const char *msg)
{
perror(msg);
exit(1);
}
static void
_preload_init(void)
{
void *libc;
#ifndef DL_LAZY
# define DL_LAZY RTLD_LAZY
#endif
if (!(libc = dlopen(_PATH_LIBC, DL_LAZY))) {
_fatal("couldn't dlopen " _PATH_LIBC);
} else if (!(_sys_open = dlsym(libc, "open"))) {
_fatal("couldn't dlsym 'open'");
#ifdef HAVE_OPEN64
} else if (!(_sys_open = dlsym(libc, "open64"))) {
_fatal("couldn't dlsym 'open64'");
#endif
} else if (!(_sys_fopen = dlsym(libc, "fopen"))) {
_fatal("couldn't dlsym 'fopen'");
#ifdef HAVE_FOPEN64
} else if (!(_sys_fopen64 = dlsym(libc, "fopen64"))) {
_fatal("couldn't dlsym 'fopen64'");
#endif
}
}
const char *
_replace(const char *filename)
{
if (strcmp(filename, "/etc/pam.d/testpam") == 0 ||
strcmp(filename, "/etc/pam.conf") == 0) {
return (getenv("PAM_CONF"));
}
return (filename);
}
int
_isfallback(void)
{
char *t = getenv("FALLBACK");
return (t ? atoi(t) : 0);
}
int
open(const char *filename, int flags, ...)
{
return ((*_sys_open)(_replace(filename), flags));
}
int
open64(const char *filename, int flags, ...)
{
return ((*_sys_open64)(_replace(filename), flags));
}
FILE *
fopen(const char *filename, const char *mode)
{
return ((*_sys_fopen)(_replace(filename), mode));
}
FILE *
fopen64(const char *filename, const char *mode)
{
return ((*_sys_fopen64)(_replace(filename), mode));
}
char *
inet_ntoa(struct in_addr in)
{
if (_isfallback()) {
return "1.2.3.4";
}
else {
_sys_inet_ntoa = dlsym(RTLD_NEXT, "inet_ntoa");
return (*_sys_inet_ntoa)(in);
}
}
void
modify_gecos(const char *username, struct passwd *pass)
{
if (strcmp(username, "gecos/6") == 0) {
pass->pw_gecos = strdup("1/2/3/4/5/gecos_user_gecos_field6");
} else if (strcmp(username, "gecos/3") == 0) {
pass->pw_gecos = strdup("1/2/gecos_user_gecos_field3/4/5/6");
} else if (strcmp(username, "gecos,6") == 0) {
pass->pw_gecos = strdup("1,2,3,4,5,gecos_user_gecos_field6");
} else if (strcmp(username, "gecos,3") == 0) {
pass->pw_gecos = strdup("1,2,gecos_user_gecos_field3,4,5,6");
} else if (strcmp(username, "fullgecos") == 0) {
pass->pw_gecos = strdup("full_gecos_field");
}
}
struct passwd *
getpwnam(const char *name)
{
// Tests rely on the username being correctly set.
static char username[1024];
strncpy(username, name, 1024);
username[1024 - 1] = '\0';
static struct passwd ret;
memcpy(&ret, getpwuid(getuid()), sizeof(struct passwd));
modify_gecos(username, &ret);
ret.pw_name = username;
return &ret;
}
|