6 * The rest Copyright 2002-2005 (c) GForge Team
7 * http://fusionforge.org/
9 * This file is part of FusionForge.
11 * FusionForge 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 * FusionForge 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 along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 $gfcommon.'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',''); // use .new when testing
43 if (util_is_root_dir(forge_get_config('groupdir_prefix'))) {
44 $err .= "Error! groupdir_prefix Points To Root Directory!";
50 $res = db_query_params ('SELECT group_id FROM groups WHERE status=$1',
53 $groups = group_get_objects (util_result_column_to_array($res,'group_id'));
55 $res = db_query_params ('SELECT user_id FROM users WHERE unix_status=$1',
58 $users = user_get_objects (util_result_column_to_array($res,'user_id'));
60 // Create the entries for the GForge users
61 $gforge_lines_passwd = array();
62 $gforge_lines_shadow = array();
63 $gforge_lines_groups = array();
65 // These will be the entries that already exist
66 $unmanaged_lines_passwd = array();
67 $unmanaged_lines_shadow = array();
68 $unmanaged_lines_group = array();
70 // user description is something like "MyGForge user"
71 $user_description = preg_replace('/[^[:alnum:] _-]/', '', forge_get_config ('forge_name'));
72 $user_description .= " user";
74 /*************************************************************************
75 * Step 1: Process /etc/passwd
76 *************************************************************************/
78 // Read the passwd file line by line
79 $passwd_orig = file("/etc/passwd");
80 for ($i=0; $i < count($passwd_orig); $i++) {
81 $line = trim($passwd_orig[$i]);
83 // Skip the GForge users (will be written later)
84 if (preg_match("/^[[:blank:]]*#GFORGEBEGIN/", $line)) {
87 $line = trim($passwd_orig[$i]);
88 } while ($i < count($passwd_orig) && !preg_match("/^[[:blank:]]*#GFORGEEND/", $line));
90 // Got to end of file (shouldn't happen, means #GFORGEEND wasn't found on file, but
91 // it's not a fatal error
92 if ($i >= (count($passwd_orig)-1)) break;
96 $line = trim($passwd_orig[$i]);
99 // Here, we're outside the #GFORGE markers
100 $entries = explode(":", $line);
101 if (!empty($entries[0])) {
102 $username = $entries[0];
103 $unmanaged_usernames[] = $username;
106 $unmanaged_lines_passwd[] = $line;
109 // Now, check which of the GForge users were found outside the #GFORGE markers. In that
110 // case, the user must not be written inside the markers (means the user is managed by
112 foreach ($users as $u) {
113 $username = $u->getUnixName() ;
114 $managed_by_gforge = !in_array($username, $unmanaged_usernames);
116 if ($managed_by_gforge) {
117 $user_unix_uid = $u->getUnixUID() ;
118 $user_unix_gid = $u->getUnixGID() ;
119 $shell = DEFAULT_SHELL;
120 $unix_passwd = $u->getUnixPasswd() ;
122 $line_passwd = $username.":x:".$user_unix_uid.":".$user_unix_gid.":".
123 $user_description.":/home/".$username.":".$shell;
124 $gforge_lines_passwd[] = $line_passwd;
128 // Generate the contents of /etc/passwd
129 $passwd_contents = implode("\n", $unmanaged_lines_passwd);
130 $passwd_contents .= "\n";
131 $passwd_contents .= "#GFORGEBEGIN\n";
132 $passwd_contents .= implode("\n", $gforge_lines_passwd);
133 $passwd_contents .= "\n#GFORGEEND\n";
135 /*************************************************************************
136 * Step 2: Process /etc/shadow
137 *************************************************************************/
139 // Read the shadow file line by line
140 $shadow_orig = file("/etc/shadow");
141 for ($i=0; $i < count($shadow_orig); $i++) {
142 $line = trim($shadow_orig[$i]);
144 // Skip the GForge users (will be written later)
145 if (preg_match("/^[[:blank:]]*#GFORGEBEGIN/", $line)) {
148 $line = trim($shadow_orig[$i]);
149 } while ($i < count($shadow_orig) && !preg_match("/^[[:blank:]]*#GFORGEEND/", $line));
151 // Got to end of file (shouldn't happen, means #GFORGEEND wasn't found on file, but
152 // it's not a fatal error
153 if ($i >= (count($shadow_orig)-1)) break;
157 $line = trim($shadow_orig[$i]);
160 // Here, we're outside the #GFORGE markers
161 $entries = explode(":", $line);
162 if (!empty($entries[0])) {
163 $username = $entries[0];
164 $unmanaged_usernames[] = $username;
167 $unmanaged_lines_shadow[] = $line;
170 $userp_res = db_query_params ('SELECT unix_pw FROM users WHERE unix_status=$1',
177 for($i = 0; $i < db_numrows($userp_res); $i++) {
178 $us_pw = db_result($userp_res,$i,'unix_pw');
179 $user_pws[] = $us_pw;
184 foreach ($users as $u) {
185 $username = $u->getUnixName() ;
186 $managed_by_gforge = !in_array($username, $unmanaged_usernames);
188 if ($managed_by_gforge) {
189 $unix_passwd = $user_pws[$i];
191 $line_shadow = $username.":".$unix_passwd.":12090:0:99999:7:::";
192 $gforge_lines_shadow[] = $line_shadow;
197 // Generate the contents of /etc/shadow
198 $shadow_contents = implode("\n", $unmanaged_lines_shadow);
199 $shadow_contents .= "\n";
200 $shadow_contents .= "#GFORGEBEGIN\n";
201 $shadow_contents .= implode("\n", $gforge_lines_shadow);
202 $shadow_contents .= "\n#GFORGEEND\n";
204 /*************************************************************************
205 * Step 3: Parse /etc/group
206 *************************************************************************/
207 $group_orig = file("/etc/group");
209 // Add the groups from the gforge database
210 $group_res = db_query_params ('SELECT group_id, unix_group_name FROM groups WHERE status=$1 AND type_id=$2',
215 $gforge_groups = array();
216 for($i = 0; $i < db_numrows($group_res); $i++) {
217 $group_name = db_result($group_res,$i,'unix_group_name');
218 $gforge_groups[] = $group_name;
219 $gids[$group_name] = db_result($group_res,$i,'group_id') + 50000; // 50000: hardcoded value (for now).
224 // Add the groups from the gforge database
225 for ($i=0; $i < count($group_orig); $i++) {
226 $line = trim($group_orig[$i]);
227 // Skip the GForge groups (will be written later)
228 if (preg_match("/^[[:blank:]]*#GFORGEBEGIN/", $line)) {
231 $line = trim($group_orig[$i]);
232 } while ($i < count($group_orig) && !preg_match("/^[[:blank:]]*#GFORGEEND/", $line));
234 // Got to end of file (shouldn't happen, means #GFORGEEND wasn't found on file
235 if ($i >= (count($group_orig)-1)) break;
239 $line = trim($group_orig[$i]);
242 $entries = explode(":", $line);
243 if (!empty($entries[0])) {
244 $groupname = $entries[0];
245 if (!in_array($groupname, $gforge_groups)) {
246 // write the user only if it's not a gforge user
247 $unmanaged_lines_group[] = $line;
250 // blank line or comment
251 $unmanaged_lines_group[] = $line;
255 // Now process the GForge groups
256 // Note that we FORCE the GForge groups to be managed by GForge. This is different than the
257 // users, where the administrator could move a user outside the #GFORGE markers and manually
258 // manage the user. This is done because we must add the users to the group, and for this we
261 foreach ($groups as $g) {
262 $group_name = $g->getUnixName() ;
263 $unix_gid = $g->getID() + 50000; // 50000: hardcoded value (for now).
265 $line = "scm_".$group_name.":x:".$unix_gid.":";
267 /* we need to get the project object to check if a project
268 * has a private CVS repository - in which case we need to add
269 * the apache user to the group so that ViewCVS can be used
272 $group_id = $g->getID() ;
274 $gmembers = array () ;
275 foreach (RBACEngine::getInstance()->getUsersByAllowedAction ('scm', $group_id, 'write') as $committer) {
276 $gmembers[] = $committer->getUnixName() ;
278 if ($g->enableAnonSCM()) {
279 $gmembers[] = 'anonymous';
281 $gmembers[] = forge_get_config('apache_user');
284 $line .= implode(',', $gmembers);
285 $gforge_lines_group[] = $line;
288 // Generate the contents of /etc/group
289 $group_contents = implode("\n", $unmanaged_lines_group);
290 $group_contents .= "\n";
291 $group_contents .= "#GFORGEBEGIN\n";
292 $group_contents .= implode("\n", $gforge_lines_group);
293 $group_contents .= "\n#GFORGEEND\n";
295 /*************************************************************************
296 * Step 4: Write all the data
297 *************************************************************************/
300 $passwd_file = fopen("/etc/passwd".FILE_EXTENSION, "w");
302 fwrite($passwd_file, $passwd_contents);
303 fclose($passwd_file);
307 $shadow_file = fopen("/etc/shadow".FILE_EXTENSION, "w");
309 fwrite($shadow_file, $shadow_contents);
310 fclose($shadow_file);
314 $group_file = fopen("/etc/group".FILE_EXTENSION, "w");
316 fwrite($group_file, $group_contents);