Completed
Branch develop (45fc57)
by
unknown
27:54
created

security2.lib.php ➔ getRandomPassword()   C

Complexity

Conditions 10
Paths 4

Size

Total Lines 63
Code Lines 42

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 42
nc 4
nop 1
dl 0
loc 63
rs 6.3636
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/* Copyright (C) 2008-2011 Laurent Destailleur  <[email protected]>
3
 * Copyright (C) 2008-2017 Regis Houssin        <[email protected]>
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 3 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
 * or see http://www.gnu.org/
18
 */
19
20
/**
21
 *  \file		htdocs/core/lib/security2.lib.php
22
 *  \ingroup    core
23
 *  \brief		Set of function used for dolibarr security (not common functions).
24
 *  			Warning, this file must not depends on other library files, except function.lib.php
25
 *  			because it is used at low code level.
26
 */
27
28
29
/**
30
 *  Return user/group account of web server
31
 *
32
 *  @param	string	$mode       'user' or 'group'
33
 *  @return string				Return user or group of web server
34
 */
35
function dol_getwebuser($mode)
36
{
37
    $t='?';
38
    if ($mode=='user')  $t=getenv('APACHE_RUN_USER');   // $_ENV['APACHE_RUN_USER'] is empty
39
    if ($mode=='group') $t=getenv('APACHE_RUN_GROUP');
40
    return $t;
41
}
42
43
/**
44
 *  Return a login if login/pass was successfull
45
 *
46
 *	@param		string	$usertotest			Login value to test
47
 *	@param		string	$passwordtotest		Password value to test
48
 *	@param		string	$entitytotest		Instance of data we must check
49
 *	@param		array	$authmode			Array list of selected authentication mode array('http', 'dolibarr', 'xxx'...)
50
 *  @return		string						Login or ''
51
 */
52
function checkLoginPassEntity($usertotest,$passwordtotest,$entitytotest,$authmode)
53
{
54
	global $conf,$langs;
55
    //global $dolauthmode;    // To return authentication finally used
56
57
	// Check parameters
58
	if ($entitytotest == '') $entitytotest=1;
59
60
    dol_syslog("checkLoginPassEntity usertotest=".$usertotest." entitytotest=".$entitytotest." authmode=".join(',',$authmode));
61
	$login = '';
62
63
	// Validation of login/pass/entity with standard modules
64
	if (empty($login))
65
	{
66
	    $test=true;
67
    	foreach($authmode as $mode)
68
    	{
69
    		if ($test && $mode && ! $login)
70
    		{
71
    		    // Validation of login/pass/entity for mode $mode
72
    		    $mode=trim($mode);
73
        		$authfile='functions_'.$mode.'.php';
74
        		$fullauthfile='';
75
76
    		    $dirlogin=array_merge(array("/core/login"),(array) $conf->modules_parts['login']);
77
    		    foreach($dirlogin as $reldir)
78
    		    {
79
    		        $dir=dol_buildpath($reldir,0);
80
    		        $newdir=dol_osencode($dir);
81
82
    		        // Check if file found (do not use dol_is_file to avoid loading files.lib.php)
83
    		        if (is_file($newdir.'/'.$authfile)) $fullauthfile=$newdir.'/'.$authfile;
84
    		    }
85
86
    		    $result=false;
87
    		    if ($fullauthfile) $result=include_once $fullauthfile;
88
    			if ($fullauthfile && $result)
89
    			{
90
    				// Call function to check user/password
91
    				$function='check_user_password_'.$mode;
92
    				$login=call_user_func($function,$usertotest,$passwordtotest,$entitytotest);
93
    				if ($login)	// Login is successfull
94
    				{
95
    					$test=false;            // To stop once at first login success
96
    					$conf->authmode=$mode;	// This properties is defined only when logged to say what mode was successfully used
97
    					$dol_tz=GETPOST('tz');
98
    					$dol_dst=GETPOST('dst');
99
    					$dol_screenwidth=GETPOST('screenwidth');
100
    					$dol_screenheight=GETPOST('screenheight');
101
    				}
102
    			}
103
    			else
104
    			{
105
    				dol_syslog("Authentification ko - failed to load file '".$authfile."'",LOG_ERR);
106
    				sleep(1);
107
    				$langs->load('main');
108
    				$langs->load('other');
109
    				$langs->load('errors');
110
    				$_SESSION["dol_loginmesg"]=$langs->trans("ErrorFailedToLoadLoginFileForMode",$mode);
111
    			}
112
    		}
113
    	}
114
	}
115
116
	return $login;
117
}
118
119
120
/**
121
 * Show Dolibarr default login page.
122
 * Part of this code is also duplicated into main.inc.php::top_htmlhead
123
 *
124
 * @param		Translate	$langs		Lang object (must be initialized by a new).
125
 * @param		Conf		$conf		Conf object
126
 * @param		Societe		$mysoc		Company object
127
 * @return		void
128
 */
