Skip to content

Commit f058b14

Browse files
committed
tcb_chkpwd: Enhance the functionality of the helper program.
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]>
1 parent 2f23492 commit f058b14

File tree

2 files changed

+141
-16
lines changed

2 files changed

+141
-16
lines changed

ChangeLog

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@
4848
around unix_run_helper_binary().
4949
* pam_tcb/support.c (unix_verify_password_plain):
5050
Replace call to unix_run_helper_binary() with run_chkpwd_binary().
51+
* progs/tcb_chkpwd.c: Refactor the helper program to also perform
52+
verifications for the expiration of user accounts.
5153

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

progs/tcb_chkpwd.c

Lines changed: 139 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <string.h>
1313
#include <unistd.h>
1414
#include <syslog.h>
15+
#include <time.h>
1516
#include <pwd.h>
1617
#include <shadow.h>
1718

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

29+
enum {
30+
ACCT_0 = 0,
31+
ACCT_1,
32+
ACCT_2,
33+
ACCT_3,
34+
ACCT_4,
35+
ACCT_5,
36+
ACCT_6,
37+
ACCT_7,
38+
ACCT_SUCCESS = 255
39+
};
40+
2841
static void zeroise(char *str)
2942
{
3043
while (*str)
3144
*(str++) = '\0';
3245
}
3346

47+
static int unix_getspnam(struct spwd **spw, const struct passwd *pw, int shadow)
48+
{
49+
if (shadow) {
50+
*spw = getspnam(pw->pw_name);
51+
endspent();
52+
return 0;
53+
}
54+
55+
return 1;
56+
}
57+
58+
static int acct_shadow(const void *void_user, int shadow)
59+
{
60+
int daysleft;
61+
time_t curdays;
62+
const char *user = void_user;
63+
struct passwd *pw;
64+
struct spwd *spw = NULL;
65+
66+
pw = getpwnam(user);
67+
endpwent();
68+
if (pw) {
69+
uid_t uid = getuid();
70+
if (uid != pw->pw_uid && uid != 0)
71+
return ACCT_1;
72+
}
73+
if (!pw)
74+
return ACCT_1; /* shouldn't happen */
75+
if (!shadow && strcmp(pw->pw_passwd, "x")
76+
&& strcmp(pw->pw_passwd, "*NP*"))
77+
return ACCT_SUCCESS;
78+
79+
if (unix_getspnam(&spw, pw, shadow))
80+
return ACCT_1;
81+
82+
if (!spw)
83+
return ACCT_2;
84+
85+
curdays = time(NULL) / (60 * 60 * 24);
86+
syslog(LOG_DEBUG, "today is %ld, last change %ld",
87+
curdays, spw->sp_lstchg);
88+
if ((curdays > spw->sp_expire) && (spw->sp_expire != -1))
89+
return ACCT_3;
90+
91+
if ((curdays > (spw->sp_lstchg + spw->sp_max + spw->sp_inact)) &&
92+
(spw->sp_max != -1) && (spw->sp_inact != -1) &&
93+
(spw->sp_lstchg != 0))
94+
return ACCT_4;
95+
96+
syslog(LOG_DEBUG, "when was the last change");
97+
if (spw->sp_lstchg == 0)
98+
return ACCT_5;
99+
100+
if (((spw->sp_lstchg + spw->sp_max) < curdays) &&
101+
(spw->sp_max != -1))
102+
return ACCT_6;
103+
104+
if ((curdays > (spw->sp_lstchg + spw->sp_max - spw->sp_warn)) &&
105+
(spw->sp_max != -1) && (spw->sp_warn != -1)) {
106+
daysleft = (spw->sp_lstchg + spw->sp_max) - curdays;
107+
return ACCT_7 + 256 * daysleft;
108+
}
109+
110+
return ACCT_SUCCESS;
111+
}
112+
34113
static int unix_verify_password(const char *user, const char *pass, int nullok)
35114
{
36115
struct passwd *pw;
@@ -89,27 +168,36 @@ static int is_two_strings(char *data, unsigned int len)
89168
return (1 + strlen(data) < len);
90169
}
91170

92-
int main(void)
171+
static int acctverify(int shadow)
93172
{
94-
char option[8];
95-
char userandpass[MAX_DATA_LENGTH + 1];
96-
int datalen, nullok, retval;
173+
int datalen, retval;
174+
char username[MAX_DATA_LENGTH + 1];
97175

98-
openlog("tcb_chkpwd", LOG_CONS | LOG_PID, LOG_AUTH);
176+
retval = ACCT_0;
99177

100-
if (isatty(STDIN_FILENO) || isatty(STDOUT_FILENO)) {
101-
syslog(LOG_NOTICE, "inappropriate use by UID %d", getuid());
102-
return 1;
103-
}
178+
/* read the user from stdin (a pipe from the PAM module) */
179+
datalen = read_loop(STDIN_FILENO, username, MAX_DATA_LENGTH);
180+
if (datalen < 0)
181+
syslog(LOG_DEBUG, "no username supplied");
182+
else if (datalen >= MAX_DATA_LENGTH)
183+
syslog(LOG_DEBUG, "username too long");
184+
else
185+
retval = acct_shadow(username, shadow);
104186

105-
/* read the nullok/nonull option */
106-
memset(option, 0, sizeof(option));
107-
if (read_loop(STDIN_FILENO, option, sizeof(option)) <= 0) {
108-
syslog(LOG_DEBUG, "no option supplied");
187+
memset(username, 0, sizeof(username));
188+
189+
/* return pass or fail */
190+
if (write_loop(STDOUT_FILENO, (char *)&retval, sizeof(retval)) ==
191+
sizeof(retval))
192+
return retval == ACCT_SUCCESS ? 0 : 1;
193+
else
109194
return 1;
110-
}
111-
option[sizeof(option) - 1] = '\0';
112-
nullok = !strcmp(option, "nullok");
195+
}
196+
197+
static int passverify(int nullok)
198+
{
199+
int datalen, retval;
200+
char userandpass[MAX_DATA_LENGTH + 1];
113201

114202
retval = AUTH_FAILED;
115203

@@ -134,3 +222,38 @@ int main(void)
134222
else
135223
return 1;
136224
}
225+
226+
int main(int argc, char* argv[])
227+
{
228+
char option[8];
229+
int flag, retval = 1;
230+
231+
openlog("tcb_chkpwd", LOG_CONS | LOG_PID, LOG_AUTH);
232+
233+
if (argc != 2 || isatty(STDIN_FILENO) || isatty(STDOUT_FILENO)) {
234+
syslog(LOG_NOTICE, "inappropriate use by UID %d", getuid());
235+
goto out;
236+
}
237+
238+
/* read the applicable option from pipe */
239+
memset(option, 0, sizeof(option));
240+
if (read_loop(STDIN_FILENO, option, sizeof(option)) <= 0) {
241+
syslog(LOG_DEBUG, "no option supplied");
242+
goto out;
243+
}
244+
option[sizeof(option) - 1] = '\0';
245+
246+
if (!strcmp(argv[1], "chkacct")) {
247+
flag = !strcmp(option, "shadow");
248+
retval = acctverify(flag);
249+
goto out;
250+
}
251+
252+
if (!strcmp(argv[1], "chkpwd")) {
253+
flag = !strcmp(option, "nullok");
254+
retval = passverify(flag);
255+
}
256+
257+
out:
258+
return retval;
259+
}

0 commit comments

Comments
 (0)