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+
2841static 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+
34113static 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