129
function dol_loginfunction($langs,$conf,$mysoc)
130
{
131
	global $dolibarr_main_demo,$db;
132
	global $smartphone,$hookmanager;
133
134
	// Instantiate hooks of thirdparty module only if not already define
135
	$hookmanager->initHooks(array('mainloginpage'));
136
137
	$langs->load("main");
138
	$langs->load("other");
139
	$langs->load("help");
140
	$langs->load("admin");
141
142
	$main_authentication=$conf->file->main_authentication;
143
	$session_name=session_name();
144
145
	$dol_url_root = DOL_URL_ROOT;
146
147
	// Title
148
	$appli=constant('DOL_APPLICATION_TITLE');
149
	$title=$appli.' '.constant('DOL_VERSION');
150
	if (! empty($conf->global->MAIN_APPLICATION_TITLE)) $title=$conf->global->MAIN_APPLICATION_TITLE;
151
	$titletruedolibarrversion=constant('DOL_VERSION');	// $title used by login template after the @ to inform of true Dolibarr version
152
153
	// Note: $conf->css looks like '/theme/eldy/style.css.php'
154
	$conf->css = "/theme/".(GETPOST('theme','alpha')?GETPOST('theme','alpha'):$conf->theme)."/style.css.php";
155
	$themepath=dol_buildpath($conf->css,1);
156
	if (! empty($conf->modules_parts['theme']))		// Using this feature slow down application
157
	{
158
		foreach($conf->modules_parts['theme'] as $reldir)
159
		{
160
			if (file_exists(dol_buildpath($reldir.$conf->css, 0)))
161
			{
162
				$themepath=dol_buildpath($reldir.$conf->css, 1);
163
				break;
164
			}
165
		}
166
	}
167
	$conf_css = $themepath."?lang=".$langs->defaultlang;
168
169
	// Select templates dir
170
	if (! empty($conf->modules_parts['tpl']))	// Using this feature slow down application
171
	{
172
		$dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl/'));
173
		foreach($dirtpls as $reldir)
174
		{
175
			$tmp=dol_buildpath($reldir.'login.tpl.php');
176
			if (file_exists($tmp)) { $template_dir=preg_replace('/login\.tpl\.php$/','',$tmp); break; }
177
		}
178
	}
179
	else
180
	{
181
		$template_dir = DOL_DOCUMENT_ROOT."/core/tpl/";
182
	}
183
184
	// Set cookie for timeout management
185
	$prefix=dol_getprefix();
186
	$sessiontimeout='DOLSESSTIMEOUT_'.$prefix;
187
	if (! empty($conf->global->MAIN_SESSION_TIMEOUT)) setcookie($sessiontimeout, $conf->global->MAIN_SESSION_TIMEOUT, 0, "/", null, false, true);
188
189
	if (GETPOST('urlfrom','alpha')) $_SESSION["urlfrom"]=GETPOST('urlfrom','alpha');
190
	else unset($_SESSION["urlfrom"]);
191
192
	if (! GETPOST("username",'alpha')) $focus_element='username';
193
	else $focus_element='password';
194
195
	$demologin='';
196
	$demopassword='';
197
	if (! empty($dolibarr_main_demo))
198
	{
199
		$tab=explode(',',$dolibarr_main_demo);
200
		$demologin=$tab[0];
201
		$demopassword=$tab[1];
202
	}
203
204
	// Execute hook getLoginPageOptions (for table)
205
	$parameters=array('entity' => GETPOST('entity','int'));
206
	$reshook = $hookmanager->executeHooks('getLoginPageOptions',$parameters);    // Note that $action and $object may have been modified by some hooks.
207
	if (is_array($hookmanager->resArray) && ! empty($hookmanager->resArray)) {
208
		$morelogincontent = $hookmanager->resArray; // (deprecated) For compatibility
209
	} else {
210
		$morelogincontent = $hookmanager->resPrint;
211
	}
212
213
	// Execute hook getLoginPageExtraOptions (eg for js)
214
	$parameters=array('entity' => GETPOST('entity','int'));
215
	$reshook = $hookmanager->executeHooks('getLoginPageExtraOptions',$parameters);    // Note that $action and $object may have been modified by some hooks.
216
	$moreloginextracontent = $hookmanager->resPrint;
217
218
	// Login
219
	$login = (! empty($hookmanager->resArray['username']) ? $hookmanager->resArray['username'] : (GETPOST("username","alpha") ? GETPOST("username","alpha") : $demologin));
220
	$password = $demopassword;
221
222
	// Show logo (search in order: small company logo, large company logo, theme logo, common logo)
223
	$width=0;
224
	$urllogo=DOL_URL_ROOT.'/theme/login_logo.png';
225
226
	if (! empty($mysoc->logo_small) && is_readable($conf->mycompany->dir_output.'/logos/thumbs/'.$mysoc->logo_small))
227
	{
228
		$urllogo=DOL_URL_ROOT.'/viewimage.php?cache=1&amp;modulepart=mycompany&amp;file='.urlencode('thumbs/'.$mysoc->logo_small);
229
	}
230
	elseif (! empty($mysoc->logo) && is_readable($conf->mycompany->dir_output.'/logos/'.$mysoc->logo))
231
	{
232
		$urllogo=DOL_URL_ROOT.'/viewimage.php?cache=1&amp;modulepart=mycompany&amp;file='.urlencode($mysoc->logo);
233
		$width=128;
234
	}
235
	elseif (is_readable(DOL_DOCUMENT_ROOT.'/theme/'.$conf->theme.'/img/dolibarr_logo.png'))
236
	{
237
		$urllogo=DOL_URL_ROOT.'/theme/'.$conf->theme.'/img/dolibarr_logo.png';
238
	}
239
	elseif (is_readable(DOL_DOCUMENT_ROOT.'/theme/dolibarr_logo.png'))
240
	{
241
		$urllogo=DOL_URL_ROOT.'/theme/dolibarr_logo.png';
242
	}
243
244
	// Security graphical code
245
	$captcha=0;
246
	$captcha_refresh='';
247
	if (function_exists("imagecreatefrompng") && ! empty($conf->global->MAIN_SECURITY_ENABLECAPTCHA))
248
	{
249
		$captcha=1;
250
		$captcha_refresh=img_picto($langs->trans("Refresh"),'refresh','id="captcha_refresh_img"');
251
	}
252
253
	// Extra link
254
	$forgetpasslink=0;
255
	$helpcenterlink=0;
256
	if (empty($conf->global->MAIN_SECURITY_DISABLEFORGETPASSLINK) || empty($conf->global->MAIN_HELPCENTER_DISABLELINK))
257
	{
258
		if (empty($conf->global->MAIN_SECURITY_DISABLEFORGETPASSLINK))
259
		{
260
			$forgetpasslink=1;
261
		}
262
263
		if (empty($conf->global->MAIN_HELPCENTER_DISABLELINK))
264
		{
265
			$helpcenterlink=1;
266
		}
267
	}
268
269
	// Home message
270
	$main_home='';
271
	if (! empty($conf->global->MAIN_HOME))
272
	{
273
	    $substitutionarray=getCommonSubstitutionArray($langs);
274
	    complete_substitutions_array($substitutionarray, $langs);
275
	    $texttoshow = make_substitutions($conf->global->MAIN_HOME, $substitutionarray, $langs);
276
277
		$main_home=dol_htmlcleanlastbr($texttoshow);
278
	}
279
280
	// Google AD
281
	$main_google_ad_client = ((! empty($conf->global->MAIN_GOOGLE_AD_CLIENT) && ! empty($conf->global->MAIN_GOOGLE_AD_SLOT))?1:0);
282
283
	// Set jquery theme
284
	$dol_loginmesg = (! empty($_SESSION["dol_loginmesg"])?$_SESSION["dol_loginmesg"]:'');
285
	$favicon=dol_buildpath('/theme/'.$conf->theme.'/img/favicon.ico',1);
286
	if (! empty($conf->global->MAIN_FAVICON_URL)) $favicon=$conf->global->MAIN_FAVICON_URL;
287
	$jquerytheme = 'smoothness';
288
	if (! empty($conf->global->MAIN_USE_JQUERY_THEME)) $jquerytheme = $conf->global->MAIN_USE_JQUERY_THEME;
289
290
	// Set dol_hide_topmenu, dol_hide_leftmenu, dol_optimize_smallscreen, dol_no_mouse_hover
291
	$dol_hide_topmenu=GETPOST('dol_hide_topmenu','int');
292
	$dol_hide_leftmenu=GETPOST('dol_hide_leftmenu','int');
293
	$dol_optimize_smallscreen=GETPOST('dol_optimize_smallscreen','int');
294
	$dol_no_mouse_hover=GETPOST('dol_no_mouse_hover','int');
295
	$dol_use_jmobile=GETPOST('dol_use_jmobile','int');
296
297
	// Include login page template
298
	include $template_dir.'login.tpl.php';
0 ignored issues
show
Bug introduced by
The variable $template_dir does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
299
300
301
	$_SESSION["dol_loginmesg"] = '';
302
}
303
304
/**
305
 *  Fonction pour initialiser un salt pour la fonction crypt.
306
 *
307
 *  @param		int		$type		2=>renvoi un salt pour cryptage DES
308
 *									12=>renvoi un salt pour cryptage MD5
309
 *									non defini=>renvoi un salt pour cryptage par defaut
310
 *	@return		string				Salt string
311
 */
