6 * The rest Copyright 2002-2005 (c) GForge Team
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
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 $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','.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!";
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,'group_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;
169 foreach ($users as $u) {
170 $username = $u->getUnixName() ;
171 $managed_by_gforge = !in_array($username, $unmanaged_usernames);
173 if ($managed_by_gforge) {
174 $unix_passwd = $user_pws[$i];
176 $line_shadow = $username.":".$unix_passwd.":12090:0:99999:7:::";
177 $gforge_lines_shadow[] = $line_shadow;
181 // Generate the contents of /etc/shadow
182 $shadow_contents = implode("\n", $unmanaged_lines_shadow);
183 $shadow_contents .= "\n";
184 $shadow_contents .= "#GFORGEBEGIN\n";
185 $shadow_contents .= implode("\n", $gforge_lines_shadow);
186 $shadow_contents .= "\n#GFORGEEND\n";
188 /*************************************************************************
189 * Step 3: Parse /etc/group
190 *************************************************************************/
191 $group_orig = file("/etc/group");
193 // Add the groups from the gforge database
194 for ($i=0; $i < count($group_orig); $i++) {
195 $line = trim($group_orig[$i]);
196 // Skip the GForge groups (will be written later)
197 if (preg_match("/^[[:blank:]]*#GFORGEBEGIN/", $line)) {
200 $line = trim($group_orig[$i]);
201 } while ($i < count($group_orig) && !preg_match("/^[[:blank:]]*#GFORGEEND/", $line));
203 // Got to end of file (shouldn't happen, means #GFORGEEND wasn't found on file
204 if ($i >= (count($group_orig)-1)) break;
208 $line = trim($group_orig[$i]);
211 $entries = explode(":", $line);
212 if (!empty($entries[0])) {
213 $groupname = $entries[0];
214 if (!in_array($groupname, $gforge_groups)) {
215 // write the user only if it's not a gforge user
216 $unmanaged_lines_group[] = $line;
219 // blank line or comment
220 $unmanaged_lines_group[] = $line;
224 // Now process the GForge groups
225 // Note that we FORCE the GForge groups to be managed by GForge. This is different than the
226 // users, where the administrator could move a user outside the #GFORGE markers and manually
227 // manage the user. This is done because we must add the users to the group, and for this we
230 foreach ($groups as $g) {
231 $group_name = $g->getUnixName() ;
232 $unix_gid = $g->getID() + 50000; // 50000: hardcoded value (for now).
234 $line = $group_name.":x:".$unix_gid.":";
236 /* we need to get the project object to check if a project
237 * has a private CVS repository - in which case we need to add
238 * the apache user to the group so that ViewCVS can be used
241 $group_id = $g->getID() ;
243 $gmembers = array () ;
244 foreach (RBACEngine::getInstance()->getUsersByAllowedAction ('scm', $group_id, 'write') as $committer) {
245 $gmembers[] = $committer->getUnixName() ;
247 if ($g->enableAnonSCM()) {
248 $gmembers[] = 'anonymous';
250 $gmembers[] = forge_get_config('apache_user');
253 $line .= implode(',', $gmembers);
254 $gforge_lines_group[] = $line;
257 // Generate the contents of /etc/group
258 $group_contents = implode("\n", $unmanaged_lines_group);
259 $group_contents .= "\n";
260 $group_contents .= "#GFORGEBEGIN\n";
261 $group_contents .= implode("\n", $gforge_lines_group);
262 $group_contents .= "\n#GFORGEEND\n";
264 /*************************************************************************
265 * Step 4: Write all the data
266 *************************************************************************/
269 $passwd_file = fopen("/etc/passwd".FILE_EXTENSION, "w");
271 fwrite($passwd_file, $passwd_contents);
272 fclose($passwd_file);
276 $shadow_file = fopen("/etc/shadow".FILE_EXTENSION, "w");
278 fwrite($shadow_file, $shadow_contents);
279 fclose($shadow_file);
283 $group_file = fopen("/etc/group".FILE_EXTENSION, "w");
285 fwrite($group_file, $group_contents);