Skip to content

Commit

Permalink
tcb_chkpwd: Enhance the functionality of the helper program.
Browse files Browse the repository at this point in the history
The tcb_chkpwd helper binary is now able to also perform verifications
for the expiration of user accounts.

Signed-off-by: Björn Esser <[email protected]>
  • Loading branch information
besser82 committed Oct 12, 2021
1 parent 5cec73f commit c3b4f1e
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 16 deletions.
2 changes: 2 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
around unix_run_helper_binary().
* pam_tcb/support.c (unix_verify_password_plain):
Replace call to unix_run_helper_binary() with run_chkpwd_binary().
* progs/tcb_chkpwd.c: Refactor the helper program to also perform
verifications for the expiration of user accounts.

2021-09-30 Björn Esser <besser82 at fedoraproject.org>

Expand Down
155 changes: 139 additions & 16 deletions progs/tcb_chkpwd.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <string.h>
#include <unistd.h>
#include <syslog.h>
#include <time.h>
#include <pwd.h>
#include <shadow.h>

Expand All @@ -25,12 +26,90 @@ IO_LOOP(write_loop, write, const)
#define AUTH_PASSED TCB_MAGIC
#define AUTH_FAILED 1

enum {
ACCT_0 = 0,
ACCT_1,
ACCT_2,
ACCT_3,
ACCT_4,
ACCT_5,
ACCT_6,
ACCT_7,
ACCT_SUCCESS = 255
};

static void zeroise(char *str)
{
while (*str)
*(str++) = '\0';
}

static int unix_getspnam(struct spwd **spw, const struct passwd *pw, int shadow)
{
if (shadow) {
*spw = getspnam(pw->pw_name);
endspent();
return 0;
}

return 1;
}

static int acct_shadow(const void *void_user, int shadow)
{
int daysleft;
time_t curdays;
const char *user = void_user;
struct passwd *pw;
struct spwd *spw = NULL;

pw = getpwnam(user);
endpwent();
if (pw) {
uid_t uid = getuid();
if (uid != pw->pw_uid && uid != 0)
return ACCT_1;
}
if (!pw)
return ACCT_1; /* shouldn't happen */
if (!shadow && strcmp(pw->pw_passwd, "x")
&& strcmp(pw->pw_passwd, "*NP*"))
return ACCT_SUCCESS;

if (unix_getspnam(&spw, pw, shadow))
return ACCT_1;

if (!spw)
return ACCT_2;

curdays = time(NULL) / (60 * 60 * 24);
syslog(LOG_DEBUG, "today is %ld, last change %ld",
curdays, spw->sp_lstchg);
if ((curdays > spw->sp_expire) && (spw->sp_expire != -1))
return ACCT_3;

if ((curdays > (spw->sp_lstchg + spw->sp_max + spw->sp_inact)) &&
(spw->sp_max != -1) && (spw->sp_inact != -1) &&
(spw->sp_lstchg != 0))
return ACCT_4;

syslog(LOG_DEBUG, "when was the last change");
if (spw->sp_lstchg == 0)
return ACCT_5;

if (((spw->sp_lstchg + spw->sp_max) < curdays) &&
(spw->sp_max != -1))
return ACCT_6;

if ((curdays > (spw->sp_lstchg + spw->sp_max - spw->sp_warn)) &&
(spw->sp_max != -1) && (spw->sp_warn != -1)) {
daysleft = (spw->sp_lstchg + spw->sp_max) - curdays;
return ACCT_7 + 256 * daysleft;
}

return ACCT_SUCCESS;
}

static int unix_verify_password(const char *user, const char *pass, int nullok)
{
struct passwd *pw;
Expand Down Expand Up @@ -89,27 +168,36 @@ static int is_two_strings(char *data, unsigned int len)
return (1 + strlen(data) < len);
}

int main(void)
static int acctverify(int shadow)
{
char option[8];
char userandpass[MAX_DATA_LENGTH + 1];
int datalen, nullok, retval;
int datalen, retval;
char username[MAX_DATA_LENGTH + 1];

openlog("tcb_chkpwd", LOG_CONS | LOG_PID, LOG_AUTH);
retval = ACCT_0;

if (isatty(STDIN_FILENO) || isatty(STDOUT_FILENO)) {
syslog(LOG_NOTICE, "inappropriate use by UID %d", getuid());
return 1;
}
/* read the user from stdin (a pipe from the PAM module) */
datalen = read_loop(STDIN_FILENO, username, MAX_DATA_LENGTH);
if (datalen < 0)
syslog(LOG_DEBUG, "no username supplied");
else if (datalen >= MAX_DATA_LENGTH)
syslog(LOG_DEBUG, "username too long");
else
retval = acct_shadow(username, shadow);

/* read the nullok/nonull option */
memset(option, 0, sizeof(option));
if (read_loop(STDIN_FILENO, option, sizeof(option)) <= 0) {
syslog(LOG_DEBUG, "no option supplied");
memset(username, 0, sizeof(username));

/* return pass or fail */
if (write_loop(STDOUT_FILENO, (char *)&retval, sizeof(retval)) ==
sizeof(retval))
return retval == ACCT_SUCCESS ? 0 : 1;
else
return 1;
}
option[sizeof(option) - 1] = '\0';
nullok = !strcmp(option, "nullok");
}

static int passverify(int nullok)
{
int datalen, retval;
char userandpass[MAX_DATA_LENGTH + 1];

retval = AUTH_FAILED;

Expand All @@ -134,3 +222,38 @@ int main(void)
else
return 1;
}

int main(int argc, char* argv[])
{
char option[8];
int nullok, retval = 1, shadow;

openlog("tcb_chkpwd", LOG_CONS | LOG_PID, LOG_AUTH);

if (argc != 2 || isatty(STDIN_FILENO) || isatty(STDOUT_FILENO)) {
syslog(LOG_NOTICE, "inappropriate use by UID %d", getuid());
goto out;
}

/* read the applicable option from pipe */
memset(option, 0, sizeof(option));
if (read_loop(STDIN_FILENO, option, sizeof(option)) <= 0) {
syslog(LOG_DEBUG, "no option supplied");
goto out;
}
option[sizeof(option) - 1] = '\0';

if (!strcmp(argv[1], "chkacct")) {
shadow = !strcmp(option, "shadow");
retval = acctverify(shadow);
goto out;
}

if (!strcmp(argv[1], "chkpwd")) {
nullok = !strcmp(option, "nullok");
retval = passverify(nullok);
}

out:
return retval;
}

0 comments on commit c3b4f1e

Please sign in to comment.