Fix to return correct value instead of boolean from acl_check().
[openemr.git] / library / acl.inc
blobbaf5bd3a08b1ee12530f10d5a1465e303e0e7a62
1 <?php
2 // php-GACL access controls are included in OpenEMR. The below
3 // function will automatically create the path where gacl.class.php
4 // can be found. Note that this path can be manually set below
5 // for users who are using an external version of php-GACL.
6 // Also note that php-GACL access controls can be turned off
7 // below.
9   $phpgacl_location = dirname(__FILE__).'/../gacl';
12 // If using an external version of phpGACL, then uncomment the following
13 // line and manually place the path below.  IN THIS CASE YOU MUST ALSO
14 // COMMENT OUT ABOVE $phpgacl_location ASSIGNMENT ABOVE, OR BACKUPS WILL
15 // NOT RESTORE PROPERLY!
17 //$phpgacl_location = "/var/www/gacl";
19 // If you want to turn off php-GACL, then uncomment the following line.
20 // IN THIS CASE YOU MUST ALSO COMMENT OUT ABOVE $phpgacl_location ASSIGNMENT(S)
21 // ABOVE, OR BACKUPS WILL NOT RESTORE PROPERLY!
23 //unset($phpgacl_location);
26   // The following Access Control Objects (ACO) are currently supported.
27   // These are the "things to be protected":
28   //
29   // Section "admin" (Administration):
30   //   super       Superuser - can delete patients, encounters, issues
31   //   calendar    Calendar Settings
32   //   database    Database Reporting
33   //   forms       Forms Administration
34   //   practice    Practice Settings
35   //   superbill   Superbill Codes Administration
36   //   users       Users/Groups/Logs Administration
37   //   batchcom    Batch Communication Tool
38   //   language    Language Interface Tool
39   //   drugs       Pharmacy Dispensary
40   //   acl         ACL Administration
41   //
42   // Section "acct" (Accounting):
43   //   bill        Billing (write optional)
44   //   disc        Allowed to discount prices (in Fee Sheet or Checkout form)
45   //   eob         EOB Data Entry
46   //   rep         Financial Reporting - my encounters
47   //   rep_a       Financial Reporting - anything
48   //
49   // Section "patients" (Patient Information):
50   //   appt        Appointments (write optional)
51   //   demo        Demographics (write,addonly optional)
52   //   med         Medical Records and History (write,addonly optional)
53   //   trans       Transactions, e.g. referrals (write optional)
54   //   docs        Documents (write,addonly optional)
55   //   notes       Patient Notes (write,addonly optional)
56   //   sign        Sign Lab Results (write,addonly optional)
57   //
58   // Section "encounters" (Encounter Information):
59   //   auth        Authorize - my encounters
60   //   auth_a      Authorize - any encounters
61   //   coding      Coding - my encounters (write,wsome optional)
62   //   coding_a    Coding - any encounters (write,wsome optional)
63   //   notes       Notes - my encounters (write,addonly optional)
64   //   notes_a     Notes - any encounters (write,addonly optional)
65   //   date_a      Fix encounter dates - any encounters
66   //   relaxed     Less-private information (write,addonly optional)
67   //               (e.g. the Sports Fitness encounter form)
68   //
69   // Section "squads" applies to sports team use only:
70   //   acos in this section define the user-specified list of squads
71   //
72   // Section "sensitivities" (Sensitivities):
73   //   normal     Normal
74   //   high       High
75   //
76   // Section "lists" (Lists):
77   //   default    Default List (write,addonly optional)
78   //   state      State List (write,addonly optional)
79   //   country    Country List (write,addonly optional)
80   //   language   Language List (write,addonly optional)
81   //   ethrace    Ethnicity-Race List (write,addonly optional)
82   //
83   // Section "placeholder" (Placeholder):
84   //   filler     Placeholder (Maintains empty ACLs)
85   //
86   // Section "nationnotes" (Nation Notes):
87   //   nn_configure     Nation Notes
88   //
89   // Section "patientportal" (Patient Portal):
90   //   portal     Patient Portal
91   
93   if (isset ($phpgacl_location)) {
94     include_once("$phpgacl_location/gacl.class.php");
95     $gacl_object = new gacl();
96     //DO NOT CHANGE BELOW VARIABLE
97     $section_aro_value = 'users';
98   }
100   // acl_check should return 0 if access is denied.  Otherwise it may
101   // return anything that evaluates to true.  In addition if any of the
102   // following types of access are applicable, then the corresponding value
103   // must be returned if and only if such access is granted (ony one may
104   // be specified):
105   //
106   // * write   - the user may add or modify the ACO
107   // * wsome   - the user has limited add/modify access to the ACO
108   // * addonly - the user may view and add but not modify entries
109   //
110   function acl_check($section, $value, $user = '') {
111     global $gacl_object, $phpgacl_location, $section_aro_value;
112     if (! $user) $user = $_SESSION['authUser'];
114     if ($phpgacl_location) {
115       return $gacl_object->acl_return_value($section, $value, $section_aro_value, $user);
116     }
118     // If no phpgacl, then apply the old static rules whereby "authorized"
119     // users (providers) can do anything, and other users can do most things.
120     // If you want custom access control but don't want to mess with phpGACL,
121     // then you could customize the code below instead.
123     if ($user == 'admin') return 'write';
124     if ($section == 'admin' && $value == 'super') return 0;
125     if ($_SESSION['userauthorized']) return 'write';
127     if ($section == 'patients') {
128       if ($value == 'med') return 1;
129       return 'write';
130     }
131     else if ($section == 'encounters') {
132       if (strpos($value, 'coding' ) === 0) return 'write';
133       if (strpos($value, 'notes'  ) === 0) return 'write';
134       if ($value == 'relaxed') return 'write';
135     }
136     else if ($section != 'admin') {
137       return 'write';
138     }
140     return 0;
141   }
143   // Get the ACO name/value pairs for a designated section.  Each value
144   // is an array (section_value, value, order_value, name, hidden).
145   //
146   function acl_get_section_acos($section) {
147     global $phpgacl_location;
148     if ($phpgacl_location) {
149       include_once("$phpgacl_location/gacl_api.class.php");
150       $gacl = new gacl_api();
151       $arr1 = $gacl->get_objects($section, 1, 'ACO');
152       $arr = array();
153       if (!empty($arr1[$section])) {
154         foreach ($arr1[$section] as $value) {
155           $odata = $gacl->get_object_data($gacl->get_object_id($section, $value, 'ACO'), 'ACO');
156           $arr[$value] = $odata[0];
157         }
158       }
159       return $arr;
160     }
161     return 0;
162   }
164   // Return an array keyed on squad ACO names.
165   // This is only applicable for sports team use.
166   //
167   function acl_get_squads() {
168     return acl_get_section_acos('squads');
169   }
171   // Return an array keyed on encounter sensitivity level ACO names.
172   // Sensitivities are useful when some encounter notes are not
173   // medically sensitive (e.g. a physical fitness test), and/or if
174   // some will be "for doctor's eyes only" (e.g. STD treatment).
175   //
176   // When a non-blank sensitivity value exists in the new encounter
177   // form, it names an additional ACO required for access to all forms
178   // in the encounter.  If you want some encounters to be non-sensitive,
179   // then you also need some default nonblank sensitivity for normal
180   // encounters, as well as greater encounter notes permissions for
181   // those allowed to view non-sensitive encounters.
182   //
183   function acl_get_sensitivities() {
184     return acl_get_section_acos('sensitivities');
185   }
187   //
188   // Returns true if aco exist
189   // Returns false if aco doesn't exist
190   //    $section_name = name of section (string)
191   //    $aco_name = name of aco (string)
192   //
193   function aco_exist($section_name, $aco_name) {
194    global $phpgacl_location;
195    if (isset ($phpgacl_location)) {
196     include_once("$phpgacl_location/gacl_api.class.php");
197     $gacl = new gacl_api();
198     $aco_id = $gacl->get_object_id($section_name,  $aco_name, 'ACO');
199     if ($aco_id) {
200      return true;
201     }
202    }
203    return false;
204   }
206   //
207   // Returns a sorted array of all available Group Titles.
208   //
209   function acl_get_group_title_list() {
210     global $phpgacl_location;
211     if (isset ($phpgacl_location)) {
212       include_once("$phpgacl_location/gacl_api.class.php");
213       $gacl = new gacl_api();
214       $parent_id = $gacl->get_root_group_id();
215       $arr_group_ids = $gacl->get_group_children($parent_id, 'ARO', 'RECURSE');
216       $arr_group_titles = array();
217       foreach ($arr_group_ids as $value) {
218         $arr_group_data = $gacl->get_group_data($value, 'ARO');
219         $arr_group_titles[$value] = $arr_group_data[3];
220       }
221       sort($arr_group_titles);
222       return $arr_group_titles;
223     }
224     return 0;
225   }
227   //
228   // Returns a sorted array of group Titles that a user belongs to.
229   // Returns 0 if does not belong to any group yet.
230   //   $user_name = Username, which is login name.
231   //
232   function acl_get_group_titles($user_name) {
233     global $phpgacl_location, $section_aro_value;
234     if (isset ($phpgacl_location)) {
235       include_once("$phpgacl_location/gacl_api.class.php");
236       $gacl = new gacl_api();
237       $user_aro_id = $gacl->get_object_id($section_aro_value, $user_name, 'ARO');
238       if ($user_aro_id) {
239         $arr_group_id = $gacl->get_object_groups($user_aro_id, 'ARO', 'NO_RECURSE');
240         if ($arr_group_id) {
241           foreach ($arr_group_id as $key => $value) {
242             $arr_group_data = $gacl->get_group_data($value, 'ARO');
243             $arr_group_titles[$key] =  $arr_group_data[3];
244           }
245         sort($arr_group_titles);
246         return $arr_group_titles;
247         }
248       }
249     }
250     return 0;
251   }
253   //
254   // This will place the user aro object into selected group(s)
255   // It uses the set_user_aro() function
256   //   $username = username (string)
257   //   $group = title of group(s) (string or array)
258   //
259   function add_user_aros($username, $group) {
260    $current_user_groups = acl_get_group_titles($username);
261    if (!$current_user_groups) {
262     $current_user_groups = array();
263    }
264    if (is_array($group)){
265     foreach ($group as $value) {
266        if (!in_array($value, $current_user_groups)) { 
267         array_push($current_user_groups, $value);
268        }
269     }
270    }
271    else {
272     if (!in_array($group, $current_user_groups)) {
273      array_push($current_user_groups, $group);
274     }
275    }
276    $user_data = mysql_fetch_array(sqlStatement("select * from users where username='" .
277     $username . "'"));
278    set_user_aro($current_user_groups, $username, $user_data["fname"],
279     $user_data["mname"], $user_data["lname"]);
280    return;
281   }
283   //
284   // This will remove the user aro object from the selected group(s)
285   // It uses the set_user_aro() function
286   //   $username = username (string)
287   //   $group = title of group(s) (string or array)
288   //
289   function remove_user_aros($username, $group) {
290    $current_user_groups = acl_get_group_titles($username);
291    $new_user_groups = array();
292    if (is_array($group)){
293     foreach ($current_user_groups as $value) {
294      if (!in_array($value, $group)) {
295       array_push($new_user_groups, $value);
296      }
297     }
298    }
299    else {
300     foreach ($current_user_groups as $value) {
301      if ($value != $group) {
302       array_push($new_user_groups, $value);
303      }
304     }
305    }
306    $user_data = mysql_fetch_array(sqlStatement("select * from users where username='" .
307     $username . "'"));
308    set_user_aro($new_user_groups, $username, $user_data["fname"],
309     $user_data["mname"], $user_data["lname"]);
310    return;
311   }
313   //
314   // This will either create or edit a user aro object, and then place it
315   // in the requested groups. It will not allow removal of the 'admin'
316   // user or gacl_protected users from the 'admin' group.
317   //   $arr_group_titles = titles of the groups that user will be added to.
318   //   $user_name = username, which is login name.
319   //   $first_name = first name
320   //   $middle_name = middle name
321   //   $last_name = last name
322   //
323   function set_user_aro($arr_group_titles, $user_name, $first_name, $middle_name, $last_name) {
324     global $phpgacl_location, $section_aro_value;
326     if (isset ($phpgacl_location)) {
327       include_once("$phpgacl_location/gacl_api.class.php");
328       $gacl = new gacl_api();
330       //see if this user is gacl protected (ie. do not allow
331       //removal from the Administrators group)
332       require_once(dirname(__FILE__).'/user.inc');
333       require_once(dirname(__FILE__).'/calendar.inc');
334       $userNametoID = getIDfromUser($user_name);
335       if (checkUserSetting("gacl_protect","1",$userNametoID) || $user_name == "admin") {
336         $gacl_protect = true;
337       }
338       else {
339         $gacl_protect = false;
340       }
342       //get array of all available group ID numbers
343       $parent_id = $gacl->get_root_group_id();
344       $arr_all_group_ids = $gacl->get_group_children($parent_id, 'ARO', 'RECURSE');
346       //Cycle through ID array to find and process each selected group
347       //Create a counter since processing of first hit is unique
348       $counter = 0;
349       foreach ($arr_all_group_ids as $value) {
350         $arr_group_data = $gacl->get_group_data($value, 'ARO');
351         if ((empty($arr_group_titles)) ||
352          (in_array($arr_group_data[3], $arr_group_titles))) {
353           //We have a hit, so need to add group and increment counter
354           // because processing of first hit is unique
355           //This will also deal with an empty $arr_group_titles array
356           // removing user from all groups unless 'admin'
357           $counter = $counter + 1;
358           //create user full name field
359           if ($middle_name) {
360             $full_name = $first_name . " " . $middle_name . " " .  $last_name;
361           }
362           else {
363             if ($last_name) {
364               $full_name = $first_name . " " . $last_name;
365             }
366             else {
367               $full_name = $first_name;
368             }
369           }
371           //If this is not the first group to be added, then will skip below
372           // and will be added. If this is the first group, then need to
373           // go thru several steps before adding the group.
374           if ($counter == 1) {
375             //get ID of user ARO object, if it exist
376             $user_aro_id = $gacl->get_object_id($section_aro_value, $user_name, 'ARO');
377             if ($user_aro_id) {
378               //user ARO object already exist, so will edit it
379               $gacl->edit_object($user_aro_id, $section_aro_value, $full_name, $user_name, 10, 0, 'ARO');
381               //remove all current user ARO object group associations
382               $arr_remove_group_ids = $gacl->get_object_groups($user_aro_id, 'ARO', 'NO_RECURSE');
383               foreach ($arr_remove_group_ids as $value2) {
384                 $gacl->del_group_object($value2, $section_aro_value, $user_name, 'ARO');
385               }
386             }
387             else {
388               //user ARO object does not exist, so will create it
389               $gacl->add_object($section_aro_value, $full_name, $user_name, 10, 0, 'ARO');
390             }
391           }
393           //place the user ARO object in the selected group (if group(s) is selected)
394           if (!empty($arr_group_titles)) {
395             $gacl->add_group_object($value, $section_aro_value, $user_name, 'ARO');
396           }
398           //
399           //Below will not allow 'admin' or gacl_protected user to be removed from 'admin' group
400           //
401           if ($gacl_protect) {
402             $boolean_admin=0;
403             $admin_id = $gacl->get_object_id($section_aro_value, $user_name, 'ARO');
404             $arr_admin = $gacl->get_object_groups($admin_id, 'ARO', 'NO_RECURSE');
405             foreach ($arr_admin as $value3) {
406               $arr_admin_data = $gacl->get_group_data($value3, 'ARO');
407               if (strcmp($arr_admin_data[2], 'admin') == 0) {
408                 $boolean_admin=1;
409               }
410             }
411             if (!$boolean_admin) {
412               foreach ($arr_all_group_ids as $value4) {
413                 $arr_temp = $gacl->get_group_data($value4, 'ARO');
414                 if ($arr_temp[2] == 'admin') {
415                   $gacl->add_group_object($value4, $section_aro_value, $user_name, 'ARO');
416                 }
417               }
418             }
419           }
420         }
421         //if array of groups was empty, then we are done, and can break from loop
422         if (empty($arr_group_titles)) break;
423       }
424       return true;
425     }
426    return false;
427   }
429   //
430   // Returns true if acl exist
431   // Returns false if acl doesn't exist
432   //  EITHER $title or $name is required(send FALSE in variable
433   //  not being used). If both are sent, then only $title will be
434   //  used.
435   //  $return_value is required
436   //    $title = title of acl (string)
437   //    $name = name of acl (string)
438   //    $return_value = return value of acl (string)
439   //
440   function acl_exist($title, $name, $return_value) {
441    global $phpgacl_location;
442    if (isset ($phpgacl_location)) {
443     include_once("$phpgacl_location/gacl_api.class.php");
444     $gacl = new gacl_api();
445     if (!$name) {
446      $acl = $gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $title, FALSE, FALSE, FALSE, $return_value);
447     }
448     else if (!$title) {
449      $group_id = $gacl->get_group_id($name, NULL, 'ARO');
450      if ($group_id) {
451       $group_data = $gacl->get_group_data($group_id, 'ARO');
452       $acl = $gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $group_data[3], FALSE, FALSE, FALSE, $return_value);
453      }
454      else {
455      return false;
456      }
457     }
458     else {
459      $acl = $gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $title, FALSE, FALSE, FALSE, $return_value);
460     }
461     if (!empty($acl)) {
462      return true;
463     }
464     else {
465      return false;
466     }
467    }
468   }
470   //
471   // This will add a new acl and group(if group doesn't yet exist)
472   // with one aco in it.
473   //   $acl_title = title of acl (string)
474   //   $acl_name = name of acl (string)
475   //   $return_value = return value of acl (string)
476   //   $note = description of acl (array)
477   //
478   function acl_add($acl_title, $acl_name, $return_value, $note) {
479    global $phpgacl_location;
480    if (isset ($phpgacl_location)) {
481     include_once("$phpgacl_location/gacl_api.class.php");
482     $gacl = new gacl_api();
483     $group_id = $gacl->get_group_id($acl_name, $acl_title, 'ARO');
484     if ($group_id) {
485      //group already exist, so just create acl
486      $gacl->add_acl(array("placeholder"=>array("filler")),
487       NULL, array($group_id), NULL, NULL, 1, 1, $return_value, $note);
488     }
489     else {
490      //create group, then create acl
491      $parent_id = $gacl->get_root_group_id();
492      $aro_id = $gacl->add_group($acl_name, $acl_title, $parent_id, 'ARO');
493      $gacl->add_acl(array("placeholder"=>array("filler")),
494       NULL, array($aro_id), NULL, NULL, 1, 1, $return_value, $note);
495     }
496     return;
497    }
498    return 0;
499   }
501   //
502   // This will remove acl. It will also remove group(if the group
503   // is no longer associated with any acl's).
504   //   $acl_title = title of acl (string)
505   //   $acl_name = name of acl (string)
506   //   $return_value = return value of acl (string)
507   //   $note = description of acl (array)
508   //
509   function acl_remove($acl_title, $return_value) {
510    global $phpgacl_location;
511    if (isset ($phpgacl_location)) {
512     include_once("$phpgacl_location/gacl_api.class.php");
513     $gacl = new gacl_api();
514     //First, delete the acl
515     $acl_id=$gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $acl_title, FALSE, FALSE, FALSE, $return_value);
516     $gacl->del_acl($acl_id[0]);
517     //Then, remove the group(if no more acl's are remaining)
518     $acl_search=$gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $acl_title, FALSE, FALSE, FALSE, FALSE);
519     if (empty($acl_search)){
520      $group_id=$gacl-> get_group_id(NULL, $acl_title, 'ARO');
521      $gacl->del_group($group_id, TRUE, 'ARO');
522     }
523     return;
524    }
525    return 0;
526   }
528   //
529   // This will place the aco(s) into the selected acl
530   //   $acl_title = title of acl (string)
531   //   $return_value = return value of acl (string)
532   //   $aco_id = id of aco (array)
533   //
534   function acl_add_acos($acl_title, $return_value, $aco_id) {
535    global $phpgacl_location;
536    if (isset ($phpgacl_location)) {
537     include_once("$phpgacl_location/gacl_api.class.php");
538     $gacl = new gacl_api();
539     $acl_id = $gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $acl_title, FALSE, FALSE, FALSE, $return_value);
540     foreach ($aco_id as $value) { 
541      $aco_data = $gacl->get_object_data($value, 'ACO');
542      $aco_section = $aco_data[0][0];
543      $aco_name = $aco_data[0][1];   
544      $gacl->append_acl($acl_id[0], NULL, NULL, NULL, NULL, array($aco_section=>array($aco_name)));
545     }
546     return;
547    }
548    return 0;
549   }
551   //
552   // This will remove the aco(s) from the selected acl
553   //  Note if all aco's are removed, then will place the filler-placeholder
554   //  into the acl to avoid complete removal of the acl.
555   //   $acl_title = title of acl (string)
556   //   $return_value = return value of acl (string)
557   //   $aco_id = id of aco (array)
558   //
559   function acl_remove_acos($acl_title, $return_value, $aco_id) {
560    global $phpgacl_location;
561    if (isset ($phpgacl_location)) {
562     include_once("$phpgacl_location/gacl_api.class.php");
563     $gacl = new gacl_api();
564     $acl_id = $gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $acl_title, FALSE, FALSE, FALSE, $return_value);
566     // Check to see if removing all acos. If removing all acos then will
567     //  ensure the filler-placeholder aco in acl to avoid complete
568     //  removal of the acl.
569     if (count($aco_id) == acl_count_acos($acl_title, $return_value)) {
570      //1-get the filler-placeholder aco id
571      $filler_aco_id = $gacl->get_object_id('placeholder','filler','ACO');     
572      //2-add filler-placeholder aco
573      acl_add_acos($acl_title, $return_value, array($filler_aco_id));
574      //3-ensure filler-placeholder aco is not to be deleted
575      $safeListaco = remove_element($_POST["selection"],$filler_aco_id);
576      //4-prepare to safely delete the acos
577      $aco_id = $safeListaco;
578     }
580     foreach ($aco_id as $value) {
581      $aco_data = $gacl->get_object_data($value, 'ACO');
582      $aco_section = $aco_data[0][0];
583      $aco_name = $aco_data[0][1];
584      $gacl->shift_acl($acl_id[0], NULL, NULL, NULL, NULL, array($aco_section=>array($aco_name)));
585      }
586     return;
587    }
588    return 0;
589   }
591   //
592   // This will return the number of aco objects
593   //  in a specified acl.
594   //   $acl_title = title of acl (string)
595   //   $return_value = return value of acl (string)
596   //
597   function acl_count_acos($acl_title, $return_value) {
598    global $phpgacl_location;
599    if (isset ($phpgacl_location)) {
600     include_once("$phpgacl_location/gacl_api.class.php");
601     $gacl = new gacl_api();
602     $acl_id = $gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $acl_title, FALSE, FALSE, FALSE, $return_value);
603     $acl_data = $gacl->get_acl($acl_id[0]);
604     $aco_count = 0;
605     foreach ($acl_data['aco'] as $key => $value) {
606      $aco_count = $aco_count + count($acl_data['aco'][$key]);
607     }
608     return $aco_count;
609    }
610    return 0;
611   }
613   //
614   // Function to remove an element from an array
615   //
616   function remove_element($arr, $val){
617    $arr2 = array();
618    foreach ($arr as $value){
619     if ($value != $val) {
620      array_push($arr2,$value);
621     }
622    }
623    return $arr2;
624   }