Odyssey
admFunctions.i
1 <?php
2 /**
3  * function Set2FactorAdmin($p_pwd, $p_email, $p_conf_word, $Cn, $setCookieIfNotExists=false)
4  * Set the authentication cookie and test on next login to see if exists.
5  *
6  * @param string $p_pwd -- the password (not clear text; this is after the encrypt method or directly from the user record)
7  * @param string $p_email -- the email of the user
8  * @param string $p_conf_word -- the confidence word
9  * @param array $challengeArray -- the array of challenge questions as if just decoded from the mfaquest column
10  * @param string $Cn -- the logged in user
11  * @param boolean $setCookieIfNotExists -- if true, then the cookie will be set (on login). If false, it is will be updated iff it exists (on security changes).
12  */
13 function Set2FactorAdmin($pSysEnv, $p_pwd, $p_email, $p_conf_word, $challengeArray, $Cn, $setCookieIfNotExists=false)
14 {
15  $p_pwd = trim($p_pwd);
16  $p_email = trim($p_email);
17  $p_conf_word = trim($p_conf_word);
18 
19  $cookiename = sha1("HCUAdminTu0geethSaith7ch" . $Cn);
20 
21  if (!$setCookieIfNotExists && !isset($_COOKIE[$cookiename]))
22  return; // Do nothing.
23 
24  // if more than 23 homecu cookies exist, nuke all except the session cookies
25  if (sizeof($_COOKIE) > 23)
26  {
27  reset ($_COOKIE);
28  $persists = (time() - 3600);
29  foreach ($_COOKIE as $thisCookiename => $cookiecontent)
30  {
31  if (!preg_match("/^(Tx_aURI|aTicket|webconnect|_userc.*)/",$thisCookiename))
32  {
33  HCU_setcookie_env($pSysEnv, $thisCookiename, "", $persists);
34  }
35  }
36  }
37 
38  $addToCookie = array();
39  $challengeArray = HCU_array_key_value("answers", $challengeArray);
40  $challengeArray = $challengeArray === false ? array() : $challengeArray;
41 
42  if (isset($challengeArray))
43  {
44  ksort($challengeArray, SORT_NUMERIC); // Sort the challenge question ids numerically in the off chance that they are not sorted.
45  $find= array("\n", "\\", "=", "|");
46  $replace= array("", "\\\\", "\\=", "\\|"); // Replace = and | so that strings with them in it cannot match what they are not supposed to match.
47  foreach($challengeArray as $questId => $questValue)
48  {
49  $questId= intval($questId);
50  $questValue= trim(str_replace($find, $replace, $questValue));
51  $addToCookie[]= "$questId=$questValue";
52  }
53  }
54  $addToCookie= implode("|", $addToCookie);
55 
56  $cookiecontent=sha1($p_pwd . $p_email . $p_conf_word . $addToCookie);
57 
58  $persists = time() + $pSysEnv['ticket']['persists'];
59  HCU_setcookie_env($pSysEnv, "$cookiename", "$cookiecontent", $persists);
60 }
61 
62 /**
63  * showProductName:
64  *
65  * show the product name for the credit union
66  *
67  * @param string $pName : name of credit union
68  */
69 function showProductName($pName) {
70  ?>
71  <script type='text/javascript'>
72 
73  <?php if ($pName == "NONE" || $pName == "") { ?>
74  $("#logo-bar p.navbar-title").html("&nbsp;");
75  <?php } else { ?>
76  $("#logo-bar p.navbar-title").text("<?php echo $pName ?>");
77  <?php } ?>
78  </script>
79  <?php
80 }
81 
82 /**
83  * checkOrgName:
84  *
85  * get the org name for credit union
86  *
87  * @param string $cu : credit union code
88  * @return string $cu_pname : blank if cu code doesn't exist or pname is NONE
89  */
90 function checkOrgName($cu) {
91  global $dbh;
92 
93  $sqlSelect = "SELECT orgname FROM cuadmin a WHERE cu = '$cu'";
94  $sqlSelectRs = db_query($sqlSelect, $dbh);
95  $sqlData = db_fetch_assoc($sqlSelectRs, 0);
96 
97  $orgname = isset($sqlData['orgname']) ? $sqlData['orgname'] : null;
98  $orgname = $orgname == null ? "" : trim($orgname);
99 
100  return $orgname;
101 }
102 
103 /**
104  * function checkPerm($user, $script, $cu_name)
105  * Moved from the main script a while ago
106  *
107  * @param string $user -- the username
108  * @param string $script -- the script
109  * @param string $cu_name -- the credit union
110  * @return array --
111  * $master -- if the record is the master record for the credit union
112  * $ret_pass -- if they pass?
113  * $ret_su -- if they have master privileges
114  * $ipCheckPassed -- this one is in camelcase. If the ip check passed.
115  */
116 function checkPerm($user, $script, $cu_name)
117 {
118  global $logger, $SYSENV, $dbh;
119 
120  $settings = $SYSENV;
121 
122  $ret_pass = ""; // determines if we passed validation or not
123  $ret_su = 0; // reflects 'allow master privileges' status for non-master
124  $sth = db_query("select trim(user_name), ip_acl from cuadmin where cu='$cu_name';",$dbh);
125  list($master, $ipACL) = db_fetch_array($sth,0);
126 
127  // make sure they have IP access restrictions are set up
128  $ipCheckPassed = false;
129  if ( strlen( $ipACL ) > 0 ) {
130  // make sure the IP addresses start at character offset 1 so the strpos function is easier to test
131  $ipACL = " " . trim( $ipACL );
132 
133  // check if coming in through admin (using HomeCU's static ip addresses)
134  $ipACL .= ";{$settings['admin']['ip_acl']}";
135 
136  // see if user passes
137  $ipAddress = trim( $_SERVER["REMOTE_ADDR"] );
138 
139  if ( strpos( $ipACL, $ipAddress ) > 0 ) {
140  // ip check passed
141  $ipCheckPassed = true;
142  } else {
143  // see if user set up for remote access
144  $sql = "select userflags, remoteip
145  from cuadminusers
146  where lower(user_name) = '" . strtolower(prep_save($user)) . "'
147  and cu = '$cu_name' ";
148  $sth = db_query( $sql, $dbh );
149  list( $userFlags, $remoteIP ) = db_fetch_array( $sth, 0 );
150 
151  if ( ($userFlags & GetAdminUserFlagsValue("ADM_REMOTE_ACCESS_ALLOWED")) > 0 ) {
152  if ( trim( $remoteIP ) == $ipAddress ) {
153  $ipCheckPassed = true;
154  }
155  }
156  }
157 
158  if (!$ipCheckPassed) {
159  $logger->info("Invalid IP Address for service: {$ipAddress}");
160  }
161  } else {
162  $ipCheckPassed = true;
163  }
164 
165  if ($master == "$user") {
166  // For the master user -- Check for script in the cuadminexclude list
167  $sql = "select *
168  from cuadminexclude
169  where cuadminexclude.program = '$script'
170  and cuadminexclude.cu = '$cu_name' ";
171  $ovr_rs = db_query($sql, $dbh);
172  // If the record IS found, permission is denied
173  // FAIL even for master user
174  if (db_num_rows($ovr_rs) > 0) {
175  $ret_pass = 0;
176  } else {
177  $ret_pass = 1;
178  }
179  db_free_result($ovr_rs);
180  } else {
181  // not the master, find out what permissions user has
182 
183  $sql = "select a.user_name
184  from cuadminallow a
185  where lower(a.user_name) = '" . strtolower(prep_save($user)) . "'
186  and program = '$script' and a.cu = '$cu_name'
187  and not exists (select *
188  from cuadminexclude
189  where cuadminexclude.program = a.program
190  and cuadminexclude.cu = '$cu_name') ";
191  $sth = db_query($sql,$dbh);
192  $num = db_num_rows($sth);
193 
194  if (db_num_rows($sth) > 0) {
195  $ret_pass = 1;
196  } else {
197  $ret_pass = 0;
198  $sql = "select userflags from cuadminusers
199  where lower(user_name) = '" . strtolower(prep_save($user)) . "'
200  and cu = '$cu_name'";
201  $sth = db_query($sql,$dbh);
202  list($ret_su) = db_fetch_array($sth,0);
203  $ret_su = ($ret_su & 4);
204  }
205  db_free_result($sth);
206  }
207 
208  return array ($master, $ret_pass, $ret_su, $ipCheckPassed);
209 }
210 
211 
212 
213 /**
214  * function getVariablesForMenu(&$SYSENV)
215  * Gets particular counts that show up on the menu items
216  *
217  * @param $SYSENV -- the system environment variables
218  */
219 function getVariablesForMenu($dbh, &$menuVariables, $Cu)
220 {
221  $menuVariables["secureDocumentsText"] = "Secure Documents";
222  getNewMessageCount($dbh, $menuVariables, $Cu);
223  getAdmCount($dbh, $menuVariables, $Cu);
224  getLoanCount($dbh, $menuVariables, $Cu);
225  getExtCounts($dbh, $menuVariables, $Cu);
226 
227  $docCount = $menuVariables["secureFormCount"] + $menuVariables["messageCount"];
228  $docCount = $docCount > 0 ? ($docCount > 9 ? "9+" : "$docCount") : "";
229  $menuVariables["secureDocumentsText"]= "Secure Documents" . ($docCount == "" ? "" : " <span class='badge'>$docCount</span>");
230 }
231 
232 /**
233  * function getNewMessageCount(&$SYSENV)
234  * Gets the number of unread messages the CU has
235  *
236  * @param $SYSENV -- the system environment variables
237  */
238 function getNewMessageCount($dbh, &$menuVariables, $Cu)
239 {
240  if (trim($Cu) != "")
241  {
242  $sql = "select count(*) from cuadmeco where cu = '$Cu' and origination = 1 and unread and not admdeleted";
243  $sth = db_query($sql, $dbh);
244  list($messageCount) = db_fetch_array($sth,0);
245 
246  $text= "Secure Messages";
247  $menuVariables["messageCount"] = intval($messageCount);
248  $messageCount= $messageCount > 0 ? ($messageCount > 9 ? "9+" : "$messageCount") : "";
249  $menuVariables["messageText"] = "Secure Messages" . ($messageCount == "" ? "" : " <span class='badge'>$messageCount</span>");
250  }
251  else
252  {
253  $menuVariables["messageCount"] = 0;
254  $menuVariables["messageText"] = "Secure Messages";
255  }
256 }
257 
258 /**
259  * function getAdmCount(&$SYSENV)
260  * Gets the count for secure forms
261  *
262  * @param $SYSENV -- the system environment variables
263  */
264 function getAdmCount($dbh, &$menuVariables, $Cu)
265 {
266  if (trim($Cu) != "")
267  {
268  $secpath = "/home/" . strtolower($Cu) . "/sslforms";
269  $secforms = sizeof(glob("$secpath/*.html"));
270  $menuVariables["secureFormCount"] = $secforms;
271  $secformCount = $secforms > 0 ? ($secforms > 9 ? "9+" : "$secforms") : "";
272  $menuVariables["secureFormText"] = "Secure Forms" . ($secformCount == "" ? "" : " <span class='badge'>$secformCount</span>");
273  }
274  else
275  {
276  $menuVariables["secureFormCount"] = 0;
277  $menuVariables["secureFormText"] = "Secure Forms";
278  }
279 }
280 
281 /**
282  * function getLoanCount(&$SYSENV)
283  * Check for a configuration in the lnappconfig table. If a record exists, then show the menu.
284  *
285  * @param $SYSENV -- the system environment variables
286  */
287 function getLoanCount($dbh, &$menuVariables, $Cu)
288 {
289  $sql = "select count(*) from lnappconfig where cu = '$Cu'";
290  $sth = db_query($sql, $dbh);
291  list ($loanCount) = db_fetch_array($sth, 0);
292  $menuVariables["loanCount"] = intval($loanCount);
293 }
294 
295 /**
296  * function getEzCount(&$SYSENV)
297  * Gets the count for the EZ Card
298  *
299  * @param $SYSENV -- the system environment variables
300  */
301 function getExtCounts($dbh, &$menuVariables, $Cu)
302 {
303  if ($Cu != "")
304  {
305  include_once(dirname(__FILE__) . "/../../shared/library/cutrusted.i");
306  # check if this client uses local EZCARD settings
307  $trustedIds= array("hasEZ" => "HcuEZCARD", "hasDMI" => "HcuDMI", "hasMIR" => "HcuMIR"); // with an implode, the values are concatenated. The keys don't matter.
308  $parms = array('Cu' => $Cu, "trustedids" => $trustedIds);
309  $return = cutd_list($dbh, $parms);
310 
311  foreach($trustedIds as $key => $value)
312  {
313  $menuVariables[$key] = isset($return['data']["$Cu|$value"]);
314  }
315 
316  }
317  else
318  {
319  $menuVariables["hasEZ"] = false;
320  $menuVariables["hasDMI"] = false;
321  $menuVariables["hasMIR"] = false;
322  }
323 }
324 
325 /**
326  * function getAdmChallengeQuestions($dbh, $cuCode, $username, $showSQL= false)
327  *
328  * Gets the challenge questions for admin using the new mfaquest column, rather than the table.
329  *
330  * @param integer $dbh -- the database connection
331  * @param string $cuCode -- the CU
332  * @param string $username -- the username to log in as
333  * @param boolean $showSQL -- if true, also include all the SQL
334  *
335  * @throws exception when queries fail or when cu_flagconst.i is not included
336  * @return array("code" => "$code", "errors" => $errors, "data" => $challengeQuestions);
337  */
338 function getAdmChallengeQuestions($dbh, $cuCode, $username, $mode, $actuallyUser=false)
339 {
340  $code= 0;
341  $errors= array();
342  $challengeQuestions= array();
343  $challengeQuestionDDL= array();
344  $sqls= array();
345  $isRandom= false;
346  $noRecord= false;
347  $noChallengeQuestions= false;
348  $forceChallengeQuestions= false;
349  $forcePassword= false;
350  $username= strtolower($username);
351 
352  global $CU2_RANDOM_CHAL;
353  $bitValue= intval($CU2_RANDOM_CHAL);
354 
355  // Get the challenge questions
356  if (!$actuallyUser)
357  $sql = "select au.mfaquest, coalesce(a.flagset2,0) & $bitValue, coalesce(au.userflags, 0) & 2, au.forcechange from cuadminusers au inner join cuadmin a on au.cu = a.cu
358  and lower(au.user_name) = '" . prep_save($username, 50) . "' and au.cu = '" . prep_save($cuCode, 10) . "'";
359  else
360  $sql = "select au.mfaquest, coalesce(a.flagset2,0) & $bitValue, coalesce(au.userflags, 0) & 2, au.forcechange from ${cuCode}user au inner join cuadmin a on lower(au.user_name)='"
361  . prep_save($username, 50) . "' and a.cu = '" . prep_save($cuCode, 10) . "'";
362 
363  $sqls[] = $sql;
364  $sth = db_query($sql, $dbh);
365  if (!$sth)
366  throw new Exception("mfaquest query failed.", 1);
367  if (db_num_rows($sth) == 0)
368  {
369  $noRecord = true;
370  switch($mode)
371  {
372  case "login verify":
373  break; // do nothing because we don't want to give hacker any info.
374  case "login display": // This will pretend that it is a correct login to not give hacker any info.
375  $sql = "select quest_id, quest_text, example_text from cuquestmaster where quest_lang = 'en_US' order by random() limit 3";
376  // Get three random questions when the username or CU is not correct.
377  $sqls[] = $sql;
378  $sth = db_query($sql, $dbh);
379  if (!$sth)
380  throw new Exception("master question query failed.", 2);
381  for($i = 0; $array = db_fetch_assoc($sth, $i); $i++)
382  {
383  $array["answer"] = "";
384  $challengeQuestions[] = $array;
385  }
386  break;
387  default: // Other parts will need to notify the user
388  throw new Exception ("Username record doesn't exist.", 3);
389  break;
390  }
391  }
392  else
393  {
394  $row = db_fetch_row($sth, 0);
395  $encodedAnswers = trim($row[0]);
396  $decodedAnswers = HCU_MFADecode(HCU_JsonDecode($encodedAnswers));
397  unset($encodedAnswers);
398  $isRandom= intval($row[1]) != 0;
399  $forceChallengeQuestions = intval($row[2]) != 0 && in_array($mode, array("login verify", "login display"));
400  $forcePassword= trim($row[3]) == "Y";
401 
402  if (!$forceChallengeQuestions)
403  {
404  switch($mode)
405  {
406  case "login verify":
407  case "login display":
408  case "admin display":
409  if ($decodedAnswers["mfacount"] > 0)
410  {
411  $sql = "select quest_id, quest_text, example_text from cuquestmaster where quest_lang = 'en_US' and quest_id in (" . implode(", ", array_keys($decodedAnswers["answers"]))
412  . ") order by quest_id";
413 
414  $sqls[] = $sql;
415  $sth = db_query($sql, $dbh);
416  if (!$sth)
417  throw new Exception("master question query failed.", 4);
418  for($i = 0; $array = db_fetch_assoc($sth, $i); $i++)
419  {
420  $answer = $decodedAnswers["answers"][$array["quest_id"]];
421  $array["answer"] = $answer == null ? "" : $answer;
422  $challengeQuestions[$array["quest_id"]] = $array;
423  }
424 
425  if ($isRandom && $mode != "admin display")
426  {
427  if (intval($decodedAnswers["challenge"]) == 0)
428  {
429  // Now save with random index
430  $decodedAnswers["challenge"] = array_rand($decodedAnswers["answers"]);
431  $sql= "update cuadminusers set mfaquest = '" . prep_save(PrepareMfaQuestString($decodedAnswers))
432  . "' where lower(user_name) = '" . prep_save($username, 50)
433  . "'" . (trim($cuCode) != "" ? " and cu = '" . prep_save($cuCode, 10) . "'" : "");
434  $sqls[] = $sql;
435  $sth = db_query($sql, $dbh);
436  if (!$sth)
437  throw new Exception("update challenge query failed.", 5);
438  }
439 
440  if (intval($decodedAnswers["challenge"]) > 0)
441  {
442  $challengeQuestions= isset($challengeQuestions[$decodedAnswers["challenge"]]) ? array($challengeQuestions[$decodedAnswers["challenge"]]) : array();
443  }
444  }
445  else // not random, just need a list.
446  {
447  $challengeQuestions = array_values($challengeQuestions);
448  }
449  }
450  else $noChallengeQuestions = true;
451  break;
452  case "security display":
453  $sql = "select quest_id, quest_text, example_text from cuquestmaster where quest_lang = 'en_US' order by quest_id";
454  $sqls[] = $sql;
455  $sth = db_query($sql, $dbh);
456  if (!$sth)
457  throw new Exception("master question query failed.", 6);
458  for($i = 0; $array = db_fetch_assoc($sth, $i); $i++)
459  {
460  $id = HCU_array_key_exists("quest_id", $array) ? intval($array["quest_id"]) : 0;
461  $answer = HCU_array_key_exists($id, $decodedAnswers["answers"]) ? $decodedAnswers["answers"][$id] : null;
462  $challengeQuestionDDL[] = $array;
463  if (isset($answer))
464  {
465  $array["answer"] = $answer;
466  $challengeQuestions[] = $array;
467  }
468  }
469  break;
470  }
471  }
472 
473 
474  }
475 
476  $returnArray= array("code" => "$code", "errors" => $errors, "data" => $challengeQuestions, "noRecord" => $noRecord, "sqls" => $sqls,
477  "requireChallengeQuestions" => $noChallengeQuestions || $forceChallengeQuestions, "forcePassword" => $forcePassword);
478  if ($mode == "security display")
479  $returnArray["ddl"] = $challengeQuestionDDL;
480  return $returnArray;
481 }
482 
483 /**
484  * function loginPrintButtons($isLogin=false, $showStartOver=true)
485  * Prints out the buttons for the login screen
486  *
487  * @param boolean $isLogin -- if true, the label will be changed slightly
488  * @param boolean $showStartOver -- if true, show the start over button
489  */
490 function loginPrintButtons($isLogin = false, $showStartOver = true)
491 {
492  $continueLabel = $isLogin ? "Log In" : "Continue";
493  ?>
494  <div class="form-group hcuSpacer">
495  <div class="col-xs-12 col-sm-6 col-md-4">
496  <button tabindex="0" id="submitBtn" class="k-button k-primary hcu-all-100 hcu-xs-btn-margin-top hcu-xs-btn-pad"><i class="fa fa-lock fa-lg"></i><?php echo $continueLabel; ?></button>
497  </div>
498  <?php if ($showStartOver) { ?>
499  <div class="col-xs-12 col-sm-6 col-md-4">
500  <button tabindex="0" id="clearBtn" class="k-button hcu-all-100 hcu-xs-btn-margin-top hcu-xs-btn-pad"><i class="fa fa-refresh fa-lg"></i>Start Over</button>
501  </div>
502  <?php } ?>
503  </div>
504 <?php }
505 
506 /**
507  * function printButtons($buttonArray, $inModal=false)
508  * Prints out some buttons
509  *
510  * @param array $buttonArray -- an array of buttons
511  * @param boolean $inModal -- if it is in a modal or not
512  */
513 function printButtons($buttonArray, $inModal = false, $inTemplate = false)
514 {
515  $buttonString = "";
516  $buttonString .= "<div class=\"row form-group hcuSpacer hcu-sm-auto-width\">";
517  $buttonFound = false;
518  foreach($buttonArray as $record)
519  {
520  if (HCU_array_key_exists("isLink", $record) && $record["isLink"] !== true)
521  {
522  $buttonFound = true;
523  break;
524  }
525  }
526  foreach($buttonArray as $record)
527  {
528  $primary = HCU_array_key_exists("primary", $record) ? $record["primary"] : false;
529  $primaryClass = $primary === true ? "k-primary" : "";
530  $iconClasses = $primary === true ? "class=\"fa fa-lock fa-lg\"" : "";
531  $sz1 = 12;
532  $sz2 = 6;
533  $sz3 = 3;
534  if ($inModal)
535  {
536  $sz1--;
537  $sz2--;
538  }
539 
540  $sizeClass = HCU_array_key_exists("sizeClass", $record) ? trim($record["sizeClass"]) : "col-md-$sz3";
541  $href = HCU_array_key_exists("href", $record) ? trim($record["href"]) : "";
542  $href = $href == "" ? ($inTemplate ? 'href="\\\\#"' : "href=\"#\"") : "href=\"$href\"";
543  $type = HCU_array_key_exists("isFormSubmit", $record) ? $record["isFormSubmit"] : false;
544  $type = $type === true ? "type=\"submit\"" : "";
545  $disabledClass = HCU_array_key_exists("disabled", $record) ? $record["disabled"] : false;
546  $disabledClass = $disabledClass === true ? "k-state-disabled" : "";
547  $class = HCU_array_key_exists("class", $record) ? trim($record["class"]) : "";
548  $isLink = HCU_array_key_exists("isLink", $record) ? $record["isLink"] : false;
549  $id = HCU_array_key_exists("id", $record) ? trim($record["id"]) : "";
550  $text = HCU_array_key_exists("text", $record) ? trim($record["text"]) : "";
551  $additionalClasses = HCU_array_key_exists("additionalClasses", $record) ? trim($record["additionalClasses"]) : "";
552 
553  $buttonString .= "<div class=\"col-xs-$sz1 col-sm-$sz2 $sizeClass\">";
554  if ($isLink === true)
555  {
556  $buttonString .= "<a $href id=\"$id\" class=\"linkLikeButton $primaryClass $disabledClass $class hcu-xs-100-only hcu-all-100 hcu-xs-btn-margin-top"
557  . " hcu-xs-btn-pad $additionalClasses\">$text</a>";
558  }
559  else
560  {
561  // has to be like this because javascript doesn't handle newlines well.
562  $buttonString .= "<button $type tabindex=\"0\" id=\"$id\" class=\"k-button $primaryClass $disabledClass $class hcu-xs-100-only hcu-all-100 hcu-xs-btn-margin-top";
563  $buttonString .= " hcu-xs-btn-pad $additionalClasses\"><i $iconClasses></i>$text</button>";
564  }
565  $buttonString .= "</div>";
566  }
567  $buttonString .= "</div>";
568  print $buttonString;
569 }
570 
571 /**
572  * function printLabelBlock($labelArray)
573  * Prints out a label block
574  *
575  * @param array $labelArray -- the label block to display
576  */
577 function printHubLabelBlock($labelArray)
578 { ?>
579  <?php foreach($labelArray as $label => $value) { ?>
580  <div class="col-xs-12 col-sm-6">
581  <label><?php echo $label; ?>&nbsp;</label><?php echo trim(str_replace('\\', '\\\\', $value)); ?>
582  </div>
583  <?php } ?>
584 <?php }
585 
586 /**
587  * function loginPrintLabelBlock($labelArray)
588  * Prints out a label block for logins
589  *
590  * @param array $labelArray -- the label block to display
591  */
592 function loginPrintLabelBlock($labelArray)
593 { ?>
594  <div class="form-group col-xs-12"><div class="k-block hcu-login-block"><div class="hcu-summary-block"><div class="summary-desc">
595  <?php foreach($labelArray as $label => $value) { ?>
596  <?php if (trim($value) != "") { ?>
597  <div class="form-group col-xs-12">
598  <label class="col-xs-12"><?php echo $label; ?>&nbsp;</label>
599  <div class="col-xs-12 admIndent"><?php echo trim(str_replace('\\', '\\\\', $value)); ?></div>
600  </div>
601  <?php } ?>
602  <?php } ?>
603  </div></div></div></div>
604 <?php }
605 
606 /**
607  * function loginPrintInputLine($label, $value, $name, $maxlength=0, $autofocus=false, $hasSpacer=true, $type="text", $requiredMsg="", $additionalClasses="")
608  * Prints out an line with an input in it
609  *
610  * @param string $label -- the label to print
611  * @param string $value -- value of input
612  * @param string $name -- the name of the input
613  * @param integer $maxlength -- maxlength of the input (assuming text; otherwise does nothing)
614  * @param boolean|string $autofocus -- if true, "autofocus" attribute is used. If false, it isn't. If it a string, than that is used instead.
615  * @param boolean $hasSpacer -- uses the hcuSpacer class if true
616  * @param string $type -- the type of the input
617  * @param string $requiredMsg -- if nonempty, required attribute is set with data-required-msg set to text here.
618  * @param string $additionalClasses -- these are added to the end of whatever other classes are needed.
619  */
620 function loginPrintInputLine($label, $value, $name, $maxlength=0, $autofocus=false, $hasSpacer=true, $type="text", $requiredMsg="", $additionalClasses="", $deliminated=false)
621 {
622  $requiredMsg = trim($requiredMsg);
623  $requiredText = $requiredMsg == "" ? "" : "required data-required-msg=\"$requiredMsg\"";
624  $autofocusText = $autofocus === true ? "autofocus" : ($autofocus === false ? "" : $autofocus);
625  $spacerText = $hasSpacer ? "hcuSpacer" : "";
626  $maxlengthText = $maxlength == 0 ? "" : "maxlength=\"$maxlength\"";
627  $classes = array("hcu-all-100");
628  $typeText = "type=\"$type\"";
629  $delimStart = $deliminated ? "+ '" : "";
630  $delimEnd = $deliminated ? "'" : "";
631  ?>
632  <?php echo $delimEnd; ?><div class="row form-group <?php echo $spacerText; ?>"><?php echo $delimEnd; ?>
633  <?php echo $delimStart; ?><label class="col-xs-12 col-md-8"><?php echo $label; ?>&nbsp;</label><?php echo $delimEnd; ?>
634  <?php echo $delimStart; ?><div class="col-xs-12 col-md-8"><?php echo $delimEnd; ?>
635  <?php echo $delimStart; ?><input name="<?php echo $name; ?>" class=<?php echo chr(34); if ($type != 'checkbox') { ?>hcu-all-100 k-input k-textbox<?php }?><?php echo $delimEnd; ?>
636  <?php echo $delimStart; ?><?php echo $additionalClasses . chr(34) // fixup code highlighting; ?><?php echo " " . $requiredText; ?> <?php echo $autofocusText ; ?> value="<?php echo $value; ?>" <?php echo $delimEnd; ?>
637  <?php echo $delimStart; ?><?php echo $typeText; ?> <?php echo $maxlengthText; ?>>
638 
639  <p data-for=<?php echo chr(34) . $name . chr(34); ?> class="k-invalid-msg"></p></div></div><?php echo $delimEnd; ?>
640 <?php }
641 
642 function dialogPrintInputLine($label, $value, $name, $maxlength = 0, $autofocus = false, $type = "text", $padding=false, $additionalClasses = "", $delimiter = true, $usePlus = true,
643  $thankYouSirMayIHaveAnother = false)
644 {
645  $delimiter = $delimiter === true ? "'" : ($delimiter === false ? "" : $delimiter);
646  $usePlus = !$delimiter || !$usePlus ? "" : "+";
647  $padding = !$padding ? "hcu-no-padding" : "";
648  $spacingA = !$thankYouSirMayIHaveAnother ? "col-xs-4" : "col-xs-3";
649  $spacingB = !$thankYouSirMayIHaveAnother ? "col-xs-8" : "col-xs-9";
650  print "$usePlus $delimiter<div class=\"row hcuSpacer\"><label class=\"$spacingA $padding\">$label</label><div class=\"$spacingB $padding\">"
651  . "<input value=\"$value\" id=\"$name\" name=\"$name\" type=\"$type\" " . ($maxlength != 0 ? "maxlength=\"$maxlength\"" : "") . "$autofocus class=\"hcu-all-100 k-input k-textbox $additionalClasses\">"
652  . "</div></div>$delimiter";
653 }
654 
655 function dialogPrintCheckboxLine($name, $text, $checked=true, $additionalClasses = "", $offset = true, $padding = true, $delimiter = true, $usePlus = true,
656  $thankYouSirMayIHaveAnother = false)
657 {
658  $delimiter = $delimiter === true ? "'" : ($delimiter === false ? "" : $delimiter);
659  $usePlus = !$delimiter || !$usePlus ? "" : "+";
660  $checked = $checked === true ? "checked" : ($checked === false ? "" : $checked);
661  $padding = $padding ? "" : "hcu-no-padding";
662  $spacingA = !$thankYouSirMayIHaveAnother ? "col-xs-4" : "col-xs-3";
663  $spacingB = !$thankYouSirMayIHaveAnother ? "col-xs-8" : "col-xs-9";
664  $offset = $offset ? "<label class=\"$spacingA $padding\">&nbsp;</label>" : "";
665  print "$usePlus $delimiter<div class=\"row hcuSpacer\">$offset"
666  . "<div class=\"$spacingB checkbox $padding $additionalClasses\"><label><input name=\"$name\" type=\"checkbox\" $checked>$text</label></div></div>$delimiter";
667 }
668 
669 /**
670  * function printCheckboxLine($label, $name, $checked=false, $hasSpacer=true, $additionalClasses)
671  * Prints out a checkbox line
672  *
673  * @param string $label -- the label to print
674  * @param string $name -- the name of the input
675  * @param boolean $checked -- if true, the "checked" attribute is added
676  * @param boolean $hasSpacer -- uses the hcuSpacer class if true
677  * @param string $additionalClasses -- these are added to the end of whatever other classes are needed.
678  */
679 function printCheckboxLine($label, $name, $checked=false, $hasSpacer=true, $additionalClasses="")
680 {
681  $spacerText = $hasSpacer ? "hcuSpacer" : "";
682  $checkedText = $checked === true ? "checked" : ($checked === false ? "" : $checked);
683  ?>
684  <div class="row form-group <?php echo $spacerText; ?>">
685  <label class="col-xs-10 col-md-10"><?php echo $label; ?>&nbsp;</label>
686  <div class="col-xs-1 col-md-1">
687  <input name="<?php echo $name; ?>" type="checkbox" <?php echo $checkedText; ?> class="<?php echo $additionalClasses; ?>">
688  </div>
689  </div>
690 <?php }
691 
692 /**
693  * function loginPrintDivLine($label, $id, $hasSpacer=true, $classes="hcu-all-100")
694  * Prints out a DIV line for login
695  *
696  * @param string $label -- the label to print
697  * @param string $id -- the id of the DIV
698  * @param boolean $hasSpacer -- uses the hcuSpacer class if true
699  * @param string $classes -- what classes to add?
700  */
701 function loginPrintDivLine($label, $id, $hasSpacer=true, $classes="hcu-all-100")
702 { ?>
703  <div class="row form-group <?php echo $hasSpacer ? 'hcuSpacer' : ''; ?>">
704  <?php if (trim($label) != "") { ?>
705  <label class="col-xs-12 col-md-8"><?php echo $label; ?>&nbsp;</label>
706  <?php } ?>
707  <div class="col-xs-12 col-md-8">
708  <div id="<?php echo $id; ?>" class="<?php echo $classes; ?>"></div>
709  </div>
710  </div>
711 <?php }
712 
713 /**
714  * function printHeader($message, $isModal=false)
715  * Prints a header
716  *
717  * @param string $message -- the message
718  * @param boolean $isModal -- if modal or not
719  */
720 function printHeader($message, $isModal=false)
721 {
722  printSimple("<h4 class=\"h4 hcuSpacerx\">$message</h4>", $isModal);
723 }
724 
725 /**
726  * function printMessage($message, $isModal=false)
727  * Prints a message
728  *
729  * @param string $message -- the message
730  * @param boolean $isModal -- if modal or not
731  */
732 function printMessage($message, $isModal=false)
733 {
734  printSimple($message, $isModal);
735 }
736 
737 /**
738  * function printGridDiv($message, $isModal=false)
739  * Prints a grid DIV
740  *
741  * @param string $id -- the id of the grid
742  * @param boolean $isModal -- if modal or not
743  */
744 function printGridDiv($id, $isModal=false)
745 {
746  printSimple("<div id='$id'></div>", $isModal);
747 }
748 
749 /**
750  * function printSimple($message, $isModal=false)
751  * Prints a simple line thingy
752  *
753  * @param string $line -- the line
754  * @param boolean $isModal -- if modal or not
755  */
756 function printSimple($line, $isModal=false)
757 {
758  $sz = $isModal ? 11 : 12;
759  ?>
760  <div class="row form-group"><div class="col-xs-<?php echo $sz; ?>"><?php echo $line; ?></div></div>
761 <?php }
762 
763 /**
764  * function checkPass($dbh, $username, $password, $chksecure)
765  *
766  * @param array $pSysEnv - This is the current system environment settings from main
767  * @param integer $dbh -- the database connection
768  * @param string $username -- the username to check
769  * @param string $password -- the password to check
770  * @param boolean $chksecure -- if true, create a coooooooooooookkkkiee
771  *
772  * @throws "Invalid User Name or Password"
773  * @return array("code" => 0, "error" => "", "expired" => {true/false});
774  */
775 function checkPass($pSysEnv, $dbh, $username, $password, $cu, $chksecure, $creditUnionCookieName = "", $creditUnionCookieKey = "", $accessCheck = false, $email = "",
776  $doUnionStuff = true, $isSkip = false, $setCookieIfNotExists = true)
777 {
778  $code = 0;
779  $sqls = array();
780  $error = "";
781  global $MEM_FORCE_RESET;
782 
783  try
784  {
785  $TicketExpires = (array_key_exists('expires', $pSysEnv['ticket']) ? $pSysEnv['ticket']['expires'] : 900);
786 
787  $username = strtolower(trim($username));
788  $sql = "select trim(a.pname), trim(au.passwd), trim(au.cu), db, lastupdate, livebatch, au.failedremain, au.forceremain, au.forcechange, au.pwchange, au.lastlogin, au.failedlogin, a.flagset, a.flagset2, a.flagset3, trim(au.email), trim(au.confidence), au.userflags & {$MEM_FORCE_RESET}::int4, au.mfaquest from cuadmin a join cuadminusers au on a.cu = au.cu
789  where lower(au.user_name)='" . prep_save($username) . "' and au.cu= '" . prep_save($cu) . "' limit 1";
790  $sqls[] = $sql;
791  $sth = db_query($sql,$dbh);
792  if (!$sth)
793  throw new exception("User query failed.", 4);
794  if (db_num_rows($sth) == 0)
795  throw new Exception("User not found.", 3);
796  list($savename, $savepass,$cu, $db, $lastupdate, $lb, $failedremain, $fremain, $fchange, $pchange, $llog, $flog, $flagset, $flagset2, $flagset3,
797  $savemail,$saveword, $freset, $mfa) = db_fetch_array($sth,0);
798 
799  $failedremain = (is_null($failedremain) ? 5 : $failedremain);
800  $fremain = (is_null($fremain) ? 5 : $fremain);
801  $fchange = (is_null($fchange) ? 'N' : $fchange);
802  $db = (trim($db)=="" ? "_" : strtoupper(rtrim($db)));
803  $lastupdate = (trim("$lastupdate")=="" ? "Unknown" : urlencode(trim($lastupdate)));
804  $lb = (is_null($lb) ? "B" : strtoupper(rtrim($lb)));
805  $flagset = (is_null($flagset) ? 0 : $flagset);
806  $flagset2 = (is_null($flagset2) ? 0 : $flagset2);
807  $flagset3 = (is_null($flagset3) ? 0 : $flagset3);
808 
809  if ($doUnionStuff)
810  {
811  if ($failedremain <= 0 || (($fchange =='Y' || $freset != 0) && $fremain <=0))
812  throw new Exception("Account is Locked", 1);
813 
814  $email = trim($email);
815  if ($accessCheck && strtolower(trim($savemail)) != strtolower($email) && trim($savemail) != '')
816  throw new exception("Email doesn't match.", 5);
817 
818  if (!password_verify($password, $savepass))
819  throw new Exception("Password doesn't match.", 2);
820  }
821 
822  $pchange = (is_null($pchange) ? date('Ymd') : $pchange);
823  $llog = (trim("$llog")=="" ? "None" : urlencode(trim($llog)));
824  $flog = (trim("$flog")=="" ? "None" : urlencode(trim($flog)));
825 
826  $now = time();
827  $expires = $now + $TicketExpires;
828  $ip_address = $_SERVER['REMOTE_ADDR'];
829 
830  $mycookie = "Cip=$ip_address&Ctime=$now&Cu=$cu&Cn=$username&Cname=$savename&Cd=$db&Ch=hash&Ce=$expires&Cl=$lb&Clu=$lastupdate&Fplog=$llog&Fflog=$flog&Ffchg=$fchange"
831  . "&Ffremain=$fremain&Fset=$flagset&Fset2=$flagset2&Fset3=$flagset3";
832 
833  Set_aTicket($pSysEnv, "","$mycookie");
834 
835  apache_note('user_name',"${cu}:${username}");
836 
837  $mfa = HCU_JsonDecode($mfa);
838  if (!is_array($mfa))
839  $mfa = array("answers" => array());
840  $mfa["challenge"] = 0; // Reset because of successful login
841 
842  if (!$accessCheck && $chksecure == 'Y')
843  Set2FactorAdmin($pSysEnv, $savepass, $savemail, $saveword, $mfa, $username, $setCookieIfNotExists);
844 
845  $sql = "select admtrackmfa('$cu','$username', '" . ($isSkip ? $fchange : "N") . "','$pchange', '" . prep_save(PrepareMfaQuestString($mfa)) . "')";
846  $sqls[] = $sql;
847  $sth = db_query($sql,$dbh);
848 
849  $expired = $doUnionStuff && $fchange == 'Y';
850  if ($doUnionStuff)
851  {
852  $persists = time() + $pSysEnv['ticket']['persists'];
853  $ticketContents = hcuOpenSSLEncrypt($cu, "NONE");
854 
855  HCU_setcookie_env($pSysEnv, $creditUnionCookieName, $ticketContents["message"], $persists);
856  HCU_setcookie_env($pSysEnv, "${creditUnionCookieName}Hash", $ticketContents["hash"], $persists);
857  }
858 
859  }
860  catch(exception $e)
861  {
862  if ($e->getCode() != 1) // All get failed logging EXCEPT for locked account.
863  {
864  $sql = "select admfailmfa('$cu', '$username',32, '$mfa')";
865  $sqls[] = $sql;
866  $sth = db_query($sql, $dbh);
867  throw new Exception("Invalid User Name or Password.", 1);
868  }
869  }
870 
871  $answers = HCU_array_key_value("answers", $mfa);
872  $hasAnswers = $answers === false ? false : count($answers) > 0;
873  $returnArray = array("code" => "$code", "error" => "$error", "expired" => $expired, "cookie" => $mycookie, "forceSecurity" => $freset != 0 || !$hasAnswers,
874  "forcePassword" => $fchange == "Y");
875  return $returnArray;
876 }
877 
878 /**
879  * function printCaptureEnter()
880  * Prints code for capturing the enter key
881  */
882 function printCaptureEnter()
883 { ?>
884  $("body").on("keypress", "input,.k-button", function(e) {
885  if ([10, 13].indexOf(e.which) != -1)
886  $(this).hasClass("k-button") ? $(this).click() : $(this).closest("form").submit();
887  });
888 <?php }
889 
890 /**
891  * function printCheckboxEvents($gridSelector, $deleteBtnSelector="", $closest="", $allCheckbox=".allCheckbox", $rowCheckbox=".rowCheckbox")
892  * Prints out the logic for the checkbox columns on some grids
893  *
894  * @param string $gridSelector -- the jQuery selector of the grid with the checkboxes
895  * @param string $deleteBtnSelector -- the jQuery selector of the delete button that gets enabled/disabled based on if any checkboxes are checked.
896  * @param string $closest -- the jQuery selector of the intermediary table. Mostly unused.
897  * @param string $allCheckbox -- the jQuery selector of the allCheckbox
898  * @param string $rowCheckbox -- the jQuery selector of the rowCheckbox
899  */
900 function printCheckboxEvents($gridSelector, $deleteBtnSelector="", $closest="", $allCheckbox=".allCheckbox", $rowCheckbox=".rowCheckbox", $rowMethod="")
901 {
902  if ($closest == "")
903  {
904  $closestCommand = "";
905  $rcSelector = "$gridSelector $rowCheckbox:enabled";
906  $rcCheckedSelector = "\$(\"$rcSelector:checked\")";
907  $rcNotCheckedSelector = "\$(\"$rcSelector:not(:checked)\")";
908  $acSelector = "\$(\"$gridSelector $allCheckbox\")";
909  $rcSelector = "\$(\"$rcSelector\")";
910  }
911  else
912  {
913  $closestCommand = "var intermediate= \$(this).closest(\"$closest\");";
914  $rcSelector = "\$(intermediate).find(\"$rowCheckbox";
915  $rcCheckedSelector = "$rcSelector:checked\")";
916  $rcNotCheckedSelector = "$rcSelector:not(:checked)\")";
917  $acSelector = "\$(intermediate).find(\"$allCheckbox\")";
918  $rcSelector = "$rcSelector\")";
919  }
920  ?>
921  $("<?php echo $gridSelector; ?>").on("click", "<?php echo $allCheckbox; ?>", function() {
922  var checked = $(this).prop("checked");
923  var data = $("<?php echo $gridSelector; ?>").data("kendoGrid").dataSource.view(); <?php // Data to view: important when using a filter with the table in the case of access control. ?>
924  for(var i = 0; i != data.length; i++)
925  {
926  data[i].checked = checked;
927  }
928 
929  <?php if ($rowMethod != "") { ?>
930  if (typeof(<?php echo $rowMethod; ?>) == "function")
931  {
932  if (checked)
933  {
934  <?php echo $rcNotCheckedSelector; ?>.each(function() {
935  (<?php echo $rowMethod; ?>)(checked, $(this));
936  });
937  }
938  else
939  {
940  <?php echo $rcCheckedSelector; ?>.each(function() {
941  (<?php echo $rowMethod; ?>)(checked, $(this));
942  });
943  }
944  }
945  <?php } ?>
946 
947  <?php echo $closestCommand; ?>
948  <?php echo $rcSelector; ?>.prop("checked", checked);
949 
950  <?php if ($deleteBtnSelector != "") { ?>
951  if (<?php echo $rcCheckedSelector; ?>.length > 0)
952  $("<?php echo $deleteBtnSelector; ?>").removeClass("k-state-disabled vsgDisabled");
953  else
954  $("<?php echo $deleteBtnSelector; ?>").addClass("k-state-disabled vsgDisabled");
955  <?php } ?>
956  });
957 
958  $("<?php echo $gridSelector; ?>").on("click", "<?php echo $rowCheckbox; ?>", function() {
959  var checked = $(this).prop("checked");
960  var dataItem = $("<?php echo $gridSelector; ?>").data("kendoGrid").dataItem($(this).closest("tr"));
961  dataItem.checked = checked;
962 
963  <?php echo $closestCommand; ?>
964  if (checked && <?php echo $rcNotCheckedSelector; ?>.length == 0)
965  <?php echo $acSelector; ?>.prop("checked", true);
966  else if (!checked)
967  <?php echo $acSelector; ?>.prop("checked", false);
968 
969  <?php if ($deleteBtnSelector != "") { ?>
970  if (<?php echo $rcCheckedSelector; ?>.length > 0)
971  $("<?php echo $deleteBtnSelector; ?>").removeClass("k-state-disabled vsgDisabled");
972  else
973  $("<?php echo $deleteBtnSelector; ?>").addClass("k-state-disabled vsgDisabled");
974  <?php } ?>
975 
976  <?php if ($rowMethod != "") { ?>
977  if (typeof(<?php echo $rowMethod; ?>) == "function")
978  (<?php echo $rowMethod; ?>)(checked, $(this));
979  <?php } ?>
980  });
981 
982  <?php if ($closest == "") { ?>
983  var setAllCheckbox = <?php echo $rcSelector; ?>.length > 0 && <?php echo $rcNotCheckedSelector; ?>.length == 0;
984  <?php echo $acSelector; ?>.prop("checked", setAllCheckbox);
985  <?php } else { ?>
986  $("<?php echo "$gridSelector $closest"; ?>").each(function() {
987  var intermediate = $(this);
988  var setAllCheckbox = <?php echo $rcSelector; ?>.length > 0 && <?php echo $rcNotCheckedSelector; ?>.length == 0;
989  <?php echo $acSelector; ?>.prop("checked", setAllCheckbox);
990  });
991  <?php } ?>
992 
993  var thisParticularGrid= $("<?php echo $gridSelector; ?>").data("kendoGrid");
994  thisParticularGrid.bind("filter", function(e) {
995  if (!$("<?php echo $gridSelector; ?>").data("inFilter"))
996  {
997  $("<?php echo $gridSelector; ?>").data("inFilter", true);
998 
999  thisParticularGrid.dataSource.filter(e.filter);
1000 
1001  <?php if ($closest == "") { ?>
1002  var setAllCheckbox = <?php echo $rcSelector; ?>.length > 0 && <?php echo $rcNotCheckedSelector; ?>.length == 0;
1003  <?php echo $acSelector; ?>.prop("checked", setAllCheckbox);
1004  <?php } else { ?>
1005  $("<?php echo "$gridSelector $closest"; ?>").each(function() {
1006  var intermediate = $(this);
1007  var setAllCheckbox = <?php echo $rcSelector; ?>.length > 0 && <?php echo $rcNotCheckedSelector; ?>.length == 0;
1008  <?php echo $acSelector; ?>.prop("checked", setAllCheckbox);
1009  });
1010  <?php } ?>
1011 
1012  <?php if ($deleteBtnSelector != "") { ?>
1013  if (<?php echo $rcCheckedSelector; ?>.length > 0)
1014  $("<?php echo $deleteBtnSelector; ?>").removeClass("k-state-disabled");
1015  else
1016  $("<?php echo $deleteBtnSelector; ?>").addClass("k-state-disabled");
1017  <?php } ?>
1018 
1019  $("<?php echo $gridSelector; ?>").data("inFilter", false);
1020  }
1021  });
1022 <?php }
1023 
1024 /**
1025  * function validatePasswordRules($dbh, $cuCode, $showSQL, $password, $addRuleErrors)
1026  *
1027  * Validates the password rules for admin
1028  *
1029  * @param integer $dbh The database connection
1030  * @param string $cuCode The Credit Union
1031  * @param integer $userId The userId of the ${cuCode}user record.
1032  * @param boolean $showSQL If true, SQL is available for debug.
1033  * @param string $password The password to check.
1034  * @param boolean $addRuleErrors If true, if the password doesn't have the requirements, then it add errors. Otherwise, it just populates the forceChange boolean.
1035  *
1036  * @return array("code" => integer, "errors" => array(), "data" => array(), "validForAdmin" => boolean, "forceChange" => boolean);
1037  * If there are errors, code is non-zero. If $includeSQL is true, then array("sqls" => array()) is also available.
1038  * "validForAdmin" -- If there are any illegal characters then the password isn't valid even for admin.
1039  * "forceChange" -- If any of the password rules fails, then this will be true.
1040  */
1041 function validatePasswordRules($dbh, $cuCode, $showSQL, $password, $addRuleErrors)
1042 {
1043  $errors = array();
1044  $sqls = array();
1045  $code = 0;
1046  $validForAdmin = true;
1047  $forceChange = false;
1048 
1049  $sql = "select pwdconfig from cuadmin where cu='$cuCode'";
1050  $sqls[] = $sql;
1051  if (($sth = db_query($sql, $dbh)) === false)
1052  {
1053  $code |= 1;
1054  $errors[] = db_last_error();
1055  }
1056  else
1057  {
1058  $rules = trim(db_fetch_row($sth, 0)[0]);
1059  if ($rules != "")
1060  {
1061  $rules = HCU_JsonDecode($rules);
1062  if (!is_array($rules))
1063  {
1064  $code |= 2;
1065  $errors[] = "Password rules is not a valid json array.";
1066  }
1067  else
1068  {
1069  if (!isset($rules["use"]) || $rules["use"] != 1)
1070  $rules = array("len" => 6, "letter" => 1, "digit" => 1);
1071 
1072  if (isset($rules["len"]) && strlen($password) < $rules["len"])
1073  {
1074  $code |= 4;
1075  $errors[] = "Password is too short.";
1076  $forceChange = true;
1077  }
1078 
1079  preg_match('/\d/', $password, $numDigits);
1080  preg_match('/[[:lower:]]/', $password, $numLower);
1081  preg_match('/[[:upper:]]/', $password, $numUpper);
1082  preg_match('/[!#@$%^&*?_~()-]/', $password, $numSpec);
1083  preg_match('/[\'"]/', $password, $numInvalid);
1084 
1085  if (isset($rules["digit"]) && $numDigits < $rules["digit"])
1086  {
1087  if ($addRuleErrors)
1088  {
1089  $code |= 8;
1090  $errors[] = "Password needs " . $rules["digit"] . " digits.";
1091  }
1092  $forceChange = true;
1093  }
1094 
1095  if (isset($rules["lower"]) && $numLower < $rules["lower"])
1096  {
1097  if ($addRuleErrors)
1098  {
1099  $code |= 16;
1100  $errors[] = "Password needs " . $rules["lower"] . " lower letters.";
1101  }
1102  $forceChange = true;
1103  }
1104 
1105  if (isset($rules["upper"]) && $numUpper < $rules["upper"])
1106  {
1107  if ($addRuleErrors)
1108  {
1109  $code |= 32;
1110  $errors[] = "Password needs " . $rules["upper"] . " upper letters.";
1111  }
1112  $forceChange = true;
1113  }
1114 
1115  if (isset($rules["spec"]) && $numUpper < $rules["spec"])
1116  {
1117  if ($addRuleErrors)
1118  {
1119  $code |= 64;
1120  $errors[] = "Password needs " . $rules["spec"] . " special characters.";
1121  }
1122  $forceChange = true;
1123  }
1124 
1125  if ($numInvalid > 0)
1126  {
1127  $errors[] = "Password has illegal characters.";
1128  $validForAdmin = false;
1129  }
1130  }
1131  }
1132  }
1133 
1134  db_free_result($sth);
1135  $returnArray= array("code" => "$code", "errors" => $errors, "validForAdmin" => $validForAdmin, "forceChange" => $forceChange);
1136  if ($showSQL)
1137  $returnArray["sqls"]= $sqls;
1138  return $returnArray;
1139 }
1140 
1141 /**
1142  * function printJavascriptHashCode()
1143  * Gets a hashCode function similar to Java in JavaScript.
1144  * @link http://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/
1145  */
1146 function printJavascriptHashCode()
1147 { ?>
1148  String.prototype.hashCode = function()
1149  {
1150  var hash = 0;
1151  if (this.length == 0) return hash;
1152  for (i = 0; i < this.length; i++)
1153  {
1154  char = this.charCodeAt(i);
1155  hash = ((hash << 5)-hash)+char;
1156  hash = hash & hash; // Convert to 32bit integer
1157  }
1158  return hash;
1159  }
1160 <?php }
1161 
1162 
1163 /*--------------------------------------------
1164 Admin delete functions that will be used in user, group, and member hubs.
1165 ----------------------------------------------*/
1166 
1167 /**
1168  * function userDeletion($dbh, $Cu, $userId, &$sqls)
1169  * This will delete from all tables attached to the user.
1170  *
1171  * @param $dbh -- the database connection
1172  * @param $Cu -- the credit union
1173  * @param $userId -- the userId
1174  * @param $sqls -- the array to append SQLs to.
1175  *
1176  * @throws errors between 100 and 200 which will fail the transaction defined at a higher level.
1177  */
1178 function userDeletion($dbh, $Cu, $userId, &$sqls)
1179 {
1180  $sql = "delete from ${Cu}extaccount where user_id= $userId";
1181  $sqls[] = $sql;
1182  $sth = db_query($sql, $dbh);
1183  if (!$sth)
1184  throw new exception("extaccount delete failed.", 106);
1185 
1186  $sql = "delete from ${Cu}transdtl where id in (select dtl.id from ${Cu}transdtl dtl inner join ${Cu}transhdr hdr on dtl.transhdr_id = hdr.id and hdr.posted_by = $userId)";
1187  $sqls[] = $sql;
1188  $sth = db_query($sql, $dbh);
1189  if (!$sth)
1190  throw new exception("dtl delete failed.", 107);
1191 
1192  $sql = "delete from ${Cu}transhdr where posted_by = $userId";
1193  $sqls[] = $sql;
1194  $sth = db_query($sql, $dbh);
1195  if (!$sth)
1196  throw new exception("hdr delete failed.", 108);
1197 
1198  $sql = "delete from cu_alerts where user_id= $userId and cu= '$Cu'";
1199  $sqls[] = $sql;
1200  $sth = db_query($sql, $dbh);
1201  if (!$sth)
1202  throw new exception("cu_alerts delete failed.", 110);
1203 
1204  $sql = "delete from ${Cu}userrights where user_id= $userId";
1205  $sqls[] = $sql;
1206  $sth = db_query($sql, $dbh);
1207  if (!$sth)
1208  throw new exception("userrights delete failed.", 112);
1209 
1210  $sql = "delete from ${Cu}usercontact where contact_id in (select contact from ${Cu}user where user_id= $userId)";
1211  $sqls[] = $sql;
1212  $sth = db_query($sql, $dbh);
1213  if (!$sth)
1214  throw new exception("usercontact delete failed.", 113);
1215 
1216  $sql = "delete from ${Cu}useraccounts where user_id= $userId";
1217  $sqls[] = $sql;
1218  $sth = db_query($sql, $dbh);
1219  if (!$sth)
1220  throw new exception("useraccounts delete failed.", 114);
1221 
1222  $sql = "delete from ${Cu}memberacctrights where user_id= $userId";
1223  $sqls[] = $sql;
1224  $sth = db_query($sql, $dbh);
1225  if (!$sth)
1226  throw new exception("memberacctrights delete failed.", 115);
1227 
1228  $sql = "delete from ${Cu}user where user_id= $userId";
1229  $sqls[] = $sql;
1230  $sth = db_query($sql, $dbh);
1231  if (!$sth)
1232  throw new exception("user delete failed.", 116);
1233 
1234  $sql = "delete from ${Cu}extkey where user_id= $userId";
1235  $sqls[] = $sql;
1236  $sth = db_query($sql, $dbh);
1237  if (!$sth)
1238  throw new exception("extkey failed.", 139);
1239 
1240  $sql = "delete from cusmstransaction where user_id= $userId and cu='$Cu'";
1241  $sqls[] = $sql;
1242  $sth = db_query($sql, $dbh);
1243  if (!$sth)
1244  throw new exception("cusmstransaction failed.", 140);
1245 
1246  $sql = "delete from cuadmeco where user_id= $userId and cu='$Cu'";
1247  $sqls[] = $sql;
1248  $sth = db_query($sql, $dbh);
1249  if (!$sth)
1250  throw new exception("cuadmeco failed.", 141);
1251 
1252  $sql = "delete from cucmsresponse where user_id= $userId and cu='$Cu'";
1253  $sqls[] = $sql;
1254  $sth = db_query($sql, $dbh);
1255  if (!$sth)
1256  throw new exception("cucmsresponse failed.", 142);
1257 
1258  $sql = "delete from cusmstrack where user_id= $userId and cu='$Cu'";
1259  $sqls[] = $sql;
1260  $sth = db_query($sql, $dbh);
1261  if (!$sth)
1262  throw new exception("cusmstrack failed.", 143);
1263 
1264  $sql = "delete from cusms where user_id= $userId and cu='$Cu'";
1265  $sqls[] = $sql;
1266  $sth = db_query($sql, $dbh);
1267  if (!$sth)
1268  throw new exception("cusms failed.", 144);
1269 
1270  $sql = "delete from cu_scheduledtxn where user_id= $userId and cu='$Cu'";
1271  $sqls[] = $sql;
1272  $sth = db_query($sql, $dbh);
1273  if (!$sth)
1274  throw new exception("cu_scheduledtxn failed.", 145);
1275 }
1276 
1277 /**
1278  * function groupDeletion($dbh, $Cu, $groupId, &$sqls)
1279  * This will delete from all tables attached to the group.
1280  *
1281  * @param $dbh -- the database connection
1282  * @param $Cu -- the credit union
1283  * @param $groupId -- the group id
1284  * @param $sqls -- the array to append the SQLs to.
1285  *
1286  * @throws errors between 100 and 200 which will fail the transaction defined at a higher level.
1287  */
1288 function groupDeletion($dbh, $Cu, $groupId, &$sqls)
1289 {
1290  $sql = "delete from ${Cu}grouprights where group_id= $groupId";
1291  $sqls[] = $sql;
1292  $sth = db_query($sql, $dbh);
1293  if (!$sth)
1294  throw new exception("grouprights delete failed.", 117);
1295 
1296  $sql = "delete from ${Cu}achpartner where group_id= $groupId";
1297  $sqls[] = $sql;
1298  $sth = db_query($sql, $dbh);
1299  if (!$sth)
1300  throw new exception("achpartner delete failed.", 118);
1301 
1302  $sql = "delete from ${Cu}usercontact where contact_id in (select contact from ${Cu}group where group_id= $groupId)";
1303  $sqls[] = $sql;
1304  $sth = db_query($sql, $dbh);
1305  if (!$sth)
1306  throw new exception("usercontact delete failed.", 131);
1307 
1308  $sql = "delete from ${Cu}group where group_id= $groupId";
1309  $sqls[] = $sql;
1310  $sth = db_query($sql, $dbh);
1311  if (!$sth)
1312  throw new exception("group delete failed.", 121);
1313 }
1314 
1315 /**
1316  * function accountDeletion($dbh, $Cu, $accountnumber, &$sqls, $allMeansAll=false)
1317  * This will delete from all tables attached to the account.
1318  *
1319  * @param $dbh -- the database connection
1320  * @param $Cu -- the credit union
1321  * @param $accountnumber -- the accountnumber
1322  * @param $sqls -- the array to append the SQLs to.
1323  * @param $allMeansAll -- if true, then it will also delete accountnumber records from tables that have both an user_id and an accountnumber column.
1324  *
1325  * @throws errors between 100 and 200 which will fail the transaction defined at a higher level.
1326  */
1327 function accountDeletion($dbh, $Cu, $accountnumber, &$sqls, $allMeansAll=false)
1328 {
1329  // These are the tables that have both an accountnumber and a userid. If coming from user delete, we don't want to delete all for the accountnumber here.
1330  // Instead, we want to fail the transaction if the accountnumber is used by another user. These tables are deleted according to the user id in the user deletion function.
1331  if ($allMeansAll)
1332  {
1333  $sql = "delete from ${Cu}extkey where trim(accountnumber) = '" . prep_save($accountnumber, 12) . "'";
1334  $sqls[] = $sql;
1335  $sth = db_query($sql, $dbh);
1336  if (!$sth)
1337  throw new exception("extkey delete failed.", 124);
1338 
1339  $sql = "delete from cu_alerts where trim(accountnumber) = '" . prep_save($accountnumber, 12) . "' and cu= '$Cu'";
1340  $sqls[] = $sql;
1341  $sth = db_query($sql, $dbh);
1342  if (!$sth)
1343  throw new exception("cu_alerts delete failed.", 111);
1344 
1345  $sql = "delete from cusmstransaction where trim(accountnumber) = '" . prep_save($accountnumber, 12) . "' and cu= '$Cu'";
1346  $sqls[] = $sql;
1347  $sth = db_query($sql, $dbh);
1348  if (!$sth)
1349  throw new exception("cusmstransaction delete failed.", 126);
1350 
1351  $sql = "delete from cucmsresponse where trim(accountnumber) = '" . prep_save($accountnumber, 12) . "' and cu='$Cu'";
1352  $sqls[] = $sql;
1353  $sth = db_query($sql, $dbh);
1354  if (!$sth)
1355  throw new exception("cucmsresponse delete failed.", 128);
1356 
1357  $sql = "delete from cusmstrack where trim(accountnumber) = '" . prep_save($accountnumber, 12) . "' and cu='$Cu'";
1358  $sqls[] = $sql;
1359  $sth = db_query($sql, $dbh);
1360  if (!$sth)
1361  throw new exception("cusmstrack delete failed.", 129);
1362 
1363  $sql = "delete from cusms where trim(accountnumber) = '" . prep_save($accountnumber, 12) . "' and cu='$Cu'";
1364  $sqls[] = $sql;
1365  $sth = db_query($sql, $dbh);
1366  if (!$sth)
1367  throw new exception("cusms delete failed.", 130);
1368 
1369  $sql = "delete from ${Cu}memberacctrights where trim(accountnumber) = '" . prep_save($accountnumber, 12) . "'";
1370  $sqls[] = $sql;
1371  $sth = db_query($sql, $dbh);
1372  if (!$sth)
1373  throw new exception("memberacctrights delete failed.", 132);
1374 
1375  $sql = "delete from ${Cu}useraccounts where trim(accountnumber) = '" . prep_save($accountnumber, 12) . "'";
1376  $sqls[] = $sql;
1377  $sth = db_query($sql, $dbh);
1378  if (!$sth)
1379  throw new exception("useraccounts delete failed.", 136);
1380 
1381  $sql = "delete from ${Cu}transdtl where id in (select dtl.id from ${Cu}memorizeddtl dtl inner join ${Cu}transhdr hdr
1382  on dtl.transhdr_id = hdr.id and hdr.accountnumber= '" . prep_save($accountnumber, 12) . "')";
1383  $sqls[] = $sql;
1384  $sth = db_query($sql, $dbh);
1385  if (!$sth)
1386  throw new exception("dtl delete failed.", 137);
1387 
1388  $sql = "delete from ${Cu}transhdr where accountnumber = '" . prep_save($accountnumber, 12) . "'";
1389  $sqls[] = $sql;
1390  $sth = db_query($sql, $dbh);
1391  if (!$sth)
1392  throw new exception("hdr delete failed.", 138);
1393 
1394  $sql = "delete from ${Cu}useraccounts where accountnumber = '" . prep_save($accountnumber, 12) . "'";
1395  $sqls[] = $sql;
1396  $sth = db_query($sql, $dbh);
1397  if (!$sth)
1398  throw new exception("useraccounts delete failed.", 139);
1399  }
1400  else // Okay, but we still need to remove from tables where there is an user_id but it is nullable.
1401  {
1402  $sql = "delete from cusmstransaction where trim(accountnumber) = '" . prep_save($accountnumber, 12) . "' and cu= '$Cu' and user_id is null";
1403  $sqls[] = $sql;
1404  $sth = db_query($sql, $dbh);
1405  if (!$sth)
1406  throw new exception("cusmstransaction delete failed.", 145);
1407  }
1408 
1409  $sql = "delete from cuovermicr where trim(accountnumber) = '" . prep_save($accountnumber, 12) . "' and cu= '$Cu'";
1410  $sqls[] = $sql;
1411  $sth = db_query($sql, $dbh);
1412  if (!$sth)
1413  throw new exception("cuovermicr delete failed.", 109);
1414 
1415  $sql = "delete from ${Cu}holds where trim(accountnumber) = '" . prep_save($accountnumber, 12) . "'";
1416  $sqls[] = $sql;
1417  $sth = db_query($sql, $dbh);
1418  if (!$sth)
1419  throw new exception("holds delete failed.", 125);
1420 
1421  $sql = "delete from ${Cu}memberacct where trim(accountnumber) = '" . prep_save($accountnumber, 12) . "'";
1422  $sqls[] = $sql;
1423  $sth = db_query($sql, $dbh);
1424  if (!$sth)
1425  throw new exception("memberacct delete failed.", 133);
1426 
1427  deleteAccountHistory($dbh, $Cu, $accountnumber, $sqls);
1428 
1429  $sql = "delete from ${Cu}accountbalance where trim(accountnumber) = '" . prep_save($accountnumber, 12) . "'";
1430  $sqls[] = $sql;
1431  $sth = db_query($sql, $dbh);
1432  if (!$sth)
1433  throw new exception("accountbalance delete failed.", 134);
1434 
1435  $sql = "delete from ${Cu}loanbalance where trim(accountnumber) = '" . prep_save($accountnumber, 12) . "'";
1436  $sqls[] = $sql;
1437  $sth = db_query($sql, $dbh);
1438  if (!$sth)
1439  throw new exception("loanbalance delete failed.", 135);
1440 
1441  $sql = "delete from ${Cu}crossaccounts where trim(accountnumber) = '" . prep_save($accountnumber, 12) . "'";
1442  $sqls[] = $sql;
1443  $sth = db_query($sql, $dbh);
1444  if (!$sth)
1445  throw new exception("crossaccounts delete failed.", 136);
1446 }
1447 
1448 /**
1449  * function deleteAccountHistory($dbh, $Cu, $accountnumber, &$sqls)
1450  * This will delete from the account history tables.
1451  *
1452  * @param $dbh -- the database connection
1453  * @param $Cu -- the credit union
1454  * @param $accountnumber -- the accountnumber
1455  * @param $sqls -- the array to append the SQLs to.
1456  *
1457  * @throws errors between 100 and 200 which will fail the transaction defined at a higher level.
1458  */
1459 function deleteAccountHistory($dbh, $Cu, $accountnumber, &$sqls)
1460 {
1461  $sql = "delete from ${Cu}accounthistory where trim(accountnumber) = '" . prep_save($accountnumber, 12) . "'";
1462  $sqls[] = $sql;
1463  $sth = db_query($sql, $dbh);
1464  if (!$sth)
1465  throw new exception("Account history delete failed.", 102);
1466 
1467  $sql = "delete from ${Cu}loanhistory where trim(accountnumber) = '" . prep_save($accountnumber, 12) . "'";
1468  $sqls[] = $sql;
1469  $sth = db_query($sql, $dbh);
1470  if (!$sth)
1471  throw new exception("Loan history delete failed.", 103);
1472 }
1473 
1474 /**
1475  * function checkAccountUsage($dbh, $Cu, $userId, $accountnumber, &$sqls)
1476  * This will check to see if the account is used by another user and if so, fail.
1477  *
1478  * @param $dbh -- the database connection
1479  * @param $Cu -- the credit union
1480  * @param $userId -- the user id
1481  * @param $accountnumber -- the accountnumber
1482  * @param $sqls -- the array to append the SQLs to.
1483  *
1484  * @throws
1485  * Between 1 and 100 -- Select queries failed.
1486  * Between 200 and 300 -- There exists at least one record from the accountnumber and another user.
1487  */
1488 function checkAccountUsage($dbh, $Cu, $userId, $accountnumber, &$sqls)
1489 {
1490  $sql = "select 'FOUND' from ${Cu}extkey where trim(accountnumber) = '" . prep_save($accountnumber, 12) . "' and user_id <> $userId";
1491  $sqls[] = $sql;
1492  $sth = db_query($sql, $dbh);
1493  if (!$sth)
1494  throw new exception("extkey failed.", 108);
1495  if (db_num_rows($sth) > 0)
1496  return false;
1497 
1498  $sql = "select 'FOUND' from cu_alerts where trim(accountnumber) = '" . prep_save($accountnumber, 12) . "' and cu = '$Cu' and user_id <> $userId";
1499  $sqls[] = $sql;
1500  $sth = db_query($sql, $dbh);
1501  if (!$sth)
1502  throw new exception("cu_alerts failed.", 109);
1503  if (db_num_rows($sth) > 0)
1504  return false;
1505 
1506  $sql = "select 'FOUND' from ${Cu}useraccounts where trim(accountnumber) = '" . prep_save($accountnumber, 12) . "' and user_id <> $userId";
1507  $sqls[] = $sql;
1508  $sth = db_query($sql, $dbh);
1509  if (!$sth)
1510  throw new exception("useraccounts failed.", 100);
1511  if (db_num_rows($sth) > 0)
1512  return false;
1513 
1514  $sql = "select 'FOUND' from ${Cu}memberacctrights where trim(accountnumber) = '" . prep_save($accountnumber, 12) . "' and user_id <> $userId";
1515  $sqls[] = $sql;
1516  $sth = db_query($sql, $dbh);
1517  if (!$sth)
1518  throw new exception("memberacctrights failed.", 110);
1519  if (db_num_rows($sth) > 0)
1520  return false;
1521 
1522  $sql = "select 'FOUND' from cusmstransaction where trim(accountnumber) = '" . prep_save($accountnumber, 12) . "' and user_id is not null and user_id <> $userId and cu='$Cu'";
1523  $sqls[] = $sql;
1524  $sth = db_query($sql, $dbh);
1525  if (!$sth)
1526  throw new exception("cusmstransaction failed.", 120);
1527  if (db_num_rows($sth) > 0)
1528  return false;
1529 
1530  $sql = "select 'FOUND' from cucmsresponse where trim(accountnumber) = '" . prep_save($accountnumber, 12) . "' and user_id <> $userId and cu='$Cu'";
1531  $sqls[] = $sql;
1532  $sth = db_query($sql, $dbh);
1533  if (!$sth)
1534  throw new exception("cucmsresponse failed.", 140);
1535  if (db_num_rows($sth) > 0)
1536  return false;
1537 
1538  $sql = "select 'FOUND' from cusmstrack where trim(accountnumber) = '" . prep_save($accountnumber, 12) . "' and user_id is not null and user_id <> $userId and cu='$Cu'";
1539  $sqls[] = $sql;
1540  $sth = db_query($sql, $dbh);
1541  if (!$sth)
1542  throw new exception("cusmstrack failed.", 150);
1543  if (db_num_rows($sth) > 0)
1544  return false;
1545 
1546  $sql = "select 'FOUND' from cusms where trim(accountnumber) = '" . prep_save($accountnumber, 12) . "' and user_id is not null and user_id <> $userId and cu='$Cu'";
1547  $sqls[] = $sql;
1548  $sth = db_query($sql, $dbh);
1549  if (!$sth)
1550  throw new exception("cusms failed.", 160);
1551  if (db_num_rows($sth) > 0)
1552  return false;
1553 
1554  $sql = "select 'FOUND' from ${Cu}transhdr where trim(accountnumber) = '" . prep_save($accountnumber, 12) . "' and posted_by is not null and posted_by <> $userId";
1555  $sqls[] = $sql;
1556  $sth = db_query($sql, $dbh);
1557  if (!$sth)
1558  throw new exception("transhdr failed.", 170);
1559  if (db_num_rows($sth) > 0)
1560  return false;
1561 
1562  return true;
1563 }
1564 
1565 /*--------------------------------------------
1566 END Admin delete functions
1567 ----------------------------------------------*/
1568 
1569 /**
1570  * Print javascript necessary to print Google analytics on the page
1571  *
1572  * @param string $pServName - Server Name e.g. 'alpha.homecu.io'
1573  * @param string $pCu - Credit Union Code
1574  * @param string $pScript -
1575  */
1576 function PrintGAScript($pServName, $pCu, $pScript) {
1577 
1578  // Trim any extension off scriptname
1579  if (strrpos($pScript, ".") !== false) {
1580  $pScript = substr($pScript, 0, strrpos($pScript, "."));
1581  }
1582 
1583  print <<< GA_JS
1584  <script>
1585  if (typeof ga === 'function') {
1586  /* ** Make sure Google Analytics are installed */
1587  // tracking ID created in main.prg
1588  ga('set', 'dimension1', '$pServName' );
1589  ga('set', 'dimension2', '$pScript' );
1590  ga('set', 'dimension3', '$pCu' );
1591  ga('send', 'pageview');
1592  }
1593  </script>
1594 GA_JS;
1595 
1596 }
1597 
1598 /**
1599  * function ReadUser($dbh, $cuCode, $username, $getPrograms, $getChallengeQuestions, $getAllChallengeQuestions, $getAlertProviders)
1600  * Read user. Depending on where it is accessed, there are differences in what is shown.
1601  *
1602  * @param integer $dbh -- the database connection
1603  * @param string $cuCode -- the credit union
1604  * @param string $username -- the username to read
1605  * @param boolean $getPrograms -- if true, will get the available programs
1606  * @param boolean $getChallengeQuestions -- if true, will get the mfaquest column in the user record and extract it
1607  * @param boolean $getAllChallengeQuestions -- if true, will get all available challenge questions
1608  * @param boolean $getAlertProviders -- if true, will get a list of phone providers - removed
1609  * @param boolean $getAuditRecords -- whether or not to get the audit records.
1610  * @param object $logger -- logs
1611  *
1612  * @return array $returnArray --
1613  * integer $returnArray["status"] -- "000" if successful; nonzero otherwise
1614  * array $returnArray["error"] -- nonempty if there is an error
1615  * array $returnArray["record"] -- contains the user record
1616  * array $returnArray["privilege"] -- contains the programs that the user can see (if $getPrograms)
1617  * array $returnArray["providers"] -- contains the phone providers (if $getAlertProviders)
1618  */
1619 function ReadUser($dbh, $cuCode, $username, $getPrograms, $getChallengeQuestions, $getAllChallengeQuestions, $getAuditRecords, $logger) {
1620  //we no longer need providers here
1621  $records = array();
1622  $privilegeRecords = array();
1623  $username = mb_strtolower($username); // Needs the mb for converting Ö to ö for example.
1624  try {
1625  $sql = "select au.*, au.user_name as username, coalesce(a.retrylimit,5) as retry, coalesce(a.gracelimit,5) as grace, a.pwdconfig, a.ip_acl, a.user_name as ismaster
1626  from cuadminusers au inner join cuadmin a on au.cu = a.cu where au.cu='$cuCode' and lower(au.user_name)='" . prep_save($username, 50) . "' limit 1";
1627  $sth = db_query($sql, $dbh);
1628  if (!$sth) {
1629  throw new exception("Read query failed.", 1);
1630  }
1631  if (db_num_rows($sth) == 0) {
1632  throw new exception("No user found.", 3);
1633  }
1634  for($i = 0; $oldArray = db_fetch_assoc($sth, $i); $i++) {
1635  foreach($oldArray as $key => $value) {
1636  if ($key == "pwdconfig") {
1637  $value = HCU_JsonDecode($value);
1638  if (!is_array($value)) {
1639  throw new exception("Password array is malformed.", 4);
1640  }
1641  $array[$key] = $value;
1642  } else if ($key == "ismaster") {
1643  $array[$key] = trim($value) == trim($oldArray["username"]);
1644  } else {
1645  $array[$key] = trim($value);
1646  }
1647  }
1648  unset($oldArray);
1649 
1650  // removing provider/carrier from phone number
1651  if ($array["usersms"] == "") {
1652  $array["smsNumber"] = "";
1653  } else {
1654 
1655  $sms = explode("@", $array["usersms"]);
1656  $array["smsNumber"] = $sms[0];
1657  }
1658 
1659  if ($array["remoteip"] != "") {
1660  $validate = explode(".", $array["remoteip"]);
1661  if (count($validate) != 4) {
1662  throw new exception("Remote address is not valid.", 9);
1663  }
1664  foreach($validate as $num) {
1665  if (!is_numeric($num)) {
1666  throw new exception("Remote address are not valid.", 10);
1667  }
1668  if ($num < 0 || $num > 256) {
1669  throw new exception("Remote address are not valid.", 11);
1670  }
1671  }
1672  }
1673 
1674  if ($array["ip_acl"] == "") {
1675  $array["cuIps"] = array();
1676  } else {
1677  $cuIps = explode(";", $array["ip_acl"]);
1678  foreach($cuIps as $ip) {
1679  $validate = explode(".", $ip);
1680  if (count($validate) != 4) {
1681  throw new exception("Cu IP addresses are not valid.", 6);
1682  }
1683  foreach($validate as $num) {
1684  if (!is_numeric($num)) {
1685  throw new exception("Cu IP addresses are not valid.", 7);
1686  }
1687  if ($num < 0 || $num > 256) {
1688  throw new exception("Cu IP addresses are not valid.", 8);
1689  }
1690  }
1691  }
1692  $array["cuIps"] = $cuIps;
1693  }
1694 
1695  unset($array["usersms"]);
1696  unset($array["passwd"]);
1697  unset($array["ip_acl"]);
1698 
1699  $array["booleanForceChange"]= $array["forcechange"] == "Y";
1700 
1701  $userflags = intval($array["userflags"]);
1702  $array["booleanForceSecurity"] = ($userflags & 2) != 0;
1703  $array["booleanMasterPrivileges"] = ($userflags & 4) != 0;
1704  $array["booleanRemotePrivileges"] = ($userflags & 64) != 0;
1705  $array["booleanLockAccount"] = $array["failedremain"] < 1 || (($array["booleanForceChange"] || $array["booleanForceSecurity"]) && $array["forceremain"] < 1);
1706  $array["textLockout"] = $array["failedremain"] == -1 ? "Locked By CU" : $array["failedremain"];
1707  $array["numRemaining"] = $array["forceremain"];
1708  $array["cuRemoteEnabled"] = count($array["cuIps"]) > 0;
1709 
1710  $array["failReason"] = ($userflags & 8) != 0 ? "Email" : (($userflags & 16) != 0 ? "Challenge Response" : (($userflags & 32) != 0 ? "Password" : ""));
1711  $records[] = $array;
1712  }
1713 
1714  if ($getPrograms) { // Not shown on UI for master so why go through this effort to throw it away?
1715  $sql = "select ap.program, ap.displaytext, ap.description, a.program as checked from cuadminprogs ap
1716  left join cuadminallow a on ap.program = a.program and lower(a.user_name) = '" . prep_save($username, 50) . "' and a.cu = '$cuCode'
1717  order by ap.sort_order, ap.program";
1718  $sth = db_query($sql, $dbh);
1719  if (!$sth) {
1720  throw new exception("Program query failed.", 2);
1721  }
1722  for($i = 0; $oldArray = db_fetch_assoc($sth, $i); $i++) {
1723  foreach($oldArray as $key => $value) {
1724  $thisArray[$key] = trim($value);
1725  }
1726  unset($oldArray);
1727  $thisArray["checked"] = $thisArray["checked"] != "";
1728  $thisArray["prevChecked"] = $thisArray["checked"];
1729  $privilegeRecords[] = $thisArray;
1730  }
1731  $records[0]["programs"] = $privilegeRecords;
1732  }
1733 
1734  if ($getChallengeQuestions) {
1735  $challengeQuestions = getAdmChallengeQuestions($dbh, $cuCode, $username, $getAllChallengeQuestions ? "security display" : "admin display");
1736  $records[0]["mfaquest"] = $challengeQuestions["data"];
1737  $records[0]["mfaddl"] = $challengeQuestions["ddl"];
1738  }
1739 
1740  if ($getAuditRecords) {
1741  $records[0]["auditRecords"] = GetAuditRecords($dbh, $cuCode, $username, $logger);
1742  }
1743 
1744  $returnArray = array("status" => "000", "error" => "", "record" => $records);
1745 
1746  } catch (exception $e) {
1747  $returnArray = array("status" => $e->getCode(), "error" => $e->getMessage());
1748  }
1749  return $returnArray;
1750 }
1751 
1752 /**
1753  * function saveUser($dbh, $cuCode, $parameters, $loggedInUser, $securityMode)
1754  * Saves the admin user. This can save for the user table, cuadmin table (Master IP addresses), and add and removals from the cuadminallowprogs table.
1755  * Next error code 46
1756  *
1757  * @param array $pSysEnv -- The System Environment variable from main
1758  * with the settings for this environment (production/development)
1759  * @param integer $dbh -- the database connection
1760  * @param string $cuCode -- the credit union
1761  * @param array $parameters -- the column changed
1762  * @param string $loggedInUser -- the logged in user. For all modes, this is for the audit record. For most modes, it is also the user being saved.
1763  * @param string $securityMode -- this has various codes below. If there are no changes in one of the tables, then there will be no audit record for that table.
1764  * "none" -- Save is coming from the admin user admin screen. This means that there are a lot of stuff that can be saved. Any changes to the user record are dependent
1765  * on $parameter["isAdd"]. If this is "Y", then the audit will be a create with the code "USER_A". Otherwise, the audit will be an update with the code "USER_U".
1766  * If the user is a master and the master IP were changed, then an audit will be created with the code "RIP_U" for the cuadmin table.
1767  * If programs were added to the user, then an audit will be created with the code "PROGS_A" for the cuadminallowprogs table.
1768  * If programs were removed from the user, then an audit will be created with the code "PROGS_D" for the cuadminallowprogs table.
1769  * "basic" -- Save is coming from the first page in the "change security settings" option. User can only save email, remote access parameters, and password.
1770  * An audit will be created with the code "USER_BSU" for the user table. The authentication cookie will be updated with the new info.
1771  * "advanced" -- Save is coming from the second page in the "change security settings" option. User can only save confidence word and challenge questions.
1772  * An audit will be created with the code "USER_ASU" for the user table. The authentication cookie will be updated with the new info.
1773  * "setup" -- Save is coming from the page that occurs when logging in without the challenge questions set. User MUST save email, confidence word and challenge questions.
1774  * If the forcechange parameter is set, then password also MUST be saved. An audit will be created with the code "USER_STP" for the user table.
1775  *
1776  * @return array --
1777  * array $sql -- list of sqls
1778  * integer $code -- nonzero if error(s)
1779  * array $error -- nonempty if error(s)
1780  */
1781 function saveUser($pSysEnv, $dbh, $cuCode, $parameters, $loggedInUser, $securityMode, $createCookieIfNotExists=false, $isSkip=false, $passwordRequired=false)
1782 {
1783  $errors = array();
1784  $sqls = array();
1785  $code = 0;
1786  $updateTable = array();
1787  $adminTicketString = "";
1788  $serverIPFound = false;
1789  $serverIPFoundRelevant = false;
1790  $serverIP = trim( $_SERVER["REMOTE_ADDR"] );
1791 
1792  try
1793  {
1794  $chkSecure = HCU_array_key_value("chksecure", $parameters);
1795  $chkSecure = $chkSecure === false ? false : trim($chkSecure) == "Y";
1796  $username = mb_strtolower(isset($parameters["username"]) ? trim($parameters["username"]) : $loggedInUser);
1797  $isLogInUser = $username == $loggedInUser;
1798  $parameters["username"] = $username;
1799  // Without the mb part, Â doesn't become â so then this is different than postgres's lower function.
1800  $sql = "select userflags from cuadminusers where lower(user_name)= '$username' and cu = '$cuCode'";
1801  $sqls[] = $sql;
1802  $sth = db_query($sql, $dbh);
1803  if (!$sth)
1804  throw new exception("Userflags query failed.", 43);
1805  $row = db_fetch_row($sth);
1806  $userFlags = intval($row[0]);
1807  $previousUserFlags = $userFlags;
1808 
1809  if ($securityMode == "none")
1810  {
1811  if ($username == "")
1812  throw new exception("Username is required.", 1);
1813  if(preg_match('/[\'";+]/',$username))
1814  throw new exception("Invalid Characters in Username.", 15);
1815  }
1816  else
1817  $username = mb_strtolower($loggedInUser);
1818 
1819  $remoteAccess = HCU_array_key_exists("remoteAccess", $parameters) ? trim($parameters["remoteAccess"]) : "U";
1820  $remoteAccessSet = HCU_array_key_exists("remoteAccessSet", $parameters) ? trim($parameters["remoteAccessSet"]) : "N";
1821 
1822  $sql = "select email, passwd, confidence, mfaquest, remoteip from cuadminusers where lower(user_name)= '" . mb_strtolower($loggedInUser) . "' and cu= '$cuCode'";
1823  $sqls[] = $sql;
1824  $sth = db_query($sql, $dbh);
1825  if (!$sth)
1826  throw new exception("Email query failed.", 9);
1827 
1828  $row = db_fetch_assoc($sth);
1829  $email = trim($row["email"]);
1830  $currentPassword = trim($row["passwd"]);
1831  $confidence = trim($row["confidence"]);
1832  $remoteipSet = isset($row["remoteip"]) ? trim($row["remoteip"]) : "";
1833  $challengeArray = HCU_JsonDecode(trim($row["mfaquest"]));
1834  $emailAddress = HCU_array_key_exists("emailAddress", $parameters) ? trim($parameters["emailAddress"]) : "";
1835  $password = HCU_array_key_exists("password", $parameters) ? trim($parameters["password"]) : "";
1836 
1837 
1838  if (in_array($securityMode, array("noneWithConfidence", "setup", "combined")))
1839  {
1840  $confidence = HCU_array_key_exists("confidence", $parameters) ? trim($parameters["confidence"]) : "";
1841 
1842  if ($confidence != "")
1843  $updateTable["confidence"] = $confidence;
1844  else if ($securityMode != "combined")
1845  throw new exception("Confidence word is required.", 30);
1846 
1847 
1848  $questIds = HCU_array_key_exists("questIds", $parameters) ? trim($parameters["questIds"]) : array_keys($challengeArray["answers"]);
1849  $questResponses = HCU_array_key_exists("questResponses", $parameters) ? trim($parameters["questResponses"]) : "";
1850  if ($questIds == "" || $questResponses == "")
1851  {
1852  if ($securityMode != "combined")
1853  throw new exception("Challenge questions are required.", 31);
1854  }
1855  else
1856  {
1857  $questIds = HCU_JsonDecode($questIds);
1858  if (!is_array($questIds))
1859  throw new exception("Question ids are not valid.", 32);
1860  $questResponses = HCU_JsonDecode($questResponses);
1861  if (!is_array($questResponses))
1862  throw new exception("Question responses are not valid.", 33);
1863  if (count($questIds) != 3)
1864  throw new exception("Question ids are not valid.", 34);
1865  if (count($questResponses) != 3)
1866  throw new exception("Question responses are not valid.", 35);
1867  foreach($questIds as $id)
1868  {
1869  if (!is_numeric($id) || $id == 0)
1870  throw new exception("Question ids are not valid.", 36);
1871  }
1872  foreach($questResponses as $response)
1873  {
1874  if (!isset($response))
1875  throw new exception("Question responses are not valid.", 39); // nulls in the encoded array.
1876  }
1877 
1878  // Verify that question ids selected exist in the master table.
1879  $sql = "select 'FOUND' from cuquestmaster where quest_lang = 'en_US' and quest_id in (" . implode(",", $questIds) . ")";
1880  $sqls[] = $sql;
1881  $sth = db_query($sql, $dbh);
1882  if (!$sth)
1883  throw new exception("Master sql failed.", 37);
1884  if (db_num_rows($sth) != 3)
1885  throw new exception("Question ids are not valid.", 38);
1886  $challengeArray = array("answers" => array(), "challenge" => 0); // Replaces the array from the user table so that the 2Factor is changed below.
1887  reset($questResponses);
1888  foreach($questIds as $id)
1889  {
1890  $challengeArray["answers"]["$id"] = current($questResponses);
1891  next($questResponses);
1892  }
1893 
1894  $updateTable["mfaquest"] = PrepareMfaQuestString($challengeArray);
1895  }
1896 
1897  $userFlags &= ~2;
1898  }
1899 
1900  if (in_array($securityMode, array("setup", "combined")))
1901  {
1902  $oldPassword = HCU_array_key_exists("oldPassword", $parameters) ? trim($parameters["oldPassword"]) : "";
1903  if ($passwordRequired || $password != "") // Don't care if the password is not also filled in.
1904  {
1905  if ($passwordRequired && $password == "")
1906  throw new exception("You must enter your new password.", 45);
1907 
1908  if ($oldPassword == "")
1909  throw new exception("You must enter your current password.", 27);
1910 
1911  if (!password_verify($oldPassword, $currentPassword))
1912  throw new exception("Invalid username or password.", 29);
1913  if (trim($password) == $oldPassword)
1914  throw new exception("New password cannot be the same as the old password.", 42);
1915  $updateTable["forcechange"] = "N";
1916  }
1917  if ($emailAddress != "")
1918  $adminTicketString .= "Ffchg=N&Ml=" . urlencode($emailAddress) . "&";
1919  }
1920 
1921  if (in_array($securityMode, array("none", "noneWithConfidence", "setup", "combined")))
1922  {
1923  if ($password != "")
1924  {
1925  $thisReturnArray = validatePasswordRules($dbh, $cuCode, true, $password, true);
1926  array_merge($sqls, $thisReturnArray["sqls"]);
1927  if ($thisReturnArray["code"] != 0)
1928  throw new exception("Password doesn't conform to the rules.", 5);
1929 
1930  $hash = password_hash($password, PASSWORD_DEFAULT);
1931  $updateTable["passwd"] = "$hash";
1932  $updateTable["pwchange"] = DBTIMESTAMP_USENOW;
1933  }
1934 
1935  if ($emailAddress != "")
1936  {
1937  if ($emailAddress != "" && !(preg_match("/^[A-Za-z0-9\.\-_]*\@[A-Za-z0-9\.\-_]*\.[A-Za-z0-9\-_]*/",$emailAddress)))
1938  throw new exception("Email address appears to be invalid.", 17);
1939  $updateTable["email"] = $emailAddress;
1940  }
1941  }
1942 
1943  if (in_array($securityMode, array("combined"))) {
1944  $remoteAccessSet = ($userFlags & 64) != 0 ? "Y" : "N";
1945  $remoteAccess = "U";
1946  }
1947 
1948  if (!isset($remoteAccess) || trim($remoteAccess) == "")
1949  $remoteAccess = "U";
1950 
1951  // There are a couple of cases where a refresh is required because the remote access dialogs happen inside this JSON. Therefore, there are javascript errors AFTER a save.
1952  if (in_array($securityMode, array("none", "noneWithConfidence", "combined")))
1953  {
1954 
1955  if ($remoteAccessSet == "Y" || ($remoteAccessSet == "N" && $remoteAccess == "N"))
1956  {
1957  /* If the remote access is set to false, we are going to remove all options underneath. This is regardless of if they are set to something different.
1958  The only reason why they would be set to something different is if the user checked the box, then set them and then unchecked the box. In that case, ignore. */
1959  if ($remoteAccess == "N") {
1960  $smsNumber = "";
1961  $ipAddress = "NONE";
1962  $serverIPFoundRelevant = $isLogInUser;
1963 
1964  }
1965  else {
1966  // Underneath the remote access because changes are irrevelant if the remoteAccess is not set. (User set it, changed these values and then unset it.)
1967  $smsNumber = HCU_array_key_exists("smsNumber", $parameters) ? trim($parameters["smsNumber"]) : "";
1968  $ipAddress = HCU_array_key_exists("ipAddress", $parameters) ? trim($parameters["ipAddress"]) : "";
1969  }
1970 
1971  $valid = $smsNumber == "" ? $smsNumber == "" : $smsNumber != "";
1972 
1973 
1974  if (!$valid)
1975  throw new exception("SMS number must be defined.", 28);
1976  if ($smsNumber != "") {
1977  if (!preg_match('/[2-9][0-9]{9}/', $smsNumber))
1978  throw new exception("SMS Number is invalid.", 23);
1979  $updateTable["usersms"] = "$smsNumber";
1980  }
1981 
1982  if ($ipAddress != "")
1983  {
1984  $serverIPFoundRelevant = $isLogInUser;
1985  if ($ipAddress == "NONE")
1986  $updateTable["remoteip"] = "";
1987  else
1988  {
1989  $ips = explode(";", $ipAddress);
1990  $validIp = true;
1991  foreach($ips as $ip)
1992  {
1993  $validIp = $validIp ? filter_var($ip, FILTER_VALIDATE_IP) : false;
1994  $serverIPFound = $serverIPFound || $serverIP == trim($ip);
1995  }
1996  if (!$validIp)
1997  throw new exception("IP Address isn't formatted correctly.", 21);
1998  $updateTable["remoteip"] = $ipAddress;
1999  }
2000  }
2001  else if ($isLogInUser) {
2002  $ips = explode(";", $remoteipSet);
2003  $serverIPFound = $serverIPFound || in_array($serverIP, $ips);
2004  }
2005  }
2006  }
2007 
2008  // SecurityMode none only
2009  if (in_array($securityMode, array("none", "noneWithConfidence", "combined")))
2010  {
2011  $realName = HCU_array_key_exists("realName", $parameters) ? trim($parameters["realName"]) : "";
2012  if ($realName != "")
2013  {
2014  $updateTable["realname"] = $realName;
2015  if (preg_match('/[\'"@;]/',$realName))
2016  throw new exception("Invalid Characters in Real Name.", 16);
2017  }
2018 
2019  $forceChangesAmount = HCU_array_key_exists("forceChangesAmount", $parameters) ? trim($parameters["forceChangesAmount"]) : "";
2020  if ($forceChangesAmount != "")
2021  {
2022  if (!is_numeric($forceChangesAmount))
2023  throw new exception("Force Changes Amount is not numeric.", 2);
2024  if ($forceChangesAmount < 0 || $forceChangesAmount > 99)
2025  throw new exception("Force Changes needs to be in the range 0-99.", 3);
2026  $updateTable["forceremain"] = intval($forceChangesAmount);
2027  }
2028 
2029  $masterPrivileges = HCU_array_key_exists("masterPrivileges", $parameters) ? trim($parameters["masterPrivileges"]) : "";
2030  if ($masterPrivileges != "")
2031  {
2032  if ($masterPrivileges == "Y")
2033  $userFlags |= 4;
2034  else
2035  $userFlags &= ~4;
2036  }
2037  $forceSecurity = HCU_array_key_exists("forceSecurity", $parameters) ? trim($parameters["forceSecurity"]) : "";
2038  if ($forceSecurity != "")
2039  {
2040  if ($forceSecurity == "Y")
2041  $userFlags |= 2;
2042  else
2043  $userFlags &= ~2;
2044  }
2045  $forcePassword = HCU_array_key_exists("forcePassword", $parameters) ? trim($parameters["forcePassword"]) : "";
2046  if ($forcePassword != "")
2047  {
2048  $updateTable["forcechange"] = $forcePassword == "Y" ? "Y" : "N";
2049  }
2050 
2051  $remoteAccess == "U" ? null : ($remoteAccess == "Y" ? $userFlags|= 64 : $userFlags&= ~64);
2052 
2053  $lockAccount = HCU_array_key_exists("lockAccount", $parameters) ? trim($parameters["lockAccount"]) : "";
2054  if ($lockAccount != "")
2055  {
2056  $sql = "select retrylimit from cuadmin where cu= '$cuCode' limit 1";
2057  $sqls[] = $sql;
2058  $sth = db_query($sql,$dbh);
2059  if (!$sth)
2060  throw new exception("Lock Account query failed.", 6);
2061  $retry = trim(db_fetch_row($sth)[0]);
2062  $retry = $retry == "" ? 5 : $retry;
2063  $updateTable["failedremain"] = trim($lockAccount) == "Y" ? -1 : $retry;
2064  }
2065 
2066  $sql = "select user_name, ip_acl from cuadmin where cu= '$cuCode' limit 1";
2067  $sqls[] = $sql;
2068  $sth = db_query($sql, $dbh);
2069  if (!$sth)
2070  throw new exception("username query failed.", 18);
2071  $row = db_fetch_assoc($sth,0);
2072 
2073  $masterIpAddress = HCU_array_key_exists("masterIpAddress", $parameters) ? trim($parameters["masterIpAddress"]) : "";
2074  if ($masterIpAddress != "")
2075  {
2076  if (trim($row["user_name"]) != $username)
2077  throw new exception("Only the Cu Master user can edit Allowed IP Addresses.", 19);
2078 
2079  $serverIPFoundRelevant = $isLogInUser; // Relevant when the IP address has changed but is not null (no longer have remote access at that point.)
2080 
2081  if ($masterIpAddress != "NONE")
2082  {
2083  $ips = explode(";", $masterIpAddress);
2084  $validIp = true;
2085 
2086  foreach($ips as $ip)
2087  {
2088  $validIp = $validIp ? filter_var($ip, FILTER_VALIDATE_IP) : false;
2089  $serverIPFound = $serverIPFound || $serverIP == trim($ip);
2090  }
2091  if (!$validIp)
2092  throw new exception("Master IP Address isn't formatted correctly.", 7);
2093  }
2094  else
2095  $masterIpAddress = "";
2096  $ipUpdate = array("cuadmin" => array(array("_action" => "update", "ip_acl" => $masterIpAddress, "cu" => $cuCode)));
2097  }
2098  else if ($isLogInUser) {
2099  $ips = explode(";", trim($row["ip_acl"]));
2100  $serverIPFound = $serverIPFound || in_array($serverIP, $ips);
2101  }
2102 
2103  $permTemp = array("cu" => $cuCode, "user_name" => $username);
2104 
2105  $addPermissions = HCU_array_key_exists("addPermissions", $parameters) ? trim($parameters["addPermissions"]) : "";
2106  if ($addPermissions != "")
2107  {
2108  $addPermissions = HCU_JsonDecode($addPermissions);
2109  if (!is_array($addPermissions))
2110  throw new exception("Add Permissions is not formatted correctly.", 10);
2111  if (count($addPermissions) > 0)
2112  {
2113  $permUpdate1 = array();
2114  foreach($addPermissions as $perm)
2115  {
2116  $record = $permTemp;
2117  $record["_action"] = "create";
2118  $record["program"] = $perm;
2119  $permUpdate1[] = $record;
2120  }
2121  // Wrap that:
2122  $permUpdate1 = array("cuadminallow" => $permUpdate1);
2123  }
2124  }
2125 
2126  $removePermissions = HCU_array_key_exists("removePermissions", $parameters) ? trim($parameters["removePermissions"]) : "";
2127  if ($removePermissions != "")
2128  {
2129  $removePermissions = HCU_JsonDecode($removePermissions);
2130  if (!is_array($removePermissions))
2131  throw new exception("Remove Permissions is not formatted correctly.", 11);
2132  if (count($removePermissions) > 0)
2133  {
2134  $permUpdate2 = array();
2135  foreach($removePermissions as $perm)
2136  {
2137  $record = $permTemp;
2138  $record["_action"] = "delete";
2139  $record["program"] = $perm;
2140  $permUpdate2[] = $record;
2141  }
2142  $permUpdate2 = array("cuadminallow" => $permUpdate2);
2143  }
2144  }
2145  } // End of save if not security
2146  else if ($securityMode == "setup")
2147  {
2148  if (trim($parameters["forcechange"]) == "Y" && !isset($password))
2149  throw new exception("Password is required.", 40);
2150  if (!isset($emailAddress))
2151  throw new exception("Email Address is required.", 41);
2152 
2153  $updateTable["forcechange"] = "N"; // In order to not go to this page anymore.
2154  }
2155 
2156  $envVars = array("cu" => $cuCode);
2157 
2158  if ($previousUserFlags != $userFlags)
2159  $updateTable["userflags"] = $userFlags;
2160 
2161  // Make sure that only updating when something changed on the base table.
2162  if (count($updateTable) > 0)
2163  {
2164  $updateTable["user_name"] = $username;
2165  $updateTable["cu"] = $cuCode;
2166  $updateTable["_action"] = "update";
2167 
2168  if ($securityMode == "setup")
2169  {
2170  $shortAction = "USER_STP";
2171  $longAction = "User Security Setup";
2172  }
2173  else if ($securityMode == "combined")
2174  {
2175  $shortAction = "USER_SU";
2176  $longAction = "Security Update";
2177  }
2178  else if (trim($parameters["isAdd"]) == "Y")
2179  {
2180  $updateTable["_action"] = "create";
2181  $shortAction = "USER_A";
2182  $longAction = "User Added";
2183 
2184  $sql = "select 'FOUND' from cuadminusers where cu = '$cuCode' and lower(user_name) = '" . prep_save($username) . "'";
2185  $sqls[] = $sql;
2186  $sth = db_query($sql, $dbh);
2187  if (!$sth)
2188  throw new exception("Found query failed.", 25);
2189  if (db_num_rows($sth) > 0)
2190  throw new exception("Username is duplicated.", 26);
2191  }
2192  else
2193  {
2194  $updateTable["_action"] = "update";
2195  $shortAction = "USER_U";
2196  $longAction = "User Updated";
2197  }
2198 
2199  $updateTable= array("cuadminusers" => array($updateTable));
2200 
2201  if (DataAdminTableUpdate($dbh, $envVars, $updateTable, $username, $shortAction, "AdmUsrMaint.prg", "A", $longAction, $loggedInUser, $email, trim($_SERVER["REMOTE_ADDR"])) === false)
2202  throw new exception("User update failed.", 12);
2203  }
2204 
2205  if (isset($ipUpdate)
2206  && DataAdminTableUpdate($dbh, $envVars, $ipUpdate, $username, "RIP_U", "AdmUsrMaint.prg", "A", "Remote IP Update", $loggedInUser, $email, trim($_SERVER["REMOTE_ADDR"])) === false)
2207  throw new exception("IP update failed.", 20);
2208  if (isset($permUpdate1)
2209  && DataAdminTableUpdate($dbh, $envVars, $permUpdate1, $username, "PROGS_A", "AdmUsrMaint.prg", "A", "Add Programs", $loggedInUser, $email, trim($_SERVER["REMOTE_ADDR"])) === false)
2210  throw new exception("Add programs update failed.", 13);
2211  if (isset($permUpdate2)
2212  && DataAdminTableUpdate($dbh, $envVars, $permUpdate2, $username, "PROGS_D", "AdmUsrMaint.prg", "A", "Delete Programs", $loggedInUser, $email, trim($_SERVER["REMOTE_ADDR"])) === false)
2213  throw new exception("Remove programs update failed.", 14);
2214 
2215  $cookieExists = HCU_array_key_exists("aTicket", $_COOKIE) && trim($_COOKIE["aTicket"]) != "";
2216  if ($createCookieIfNotExists || $cookieExists) {
2217  $theseResults = checkPass($pSysEnv, $dbh, $loggedInUser, $password, $cuCode, $chkSecure, null, null, false, $emailAddress, false, $isSkip, $createCookieIfNotExists);
2218  $cookie= $theseResults["cookie"];
2219  if ($theseResults["code"] != 0)
2220  throw new exception("Check password failed.", 44);
2221  }
2222 
2223  }
2224  catch(exception $e)
2225  {
2226  return array("code" => $e->getCode(), "error" => array($e->getMessage()), "sql" => $sqls, "serverIPFound" => $serverIPFound, "serverIPFoundRelevant" => $serverIPFoundRelevant);
2227  }
2228 
2229  return array("code" => 0, "error" => array(), "sql" => $sqls, "serverIPFound" => $serverIPFound, "serverIPFoundRelevant" => $serverIPFoundRelevant);
2230 }
2231 
2232 function getUsePhonesInsteadOfMFA($dbh, $Cu)
2233 {
2234  global $CU3_MFA_AUTHCODE;
2235  try
2236  {
2237  $sql= "select flagset3 & $CU3_MFA_AUTHCODE from cuadmin where cu = '$Cu'";
2238  $sth= db_query($sql, $dbh);
2239  if (!$sth)
2240  throw new exception("Query failed.");
2241  $value= db_fetch_row($sth, 0)[0];
2242  return isset($value) ? $value != 0 : false;
2243  }
2244  catch(exception $e)
2245  {
2246  return false;
2247  }
2248 }
2249 
2250 
2251 /**
2252  * function ParseAuditRow($row, $Cu, $dbh)
2253  * This parses the audit for the admin side only. (User audits have new functions.)
2254  *
2255  * @param $row -- the database row of the audit table.
2256  * @param $Cu -- the credit union. This is needed for getting the time specific to the CU.
2257  * @param $dbh -- the database connection. This is needed for getting the time specific to the CU as well as the mask.
2258  */
2259 function ParseAuditRow($row, $Cu, $dbh) {
2260  try {
2261  $before = HCU_JsonDecode($row["before"]);
2262  if (!isset($before) || !is_array($before)) {
2263  throw new exception("Before JSON is not valid.", 13);
2264  }
2265  $after = HCU_JsonDecode($row["after"]);
2266  if (!isset($before) || !is_array($after)) {
2267  throw new exception("After JSON is not valid.", 14);
2268  }
2269  $details = array();
2270 
2271  foreach($before as $table => $changedRows) {
2272  $afterTable = HCU_array_key_value($table, $after) ? $after[$table] : null;
2273 
2274  if (!isset($afterTable)) {
2275  throw new exception("Table mismatch.", 15);
2276  }
2277  $tableDefinition = GetTableDefinition (array("cu" => $Cu), $table)[$table];
2278 
2279  $label = isset($tableDefinition["_label"]) ? $tableDefinition["_label"] : $table;
2280  $newTableRow = array("table" => $table, "label" => $label, "rows" => array());
2281  $tableTypeMap = array();
2282  $passwordMask = "********";
2283 
2284  if (!isset($changedRows) || !is_array($changedRows)) {
2285  throw new exception ("Changed rows is not valid.", 1);
2286  }
2287  foreach($changedRows as $j => $beforeRow) {
2288  $afterRow = $afterTable[$j];
2289 
2290  if (!isset($afterRow)) {
2291  throw new exception("Table mismatch.", 16);
2292  }
2293  $beforeEmpty = count($beforeRow) == 0;
2294  $afterEmpty = count($afterRow) == 0;
2295  $combinedRow = array();
2296  if ($beforeEmpty) {
2297  if ($afterEmpty) {
2298  continue;
2299  } else {
2300  if (!isset($afterRow) || !is_array($afterRow)) {
2301  throw new exception ("After row is not an array.", 21);
2302  }
2303  foreach($afterRow as $colName => $colValue) {
2304  $colDef = $tableDefinition["_cols"][$colName];
2305  if (!isset($colDef)) {
2306  throw new exception("Table mismatch.", 17);
2307  }
2308  $label = isset($colDef["label"]) ? $colDef["label"] : $colName;
2309 
2310  $afterValue = !isset($colValue) || trim($colValue) == "" ? true : $colValue;
2311  $same = false;
2312 
2313  // Empty and null are the same and are set to "--"
2314  $beforeValue = "--";
2315  $afterValue = $afterValue === true ? "--" : (trim($colName) == "passwd" && $afterValue != "" ? $passwordMask : trim($afterValue));
2316 
2317  // If time or timestamp, then format the output. If timestamp, then remember to also output it in Credit Union time.
2318  // NOTE: this doesn't catch the prior login / failed login / current login because that is in a STRING field for some reason.
2319  switch($colDef["type"]) {
2320  case DBTYPE_DATE:
2321  $beforeValue = GetAuditTime($dbh, $beforeValue, $Cu, false, $tz);
2322  $afterValue = GetAuditTime($dbh, $afterValue, $Cu, false, $tz);
2323  break;
2324  case DBTYPE_TIMESTAMPTZ:
2325  case DBTYPE_TIMESTAMP:
2326  case DBTIMESTAMP_USENOW:
2327  $beforeValue = GetAuditTime($dbh, $beforeValue, $Cu, true, $tz);
2328  $afterValue = GetAuditTime($dbh, $afterValue, $Cu, true, $tz);
2329  break;
2330  }
2331 
2332  $combinedRow[] = array("col" => trim($colName), "before" => $beforeValue, "after" => $afterValue, "label" => trim($label), "same" => false);
2333  }
2334  $combinedRow = array("type" => "add", "values" => $combinedRow);
2335  $tableTypeMap["add"] = "add";
2336  }
2337  } else {
2338  if (!isset($beforeRow) || !is_array($beforeRow)) {
2339  throw new exception ("before row is invalid.", 2);
2340  }
2341  foreach($beforeRow as $colName => $colValue) {
2342  $colDef = $tableDefinition["_cols"][$colName];
2343  if (!isset($colDef)) {
2344  throw new exception("Table mismatch.", 18);
2345  }
2346 
2347  $label = isset($colDef["label"]) ? $colDef["label"] : $colName;
2348  $afterValue = $afterEmpty || !HCU_array_key_exists($colName, $afterRow) ? false :
2349  (!isset($afterRow[$colName]) || trim($afterRow[$colName]) == "" ? true : $afterRow[$colName]);
2350  $beforeValue = !isset($colValue) || trim($colValue) == "" ? true : $colValue;
2351  $same = false;
2352  if (!$afterEmpty && ($afterValue === false || $beforeValue === $afterValue)) {
2353  // If the afterValue was not found or if they are the same, then clear it and that means that it is the same.
2354  $afterValue = "";
2355  $same = true;
2356  }
2357 
2358  // Empty and null are the same and are set to "--"
2359  $beforeValue = $beforeValue === true ? "--" : (trim($colName) == "passwd" ? $passwordMask : trim($beforeValue));
2360  $afterValue = $afterValue === true ? "--" : (trim($colName) == "passwd" && $afterValue != "" ? $passwordMask : trim($afterValue));
2361 
2362  // If time or timestamp, then format the output. If timestamp, then remember to also output it in Credit Union time.
2363  // NOTE: this doesn't catch the prior login / failed login / current login because that is in a STRING field for some reason.
2364  $tz = null;
2365  switch($colDef["type"]) {
2366  case DBTYPE_DATE:
2367  $beforeValue = GetAuditTime($dbh, $beforeValue, $Cu, false, $tz);
2368  $afterValue = GetAuditTime($dbh, $afterValue, $Cu, false, $tz);
2369  break;
2370  case DBTYPE_TIMESTAMPTZ:
2371  case DBTYPE_TIMESTAMP:
2372  case DBTIMESTAMP_USENOW:
2373  $beforeValue = GetAuditTime($dbh, $beforeValue, $Cu, true, $tz);
2374  $afterValue = GetAuditTime($dbh, $afterValue, $Cu, true, $tz);
2375  break;
2376  }
2377 
2378  $combinedRow[] = array("col" => trim($colName), "before" => $beforeValue, "after" => $afterValue, "label" => trim($label), "same" => $same);
2379  }
2380  if (!$afterEmpty) {
2381  if (!isset($afterRow) || !is_array($afterRow)) {
2382  throw new exception ("After row is not an array.", 20);
2383  }
2384  foreach($afterRow as $colName => $colValue) {
2385  $colDef = $tableDefinition["_cols"][$colName];
2386  if (isset($beforeRow[$colName])) {
2387  continue; // Already processed above.
2388  }
2389  if (!isset($colDef)) {
2390  throw new exception("Table mismatch.", 19);
2391  }
2392 
2393  $label = isset($colDef["label"]) ? $colDef["label"] : $colName;
2394  $afterValue = !isset($colValue) || trim($colValue) == "" ? true : $colValue;
2395  $beforeValue = !HCU_array_key_exists($colName, $beforeRow) ? false :
2396  (!isset($beforeRow[$colName]) || trim($beforeRow[$colName]) == "" ? true : $beforeRow[$colName]);
2397  $same = false;
2398 
2399  // Empty and null are the same and are set to "--"
2400  $beforeValue = $beforeValue === true ? "--" : (trim($colName) == "passwd" ? $passwordMask : trim($beforeValue));
2401  $afterValue = $afterValue === true ? "--" : (trim($colName) == "passwd" && $afterValue != "" ? $passwordMask : trim($afterValue));
2402 
2403  // If time or timestamp, then format the output. If timestamp, then remember to also output it in Credit Union time.
2404  // NOTE: this doesn't catch the prior login / failed login / current login because that is in a STRING field for some reason.
2405  switch($colDef["type"]) {
2406  case DBTYPE_DATE:
2407  $beforeValue = GetAuditTime($dbh, $beforeValue, $Cu, false, $tz);
2408  $afterValue = GetAuditTime($dbh, $afterValue, $Cu, false, $tz);
2409  break;
2410  case DBTYPE_TIMESTAMPTZ:
2411  case DBTYPE_TIMESTAMP:
2412  case DBTIMESTAMP_USENOW:
2413  $beforeValue = GetAuditTime($dbh, $beforeValue, $Cu, true, $tz);
2414  $afterValue = GetAuditTime($dbh, $afterValue, $Cu, true, $tz);
2415  break;
2416  }
2417 
2418  $combinedRow[] = array("col" => trim($colName), "before" => $beforeValue, "after" => $afterValue, "label" => trim($label), "same" => $same);
2419  }
2420  }
2421  $type = $afterEmpty ? "remove" : "update";
2422  $combinedRow = array("type" => $type, "values" => $combinedRow);
2423  $tableTypeMap[$type] = $type;
2424  }
2425 
2426  $newTableRow["rows"][] = $combinedRow;
2427  $newTableRow["type"] = count($tableTypeMap) > 1 ? "mixed" : current($tableTypeMap);
2428  }
2429 
2430  $details[] = $newTableRow;
2431  }
2432 
2433  unset($row["before"]);
2434  unset($row["after"]);
2435  $row["details"] = $details;
2436 
2437  $returnArray = array("status" => "000", "error" => "", "row" => $row);
2438  } catch (exception $e) {
2439 
2440  $returnArray = array("status" => $e->getCode(), "error" => $e->getMessage());
2441  }
2442 
2443  return $returnArray;
2444 }
2445 
2446 /**
2447  * This function will determine if a particular header has been set for response to the client
2448  *
2449  * @param string $header The header text in question
2450  *
2451  * @return boolean {true - if header was found}
2452  */
2453 function FindHeaderSent($header) {
2454  $headers = headers_list();
2455  $header = trim($header,': ');
2456  $result = false;
2457 
2458  if (count($headers) > 0) {
2459  foreach ($headers as $hdr) {
2460  if (stripos($hdr, $header) !== false) {
2461  $result = true;
2462  }
2463  }
2464  }
2465  return $result;
2466 }
2467 
2468 /**
2469  * HasMasterAccess
2470  * this function will check if the admin user currently
2471  * logged in has master access. Master access can come
2472  * from the user flag set in user maintenance or the cu
2473  * super user: cu name = username.
2474  *
2475  * @param $pAdmEnv array environment variable
2476  * this usually holds the username, cu name and
2477  * database handle.
2478  * @return $access boolean
2479  */
2480 function AdminHasMasterAccess($pAdmEnv) {
2481  $sql = "
2482  SELECT userflags FROM cuadminusers
2483  WHERE user_name = '{$pAdmEnv['Cn']}'
2484  AND cu = '{$pAdmEnv['Cu']}' ";
2485  $sqlRs = db_query($sql, $pAdmEnv['dbh']);
2486  if (!$sqlRs) {
2487  throw new Exception("Failed to read user access", 20);
2488  }
2489 
2490  $userFlagsAry = db_fetch_array($sqlRs, 0);
2491  $userFlags = $userFlagsAry['userflags'];
2492 
2493  $hasMasterFlag = ($userFlags & GetAdminUserFlagsValue("ADM_MASTER_PRIV")) == GetAdminUserFlagsValue("ADM_MASTER_PRIV");
2494  $hasSuperPrivillages = (strtolower($pAdmEnv['Cu']) == strtolower($pAdmEnv['Cn']));
2495 
2496  return ($hasSuperPrivillages || $hasMasterFlag);
2497 }