Skip to content

Commit 5b7ddd4

Browse files
pbailiebmcutler
authored andcommitted
Accounts.php Update (#5)
* Process By Active Status pam_accounts/accounts.php WIP * accounts.php update pam_accounts/accounts.php WIP * Accounts.php Update pam_accounts/accounts.php WIP * Accounts.php update pam_accounts/accounts.php WIP * Accounts.php update /pam_accounts/accounts.php WIP, refactor * Accounts.php update pam_accounts/account.php WIP, comment update * Accounts.php Update Changes to be committed: modified: pam_accounts/accounts.php WIP, Debugging * Accounts.php Update Changes to be committed: modified: pam_accounts/accounts.php WIP * Accounts.php Update Changes to be committed: modified: pam_accounts/readme.md Updated Readme * Accounts.php Update Changes to be committed: modified: pam_accounts/readme.md Readme correction * Accouns.php Update Changes to be committed: modified: pam_accounts/accounts.php modified: pam_accounts/readme.md Pull request candidate * Accounts.php update Changes to be committed: modified: pam_accounts/accounts.php Last minute tweaks to comments and config template.
1 parent c1b4e4d commit 5b7ddd4

File tree

2 files changed

+242
-95
lines changed

2 files changed

+242
-95
lines changed

pam_accounts/accounts.php

+224-87
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@
1515
*
1616
* "30 * * * * /var/local/submitty/bin/accounts.php"
1717
*
18-
* You may specify the term on the command line with "-t".
18+
* You may specify on the command line:
19+
* "-t [term code]" make auth accounts for [term code].
1920
* "-g" can be used to guess the term by the server's calendar month and year.
21+
* "-a" will make auth accounts for all instructors and all active courses.
22+
* "-r" will remove grader and student auth accounts from inactive courses.
2023
* For example:
2124
*
2225
* ./accounts.php -t s18
@@ -26,22 +29,22 @@
2629
* @author Peter Bailie, Systems Programmer (RPI dept of computer science)
2730
*/
2831

29-
error_reporting(0);
30-
ini_set('display_errors', 0);
32+
error_reporting(null);
33+
ini_set('display_errors', '0');
3134

3235
//Database access
33-
define('DB_LOGIN', 'hsdbu');
34-
define('DB_PASSWD', 'hsdbu_pa55w0rd');
36+
define('DB_LOGIN', 'submitty_dbuser');
37+
define('DB_PASSWD', 'submitty_dbuser_pa55W0rd');
3538
define('DB_HOST', 'localhost');
36-
define('DB_NAME', 'submitty');
3739

3840
//Location of accounts creation error log file
39-
define('ERROR_LOG_FILE', '/var/local/submitty/bin/accounts_errors.log');
41+
define('ERROR_LOG_FILE', 'accounts_script_error.log');
4042

4143
//Where to email error messages so they can get more immediate attention.
4244
//Set to null to not send email.
4345
define('ERROR_EMAIL', '[email protected]');
4446

47+
4548
/* SUGGESTED SETTINGS FOR TIMEZONES IN USA -------------------------------------
4649
*
4750
* Eastern ........... America/New_York
@@ -61,90 +64,227 @@
6164
date_default_timezone_set('America/New_York');
6265

6366
//Start process
64-
main();
65-
exit(0);
66-
67-
/** Main process */
68-
function main() {
69-
//IMPORTANT: This script needs to be run as root!
70-
if (posix_getuid() !== 0) {
71-
exit("This script must be run as root." . PHP_EOL);
67+
new make_accounts();
68+
69+
/** Class constructor manages script workflow */
70+
class make_accounts {
71+
72+
/** @static @var resource pgsql database connection */
73+
private static $db_conn;
74+
/** @static @var string what workflow to process */
75+
private static $workflow;
76+
/** @static @var array paramater list for DB query */
77+
private static $db_params;
78+
/** @static @var string DB query to be run */
79+
private static $db_query;
80+
/** @static @var string function to call to process $workflow */
81+
private static $workflow_function;
82+
/** @static @var array user_id list of 'auth only accounts', read from /etc/passwd */
83+
private static $auth_only_accounts;
84+
85+
public function __construct() {
86+
//IMPORTANT: This script needs to be run as root!
87+
if (posix_getuid() !== 0) {
88+
exit("This script must be run as root." . PHP_EOL);
89+
}
90+
91+
//Init class properties, quit on error.
92+
if ($this->init() === false) {
93+
exit(1);
94+
}
95+
96+
//Do workflow, quit on error.
97+
if ($this->process() === false) {
98+
exit(1);
99+
}
100+
101+
//All done.
102+
exit(0);
72103
}
73104

74-
//Check for semester among CLI arguments.
75-
$semester = cli_args::parse_args();
76-
if ($semester === false) {
77-
exit(1);
105+
public function __destruct() {
106+
//Close DB connection, if it exists.
107+
if (pg_connection_status(self::$db_conn) === PGSQL_CONNECTION_OK) {
108+
pg_close(self::$db_conn);
109+
}
110+
}
111+
112+
/**
113+
* Initialize class properties, based on self::$workflow
114+
*
115+
* @access private
116+
* @return boolean TRUE on success, FALSE when there is a problem.
117+
*/
118+
private function init() {
119+
//Check CLI args.
120+
if (($cli_args = cli_args::parse_args()) === false) {
121+
return false;
122+
}
123+
self::$workflow = $cli_args[0];
124+
self::$db_params = is_null($cli_args[1]) ? array() : array($cli_args[1]);
125+
126+
//Define database query AND system call based on workflow.
127+
switch(self::$workflow) {
128+
case 'term':
129+
self::$db_query = <<<SQL
130+
SELECT DISTINCT user_id
131+
FROM courses_users
132+
WHERE semester=$1
133+
SQL;
134+
self::$workflow_function = 'add_user';
135+
break;
136+
137+
case 'active':
138+
self::$db_query = <<<SQL
139+
SELECT DISTINCT cu.user_id
140+
FROM courses_users as cu
141+
LEFT OUTER JOIN courses as c ON cu.course=c.course AND cu.semester=c.semester
142+
WHERE cu.user_group=1 OR (cu.user_group<>1 AND c.status=1)
143+
SQL;
144+
self::$workflow_function = 'add_user';
145+
break;
146+
147+
case 'clean':
148+
//'clean' workflow requires list of 'auth only accounts' from /etc/passwd.
149+
self::$auth_only_accounts = array();
150+
if (($fh = fopen('/etc/passwd', 'r')) === false) {
151+
$this->logit("Cannot open '/etc/passwd' to check for auth only accounts.");
152+
return false;
153+
}
154+
while (($row = fgetcsv($fh, 0, ':')) !== false) {
155+
if (strpos($row[4], 'auth only account') !== false) {
156+
self::$auth_only_accounts[] = $row[0];
157+
}
158+
}
159+
fclose($fh);
160+
self::$db_query = <<<SQL
161+
SELECT DISTINCT cu.user_id
162+
FROM courses_users as cu
163+
LEFT OUTER JOIN courses as c ON cu.course=c.course AND cu.semester=c.semester
164+
WHERE cu.user_group<>1 AND c.status<>1
165+
SQL;
166+
self::$workflow_function = 'remove_user';
167+
break;
168+
169+
default:
170+
$this->log_it("Invalid self::$workflow during init()");
171+
return false;
172+
}
173+
174+
//Signal success
175+
return true;
78176
}
79177

80-
$user_list = get_user_list($semester);
81-
if ($user_list !== false) {
82-
foreach($user_list as $user) {
83-
//We don't care if user already exists as adduser will skip over any account that already exists.
84-
system ("/usr/sbin/adduser --quiet --home /tmp --gecos 'RCS auth account' --no-create-home --disabled-password --shell /usr/sbin/nologin {$user} > /dev/null 2>&1");
178+
/**
179+
* Process workflow
180+
*
181+
* @access private
182+
* @return boolean TRUE on success, FALSE when there is a problem.
183+
*/
184+
private function process() {
185+
//Connect to database. Quit on failure.
186+
if ($this->db_connect() === false) {
187+
$this->log_it("Submitty Auto Account Creation: Cannot connect to DB {$db_name}.");
188+
return false;
85189
}
190+
191+
//Get user list based on command. Quit on failure.
192+
if (($result = pg_query_params(self::$db_conn, self::$db_query, self::$db_params)) === false) {
193+
$this->log_it("Submitty Auto Account Creation: Cannot read user list from {$db_name}.");
194+
return false;
195+
}
196+
197+
$num_rows = pg_num_rows($result);
198+
for ($i = 0; $i < $num_rows; $i++) {
199+
$user = pg_fetch_result($result, $i, 'user_id');
200+
call_user_func(array($this, self::$workflow_function), $user);
201+
}
202+
203+
//Signal success
204+
return true;
86205
}
87-
}
88206

89-
/**
90-
* Retrieve user list from courses_users
91-
*
92-
* @param string $semester
93-
* @return array of user ids on success, boolean false on failure.
94-
*/
95-
function get_user_list($semester) {
96-
$db_user = DB_LOGIN;
97-
$db_pass = DB_PASSWD;
98-
$db_host = DB_HOST;
99-
$db_name = DB_NAME;
100-
$db_conn = pg_connect("host={$db_host} dbname={$db_name} user={$db_user} password={$db_pass}");
101-
if ($db_conn === false) {
102-
log_it("Submitty Auto Account Creation: Cannot connect to DB {$db_name}.");
103-
return false;
207+
/**
208+
* Establish connection to Submitty Database
209+
*
210+
* @access private
211+
* @return boolean TRUE on success, FALSE when there is a problem.
212+
*/
213+
private function db_connect() {
214+
$db_user = DB_LOGIN;
215+
$db_pass = DB_PASSWD;
216+
$db_host = DB_HOST;
217+
self::$db_conn = pg_connect("host={$db_host} dbname=submitty user={$db_user} password={$db_pass} sslmode=prefer");
218+
if (pg_connection_status(self::$db_conn) !== PGSQL_CONNECTION_OK) {
219+
$this->log_it(pg_last_error(self::$db_conn));
220+
return false;
221+
}
222+
223+
//Signal success
224+
return true;
225+
}
226+
227+
/**
228+
* Add a user for authentication with PAM.
229+
*
230+
* @access private
231+
* @param string $user User ID to added.
232+
*/
233+
private function add_user($user) {
234+
system("/usr/sbin/adduser --quiet --home /tmp --gecos 'auth only account' --no-create-home --disabled-password --shell /usr/sbin/nologin {$user} > /dev/null 2>&1");
104235
}
105236

106-
$db_query = pg_query_params($db_conn, "SELECT DISTINCT user_id FROM courses_users WHERE semester=$1;", array($semester));
107-
if ($db_query === false) {
108-
log_it("Submitty Auto Account Creation: Cannot read user list from {$db_name}.");
109-
return false;
237+
/**
238+
* Remove an 'auth only user' from authenticating with PAM
239+
*
240+
* @access private
241+
* @param string $user User ID to be checked/removed.
242+
*/
243+
private function remove_user($user) {
244+
//Make sure $user is an "auth only account" before removing.
245+
if (array_search($user, self::$auth_only_accounts) !== false) {
246+
system("/usr/sbin/deluser --quiet {$user} > /dev/null 2>&1");
247+
}
110248
}
111249

112-
$user_list = pg_fetch_all_columns($db_query, 0);
113-
pg_close($db_conn);
114-
return $user_list;
115-
}
250+
/**
251+
* Log message to email and text files
252+
*
253+
* @access private
254+
* @param string $msg
255+
*/
256+
private function log_it($msg) {
257+
$msg = date('m/d/y H:i:s : ', time()) . $msg . PHP_EOL;
258+
error_log($msg, 3, ERROR_LOG_FILE);
259+
260+
if (!is_null(ERROR_EMAIL)) {
261+
error_log($msg, 1, ERROR_EMAIL);
262+
}
263+
}
264+
} //END class make_accounts
116265

117266
/**
118-
* Log message to email and text files
267+
* class to parse command line arguments
119268
*
120-
* @param string $msg
269+
* @static
121270
*/
122-
function log_it($msg) {
123-
$msg = date('m/d/y H:i:s : ', time()) . $msg . PHP_EOL;
124-
error_log($msg, 3, ERROR_LOG_FILE);
125-
126-
if (!is_null(ERROR_EMAIL)) {
127-
error_log($msg, 1, ERROR_EMAIL);
128-
}
129-
}
130-
131-
/** @static class to parse command line arguments */
132271
class cli_args {
133272

134-
/** @var array holds all CLI argument flags and their values */
135-
private static $args;
136273
/** @var string usage help message */
137-
private static $help_usage = "Usage: accounts.php [-h | --help] (-t [term code] | -g)" . PHP_EOL;
274+
private static $help_usage = "Usage: accounts.php [-h | --help] (-a | -t [term code] | -g | -r)" . PHP_EOL;
138275
/** @var string short description help message */
139276
private static $help_short_desc = "Read student enrollment from Submitty DB and create accounts for PAM auth." . PHP_EOL;
140277
/** @var string argument list help message */
141278
private static $help_args_list = <<<HELP
142279
Arguments
143280
-h --help Show this help message.
144-
-t [term code] Term code associated with student enrollment.
145-
-g Guess the term code based on calendar month and year.
281+
-a Make auth accounts for all active courses.
282+
-t [term code] Make auth accounts for specified term code.
283+
-g Make auth accounts for guessed term code, based on calendar
284+
month and year.
285+
-r Remove auth accounts from inactive courses.
146286
147-
NOTE: -t and -g are mutally exclusive. One is required.
287+
NOTE: Argument precedence order is -a, -t, -g, -r. One is required.
148288
149289
HELP;
150290

@@ -154,32 +294,29 @@ class cli_args {
154294
* Called with 'cli_args::parse_args()'
155295
*
156296
* @access public
157-
* @return mixed term code as string or boolean false when no term code is present.
297+
* @return array consisting of process command (string) and possibly associated term code (string or null) or boolean false on error.
158298
*/
159299
public static function parse_args() {
160-
161-
self::$args = getopt('hgt:', array('help'));
300+
$args = getopt('t:agrh', array('help'));
162301

163302
switch(true) {
164-
case array_key_exists('h', self::$args):
165-
case array_key_exists('help', self::$args):
303+
case array_key_exists('h', $args):
304+
case array_key_exists('help', $args):
166305
self::print_help();
167306
return false;
168-
case array_key_exists('g', self::$args):
169-
if (array_key_exists('t', self::$args)) {
170-
//-t and -g are mutually exclusive
171-
print "-g and -t cannot be used together." . PHP_EOL;
172-
return false;
173-
} else {
174-
//Guess current term
175-
//(s)pring is month <= 5, (f)all is month >= 8, s(u)mmer are months 6 and 7.
176-
//if ($month <= 5) {...} else if ($month >= 8) {...} else {...}
177-
$month = intval(date("m", time()));
178-
$year = date("y", time());
179-
return ($month <= 5) ? "s{$year}" : (($month >= 8) ? "f{$year}" : "u{$year}");
180-
}
181-
case array_key_exists('t', self::$args):
182-
return self::$args['t'];
307+
case array_key_exists('a', $args):
308+
return array("active", null);
309+
case array_key_exists('t', $args):
310+
return array("term", $args['t']);
311+
case array_key_exists('g', $args):
312+
//Guess current term
313+
//(s)pring is month <= 5, (f)all is month >= 8, s(u)mmer are months 6 and 7.
314+
//if ($month <= 5) {...} else if ($month >= 8) {...} else {...}
315+
$month = intval(date("m", time()));
316+
$year = date("y", time());
317+
return ($month <= 5) ? array("term", "s{$year}") : (($month >= 8) ? array("term", "f{$year}") : array("term", "u{$year}"));
318+
case array_key_exists('r', $args):
319+
return array("clean", null);
183320
default:
184321
print self::$help_usage . PHP_EOL;
185322
return false;
@@ -200,7 +337,7 @@ private static function print_help() {
200337
//Arguments list
201338
print self::$help_args_list . PHP_EOL;
202339
}
203-
}
340+
} //END class parse_args
204341

205342
/* EOF ====================================================================== */
206343
?>

0 commit comments

Comments
 (0)