CVE-2022-0731 (PHP, published 2022-02-23T19:15Z)
Description: value: Improper Access Control (IDOR) in GitHub repository dolibarr/dolibarr prior to 16.0.
Severity: MEDIUM (CVSS v3 base score: 6.5)
Weakness: CWE-639 \u2014 Authorization Bypass Through User-Controlled Key
The system's authorization functionality does not prevent one user from gaining access to another user's data or record by modifying the key value identifying the data.
Repository: https://github.com/dolibarr/dolibarr
Files changed:
htdocs/core/class/html.form.class.php
htdocs/core/lib/files.lib.php
htdocs/install/upgrade2.php
htdocs/user/card.php
Commit message: FIX #hunterb812ea22-0c02-46fe-b89f-04519dfb1ebd

Vulnerable code:
						$file = get_exdir(0, 0, 0, 0, $object, 'user').getImageFileNameForSize($object->photo, '_mini');
						$file = get_exdir(0, 0, 0, 0, $object, 'user').getImageFileNameForSize($object->photo, '_small');
						$file = get_exdir(0, 0, 0, 0, $object, 'user').$object->photo;
					$originalfile = get_exdir(0, 0, 0, 0, $object, 'user').$object->photo;
		// Wrapping for *.log files, like when used with url http://.../document.php?modulepart=logs&file=dolibarr.log
		// Wrapping for *.zip files, like when used with url http://.../document.php?modulepart=packages&file=module_myfile.zip
		// Wrapping for *.zip files, like when used with url http://.../document.php?modulepart=packages&file=module_myfile.zip
		$accessallowed = 1;
		$accessallowed = 1;
		// Wrapping pour les apercu supplier invoice
							} else // it is a file
							{
						$fileimg = $conf->user->dir_output.'/'.get_exdir(0, 0, 0, 0, $object, 'user').$object->oldcopy->photo;
						$dirthumbs = $conf->user->dir_output.'/'.get_exdir(0, 0, 0, 0, $object, 'user').'/thumbs';
						$dir = $conf->user->dir_output.'/'.get_exdir(0, 0, 0, 1, $object, 'user');

Fixed code:
						$file = get_exdir(0, 0, 0, 0, $object, 'user').'photos/'.getImageFileNameForSize($object->photo, '_mini');
						$file = get_exdir(0, 0, 0, 0, $object, 'user').'photos/'.getImageFileNameForSize($object->photo, '_small');
						$file = get_exdir(0, 0, 0, 0, $object, 'user').'photos/'.$object->photo;
					$originalfile = get_exdir(0, 0, 0, 0, $object, 'user').'photos/'.$object->photo;
		// Wrapping for doctemplates
		// Wrapping for doctemplates of websites
		// Wrapping for *.zip package files, like when used with url http://.../document.php?modulepart=packages&file=module_myfile.zip
		$accessallowed = 0;
		if (preg_match('/^\d+\/photos\//', $original_file)) {
			$accessallowed = 1;
		}
		$accessallowed = 0;
		if (preg_match('/^\d+\/photos\//', $original_file)) {
			$accessallowed = 1;
		}
		// Wrapping pour les apercu expense report

		// Scripts for 16.0
		$afterversionarray = explode('.', '15.0.9');
		$beforeversionarray = explode('.', '16.0.9');
		if (versioncompare($versiontoarray, $afterversionarray) >= 0 && versioncompare($versiontoarray, $beforeversionarray) <= 0) {
			migrate_user_photospath2();
		}
							} else { // it is a file
/**
 * Migrate file from old path users/99/file.jpg into users/99/photos/file.jpg
 *
 * @return	void
 */
function migrate_user_photospath2()
{
	global $conf, $db, $langs, $user;

	print '<tr><td colspan="4">';

	print '<b>'.$langs->trans('MigrationUserPhotoPath')."</b><br>\n";

	include_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
	$fuser = new User($db);

	if (!is_object($user)) {
		$user = $fuser; // To avoid error during migration
	}

	$sql = "SELECT rowid as uid from ".MAIN_DB_PREFIX."user"; // Get list of all users
	$resql = $db->query($sql);
	if ($resql) {
		while ($obj = $db->fetch_object($resql)) {
			$fuser->fetch($obj->uid);
			//echo '<hr>'.$fuser->id.' -> '.$fuser->entity;
			$entity = (empty($fuser->entity) ? 1 : $fuser->entity);
			if ($entity > 1) {
				$dir = DOL_DATA_ROOT.'/'.$entity.'/users';
			} else {
				$dir = $conf->user->multidir_output[$entity]; // $conf->user->multidir_output[] for each entity is construct by the multicompany module
			}

			if ($dir) {
				//print "Process user id ".$fuser->id."<br>\n";
				$origin = $dir.'/'.$fuser->id;
				$destin = $dir.'/'.$fuser->id.'/photos';

				$origin_osencoded = dol_osencode($origin);

				dol_mkdir($destin);

				//echo '<hr>'.$origin.' -> '.$destin;
				if (dol_is_dir($origin)) {
					$handle = opendir($origin_osencoded);
					if (is_resource($handle)) {
						while (($file = readdir($handle)) !== false) {
							if ($file == '.' || $file == '..' || $file == 'photos') {
								continue;
							}
							if (!empty($fuser->photo) && ($file != $fuser->photo && $file != 'thumbs')) {
								continue;
							}

							if (dol_is_dir($origin.'/'.$file)) {	// it is a dir (like 'thumbs')
								$thumbs = opendir($origin_osencoded.'/'.$file);
								if (is_resource($thumbs)) {
									dol_mkdir($destin.'/'.$file);
									while (($thumb = readdir($thumbs)) !== false) {
										if (!dol_is_file($destin.'/'.$file.'/'.$thumb)) {
											if ($thumb == '.' || $thumb == '..') {
												continue;
											}

											//print $origin.'/'.$file.'/'.$thumb.' -> '.$destin.'/'.$file.'/'.$thumb.'<br>'."\n";
											print '.';
											dol_copy($origin.'/'.$file.'/'.$thumb, $destin.'/'.$file.'/'.$thumb, 0, 0);
										}
									}
									// dol_delete_dir($origin.'/'.$file);
								}
							} else { // it is a file
								if (!dol_is_file($destin.'/'.$file)) {
									//print $origin.'/'.$file.' -> '.$destin.'/'.$file.'<br>'."\n";
									print '.';
									dol_copy($origin.'/'.$file, $destin.'/'.$file, 0, 0);
								}
							}
						}
					}
				}
			}
		}
	}

	print '</td></tr>';
}

						$fileimg = $conf->user->dir_output.'/'.get_exdir(0, 0, 0, 0, $object, 'user').'photos/'.$object->oldcopy->photo;
						$dirthumbs = $conf->user->dir_output.'/'.get_exdir(0, 0, 0, 0, $object, 'user').'photos/thumbs';
						$dir = $conf->user->dir_output.'/'.get_exdir(0, 0, 0, 1, $object, 'user').'/photos';