15
15
*
16
16
* "30 * * * * /var/local/submitty/bin/accounts.php"
17
17
*
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].
19
20
* "-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.
20
23
* For example:
21
24
*
22
25
* ./accounts.php -t s18
26
29
* @author Peter Bailie, Systems Programmer (RPI dept of computer science)
27
30
*/
28
31
29
- error_reporting (0 );
30
- ini_set ('display_errors ' , 0 );
32
+ error_reporting (null );
33
+ ini_set ('display_errors ' , ' 0 ' );
31
34
32
35
//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 ' );
35
38
define ('DB_HOST ' , 'localhost ' );
36
- define ('DB_NAME ' , 'submitty ' );
37
39
38
40
//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 ' );
40
42
41
43
//Where to email error messages so they can get more immediate attention.
42
44
//Set to null to not send email.
43
45
define (
'ERROR_EMAIL ' ,
'[email protected] ' );
44
46
47
+
45
48
/* SUGGESTED SETTINGS FOR TIMEZONES IN USA -------------------------------------
46
49
*
47
50
* Eastern ........... America/New_York
61
64
date_default_timezone_set ('America/New_York ' );
62
65
63
66
//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 );
72
103
}
73
104
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 ;
78
176
}
79
177
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 ;
85
189
}
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 ;
86
205
}
87
- }
88
206
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 " );
104
235
}
105
236
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
+ }
110
248
}
111
249
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
116
265
117
266
/**
118
- * Log message to email and text files
267
+ * class to parse command line arguments
119
268
*
120
- * @param string $msg
269
+ * @static
121
270
*/
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 */
132
271
class cli_args {
133
272
134
- /** @var array holds all CLI argument flags and their values */
135
- private static $ args ;
136
273
/** @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 ;
138
275
/** @var string short description help message */
139
276
private static $ help_short_desc = "Read student enrollment from Submitty DB and create accounts for PAM auth. " . PHP_EOL ;
140
277
/** @var string argument list help message */
141
278
private static $ help_args_list = <<<HELP
142
279
Arguments
143
280
-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.
146
286
147
- NOTE: -t and -g are mutally exclusive . One is required.
287
+ NOTE: Argument precedence order is -a, -t, -g, -r . One is required.
148
288
149
289
HELP ;
150
290
@@ -154,32 +294,29 @@ class cli_args {
154
294
* Called with 'cli_args::parse_args()'
155
295
*
156
296
* @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 .
158
298
*/
159
299
public static function parse_args () {
160
-
161
- self ::$ args = getopt ('hgt: ' , array ('help ' ));
300
+ $ args = getopt ('t:agrh ' , array ('help ' ));
162
301
163
302
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 ):
166
305
self ::print_help ();
167
306
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 );
183
320
default :
184
321
print self ::$ help_usage . PHP_EOL ;
185
322
return false ;
@@ -200,7 +337,7 @@ private static function print_help() {
200
337
//Arguments list
201
338
print self ::$ help_args_list . PHP_EOL ;
202
339
}
203
- }
340
+ } //END class parse_args
204
341
205
342
/* EOF ====================================================================== */
206
343
?>
0 commit comments