312
function makesalt($type=CRYPT_SALT_LENGTH)
313
{
314
	dol_syslog("makesalt type=".$type);
315
	switch($type)
316
	{
317
		case 12:	// 8 + 4
318
			$saltlen=8; $saltprefix='$1$'; $saltsuffix='$'; break;
319
		case 8:		// 8 (Pour compatibilite, ne devrait pas etre utilise)
320
			$saltlen=8; $saltprefix='$1$'; $saltsuffix='$'; break;
321
		case 2:		// 2
322
		default: 	// by default, fall back on Standard DES (should work everywhere)
323
			$saltlen=2; $saltprefix=''; $saltsuffix=''; break;
324
	}
325
	$salt='';
326
	while(dol_strlen($salt) < $saltlen) $salt.=chr(mt_rand(64,126));
327
328
	$result=$saltprefix.$salt.$saltsuffix;
329
	dol_syslog("makesalt return=".$result);
330
	return $result;
331
}
332
333
/**
334
 *  Encode or decode database password in config file
335
 *
336
 *  @param   	int		$level   	Encode level: 0 no encoding, 1 encoding
337
 *	@return		int					<0 if KO, >0 if OK
338
 */
339
function encodedecode_dbpassconf($level=0)
340
{
341
	dol_syslog("encodedecode_dbpassconf level=".$level, LOG_DEBUG);
342
	$config = '';
343
	$passwd='';
344
	$passwd_crypted='';
345
346
	if ($fp = fopen(DOL_DOCUMENT_ROOT.'/conf/conf.php','r'))
347
	{
348
		while(!feof($fp))
349
		{
350
			$buffer = fgets($fp,4096);
351
352
			$lineofpass=0;
353
354
			if (preg_match('/^[^#]*dolibarr_main_db_encrypted_pass[\s]*=[\s]*(.*)/i',$buffer,$reg))	// Old way to save crypted value
355
			{
356
				$val = trim($reg[1]);	// This also remove CR/LF
357
				$val=preg_replace('/^["\']/','',$val);
358
				$val=preg_replace('/["\'][\s;]*$/','',$val);
359
				if (! empty($val))
360
				{
361
					$passwd_crypted = $val;
362
					$val = dol_decode($val);
363
					$passwd = $val;
364
					$lineofpass=1;
365
				}
366
			}
367
			elseif (preg_match('/^[^#]*dolibarr_main_db_pass[\s]*=[\s]*(.*)/i',$buffer,$reg))
368
			{
369
				$val = trim($reg[1]);	// This also remove CR/LF
370
				$val=preg_replace('/^["\']/','',$val);
371
				$val=preg_replace('/["\'][\s;]*$/','',$val);
372
				if (preg_match('/crypted:/i',$buffer))
373
				{
374
					$val = preg_replace('/crypted:/i','',$val);
375
					$passwd_crypted = $val;
376
					$val = dol_decode($val);
377
					$passwd = $val;
378
				}
379
				else
380
				{
381
					$passwd = $val;
382
					$val = dol_encode($val);
383
					$passwd_crypted = $val;
384
				}
385
				$lineofpass=1;
386
			}
387
388
			// Output line
389
			if ($lineofpass)
390
			{
391
				// Add value at end of file
392
				if ($level == 0)
393
				{
394
					$config .= '$dolibarr_main_db_pass=\''.$passwd.'\';'."\n";
395
				}
396
				if ($level == 1)
397
				{
398
					$config .= '$dolibarr_main_db_pass=\'crypted:'.$passwd_crypted.'\';'."\n";
399
				}
400
401
				//print 'passwd = '.$passwd.' - passwd_crypted = '.$passwd_crypted;
402
				//exit;
403
			}
404
			else
405
			{
406
				$config .= $buffer;
407
			}
408
		}
409
		fclose($fp);
410
411
		// Write new conf file
412
		$file=DOL_DOCUMENT_ROOT.'/conf/conf.php';
413
		if ($fp = @fopen($file,'w'))
414
		{
415
			fputs($fp, $config);
416
			fflush($fp);
417
			fclose($fp);
418
			clearstatcache();
419
420
			// It's config file, so we set read permission for creator only.
421
			// Should set permission to web user and groups for users used by batch
422
			//@chmod($file, octdec('0600'));
423
424
			return 1;
425
		}
426
		else
427
		{
428
			dol_syslog("encodedecode_dbpassconf Failed to open conf.php file for writing", LOG_WARNING);
429
			return -1;
430
		}
431
	}
432
	else
433
	{
434
		dol_syslog("encodedecode_dbpassconf Failed to read conf.php", LOG_ERR);
435
		return -2;
436
	}
437
}
438
439
/**
440
 * Return a generated password using default module
441
 *
442
 * @param		boolean		$generic		true=Create generic password (32 chars/numbers), false=Use the configured password generation module
443
 * @return		string						New value for password
444
 */
