...

Text file src/golang.org/x/crypto/ssh/test/sshd_test_pw.c

Documentation: golang.org/x/crypto/ssh/test

     1// Copyright 2017 The Go Authors. All rights reserved.
     2// Use of this source code is governed by a BSD-style
     3// license that can be found in the LICENSE file.
     4
     5// sshd_test_pw.c
     6// Wrapper to inject test password data for sshd PAM authentication
     7//
     8// This wrapper implements custom versions of getpwnam, getpwnam_r,
     9// getspnam and getspnam_r. These functions first call their real
    10// libc versions, then check if the requested user matches test user
    11// specified in env variable TEST_USER and if so replace the password
    12// with crypted() value of TEST_PASSWD env variable.
    13//
    14// Compile:
    15// gcc -Wall -shared -o sshd_test_pw.so -fPIC sshd_test_pw.c
    16//
    17// Compile with debug:
    18// gcc -DVERBOSE -Wall -shared -o sshd_test_pw.so -fPIC sshd_test_pw.c
    19//
    20// Run sshd:
    21// LD_PRELOAD="sshd_test_pw.so" TEST_USER="..." TEST_PASSWD="..." sshd ...
    22
    23//go:build ignore
    24
    25#define _GNU_SOURCE
    26#include <string.h>
    27#include <pwd.h>
    28#include <shadow.h>
    29#include <dlfcn.h>
    30#include <stdlib.h>
    31#include <unistd.h>
    32#include <stdio.h>
    33
    34#ifdef VERBOSE
    35#define DEBUG(X...) fprintf(stderr, X)
    36#else
    37#define DEBUG(X...) while (0) { }
    38#endif
    39
    40/* crypt() password */
    41static char *
    42pwhash(char *passwd) {
    43  return strdup(crypt(passwd, "$6$"));
    44}
    45
    46/* Pointers to real functions in libc */
    47static struct passwd * (*real_getpwnam)(const char *) = NULL;
    48static int (*real_getpwnam_r)(const char *, struct passwd *, char *, size_t, struct passwd **) = NULL;
    49static struct spwd * (*real_getspnam)(const char *) = NULL;
    50static int (*real_getspnam_r)(const char *, struct spwd *, char *, size_t, struct spwd **) = NULL;
    51
    52/* Cached test user and test password */
    53static char *test_user = NULL;
    54static char *test_passwd_hash = NULL;
    55
    56static void
    57init(void) {
    58  /* Fetch real libc function pointers */
    59  real_getpwnam = dlsym(RTLD_NEXT, "getpwnam");
    60  real_getpwnam_r = dlsym(RTLD_NEXT, "getpwnam_r");
    61  real_getspnam = dlsym(RTLD_NEXT, "getspnam");
    62  real_getspnam_r = dlsym(RTLD_NEXT, "getspnam_r");
    63  
    64  /* abort if env variables are not defined */
    65  if (getenv("TEST_USER") == NULL || getenv("TEST_PASSWD") == NULL) {
    66    fprintf(stderr, "env variables TEST_USER and TEST_PASSWD are missing\n");
    67    abort();
    68  }
    69
    70  /* Fetch test user and test password from env */
    71  test_user = strdup(getenv("TEST_USER"));
    72  test_passwd_hash = pwhash(getenv("TEST_PASSWD"));
    73
    74  DEBUG("sshd_test_pw init():\n");
    75  DEBUG("\treal_getpwnam: %p\n", real_getpwnam);
    76  DEBUG("\treal_getpwnam_r: %p\n", real_getpwnam_r);
    77  DEBUG("\treal_getspnam: %p\n", real_getspnam);
    78  DEBUG("\treal_getspnam_r: %p\n", real_getspnam_r);
    79  DEBUG("\tTEST_USER: '%s'\n", test_user);
    80  DEBUG("\tTEST_PASSWD: '%s'\n", getenv("TEST_PASSWD"));
    81  DEBUG("\tTEST_PASSWD_HASH: '%s'\n", test_passwd_hash);
    82}
    83
    84static int
    85is_test_user(const char *name) {
    86  if (test_user != NULL && strcmp(test_user, name) == 0)
    87    return 1;
    88  return 0;
    89}
    90
    91/* getpwnam */
    92
    93struct passwd *
    94getpwnam(const char *name) {
    95  struct passwd *pw;
    96
    97  DEBUG("sshd_test_pw getpwnam(%s)\n", name);
    98  
    99  if (real_getpwnam == NULL)
   100    init();
   101  if ((pw = real_getpwnam(name)) == NULL)
   102    return NULL;
   103
   104  if (is_test_user(name))
   105    pw->pw_passwd = strdup(test_passwd_hash);
   106      
   107  return pw;
   108}
   109
   110/* getpwnam_r */
   111
   112int
   113getpwnam_r(const char *name,
   114	   struct passwd *pwd,
   115	   char *buf,
   116	   size_t buflen,
   117	   struct passwd **result) {
   118  int r;
   119
   120  DEBUG("sshd_test_pw getpwnam_r(%s)\n", name);
   121  
   122  if (real_getpwnam_r == NULL)
   123    init();
   124  if ((r = real_getpwnam_r(name, pwd, buf, buflen, result)) != 0 || *result == NULL)
   125    return r;
   126
   127  if (is_test_user(name))
   128    pwd->pw_passwd = strdup(test_passwd_hash);
   129  
   130  return 0;
   131}
   132
   133/* getspnam */
   134
   135struct spwd *
   136getspnam(const char *name) {
   137  struct spwd *sp;
   138
   139  DEBUG("sshd_test_pw getspnam(%s)\n", name);
   140  
   141  if (real_getspnam == NULL)
   142    init();
   143  if ((sp = real_getspnam(name)) == NULL)
   144    return NULL;
   145
   146  if (is_test_user(name))
   147    sp->sp_pwdp = strdup(test_passwd_hash);
   148  
   149  return sp;
   150}
   151
   152/* getspnam_r */
   153
   154int
   155getspnam_r(const char *name,
   156	   struct spwd *spbuf,
   157	   char *buf,
   158	   size_t buflen,
   159	   struct spwd **spbufp) {
   160  int r;
   161
   162  DEBUG("sshd_test_pw getspnam_r(%s)\n", name);
   163  
   164  if (real_getspnam_r == NULL)
   165    init();
   166  if ((r = real_getspnam_r(name, spbuf, buf, buflen, spbufp)) != 0)
   167    return r;
   168
   169  if (is_test_user(name))
   170    spbuf->sp_pwdp = strdup(test_passwd_hash);
   171  
   172  return r;
   173}

View as plain text