This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * Copyright (c) Xerox Corporation, Codendi Team, 2001-2009. All rights reserved |
||
4 | * Copyright (c) Enalean, 2015. All Rights Reserved. |
||
5 | * |
||
6 | * Tuleap is free software; you can redistribute it and/or modify |
||
7 | * it under the terms of the GNU General Public License as published by |
||
8 | * the Free Software Foundation; either version 2 of the License, or |
||
9 | * (at your option) any later version. |
||
10 | * |
||
11 | * Tuleap is distributed in the hope that it will be useful, |
||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
14 | * GNU General Public License for more details. |
||
15 | * |
||
16 | * You should have received a copy of the GNU General Public License |
||
17 | * along with Tuleap; if not, write to the Free Software |
||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||
19 | */ |
||
20 | |||
21 | class BackendCVS extends Backend { |
||
22 | |||
23 | protected $CVSRootListNeedUpdate; |
||
24 | protected $UseCVSNT; |
||
25 | |||
26 | /** |
||
27 | * Return an instance of ServiceDao |
||
28 | * |
||
29 | * @return ServiceDao |
||
30 | */ |
||
31 | function _getServiceDao() { |
||
32 | return new ServiceDao(CodendiDataAccess::instance()); |
||
33 | } |
||
34 | |||
35 | |||
36 | /** |
||
37 | * Return true if server uses CVS NT, or false if it uses GNU CVS |
||
38 | * |
||
39 | * @return Boolean |
||
40 | */ |
||
41 | function useCVSNT() { |
||
42 | if (isset($this->UseCVSNT)) { |
||
43 | return $this->UseCVSNT; |
||
44 | } |
||
45 | if (is_file("/usr/bin/cvsnt")) { |
||
46 | $this->UseCVSNT=true; |
||
47 | } else { |
||
48 | $this->UseCVSNT=false; |
||
49 | } |
||
50 | return $this->UseCVSNT; |
||
51 | } |
||
52 | |||
53 | /** |
||
54 | * Check if repository of given project exists |
||
55 | * |
||
56 | * @param Project $project Project for wich repository will be checked |
||
57 | * |
||
58 | * @return true is repository already exists, false otherwise |
||
59 | */ |
||
60 | function repositoryExists($project) { |
||
61 | $unix_group_name=$project->getUnixName(false); // May contain upper-case letters |
||
62 | $cvs_dir=$GLOBALS['cvs_prefix']."/".$unix_group_name; |
||
63 | if (is_dir($cvs_dir)) { |
||
64 | return true; |
||
65 | } else { |
||
66 | return false; |
||
67 | } |
||
68 | } |
||
69 | |||
70 | /** |
||
71 | * Create project CVS repository |
||
72 | * If the directory already exists, nothing is done. |
||
73 | * |
||
74 | * @param Integer $group_id project id for wic CVS repository will be created |
||
75 | * |
||
76 | * @return true if repo is successfully created, false otherwise |
||
77 | */ |
||
78 | public function createProjectCVS($group_id) { |
||
79 | $project = $this->getProjectManager()->getProject($group_id); |
||
80 | if (!$project) { |
||
81 | return false; |
||
82 | } |
||
83 | |||
84 | $unix_group_name = $project->getUnixName(false); |
||
85 | $cvs_dir = $GLOBALS['cvs_prefix']."/".$unix_group_name; |
||
86 | |||
87 | if (! is_dir($cvs_dir)) { |
||
88 | // Let's create a CVS repository for this group |
||
89 | if (! mkdir($cvs_dir)) { |
||
90 | $this->log("Can't create project CVS dir: $cvs_dir", Backend::LOG_ERROR); |
||
91 | return false; |
||
92 | } |
||
93 | |||
94 | $return_code = 0; |
||
95 | $output = ''; |
||
96 | $cvs_command = $GLOBALS['cvs_cmd']; |
||
97 | |||
98 | if (! file_exists($cvs_command)) { |
||
99 | $this->log("CVS command not found", Backend::LOG_ERROR); |
||
100 | return false; |
||
101 | } |
||
102 | |||
103 | if ($this->useCVSNT()) { |
||
104 | // Tell cvsnt not to update /etc/cvsnt/PServer: this is done later by this the script. |
||
105 | $output = $this->system("$cvs_command -d$cvs_dir init -n ", $return_code); |
||
106 | } else { |
||
107 | $output = $this->system("$cvs_command -d$cvs_dir init", $return_code); |
||
108 | } |
||
109 | |||
110 | if ($return_code > 0) { |
||
111 | $this->log("CVS init command return: $output", Backend::LOG_ERROR); |
||
112 | return false; |
||
113 | } |
||
114 | |||
115 | if (! is_dir("$cvs_dir/CVSROOT")) { |
||
116 | $this->log("Folder $cvs_dir/CVSROOT does not exist", Backend::LOG_ERROR); |
||
117 | return false; |
||
118 | } |
||
119 | |||
120 | // Turn off pserver writers, on anonymous readers |
||
121 | // See CVS writers update below. Just create an |
||
122 | // empty writers file so that we can set up the appropriate |
||
123 | // ownership right below. We will put names in writers |
||
124 | // later in the script |
||
125 | |||
126 | $return_code_turn_off = 0; |
||
127 | |||
128 | $output_turn_off = $this->system("echo '' > $cvs_dir/CVSROOT/writers", $return_code_turn_off); |
||
129 | |||
130 | if ($return_code_turn_off > 0) { |
||
131 | $this->log("Echo in /CVSROOT/writers returns: $output_turn_off", Backend::LOG_ERROR); |
||
132 | return false; |
||
133 | } |
||
134 | |||
135 | if (! $this->useCVSNT()) { |
||
136 | // But to allow checkout/update to registered users we |
||
137 | // need to setup a world writable directory for CVS lock files |
||
138 | $lockdir=$GLOBALS['cvslock_prefix']."/$unix_group_name"; |
||
139 | $filename= "$cvs_dir/CVSROOT/config"; |
||
140 | $this->_RcsCheckout($filename); |
||
141 | $this->system("echo >> $filename"); |
||
142 | $this->system("echo '# !!! Codendi Specific !!! DO NOT REMOVE' >> $filename"); |
||
143 | $this->system("echo '# Put all CVS lock files in a single directory world writable' >> $filename"); |
||
144 | $this->system("echo '# directory so that any registered user can checkout/update' >> $filename"); |
||
145 | $this->system("echo '# without having write permission on the entire cvs tree.' >> $filename"); |
||
146 | $this->system("echo 'LockDir=$lockdir' >> $filename"); |
||
147 | // commit changes to config file (directly with RCS) |
||
148 | $this->_RcsCommit($filename); |
||
149 | |||
150 | // Create lock dir |
||
151 | $this->createLockDirIfMissing($project); |
||
152 | } |
||
153 | |||
154 | // put an empty line in in the valid tag cache (means no tag yet) |
||
155 | // (this file is not under version control so don't check it in) |
||
156 | $this->system("echo \"\" > $cvs_dir/CVSROOT/val-tags"); |
||
157 | $this->system("chmod 0664 $cvs_dir/CVSROOT/val-tags"); |
||
158 | |||
159 | // set group ownership, http user |
||
160 | $this->changeRepoOwnership($cvs_dir, $unix_group_name); |
||
161 | $this->recursiveSgidOnDirectories($cvs_dir); |
||
162 | } |
||
163 | |||
164 | // Create writer file |
||
165 | if (! $this->updateCVSwriters($group_id)) { |
||
166 | $this->log("Error while updating CVS Writers", Backend::LOG_ERROR); |
||
167 | return false; |
||
168 | } |
||
169 | |||
170 | // history was deleted (or not created)? Recreate it. |
||
171 | if ($this->useCVSNT()) { |
||
172 | // Create history file (not created by default by cvsnt) |
||
173 | $this->system("touch $cvs_dir/CVSROOT/history"); |
||
174 | // Must be writable |
||
175 | $this->system("chmod 0666 $cvs_dir/CVSROOT/history"); |
||
176 | $this->recurseChownChgrp($cvs_dir."/CVSROOT", $this->getHTTPUser(), $unix_group_name); |
||
177 | } |
||
178 | |||
179 | // Update post-commit hooks |
||
180 | if (! $this->updatePostCommit($project)) { |
||
181 | return false; |
||
182 | } |
||
183 | |||
184 | // Update watch mode |
||
185 | if (! $this->updateCVSWatchMode($group_id)) { |
||
186 | return false; |
||
187 | } |
||
188 | |||
189 | return true; |
||
190 | } |
||
191 | |||
192 | protected function recursiveSgidOnDirectories($root) { |
||
193 | $this->system('find '.$root.' -type d -exec chmod g+rws {} \;'); |
||
194 | } |
||
195 | |||
196 | /** |
||
197 | * Create lock dir if missing |
||
198 | * |
||
199 | * @param Project $project project for wich the lock dir will be created |
||
200 | * |
||
201 | * @return Boolean |
||
202 | */ |
||
203 | public function createLockDirIfMissing($project) { |
||
204 | // Lockdir does not exist? (Re)create it. |
||
205 | if (!$this->useCVSNT()) { |
||
206 | $lockdir=$GLOBALS['cvslock_prefix']."/".$project->getUnixName(false); |
||
207 | if (! is_dir($lockdir)) { |
||
208 | if (!mkdir("$lockdir",02777)) { |
||
209 | $this->log("Can't create project CVS lock dir: $lockdir", Backend::LOG_ERROR); |
||
210 | return false; |
||
211 | } |
||
212 | $this->system("chmod 02777 $lockdir"); // overwrite umask value |
||
213 | } |
||
214 | } |
||
215 | return true; |
||
216 | } |
||
217 | |||
218 | /** |
||
219 | * Update post-commit hooks |
||
220 | * |
||
221 | * @param Project $project project for wich post-commit hooks will be updated |
||
222 | * |
||
223 | * @return Boolean |
||
224 | */ |
||
225 | public function updatePostCommit($project) { |
||
226 | $unix_group_name=$project->getUnixName(false); // May contain upper-case letters |
||
227 | $cvs_dir=$GLOBALS['cvs_prefix']."/".$unix_group_name; |
||
228 | if ($project->isCVSTracked()) { |
||
229 | // hook for commit tracking in cvs loginfo file |
||
230 | $filename = "$cvs_dir/CVSROOT/loginfo"; |
||
231 | $file_array=file($filename); |
||
232 | if (!in_array($this->block_marker_start, $file_array)) { |
||
233 | if ($this->useCVSNT()) { |
||
234 | $command = "ALL ".$GLOBALS['codendi_bin_prefix']."/log_accum -T $unix_group_name -C $unix_group_name -s %{sVv}"; |
||
235 | } else { |
||
236 | $command = "ALL (".$GLOBALS['codendi_bin_prefix']."/log_accum -T $unix_group_name -C $unix_group_name -s %{sVv})>/dev/null 2>&1"; |
||
237 | } |
||
238 | $this->_RcsCheckout($filename); |
||
239 | $this->addBlock($filename, $command); |
||
240 | $this->_RcsCommit($filename); |
||
241 | $this->recurseChownChgrp($cvs_dir."/CVSROOT", $this->getHTTPUser(), $unix_group_name); |
||
242 | } |
||
243 | |||
244 | |||
245 | // hook for commit tracking in cvs commitinfo file |
||
246 | $filename = "$cvs_dir/CVSROOT/commitinfo"; |
||
247 | $file_array=file($filename); |
||
248 | if (!in_array($this->block_marker_start, $file_array)) { |
||
249 | $this->_RcsCheckout($filename); |
||
250 | $this->addBlock($filename, "ALL ".$GLOBALS['codendi_bin_prefix']."/commit_prep -T $unix_group_name -r"); |
||
251 | $this->_RcsCommit($filename); |
||
252 | $this->recurseChownChgrp($cvs_dir."/CVSROOT", $this->getHTTPUser(), $unix_group_name); |
||
253 | } |
||
254 | } else { |
||
255 | // Remove Codendi blocks if needed |
||
256 | $filename = "$cvs_dir/CVSROOT/loginfo"; |
||
257 | $file_array=file($filename); |
||
258 | if (in_array($this->block_marker_start, $file_array)) { |
||
259 | $this->removeBlock($filename); |
||
260 | } |
||
261 | $filename = "$cvs_dir/CVSROOT/commitinfo"; |
||
262 | $file_array=file($filename); |
||
263 | if (in_array($this->block_marker_start, $file_array)) { |
||
264 | $this->removeBlock($filename); |
||
265 | } |
||
266 | } |
||
267 | return true; |
||
268 | } |
||
269 | |||
270 | /** |
||
271 | * Update (or create) file CVSROOT/writers that should contain project members |
||
272 | * |
||
273 | * On Codendi writers go through pserver as well so put |
||
274 | * group members in writers file. Do not write anything |
||
275 | * in the CVS passwd file. The pserver protocol will fallback |
||
276 | * on /etc/passwd (or NSS) for user authentication |
||
277 | * |
||
278 | * @param Integer $group_id Project id for which committers will be updated |
||
279 | * |
||
280 | * @return Boolean |
||
281 | */ |
||
282 | public function updateCVSwriters($group_id) { |
||
283 | $project = $this->getProjectManager()->getProject($group_id); |
||
284 | if (! $project) { |
||
285 | return false; |
||
286 | } |
||
287 | |||
288 | $unix_group_name = $project->getUnixName(false); // May contain upper-case letters |
||
289 | $cvs_dir = $GLOBALS['cvs_prefix']."/".$unix_group_name; |
||
290 | $cvswriters_file = "$cvs_dir/CVSROOT/writers"; |
||
291 | |||
292 | // Get list of project members (Unix names) |
||
293 | $members_id_array = $project->getMembersUserNames(); |
||
294 | $members_name_array = array(); |
||
295 | foreach ($members_id_array as $member) { |
||
296 | $members_name_array[] = strtolower($member['user_name'])."\n"; |
||
297 | } |
||
298 | |||
299 | return $this->writeArrayToFile($members_name_array, $cvswriters_file); |
||
300 | } |
||
301 | /** |
||
302 | * Update CVS writers into all projects that given user belongs to |
||
303 | * |
||
304 | * @param PFUser $user member to add as committer |
||
305 | * |
||
306 | * @return Boolean |
||
307 | */ |
||
308 | public function updateCVSWritersForGivenMember($user) { |
||
309 | $projects = $user->getProjects(); |
||
310 | if (isset($projects)) { |
||
311 | $pm = $this->getProjectManager(); |
||
312 | foreach ($projects as $groupId) { |
||
313 | $project = $pm->getProject($groupId); |
||
314 | if ($this->repositoryExists($project)) { |
||
315 | if (!$this->updateCVSwriters($groupId)) { |
||
316 | return false; |
||
317 | } |
||
318 | } |
||
319 | } |
||
320 | } |
||
321 | return true; |
||
322 | } |
||
323 | |||
324 | |||
325 | /** |
||
326 | * Update CVS Watch Mode |
||
327 | * |
||
328 | * @param Integer $group_id Project id for wich watch mode will be updated |
||
329 | * |
||
330 | * @return Boolean |
||
331 | */ |
||
332 | public function updateCVSWatchMode($group_id) { |
||
333 | $project=$this->getProjectManager()->getProject($group_id); |
||
334 | if (!$project) { |
||
335 | $this->log("Project not found: $group_id", Backend::LOG_ERROR); |
||
336 | return false; |
||
337 | } |
||
338 | |||
339 | $unix_group_name=$project->getUnixName(false); // May contain upper-case letters |
||
340 | $cvs_dir=$GLOBALS['cvs_prefix']."/".$unix_group_name; |
||
341 | $filename = "$cvs_dir/CVSROOT/notify"; |
||
342 | //If notify file does not exist, we should raise error in log |
||
343 | //and return false |
||
344 | if (!file_exists($filename)) { |
||
345 | $this->log("No such file: $filename", Backend::LOG_ERROR); |
||
346 | return false; |
||
347 | } |
||
348 | $file_array=file($filename); |
||
349 | |||
350 | // Add notify command if cvs_watch_mode is on |
||
351 | if ($project->getCVSWatchMode()) { |
||
352 | if (!in_array($this->block_marker_start, $file_array)) { |
||
353 | $this->_RcsCheckout($filename); |
||
354 | $this->addBlock($filename, 'ALL mail %s -s "CVS notification"'); |
||
355 | $this->_RcsCommit($filename); |
||
356 | |||
357 | // Apply cvs watch on only if cvs_watch_mode changed to on |
||
358 | $this->CVSWatch($cvs_dir, $unix_group_name, 1); |
||
359 | $this->changeRepoOwnership($cvs_dir, $unix_group_name); |
||
360 | $this->system("chmod g+rws $cvs_dir"); |
||
361 | } |
||
362 | } else { |
||
363 | // Remove notify command if cvs_watch_mode is off. |
||
364 | if (in_array($this->block_marker_start, $file_array)) { |
||
365 | // Switch to cvs watch off |
||
366 | $this->_RcsCheckout($filename); |
||
367 | $this->removeBlock($filename); |
||
368 | $this->_RcsCommit($filename); |
||
369 | $this->recurseChownChgrp($cvs_dir."/CVSROOT", $this->getHTTPUser(), $unix_group_name); |
||
370 | $this->CVSWatch($cvs_dir, $unix_group_name, 0); |
||
371 | } |
||
372 | } |
||
373 | return true; |
||
374 | } |
||
375 | |||
376 | /** |
||
377 | * Setup the watch mode on the CVS repository |
||
378 | * |
||
379 | * @param String $cvs_dir CVS root directory |
||
380 | * @param String $unix_group_name name of the project |
||
381 | * @param Integer $watch_mode defines the watch mode |
||
382 | * |
||
383 | * @return Boolean |
||
384 | */ |
||
385 | function CVSWatch($cvs_dir, $unix_group_name, $watch_mode) { |
||
386 | $sandbox_dir = $GLOBALS['tmp_dir']."/".$unix_group_name.".cvs_watch_sandbox"; |
||
387 | if (is_dir($sandbox_dir)) { |
||
388 | return false; |
||
389 | } else { |
||
390 | mkdir("$sandbox_dir", 0700); |
||
391 | $this->system("chmod 0700 $sandbox_dir"); // overwrite umask value |
||
392 | } |
||
393 | if ($watch_mode == 1) { |
||
394 | $this->system("cd $sandbox_dir;cvs -d$cvs_dir co . 2>/dev/null 1>&2;cvs -d$cvs_dir watch on 2>/dev/null 1>&2;"); |
||
395 | } else { |
||
396 | $this->system("cd $sandbox_dir;cvs -d$cvs_dir co . 2>/dev/null 1>&2;cvs -d$cvs_dir watch off 2>/dev/null 1>&2;"); |
||
397 | } |
||
398 | $this->system("rm -rf $sandbox_dir;"); |
||
399 | return true; |
||
400 | } |
||
401 | |||
402 | /** |
||
403 | * Checkout the file |
||
404 | * |
||
405 | * @param File $file file to checkout |
||
406 | * |
||
407 | * @return void |
||
408 | */ |
||
409 | function _RcsCheckout($file, &$output='') { |
||
410 | $rcode = 0; |
||
411 | $output = $this->system("co -q -l $file", $rcode); |
||
412 | return $rcode; |
||
413 | } |
||
414 | |||
415 | /** |
||
416 | * Commit the file |
||
417 | * |
||
418 | * @param File $file file to be committed |
||
419 | * |
||
420 | * @return void |
||
421 | */ |
||
422 | function _RcsCommit($file, &$output='') { |
||
423 | $rcode = 0; |
||
424 | $output = $this->system("/usr/bin/rcs -q -l $file; ci -q -m\"Codendi modification\" $file; co -q $file", $rcode); |
||
425 | return $rcode; |
||
426 | } |
||
427 | |||
428 | /** |
||
429 | * Archive CVS repository: stores a tgz in temp dir, and remove the directory |
||
430 | * |
||
431 | * @param Integer $group_id id of the project for which CVS repository will be archived |
||
432 | * |
||
433 | * @return Boolean |
||
434 | */ |
||
435 | public function archiveProjectCVS($group_id) { |
||
436 | $project=$this->getProjectManager()->getProject($group_id); |
||
437 | if (!$project) { |
||
438 | return false; |
||
439 | } |
||
440 | $mydir=$GLOBALS['cvs_prefix']."/".$project->getUnixName(false); |
||
441 | $backupfile=ForgeConfig::get('sys_project_backup_path')."/".$project->getUnixName(false)."-cvs.tgz"; |
||
442 | |||
443 | if (is_dir($mydir)) { |
||
444 | $this->system("cd ".$GLOBALS['cvs_prefix']."; tar cfz $backupfile ".$project->getUnixName(false)); |
||
445 | chmod($backupfile, 0600); |
||
446 | $this->recurseDeleteInDir($mydir); |
||
447 | rmdir($mydir); |
||
448 | } |
||
449 | return true; |
||
450 | } |
||
451 | |||
452 | /** |
||
453 | * Update the "cvs_root_allow" file that contains the list of authorised CVS repositories |
||
454 | * |
||
455 | * @return Boolean |
||
456 | */ |
||
457 | public function CVSRootListUpdate() { |
||
458 | $cvs_root_allow_array = array(); |
||
459 | $projlist = array(); |
||
460 | $repolist = array(); |
||
461 | |||
462 | $service_dao = $this->_getServiceDao(); |
||
463 | $dar = $service_dao->searchActiveUnixGroupByUsedService('cvs'); |
||
464 | foreach ($dar as $row) { |
||
465 | $repolist[]="/cvsroot/".$row['unix_group_name']; |
||
466 | } |
||
467 | |||
468 | |||
469 | if ($this->useCVSNT()) { |
||
470 | $config_file=$GLOBALS['cvsnt_config_file']; |
||
471 | $cvsnt_marker="DON'T EDIT THIS LINE - END OF CODENDI BLOCK"; |
||
472 | } else { |
||
473 | $config_file=$GLOBALS['cvs_root_allow_file']; |
||
474 | } |
||
475 | $config_file_old=$config_file.".old"; |
||
476 | $config_file_new=$config_file.".new"; |
||
477 | |||
478 | if (is_file($config_file)) { |
||
479 | $cvs_config_array = file($config_file); |
||
480 | } |
||
481 | |||
482 | $fp = fopen($config_file_new, 'w'); |
||
483 | |||
484 | if ($this->useCVSNT()) { |
||
485 | fwrite($fp, "# Codendi CVSROOT directory list: do not edit this list!\n"); |
||
486 | |||
487 | $num=0; |
||
488 | foreach ($repolist as $reponame) { |
||
489 | fwrite($fp, "Repository$num=$reponame\n"); |
||
490 | $num++; |
||
491 | } |
||
492 | fwrite($fp, "# End of Codendi CVSROOT directory list: you may change options below $cvsnt_marker\n"); |
||
493 | |||
494 | // and recopy other configuration instructions |
||
495 | $configlines=0; |
||
496 | foreach ($cvs_config_array as $line) { |
||
497 | if ($configlines) { |
||
498 | fwrite($fp, $line); |
||
499 | } |
||
500 | if (strpos($line, $cvsnt_marker)) { |
||
501 | $configlines=1; |
||
502 | } |
||
503 | } |
||
504 | } else { |
||
505 | // CVS: simple list of allowed CVS roots |
||
506 | foreach ($repolist as $reponame) { |
||
507 | fwrite($fp, "$reponame\n"); |
||
508 | } |
||
509 | } |
||
510 | fclose($fp); |
||
511 | |||
512 | // Backup existing file and install new one if they are different |
||
513 | $this->installNewFileVersion($config_file_new, $config_file, $config_file_old); |
||
514 | |||
515 | return true; |
||
516 | } |
||
517 | |||
518 | /** |
||
519 | * set whether CVS root need to be updated or not |
||
520 | * |
||
521 | * @return void |
||
522 | */ |
||
523 | public function setCVSRootListNeedUpdate() { |
||
524 | $this->CVSRootListNeedUpdate=true; |
||
525 | } |
||
526 | |||
527 | /** |
||
528 | * Check if CVS root need update |
||
529 | * |
||
530 | * @return Boolean |
||
531 | */ |
||
532 | public function getCVSRootListNeedUpdate() { |
||
533 | return $this->CVSRootListNeedUpdate; |
||
534 | } |
||
535 | |||
536 | /** |
||
537 | * Make the cvs repository of the project private or public |
||
538 | * |
||
539 | * @param Project $project project for which project privacy is set |
||
540 | * @param boolean $is_private true if the repository is private |
||
541 | * |
||
542 | * @return boolean true if success |
||
543 | */ |
||
544 | public function setCVSPrivacy($project, $is_private) { |
||
545 | $perms = $is_private ? 02770 : 02775; |
||
546 | $cvsroot = $GLOBALS['cvs_prefix'] . '/' . $project->getUnixName(false); |
||
547 | return is_dir($cvsroot) && $this->chmod($cvsroot, $perms); |
||
548 | } |
||
549 | |||
550 | |||
551 | /** |
||
552 | * Check ownership/mode/privacy of repository |
||
553 | * |
||
554 | * @param Project $project The project to work on |
||
555 | * |
||
556 | * @return boolean true if success |
||
557 | */ |
||
558 | public function checkCVSMode($project) { |
||
559 | $unix_group_name = $project->getUnixName(false); |
||
560 | $cvsroot = $GLOBALS['cvs_prefix'] . '/' . $unix_group_name; |
||
561 | $is_private = !$project->isPublic() || $project->isCVSPrivate(); |
||
562 | if ($is_private) { |
||
563 | $perms = fileperms($cvsroot); |
||
564 | // 'others' should have no right on the repository |
||
565 | if (($perms & 0x0004) || ($perms & 0x0002) || ($perms & 0x0001) || ($perms & 0x0200)) { |
||
566 | $this->log("Restoring privacy on CVS dir: $cvsroot", Backend::LOG_WARNING); |
||
567 | $this->setCVSPrivacy($project, $is_private); |
||
568 | } |
||
569 | } |
||
570 | // Sometimes, there might be a bad ownership on file (e.g. chmod failed, maintenance done as root...) |
||
571 | $files_to_check=array('CVSROOT/loginfo', 'CVSROOT/commitinfo', 'CVSROOT/config'); |
||
572 | $need_owner_update = false; |
||
573 | foreach ($files_to_check as $file) { |
||
574 | if (file_exists($cvsroot.'/'.$file)) { |
||
575 | // Get file stat |
||
576 | $stat = stat("$cvsroot/$file"); |
||
577 | if ($stat) { |
||
0 ignored issues
–
show
|
|||
578 | if ( ($stat['uid'] != $this->getHTTPUserUID()) || ($stat['gid'] != $project->getUnixGID()) ) { |
||
579 | $need_owner_update = true; |
||
580 | } |
||
581 | } |
||
582 | } else { |
||
583 | $this->log("File not found in cvsroot: $cvsroot/$file", Backend::LOG_WARNING); |
||
584 | } |
||
585 | } |
||
586 | if ($need_owner_update) { |
||
587 | $this->log("Restoring ownership on CVS dir: $cvsroot", Backend::LOG_INFO); |
||
588 | $this->changeRepoOwnership($cvsroot, $unix_group_name); |
||
589 | $this->system('chmod g+rws '.$cvsroot); |
||
590 | } |
||
591 | |||
592 | return true; |
||
593 | } |
||
594 | |||
595 | public function changeRepoOwnership($repo_path, $unix_group_name) { |
||
596 | return $this->system("chown -R {$this->getHTTPUser()}:{$unix_group_name} $repo_path"); |
||
597 | } |
||
598 | |||
599 | /** |
||
600 | * Deleting files older than 2 hours in /var/run/log_accum that contain 'files' |
||
601 | * (they have not been deleted due to commit abort) |
||
602 | * |
||
603 | * @return void |
||
604 | */ |
||
605 | public function cleanup() { |
||
606 | // TODO: test! |
||
607 | $filelist = shell_exec("/usr/bin/find ".$GLOBALS['cvs_hook_tmp_dir'].' -name "*.files.*" -amin +120;'); |
||
608 | $files = explode("\n", $filelist); |
||
609 | // Remove last (empty) element |
||
610 | array_pop($files); |
||
611 | |||
612 | foreach ($files as $file) { |
||
613 | unlink($file); |
||
614 | } |
||
615 | } |
||
616 | |||
617 | /** |
||
618 | * Check if given name is not used by a repository or a file or a link |
||
619 | * |
||
620 | * @param String $name checked filename |
||
621 | * |
||
622 | * @return false if repository or file or link already exists, true otherwise |
||
623 | */ |
||
624 | function isNameAvailable($name) { |
||
625 | $path = $GLOBALS['cvs_prefix']."/".$name; |
||
626 | return (!$this->fileExists($path)); |
||
627 | } |
||
628 | |||
629 | |||
630 | /** |
||
631 | * Rename cvs repository (following project unix_name change) |
||
632 | * |
||
633 | * @param Project $project Project to rename |
||
634 | * @param String $newName New name |
||
635 | * |
||
636 | * @return Boolean |
||
637 | */ |
||
638 | public function renameCVSRepository($project, $newName) { |
||
639 | if (rename($GLOBALS['cvs_prefix'].'/'.$project->getUnixName(false), $GLOBALS['cvs_prefix'].'/'.$newName)) { |
||
640 | $this->renameLockDir($project, $newName); |
||
641 | $this->renameLogInfoFile($project, $newName); |
||
642 | $this->renameCommitInfoFile($project, $newName); |
||
643 | return true; |
||
644 | } |
||
645 | return false; |
||
646 | } |
||
647 | |||
648 | /** |
||
649 | * Rename CVS lock dir and corresponding file in repository |
||
650 | * |
||
651 | * @param Project $project Project to rename |
||
652 | * @param String $newName New name |
||
653 | * |
||
654 | * @return Boolean |
||
655 | */ |
||
656 | public function renameLockDir($project, $newName) { |
||
657 | $oldLockDir = $GLOBALS['cvslock_prefix'].'/'.$project->getUnixName(false); |
||
658 | $newLockDir = $GLOBALS['cvslock_prefix'].'/'.$newName; |
||
659 | if (is_dir($oldLockDir)) { |
||
660 | rename($oldLockDir, $newLockDir); |
||
661 | } |
||
662 | |||
663 | $filename = $GLOBALS['cvs_prefix'].'/'.$newName.'/CVSROOT/config'; |
||
664 | $this->_RcsCheckout($filename); |
||
665 | $file = file_get_contents($filename); |
||
666 | $file = preg_replace('%'.$oldLockDir.'%m', $newLockDir, $file); |
||
667 | file_put_contents($filename, $file); |
||
668 | $this->_RcsCommit($filename); |
||
669 | |||
670 | return true; |
||
671 | } |
||
672 | |||
673 | /** |
||
674 | * Rename all project occurrences in the loginfo file |
||
675 | * |
||
676 | * @param Project $project Project to rename |
||
677 | * @param String $newName New name |
||
678 | * |
||
679 | * @return Boolean |
||
680 | */ |
||
681 | public function renameLogInfoFile($project, $newName) { |
||
682 | $filename = $GLOBALS['cvs_prefix'].'/'.$newName.'/CVSROOT/loginfo'; |
||
683 | $this->_RcsCheckout($filename); |
||
684 | $file = file_get_contents($filename); |
||
685 | $file = preg_replace('%(\s+)'.$project->getUnixName(false).'(\s+)%m', '$1'.$newName.'$2', $file); |
||
686 | $file = preg_replace('%'.$GLOBALS['cvs_prefix'].'/'.$project->getUnixName(false).'%m', $GLOBALS['cvs_prefix'].'/'.$newName, $file); |
||
687 | file_put_contents($filename, $file); |
||
688 | $this->_RcsCommit($filename); |
||
689 | return true; |
||
690 | } |
||
691 | |||
692 | /** |
||
693 | * Rename all project occurrences in the commit file |
||
694 | * |
||
695 | * @param Project $project Project to rename |
||
696 | * @param String $newName New name |
||
697 | * |
||
698 | * @return Boolean |
||
699 | */ |
||
700 | public function renameCommitInfoFile($project, $newName) { |
||
701 | $filename = $GLOBALS['cvs_prefix'].'/'.$newName.'/CVSROOT/commitinfo'; |
||
702 | $this->_RcsCheckout($filename); |
||
703 | $file = file_get_contents($filename); |
||
704 | $file = preg_replace('%(\s+)'.$project->getUnixName(false).'(\s+)%m', '$1'.$newName.'$2', $file); |
||
705 | file_put_contents($filename, $file); |
||
706 | $this->_RcsCommit($filename); |
||
707 | return true; |
||
708 | } |
||
709 | } |
||
710 | |||
711 | ?> |
||
712 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.