mirror of
https://github.com/genuinetools/reg.git
synced 2024-09-12 14:21:01 -04:00
174 lines
4.2 KiB
C
174 lines
4.2 KiB
C
|
// Copyright 2017 The Go Authors. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style
|
||
|
// license that can be found in the LICENSE file.
|
||
|
|
||
|
// sshd_test_pw.c
|
||
|
// Wrapper to inject test password data for sshd PAM authentication
|
||
|
//
|
||
|
// This wrapper implements custom versions of getpwnam, getpwnam_r,
|
||
|
// getspnam and getspnam_r. These functions first call their real
|
||
|
// libc versions, then check if the requested user matches test user
|
||
|
// specified in env variable TEST_USER and if so replace the password
|
||
|
// with crypted() value of TEST_PASSWD env variable.
|
||
|
//
|
||
|
// Compile:
|
||
|
// gcc -Wall -shared -o sshd_test_pw.so -fPIC sshd_test_pw.c
|
||
|
//
|
||
|
// Compile with debug:
|
||
|
// gcc -DVERBOSE -Wall -shared -o sshd_test_pw.so -fPIC sshd_test_pw.c
|
||
|
//
|
||
|
// Run sshd:
|
||
|
// LD_PRELOAD="sshd_test_pw.so" TEST_USER="..." TEST_PASSWD="..." sshd ...
|
||
|
|
||
|
// +build ignore
|
||
|
|
||
|
#define _GNU_SOURCE
|
||
|
#include <string.h>
|
||
|
#include <pwd.h>
|
||
|
#include <shadow.h>
|
||
|
#include <dlfcn.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <unistd.h>
|
||
|
#include <stdio.h>
|
||
|
|
||
|
#ifdef VERBOSE
|
||
|
#define DEBUG(X...) fprintf(stderr, X)
|
||
|
#else
|
||
|
#define DEBUG(X...) while (0) { }
|
||
|
#endif
|
||
|
|
||
|
/* crypt() password */
|
||
|
static char *
|
||
|
pwhash(char *passwd) {
|
||
|
return strdup(crypt(passwd, "$6$"));
|
||
|
}
|
||
|
|
||
|
/* Pointers to real functions in libc */
|
||
|
static struct passwd * (*real_getpwnam)(const char *) = NULL;
|
||
|
static int (*real_getpwnam_r)(const char *, struct passwd *, char *, size_t, struct passwd **) = NULL;
|
||
|
static struct spwd * (*real_getspnam)(const char *) = NULL;
|
||
|
static int (*real_getspnam_r)(const char *, struct spwd *, char *, size_t, struct spwd **) = NULL;
|
||
|
|
||
|
/* Cached test user and test password */
|
||
|
static char *test_user = NULL;
|
||
|
static char *test_passwd_hash = NULL;
|
||
|
|
||
|
static void
|
||
|
init(void) {
|
||
|
/* Fetch real libc function pointers */
|
||
|
real_getpwnam = dlsym(RTLD_NEXT, "getpwnam");
|
||
|
real_getpwnam_r = dlsym(RTLD_NEXT, "getpwnam_r");
|
||
|
real_getspnam = dlsym(RTLD_NEXT, "getspnam");
|
||
|
real_getspnam_r = dlsym(RTLD_NEXT, "getspnam_r");
|
||
|
|
||
|
/* abort if env variables are not defined */
|
||
|
if (getenv("TEST_USER") == NULL || getenv("TEST_PASSWD") == NULL) {
|
||
|
fprintf(stderr, "env variables TEST_USER and TEST_PASSWD are missing\n");
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
/* Fetch test user and test password from env */
|
||
|
test_user = strdup(getenv("TEST_USER"));
|
||
|
test_passwd_hash = pwhash(getenv("TEST_PASSWD"));
|
||
|
|
||
|
DEBUG("sshd_test_pw init():\n");
|
||
|
DEBUG("\treal_getpwnam: %p\n", real_getpwnam);
|
||
|
DEBUG("\treal_getpwnam_r: %p\n", real_getpwnam_r);
|
||
|
DEBUG("\treal_getspnam: %p\n", real_getspnam);
|
||
|
DEBUG("\treal_getspnam_r: %p\n", real_getspnam_r);
|
||
|
DEBUG("\tTEST_USER: '%s'\n", test_user);
|
||
|
DEBUG("\tTEST_PASSWD: '%s'\n", getenv("TEST_PASSWD"));
|
||
|
DEBUG("\tTEST_PASSWD_HASH: '%s'\n", test_passwd_hash);
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
is_test_user(const char *name) {
|
||
|
if (test_user != NULL && strcmp(test_user, name) == 0)
|
||
|
return 1;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* getpwnam */
|
||
|
|
||
|
struct passwd *
|
||
|
getpwnam(const char *name) {
|
||
|
struct passwd *pw;
|
||
|
|
||
|
DEBUG("sshd_test_pw getpwnam(%s)\n", name);
|
||
|
|
||
|
if (real_getpwnam == NULL)
|
||
|
init();
|
||
|
if ((pw = real_getpwnam(name)) == NULL)
|
||
|
return NULL;
|
||
|
|
||
|
if (is_test_user(name))
|
||
|
pw->pw_passwd = strdup(test_passwd_hash);
|
||
|
|
||
|
return pw;
|
||
|
}
|
||
|
|
||
|
/* getpwnam_r */
|
||
|
|
||
|
int
|
||
|
getpwnam_r(const char *name,
|
||
|
struct passwd *pwd,
|
||
|
char *buf,
|
||
|
size_t buflen,
|
||
|
struct passwd **result) {
|
||
|
int r;
|
||
|
|
||
|
DEBUG("sshd_test_pw getpwnam_r(%s)\n", name);
|
||
|
|
||
|
if (real_getpwnam_r == NULL)
|
||
|
init();
|
||
|
if ((r = real_getpwnam_r(name, pwd, buf, buflen, result)) != 0 || *result == NULL)
|
||
|
return r;
|
||
|
|
||
|
if (is_test_user(name))
|
||
|
pwd->pw_passwd = strdup(test_passwd_hash);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* getspnam */
|
||
|
|
||
|
struct spwd *
|
||
|
getspnam(const char *name) {
|
||
|
struct spwd *sp;
|
||
|
|
||
|
DEBUG("sshd_test_pw getspnam(%s)\n", name);
|
||
|
|
||
|
if (real_getspnam == NULL)
|
||
|
init();
|
||
|
if ((sp = real_getspnam(name)) == NULL)
|
||
|
return NULL;
|
||
|
|
||
|
if (is_test_user(name))
|
||
|
sp->sp_pwdp = strdup(test_passwd_hash);
|
||
|
|
||
|
return sp;
|
||
|
}
|
||
|
|
||
|
/* getspnam_r */
|
||
|
|
||
|
int
|
||
|
getspnam_r(const char *name,
|
||
|
struct spwd *spbuf,
|
||
|
char *buf,
|
||
|
size_t buflen,
|
||
|
struct spwd **spbufp) {
|
||
|
int r;
|
||
|
|
||
|
DEBUG("sshd_test_pw getspnam_r(%s)\n", name);
|
||
|
|
||
|
if (real_getspnam_r == NULL)
|
||
|
init();
|
||
|
if ((r = real_getspnam_r(name, spbuf, buf, buflen, spbufp)) != 0)
|
||
|
return r;
|
||
|
|
||
|
if (is_test_user(name))
|
||
|
spbuf->sp_pwdp = strdup(test_passwd_hash);
|
||
|
|
||
|
return r;
|
||
|
}
|