6 * The rest Copyright 2002-2005 (c) GForge Team
9 * This file is part of GForge.
11 * GForge is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * GForge is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with GForge; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 This file creates user / group permissions by editing
28 the /etc/passwd /etc/shadow and /etc/group files
30 require_once dirname(__FILE__).'/../../env.inc.php';
31 require_once $gfwww.'include/pre.php';
32 require $gfcommon.'include/cron_utils.php';
38 // Default values for the script
40 define('DEFAULT_SHELL','/bin/cvssh.pl'); //use /bin/grap for cvs-only
41 define('FILE_EXTENSION','.new'); // use .new when testing
43 if (util_is_root_dir(forge_get_config('groupdir_prefix'))) {
44 $err .= "Error! groupdir_prefix Points To Root Directory!";
51 // Get the users' unix_name and password out of the database
52 // ONLY USERS WITH CVS READ AND COMMIT PRIVS ARE ADDED
54 $res = db_query_params ('SELECT distinct users.user_name,users.unix_pw,users.unix_uid,users.unix_gid,users.user_id
55 FROM users,user_group,groups
56 WHERE users.user_id=user_group.user_id
57 AND user_group.group_id=groups.group_id
59 AND user_group.cvs_flags IN ($2,$3)
61 ORDER BY users.user_id ASC',
68 $gforge_users =& util_result_column_to_array($res,'user_name');
69 $user_unix_uids =& util_result_column_to_array($res,'unix_uid');
70 $user_unix_gids =& util_result_column_to_array($res,'unix_gid');
71 $user_pws =& util_result_column_to_array($res,'unix_pw');
73 // Create the entries for the GForge users
74 $gforge_lines_passwd = array();
75 $gforge_lines_shadow = array();
76 $gforge_lines_groups = array();
78 // These will be the entries that already exist
79 $unmanaged_lines_passwd = array();
80 $unmanaged_lines_shadow = array();
81 $unmanaged_lines_group = array();
83 // user description is something like "MyGForge user"
84 $user_description = preg_replace('/[^[:alnum:] _-]/', '', forge_get_config ('forge_name'));
85 $user_description .= " user";
88 for ($i=0; $i < count($gforge_users); $i++) {
89 $username = $gforge_users[$i];
90 $user_unix_uid = $user_unix_uids[$i];
91 $user_unix_gid = $user_unix_gids[$i];
92 $shell = DEFAULT_SHELL;
93 $unix_passwd = $user_pws[$i];
95 $line_passwd = $username.":x:".$user_unix_uid.":".$user_unix_gid.":".
96 $user_description.":/home/".$username.":".$shell;
97 $line_shadow = $username.":".$unix_passwd.":12090:0:99999:7:::";
102 /*************************************************************************
103 * Step 1: Process /etc/passwd
104 *************************************************************************/
106 // Read the passwd file line by line
107 $passwd_orig = file("/etc/passwd");
108 for ($i=0; $i < count($passwd_orig); $i++) {
109 $line = trim($passwd_orig[$i]);
111 // Skip the GForge users (will be written later)
112 if (preg_match("/^[[:blank:]]*#GFORGEBEGIN/", $line)) {
115 $line = trim($passwd_orig[$i]);
116 } while ($i < count($passwd_orig) && !preg_match("/^[[:blank:]]*#GFORGEEND/", $line));
118 // Got to end of file (shouldn't happen, means #GFORGEEND wasn't found on file, but
119 // it's not a fatal error
120 if ($i >= (count($passwd_orig)-1)) break;
124 $line = trim($passwd_orig[$i]);
127 // Here, we're outside the #GFORGE markers
128 $entries = explode(":", $line);
129 if (!empty($entries[0])) {
130 $username = $entries[0];
131 $unmanaged_usernames[] = $username;
134 $unmanaged_lines_passwd[] = $line;
137 // Now, check which of the GForge users were found outside the #GFORGE markers. In that
138 // case, the user must not be written inside the markers (means the user is managed by
140 for ($i=0; $i < count($gforge_users); $i++) {
141 $username = $gforge_users[$i];
142 $managed_by_gforge = !in_array($username, $unmanaged_usernames);
144 if ($managed_by_gforge) {
145 $user_unix_uid = $user_unix_uids[$i];
146 $user_unix_gid = $user_unix_gids[$i];
147 $shell = DEFAULT_SHELL;
148 $unix_passwd = $user_pws[$i];
150 $line_passwd = $username.":x:".$user_unix_uid.":".$user_unix_gid.":".
151 $user_description.":/home/".$username.":".$shell;
152 $gforge_lines_passwd[] = $line_passwd;
156 // Generate the contents of /etc/passwd
157 $passwd_contents = implode("\n", $unmanaged_lines_passwd);
158 $passwd_contents .= "\n";
159 $passwd_contents .= "#GFORGEBEGIN\n";
160 $passwd_contents .= implode("\n", $gforge_lines_passwd);
161 $passwd_contents .= "\n#GFORGEEND\n";
163 /*************************************************************************
164 * Step 2: Process /etc/shadow
165 *************************************************************************/
167 // Read the shadow file line by line
168 $shadow_orig = file("/etc/shadow");
169 for ($i=0; $i < count($shadow_orig); $i++) {
170 $line = trim($shadow_orig[$i]);
172 // Skip the GForge users (will be written later)
173 if (preg_match("/^[[:blank:]]*#GFORGEBEGIN/", $line)) {
176 $line = trim($shadow_orig[$i]);
177 } while ($i < count($shadow_orig) && !preg_match("/^[[:blank:]]*#GFORGEEND/", $line));
179 // Got to end of file (shouldn't happen, means #GFORGEEND wasn't found on file, but
180 // it's not a fatal error
181 if ($i >= (count($shadow_orig)-1)) break;
185 $line = trim($shadow_orig[$i]);
188 // Here, we're outside the #GFORGE markers
189 $entries = explode(":", $line);
190 if (!empty($entries[0])) {
191 $username = $entries[0];
192 $unmanaged_usernames[] = $username;
195 $unmanaged_lines_shadow[] = $line;
197 for ($i=0; $i < count($gforge_users); $i++) {
198 $username = $gforge_users[$i];
199 $managed_by_gforge = !in_array($username, $unmanaged_usernames);
201 if ($managed_by_gforge) {
202 $unix_passwd = $user_pws[$i];
204 $line_shadow = $username.":".$unix_passwd.":12090:0:99999:7:::";
205 $gforge_lines_shadow[] = $line_shadow;
209 // Generate the contents of /etc/shadow
210 $shadow_contents = implode("\n", $unmanaged_lines_shadow);
211 $shadow_contents .= "\n";
212 $shadow_contents .= "#GFORGEBEGIN\n";
213 $shadow_contents .= implode("\n", $gforge_lines_shadow);
214 $shadow_contents .= "\n#GFORGEEND\n";
216 /*************************************************************************
217 * Step 3: Parse /etc/group
218 *************************************************************************/
219 $group_orig = file("/etc/group");
221 // Add the groups from the gforge database
222 $group_res = db_query_params ('SELECT group_id, unix_group_name, (is_public=1 AND enable_anonscm=1 AND type_id=1) AS enable_pserver FROM groups WHERE status=$1 AND type_id=$2',
227 $gforge_groups = array();
228 for($i = 0; $i < db_numrows($group_res); $i++) {
229 $group_name = db_result($group_res,$i,'unix_group_name');
230 $gforge_groups[] = $group_name;
231 $gids[$group_name] = db_result($group_res,$i,'group_id') + 50000; // 50000: hardcoded value (for now).
234 for ($i=0; $i < count($group_orig); $i++) {
235 $line = trim($group_orig[$i]);
236 // Skip the GForge groups (will be written later)
237 if (preg_match("/^[[:blank:]]*#GFORGEBEGIN/", $line)) {
240 $line = trim($group_orig[$i]);
241 } while ($i < count($group_orig) && !preg_match("/^[[:blank:]]*#GFORGEEND/", $line));
243 // Got to end of file (shouldn't happen, means #GFORGEEND wasn't found on file
244 if ($i >= (count($group_orig)-1)) break;
248 $line = trim($group_orig[$i]);
251 $entries = explode(":", $line);
252 if (!empty($entries[0])) {
253 $groupname = $entries[0];
254 if (!in_array($groupname, $gforge_groups)) {
255 // write the user only if it's not a gforge user
256 $unmanaged_lines_group[] = $line;
259 // blank line or comment
260 $unmanaged_lines_group[] = $line;
264 // Now process the GForge groups
265 // Note that we FORCE the GForge groups to be managed by GForge. This is different than the
266 // users, where the administrator could move a user outside the #GFORGE markers and manually
267 // manage the user. This is done because we must add the users to the group, and for this we
270 for ($i = 0; $i < count($gforge_groups); $i++) {
271 $group_name = $gforge_groups[$i];
272 $unix_gid = $gids[$group_name];
274 $line = $group_name.":x:".$unix_gid.":";
276 /* we need to get the project object to check if a project
277 * has a private CVS repository - in which case we need to add
278 * the apache user to the group so that ViewCVS can be used
281 $group_id = db_result($group_res, $i, 'group_id');
282 $project = &group_get_object($group_id);
283 $enable_pserver = (db_result($group_res, $i, 'enable_pserver') == 't');
285 $resusers = db_query_params ('SELECT user_name
286 FROM users,user_group,groups
287 WHERE groups.group_id=user_group.group_id
288 AND users.user_id=user_group.user_id
289 AND user_group.cvs_flags IN ($1,$2)
291 AND groups.unix_group_name=$4',
296 $gmembers = util_result_column_to_array($resusers,'user_name');
297 if ($enable_pserver) $gmembers[] = 'anonymous';
298 if (!$project->enableAnonSCM()) {
299 $gmembers[] = forge_get_config('apache_user');
302 $line .= implode(',', $gmembers);
303 $gforge_lines_group[] = $line;
306 // Generate the contents of /etc/group
307 $group_contents = implode("\n", $unmanaged_lines_group);
308 $group_contents .= "\n";
309 $group_contents .= "#GFORGEBEGIN\n";
310 $group_contents .= implode("\n", $gforge_lines_group);
311 $group_contents .= "\n#GFORGEEND\n";
313 /*************************************************************************
314 * Step 4: Write all the data
315 *************************************************************************/
318 $passwd_file = fopen("/etc/passwd".FILE_EXTENSION, "w");
320 fwrite($passwd_file, $passwd_contents);
321 fclose($passwd_file);
325 $shadow_file = fopen("/etc/shadow".FILE_EXTENSION, "w");
327 fwrite($shadow_file, $shadow_contents);
328 fclose($shadow_file);
332 $group_file = fopen("/etc/group".FILE_EXTENSION, "w");
334 fwrite($group_file, $group_contents);