PageRenderTime 54ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/library/log.inc

https://github.com/robytj/openemr
PHP | 746 lines | 707 code | 13 blank | 26 comment | 57 complexity | 251bb0983d06c321915fb4e2441c3c2e MD5 | raw file
Possible License(s): LGPL-2.1, AGPL-1.0, GPL-2.0
  1. <?php
  2. #require_once("{$GLOBALS['srcdir']}/sql.inc");
  3. require_once(dirname(__FILE__). "/sql.inc");
  4. function newEvent($event, $user, $groupname, $success, $comments="") {
  5. $adodb = $GLOBALS['adodb']['db'];
  6. $crt_user=$_SERVER['SSL_CLIENT_S_DN_CN'];
  7. /* More details added to the log */
  8. $sql = "insert into log ( date, event, user, groupname, success, comments, crt_user) " .
  9. "values ( NOW(), " . $adodb->qstr($event) . "," . $adodb->qstr($user) .
  10. "," . $adodb->qstr($groupname) . "," . $adodb->qstr($success) . "," .
  11. $adodb->qstr($comments) ."," .
  12. $adodb->qstr($crt_user) . ")";
  13. //$ret = sqlInsertClean($sql);
  14. // Call the new function created for audit log
  15. $ret = sqlInsertClean_audit($sql);
  16. send_atna_audit_msg($user, $groupname, $event, 0, $success, $comments);
  17. }
  18. function getEventByDate($date, $user="", $cols="DISTINCT date, event, user, groupname, patient_id, success, comments, checksum")
  19. {
  20. $sql = "SELECT $cols FROM log WHERE date >= '$date 00:00:00' AND date <= '$date 23:59:59'";
  21. if ($user) $sql .= " AND user LIKE '$user'";
  22. $sql .= " ORDER BY date DESC LIMIT 5000";
  23. $res = sqlStatement($sql);
  24. for($iter=0; $row=sqlFetchArray($res); $iter++) {
  25. $all[$iter] = $row;
  26. }
  27. return $all;
  28. }
  29. /******************
  30. * Get records from the LOG and Extended_Log table
  31. * using the optional parameters:
  32. * date : a specific date (defaults to today)
  33. * user : a specific user (defaults to none)
  34. * cols : gather specific columns (defaults to date,event,user,groupname,comments)
  35. * sortby : sort the results by (defaults to none)
  36. * RETURNS:
  37. * array of results
  38. ******************/
  39. function getEvents($params)
  40. {
  41. // parse the parameters
  42. $cols = "DISTINCT date, event, user, groupname, patient_id, success, comments,checksum,crt_user";
  43. if (isset($params['cols']) && $params['cols'] != "") $cols = $params['cols'];
  44. $date1 = date("Y-m-d", time());
  45. if (isset($params['sdate']) && $params['sdate'] != "") $date1= $params['sdate'];
  46. $date2 = date("Y-m-d", time());
  47. if (isset($params['edate']) && $params['edate'] != "") $date2= $params['edate'];
  48. $user = "";
  49. if (isset($params['user']) && $params['user'] != "") $user= $params['user'];
  50. //VicarePlus :: For Generating log with patient id.
  51. $patient = "";
  52. if (isset($params['patient']) && $params['patient'] != "") $patient= $params['patient'];
  53. $sortby = "";
  54. if (isset($params['sortby']) && $params['sortby'] != "") $sortby = $params['sortby'];
  55. $levent = "";
  56. if (isset($params['levent']) && $params['levent'] != "") $levent = $params['levent'];
  57. $tevent = "";
  58. if (isset($params['tevent']) && $params['tevent'] != "") $tevent = $params['tevent'];
  59. $event = "";
  60. if (isset($params['event']) && $params['event'] != "") $event = $params['event'];
  61. if ($event!=""){
  62. if ($sortby == "comments") $sortby = "description";
  63. if ($sortby == "groupname") $sortby = ""; //VicarePlus :: since there is no groupname in extended_log
  64. if ($sortby == "success") $sortby = ""; //VicarePlus :: since there is no success field in extended_log
  65. if ($sortby == "checksum") $sortby = ""; //VicarePlus :: since there is no checksum field in extended_log
  66. $columns = "DISTINCT date, event, user, recipient,patient_id,description";
  67. $sql = "SELECT $columns FROM extended_log WHERE date >= '$date1 00:00:00' AND date <= '$date2 23:59:59'";
  68. if ($user != "") $sql .= " AND user LIKE '$user'";
  69. if ($patient != "") $sql .= " AND patient_id LIKE '$patient'";
  70. if ($levent != "") $sql .= " AND event LIKE '$levent%'";
  71. if ($sortby != "") $sql .= " ORDER BY ".$sortby." DESC "; // descending order
  72. $sql .= " LIMIT 5000";
  73. }
  74. else
  75. {
  76. // do the query
  77. $sql = "SELECT $cols FROM log WHERE date >= '$date1 00:00:00' AND date <= '$date2 23:59:59'";
  78. if ($user != "") $sql .= " AND user LIKE '$user'";
  79. if ($patient != "") $sql .= " AND patient_id LIKE '$patient'";
  80. if ($levent != "") $sql .= " AND event LIKE '$levent%'";
  81. if ($tevent != "") $sql .= " AND event LIKE '%$tevent'";
  82. if ($sortby != "") $sql .= " ORDER BY ".$sortby." DESC "; // descending order
  83. $sql .= " LIMIT 5000";
  84. }
  85. $res = sqlStatement($sql);
  86. for($iter=0; $row=sqlFetchArray($res); $iter++) {
  87. $all[$iter] = $row;
  88. }
  89. return $all;
  90. }
  91. /* Given an SQL insert/update that was just performeds:
  92. * - Find the table and primary id of the row that was created/modified
  93. * - Calculate the SHA1 checksum of that row (with all the
  94. * column values concatenated together).
  95. * - Return the SHA1 checksum as a 40 char hex string.
  96. * If this is not an insert/update query, return "".
  97. * If multiple rows were modified, return "".
  98. * If we're unable to determine the row modified, return "".
  99. */
  100. function sql_checksum_of_modified_row($statement)
  101. {
  102. $table = "";
  103. $rid = "";
  104. $tokens = preg_split("/[\s,(\'\"]+/", $statement);
  105. /* Identifying the id for insert/replace statements for calculating the checksum */
  106. if((strcasecmp($tokens[0],"INSERT")==0) || (strcasecmp($tokens[0],"REPLACE")==0)){
  107. $table = $tokens[2];
  108. $rid = mysql_insert_id($GLOBALS['dbh']);
  109. /* For handling the table that doesn't have auto-increment column */
  110. if ($rid === 0 || $rid === FALSE) {
  111. if($table == "gacl_aco_map" || $table == "gacl_aro_groups_map" || $table == "gacl_aro_map" || $table == "gacl_axo_groups_map" || $table == "gacl_axo_map")
  112. $id="acl_id";
  113. else if($table == "gacl_groups_aro_map" || $table == "gacl_groups_axo_map")
  114. $id="group_id";
  115. else
  116. $id="id";
  117. /* To handle insert statements */
  118. if($tokens[3] == $id){
  119. for($i=4;$i<count($tokens);$i++){
  120. if(strcasecmp($tokens[$i],"VALUES")==0){
  121. $rid=$tokens[$i+1];
  122. break;
  123. }// if close
  124. }//for close
  125. }//if close
  126. /* To handle replace statements */
  127. else if(strcasecmp($tokens[3],"SET")==0){
  128. if((strcasecmp($tokens[4],"ID")==0) || (strcasecmp($tokens[4],"`ID`")==0)){
  129. $rid=$tokens[6];
  130. }// if close
  131. }
  132. else {
  133. return "";
  134. }
  135. }
  136. }
  137. /* Identifying the id for update statements for calculating the checksum */
  138. else if(strcasecmp($tokens[0],"UPDATE")==0){
  139. $table = $tokens[1];
  140. $offset = 3;
  141. $total = count($tokens);
  142. /* Identifying the primary key column for the updated record */
  143. if ($table == "form_physical_exam") {
  144. $id = "forms_id";
  145. }
  146. else if ($table == "claims"){
  147. $id = "patient_id";
  148. }
  149. else if ($table == "openemr_postcalendar_events") {
  150. $id = "pc_eid";
  151. }
  152. else if ($table == "lang_languages"){
  153. $id = "lang_id";
  154. }
  155. else if ($table == "openemr_postcalendar_categories" || $table == "openemr_postcalendar_topics"){
  156. $id = "pc_catid";
  157. }
  158. else if ($table == "openemr_postcalendar_limits"){
  159. $id = "pc_limitid";
  160. }
  161. else if($table == "gacl_aco_map" || $table == "gacl_aro_groups_map" || $table == "gacl_aro_map" || $table == "gacl_axo_groups_map" || $table == "gacl_axo_map"){
  162. $id="acl_id";
  163. }
  164. else if($table == "gacl_groups_aro_map" || $table == "gacl_groups_axo_map"){
  165. $id="group_id";
  166. }
  167. else {
  168. $id = "id";
  169. }
  170. /* Identifying the primary key value for the updated record */
  171. while ($offset < $total) {
  172. /* There are 4 possible ways that the id=123 can be parsed:
  173. * ('id', '=', '123')
  174. * ('id=', '123')
  175. * ('id=123')
  176. * ('id', '=123')
  177. */
  178. $rid = "";
  179. /*id=', '123'*/
  180. if (($tokens[$offset] == "$id=") && ($offset + 1 < $total)) {
  181. $rid = $tokens[$offset+1];
  182. break;
  183. }
  184. /* 'id', '=', '123' */
  185. else if ($tokens[$offset] == "$id" && $tokens[$offset+1] == "=" && ($offset+2 < $total)) {
  186. $rid = $tokens[$offset+2];
  187. break;
  188. }
  189. /*id=123*/
  190. else if (strpos($tokens[$offset], "$id=") === 0) {
  191. $tid = substr($tokens[$offset], strlen($id)+1);
  192. if(is_numeric($tid))
  193. $rid=$tid;
  194. break;
  195. }
  196. /*'id', '=123' */
  197. else if($tokens[$offset] == "$id") {
  198. $tid = substr($tokens[$offset+1],1);
  199. if(is_numeric($tid))
  200. $rid=$tid;
  201. break;
  202. }
  203. $offset += 1;
  204. }//while ($offset < $total)
  205. }// else if ($tokens[0] == 'update' || $tokens[0] == 'UPDATE' )
  206. if ($table == "" || $rid == "") {
  207. return "";
  208. }
  209. /* Framing sql statements for calculating checksum */
  210. if ($table == "form_physical_exam") {
  211. $sql = "select * from $table where forms_id = $rid";
  212. }
  213. else if ($table == "claims"){
  214. $sql = "select * from $table where patient_id = $rid";
  215. }
  216. else if ($table == "openemr_postcalendar_events") {
  217. $sql = "select * from $table where pc_eid = $rid";
  218. }
  219. else if ($table == "lang_languages") {
  220. $sql = "select * from $table where lang_id = $rid";
  221. }
  222. else if ($table == "openemr_postcalendar_categories" || $table == "openemr_postcalendar_topics"){
  223. $sql = "select * from $table where pc_catid = $rid";
  224. }
  225. else if ($table == "openemr_postcalendar_limits"){
  226. $sql = "select * from $table where pc_limitid = $rid";
  227. }
  228. else if ($table == "gacl_aco_map" || $table == "gacl_aro_groups_map" || $table == "gacl_aro_map" || $table == "gacl_axo_groups_map" || $table == "gacl_axo_map"){
  229. $sql = "select * from $table where acl_id = $rid";
  230. }
  231. else if($table == "gacl_groups_aro_map" || $table == "gacl_groups_axo_map"){
  232. $sql = "select * from $table where group_id = $rid";
  233. }
  234. else {
  235. $sql = "select * from $table where id = $rid";
  236. }
  237. $results = sqlQuery($sql,'true');
  238. $column_values = "";
  239. /* Concatenating the column values for the row inserted/updated */
  240. if (is_array($results)) {
  241. foreach ($results as $field_name => $field) {
  242. $column_values .= $field;
  243. }
  244. }
  245. // ViCarePlus: As per NIST standard, the encryption algorithm SHA1 is used
  246. return sha1($column_values);
  247. }
  248. /* Create an XML audit record corresponding to RFC 3881.
  249. * The parameters passed are the column values (from table 'log')
  250. * for a single audit record.
  251. */
  252. function create_rfc3881_msg($user, $group, $event, $patient_id, $outcome, $comments)
  253. {
  254. /* Event action codes indicate whether the event is read/write.
  255. * C = create, R = read, U = update, D = delete, E = execute
  256. */
  257. $eventActionCode = 'E';
  258. if (substr($event, -7) == "-create") {
  259. $eventActionCode = 'C';
  260. }
  261. else if (substr($event, -7) == "-insert") {
  262. $eventActionCode = 'C';
  263. }
  264. else if (substr($event, -7) == "-select") {
  265. $eventActionCode = 'R';
  266. }
  267. else if (substr($event, -7) == "-update") {
  268. $eventActionCode = 'U';
  269. }
  270. else if (substr($event, -7) == "-delete") {
  271. $eventActionCode = 'D';
  272. }
  273. $date_obj = new DateTime();
  274. $eventDateTime = $date_obj->format(DATE_ATOM);
  275. /* For EventOutcomeIndicator, 0 = success and 4 = minor error */
  276. $eventOutcome = ($outcome === 1) ? 0 : 4;
  277. /* The choice of event codes is up to OpenEMR.
  278. * We're using the same event codes as
  279. * https://iheprofiles.projects.openhealthtools.org/
  280. */
  281. $eventIDcodeSystemName = "DCM";
  282. $eventIDcode = 0;
  283. $eventIDdisplayName = $event;
  284. if (strpos($event, 'patient-record') !== FALSE) {
  285. $eventIDcode = 110110;
  286. $eventIDdisplayName = 'Patient Record';
  287. }
  288. else if (strpos($event, 'view') !== FALSE) {
  289. $eventIDCode = 110110;
  290. $eventIDdisplayName = 'Patient Record';
  291. }
  292. else if (strpos($event, 'login') !== FALSE) {
  293. $eventIDcode = 110122;
  294. $eventIDdisplayName = 'Login';
  295. }
  296. else if (strpos($event, 'logout') !== FALSE) {
  297. $eventIDcode = 110123;
  298. $eventIDdisplayName = 'Logout';
  299. }
  300. else if (strpos($event, 'scheduling') !== FALSE) {
  301. $eventIDcode = 110111;
  302. $eventIDdisplayName = 'Patient Care Assignment';
  303. }
  304. else if (strpos($event, 'security-administration') !== FALSE) {
  305. $eventIDcode = 110129;
  306. $eventIDdisplayName = 'Security Administration';
  307. }
  308. /* Variables used in ActiveParticipant section, which identifies
  309. * the IP address and application of the source and destination.
  310. */
  311. $srcUserID = $_SERVER['SERVER_NAME'] . '|OpenEMR';
  312. $srcNetwork = $_SERVER['SERVER_ADDR'];
  313. $destUserID = $GLOBALS['atna_audit_host'];
  314. $destNetwork = $GLOBALS['atna_audit_host'];
  315. $userID = $user;
  316. $userTypeCode = 1;
  317. $userRole = 6;
  318. $userCode = 11;
  319. $userDisplayName = 'User Identifier';
  320. $patientID = "";
  321. $patientTypeCode = "";
  322. $patientRole = "";
  323. $patientCode = "";
  324. $patientDisplayName = "";
  325. if ($eventIdDisplayName == 'Patient Record') {
  326. $patientID = $patient_id;
  327. $pattientTypeCode = 1;
  328. $patientRole = 1;
  329. $patientCode = 2;
  330. $patientDisplayName = 'Patient Number';
  331. }
  332. /* Construct the XML audit message, and save to $msg */
  333. $msg = '<?xml version="1.0" encoding="ASCII"?>';
  334. $msg .= '<AuditMessage xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ';
  335. $msg .= 'xsi:noNamespaceSchemaLocation="healthcare-security-audit.xsd">';
  336. /* Indicate the event code, text name, read/write type, and date/time */
  337. $msg .= "<EventIdentification EventActionCode=\"$eventActionCode\" ";
  338. $msg .= "EventDateTime=\"$eventDateTime\" ";
  339. $msg .= "EventOutcomeIndicator=\"$eventOutcome\">";
  340. $msg .= "<EventID code=\"eventIDcode\" displayName=\"$eventIDdisplayName\" ";
  341. $msg .= "codeSystemName=\"DCM\" />";
  342. $msg .= "</EventIdentification>";
  343. /* Indicate the IP address and application of the source and destination */
  344. $msg .= "<ActiveParticipant UserID=\"$srcUserID\" UserIsRequestor=\"true\" ";
  345. $msg .= "NetworkAccessPointID=\"$srcNetwork\" NetworkAccessPointTypeCode=\"2\" >";
  346. $msg .= "<RoleIDCode code=\"110153\" displayName=\"Source\" codeSystemName=\"DCM\" />";
  347. $msg .= "</ActiveParticipant>";
  348. $msg .= "<ActiveParticipant UserID=\"$destUserID\" UserIsRequestor=\"false\" ";
  349. $msg .= "NetworkAccessPointID=\"$destNetwork\" NetworkAccessPointTypeCode=\"2\" >";
  350. $msg .= "<RoleIDCode code=\"110152\" displayName=\"Destination\" codeSystemName=\"DCM\" />";
  351. $msg .= "</ActiveParticipant>";
  352. $msg .= "<AuditSourceIdentification AuditSourceID=\"$srcUserID\" />";
  353. /* Indicate the username who generated this audit record */
  354. $msg .= "<ParticipantObjectIdentification ParticipantObjectID=\"$user\" ";
  355. $msg .= "ParticipantObjectTypeCode=\"1\" ";
  356. $msg .= "ParticipantObjectTypeCodeRole=\"6\" >";
  357. $msg .= "<ParticipantObjectIDTypeCode code=\"11\" ";
  358. $msg .= "displayName=\"User Identifier\" ";
  359. $msg .= "codeSystemName=\"RFC-3881\" /></ParticipantObjectIdentification>";
  360. if ($eventIDdisplayName == 'Patient Record' && $patient_id != 0) {
  361. $msg .= "<ParticipantObjectIdentification ParticipantObjectID=\"$patient_id\" ";
  362. $msg .= "ParticipantObjectTypeCode=\"1\" ";
  363. $msg .= "ParticipantObjectTypeCodeRole=\"1\" >";
  364. $msg .= "<ParticipantObjectIDTypeCode code=\"2\" ";
  365. $msg .= "displayName=\"Patient Number\" ";
  366. $msg .= "codeSystemName=\"RFC-3881\" /></ParticipantObjectIdentification>";
  367. }
  368. $msg .= "</AuditMessage>";
  369. /* Add the syslog header */
  370. $date_obj = new DateTime($date);
  371. $datestr= $date_obj->format(DATE_ATOM);
  372. $msg = "<13> " . $datestr . " " . $_SERVER['SERVER_NAME'] . " " . $msg;
  373. return $msg;
  374. }
  375. /* Create a TLS (SSLv3) connection to the given host/port.
  376. * $localcert is the path to a PEM file with a client certificate and private key.
  377. * $cafile is the path to the CA certificate file, for
  378. * authenticating the remote machine's certificate.
  379. * If $cafile is "", the remote machine's certificate is not verified.
  380. * If $localcert is "", we don't pass a client certificate in the connection.
  381. *
  382. * Return a stream resource that can be used with fwrite(), fread(), etc.
  383. * Returns FALSE on error.
  384. */
  385. function create_tls_conn($host, $port, $localcert, $cafile) {
  386. $sslopts = array();
  387. if ($cafile !== null && $cafile != "") {
  388. $sslopts['cafile'] = $cafile;
  389. $sslopts['verify_peer'] = TRUE;
  390. $sslopts['verify_depth'] = 10;
  391. }
  392. if ($localcert !== null && $localcert != "") {
  393. $sslopts['local_cert'] = $localcert;
  394. }
  395. $opts = array('tls' => $sslopts, 'ssl' => $sslopts);
  396. $ctx = stream_context_create($opts);
  397. $timeout = 60;
  398. $flags = STREAM_CLIENT_CONNECT;
  399. $olderr = error_reporting(0);
  400. $conn = stream_socket_client('tls://' . $host . ":" . $port, $errno, $errstr,
  401. $timeout, $flags, $ctx);
  402. error_reporting($olderr);
  403. return $conn;
  404. }
  405. /* This function is used to send audit records to an Audit Repository Server,
  406. * as described in the Audit Trail and Node Authentication (ATNA) standard.
  407. * Given the fields in a single audit record:
  408. * - Create an XML audit message according to RFC 3881, including the RFC5425 syslog header.
  409. * - Create a TLS connection that performs bi-directions certificate authentication,
  410. * according to RFC 5425.
  411. * - Send the XML message on the TLS connection.
  412. */
  413. function send_atna_audit_msg($user, $group, $event, $patient_id, $outcome, $comments)
  414. {
  415. /* If no ATNA repository server is configured, return */
  416. if ($GLOBALS['atna_audit_host'] === null || $GLOBALS['atna_audit_host'] == "" || !($GLOBALS['enable_atna_audit'])) {
  417. return;
  418. }
  419. $host = $GLOBALS['atna_audit_host'];
  420. $port = $GLOBALS['atna_audit_port'];
  421. $localcert = $GLOBALS['atna_audit_localcert'];
  422. $cacert = $GLOBALS['atna_audit_cacert'];
  423. $conn = create_tls_conn($host, $port, $localcert, $cacert);
  424. if ($conn !== FALSE) {
  425. $msg = create_rfc3881_msg($user, $group, $event, $patient_id, $outcome, $comments);
  426. $len = strlen($msg);
  427. fwrite($conn, $msg);
  428. fclose($conn);
  429. }
  430. }
  431. /* Add an entry into the audit log table, indicating that an
  432. * SQL query was performed. $outcome is true if the statement
  433. * successfully completed. Determine the event type based on
  434. * the tables present in the SQL query.
  435. */
  436. function auditSQLEvent($statement, $outcome)
  437. {
  438. $user = $_SESSION['authUser'];
  439. /* Don't log anything if the audit logging is not enabled. Exception for "emergency" users */
  440. if (!($GLOBALS['enable_auditlog']))
  441. {
  442. if ((soundex($user) != soundex("emergency")) && (soundex($user) != soundex("breakglass")))
  443. return;
  444. }
  445. // ViCarePlus : Fix for Audit Issue :: Sep 24, 2010
  446. // Issue: When the audit logging is enabled and when SELECT QUERY (query=1 in globals.php) is enabled to log,
  447. // the issue of LAST_INSERT_ID arises.
  448. // This is because, the function sql_checksum_of_modified_row() is triggered more than
  449. // once for SELECT Queries and thus the expected value (LAST_INSERT_ID) in the $GLOBALS['lastidado'] is getting altered.
  450. // Since, the $GLOBALS['lastidado'] is manipulated by the other function calls(sql_checksum_of_modified_row),
  451. // this issue is arised.
  452. // Fix:
  453. // The task of assigning LAST_INSERT_ID to a global variable $GLOBALS['lastidado'] is moved from sql.inc to this file.
  454. // Following code will get executed, when (a) when audit is enabled (b) When break glass is invoked.
  455. // Retrieve LAST_INSERT_ID and assign it to a global variable and eventually it can be used by other functions.
  456. $lastid=mysql_insert_id($GLOBALS['dbh']);
  457. $GLOBALS['lastidado']=$lastid;
  458. // ViCarePlus : Audit fix - ends here :: Sep 24,2010
  459. $statement = trim($statement);
  460. /* Don't audit SQL statements done to the audit log,
  461. * or we'll have an infinite loop.
  462. */
  463. if ((stripos($statement, "insert into log") !== FALSE) ||
  464. (stripos($statement, "FROM log ") !== FALSE) ) {
  465. return;
  466. }
  467. $group = $_SESSION['authGroup'];
  468. $comments = $statement;
  469. $success = 1;
  470. $checksum = "";
  471. if ($outcome === FALSE) {
  472. $success = 0;
  473. }
  474. if ($outcome !== FALSE) {
  475. $checksum = sql_checksum_of_modified_row($statement);
  476. }
  477. /* Determine the query type (select, update, insert, delete) */
  478. $querytype = "select";
  479. $querytypes = array("select", "update", "insert", "delete","replace");
  480. foreach ($querytypes as $qtype) {
  481. if (stripos($statement, $qtype) === 0) {
  482. $querytype = $qtype;
  483. }
  484. }
  485. /* Determine the audit event based on the database tables */
  486. $event = "other";
  487. $tables = array("billing" => "patient-record",
  488. "claims" => "patient-record",
  489. "employer_data" => "patient-record",
  490. "forms" => "patient-record",
  491. "form_encounter" => "patient-record",
  492. "form_dictation" => "patient-record",
  493. "form_misc_billing_options" => "patient-record",
  494. "form_reviewofs" => "patient-record",
  495. "form_ros" => "patient-record",
  496. "form_soap" => "patient-record",
  497. "form_vitals" => "patient-record",
  498. "history_data" => "patient-record",
  499. "immunizations" => "patient-record",
  500. "insurance_data" => "patient-record",
  501. "issue_encounter" => "patient-record",
  502. "lists" => "patient-record",
  503. "patient_data" => "patient-record",
  504. "payments" => "patient-record",
  505. "pnotes" => "patient-record",
  506. "onotes" => "patient-record",
  507. "prescriptions" => "order",
  508. "transactions" => "patient-record",
  509. "facility" => "security-administration",
  510. "pharmacies" => "security-administration",
  511. "addresses" => "security-administration",
  512. "phone_numbers" => "security-administration",
  513. "x12_partners" => "security-administration",
  514. "insurance_companies" => "security-administration",
  515. "codes" => "security-administration",
  516. "registry" => "security-administration",
  517. "users" => "security-administration",
  518. "groups" => "security-administration",
  519. "openemr_postcalendar_events" => "scheduling",
  520. "openemr_postcalendar_categories" => "security-administration",
  521. "openemr_postcalendar_limits" => "security-administration",
  522. "openemr_postcalendar_topics" => "security-administration",
  523. "gacl_acl" => "security-administration",
  524. "gacl_acl_sections" => "security-administration",
  525. "gacl_acl_seq" => "security-administration",
  526. "gacl_aco" => "security-administration",
  527. "gacl_aco_map" => "security-administration",
  528. "gacl_aco_sections" => "security-administration",
  529. "gacl_aco_sections_seq" => "security-administration",
  530. "gacl_aco_seq" => "security-administration",
  531. "gacl_aro" => "security-administration",
  532. "gacl_aro_groups" => "security-administration",
  533. "gacl_aro_groups_id_seq" => "security-administration",
  534. "gacl_aro_groups_map" => "security-administration",
  535. "gacl_aro_map" => "security-administration",
  536. "gacl_aro_sections" => "security-administration",
  537. "gacl_aro_sections_seq" => "security-administration",
  538. "gacl_aro_seq" => "security-administration",
  539. "gacl_axo" => "security-administration",
  540. "gacl_axo_groups" => "security-administration",
  541. "gacl_axo_groups_map" => "security-administration",
  542. "gacl_axo_map" => "security-administration",
  543. "gacl_axo_sections" => "security-administration",
  544. "gacl_groups_aro_map" => "security-administration",
  545. "gacl_groups_axo_map" => "security-administration",
  546. "gacl_phpgacl" => "security-administration"
  547. );
  548. /* When searching for table names, truncate the SQL statement,
  549. * removing any WHERE, SET, or VALUE clauses.
  550. */
  551. $truncated_sql = $statement;
  552. $truncated_sql = str_replace("\n", " ", $truncated_sql);
  553. if ($querytype == "select") {
  554. $startwhere = stripos($truncated_sql, " where ");
  555. if ($startwhere > 0) {
  556. $truncated_sql = substr($truncated_sql, 0, $startwhere);
  557. }
  558. }
  559. else {
  560. $startparen = stripos($truncated_sql, "(" );
  561. $startset = stripos($truncated_sql, " set ");
  562. $startvalues = stripos($truncated_sql, " values ");
  563. if ($startparen > 0) {
  564. $truncated_sql = substr($truncated_sql, 0, $startparen);
  565. }
  566. if ($startvalues > 0) {
  567. $truncated_sql = substr($truncated_sql, 0, $startvalues);
  568. }
  569. if ($startset > 0) {
  570. $truncated_sql = substr($truncated_sql, 0, $startset);
  571. }
  572. }
  573. foreach ($tables as $table => $value) {
  574. if (strpos($truncated_sql, $table) !== FALSE) {
  575. $event = $value;
  576. break;
  577. }
  578. else if (strpos($truncated_sql, "form_") !== FALSE) {
  579. $event = "patient-record";
  580. break;
  581. }
  582. }
  583. /* Avoid filling the audit log with trivial SELECT statements.
  584. * Skip SELECTs from unknown tables.
  585. * Skip SELECT count() statements.
  586. * Skip the SELECT made by the authCheckSession() function.
  587. */
  588. if ($querytype == "select") {
  589. if ($event == "other")
  590. return;
  591. if (stripos($statement, "SELECT count(" ) === 0)
  592. return;
  593. if (stripos($statement, "select username, password from users") === 0)
  594. return;
  595. }
  596. /* If the event is a patient-record, then note the patient id */
  597. $pid = 0;
  598. if ($event == "patient-record") {
  599. if (array_key_exists('pid', $_SESSION) && $_SESSION['pid'] != '') {
  600. $pid = $_SESSION['pid'];
  601. }
  602. }
  603. /* If query events are not enabled, don't log them */
  604. if (($querytype == "select") && !($GLOBALS['audit_events_query']))
  605. {
  606. if ((soundex($user) != soundex("emergency")) && (soundex($user) != soundex("breakglass")))
  607. return;
  608. }
  609. if (!($GLOBALS["audit_events_${event}"]))
  610. {
  611. if ((soundex($user) != soundex("emergency")) && (soundex($user) != soundex("breakglass")))
  612. return;
  613. }
  614. $event = $event . "-" . $querytype;
  615. $adodb = $GLOBALS['adodb']['db'];
  616. // ViSolve : Don't log sequences - to avoid the affect due to GenID calls
  617. if (strpos($comments, "sequences") !== FALSE) return;
  618. $sql = "insert into log (date, event, user, groupname, comments, patient_id, success, checksum,crt_user) " .
  619. "values ( NOW(), " .
  620. $adodb->qstr($event) . ", " .
  621. $adodb->qstr($user) . "," .
  622. $adodb->qstr($group) . "," .
  623. $adodb->qstr($comments) . "," .
  624. $adodb->qstr($pid) . "," .
  625. $adodb->qstr($success) . "," .
  626. $adodb->qstr($checksum) . "," .
  627. $adodb->qstr($_SERVER['SSL_CLIENT_S_DN_CN']) .")";
  628. //$ret = sqlInsertClean($sql);
  629. //ViSolve: Call the new function created for audit logs
  630. sqlInsertClean_audit($sql);
  631. send_atna_audit_msg($user, $group, $event, $pid, $success, $comments);
  632. //return $ret;
  633. }
  634. /**
  635. * Record the patient disclosures.
  636. * @param $dates - The date when the disclosures are sent to the thrid party.
  637. * @param $event - The type of the disclosure.
  638. * @param $pid - The id of the patient for whom the disclosures are recorded.
  639. * @param $comment - The recipient name and description of the disclosure.
  640. * @uname - The username who is recording the disclosure.
  641. */
  642. function recordDisclosure($dates,$event,$pid,$recipient,$description,$user)
  643. {
  644. $adodb = $GLOBALS['adodb']['db'];
  645. $crt_user= $_SERVER['SSL_CLIENT_S_DN_CN'];
  646. $groupname=$_SESSION['authProvider'];
  647. $success=1;
  648. $sql = "insert into extended_log ( date, event, user, recipient, patient_id, description) " .
  649. "values (" . $adodb->qstr($dates) . "," . $adodb->qstr($event) . "," . $adodb->qstr($user) .
  650. "," . $adodb->qstr($recipient) . ",".
  651. $adodb->qstr($pid) ."," .
  652. $adodb->qstr($description) .")";
  653. $ret = sqlInsertClean_audit($sql);
  654. }
  655. /**
  656. * Edit the disclosures that is recorded.
  657. * @param $dates - The date when the disclosures are sent to the thrid party.
  658. * @param $event - The type of the disclosure.
  659. * param $comment - The recipient and the description of the disclosure are appended.
  660. * $logeventid - The id of the record which is to be edited.
  661. */
  662. function updateRecordedDisclosure($dates,$event,$recipient,$description,$disclosure_id)
  663. {
  664. $adodb = $GLOBALS['adodb']['db'];
  665. $sql="update extended_log set
  666. event=" . $adodb->qstr($event) . ",
  667. date=" . $adodb->qstr($dates) . ",
  668. recipient=" . $adodb->qstr($recipient) . ",
  669. description=" . $adodb->qstr($description) . "
  670. where id=" . $adodb->qstr($disclosure_id) . "";
  671. $ret = sqlInsertClean_audit($sql);
  672. }
  673. /**
  674. * Delete the disclosures that is recorded.
  675. * $deleteid - The id of the record which is to be deleted.
  676. */
  677. function deleteDisclosure($deletelid)
  678. {
  679. $sql="delete from extended_log where id='$deletelid'";
  680. $ret = sqlInsertClean_audit($sql);
  681. }
  682. ?>