445
function getRandomPassword($generic=false)
446
{
447
	global $db,$conf,$langs,$user;
448
449
	$generated_password='';
450
	if ($generic)
451
	{
452
		$length = 32;
453
		$lowercase = "qwertyuiopasdfghjklzxcvbnm";
454
		$uppercase = "ASDFGHJKLZXCVBNMQWERTYUIOP";
455
		$numbers = "1234567890";
456
		$randomCode = "";
457
		$nbofchar = round($length/3);
458
		$nbofcharlast = ($length - 2*$nbofchar);
459
		var_dump($nbofchar.'-'.$nbofcharlast);
0 ignored issues
show
Security Debugging Code introduced by
var_dump($nbofchar . '-' . $nbofcharlast); looks like debug code. Are you sure you do not want to remove it? This might expose sensitive data.
Loading history...
460
		if (function_exists('random_int'))	// Cryptographic random
461
		{
462
			$max = strlen($lowercase) - 1;
463
			for ($x = 0; $x < $nbofchar; $x++) {
464
				$randomCode .= $lowercase{random_int(0, $max)};
465
			}
466
			$max = strlen($uppercase) - 1;
467
			for ($x = 0; $x < $nbofchar; $x++) {
468
				$randomCode .= $uppercase{random_int(0, $max)};
469
			}
470
			$max = strlen($numbers) - 1;
471
			for ($x = 0; $x < $nbofcharlast; $x++) {
472
				$randomCode .= $numbers{random_int(0, $max)};
473
			}
474
475
			$generated_password=str_shuffle($randomCode);
476
		}
477
		else	// Old platform, non cryptographic random
478
		{
479
			$max = strlen($lowercase) - 1;
480
			for ($x = 0; $x < $nbofchar; $x++) {
481
				$randomCode .= $lowercase{mt_rand(0, $max)};
482
			}
483
			$max = strlen($uppercase) - 1;
484
			for ($x = 0; $x < $nbofchar; $x++) {
485
				$randomCode .= $uppercase{mt_rand(0, $max)};
486
			}
487
			$max = strlen($numbers) - 1;
488
			for ($x = 0; $x < $nbofcharlast; $x++) {
489
				$randomCode .= $numbers{mt_rand(0, $max)};
490
			}
491
492
			$generated_password=str_shuffle($randomCode);
493
		}
494
	}
495
	else if (! empty($conf->global->USER_PASSWORD_GENERATED))
496
	{
497
		$nomclass="modGeneratePass".ucfirst($conf->global->USER_PASSWORD_GENERATED);
498
		$nomfichier=$nomclass.".class.php";
499
		//print DOL_DOCUMENT_ROOT."/core/modules/security/generate/".$nomclass;
500
		require_once DOL_DOCUMENT_ROOT."/core/modules/security/generate/".$nomfichier;
501
		$genhandler=new $nomclass($db,$conf,$langs,$user);
502
		$generated_password=$genhandler->getNewGeneratedPassword();
503
		unset($genhandler);
504
	}
505
506
	return $generated_password;
507
}
508
509