2 #require_once("{$GLOBALS['srcdir']}/sql.inc");
3 require_once(dirname(__FILE__). "/sql.inc");
4 require_once(dirname(__FILE__). "/formdata.inc.php");
6 function newEvent($event, $user, $groupname, $success, $comments="", $patient_id=null) {
7 $adodb = $GLOBALS['adodb']['db'];
8 $crt_user=isset($_SERVER['SSL_CLIENT_S_DN_CN']) ? $_SERVER['SSL_CLIENT_S_DN_CN'] : null;
9 /* More details added to the log */
10 $sql = "insert into log ( date, event, user, groupname, success, comments, crt_user, patient_id) " .
11 "values ( NOW(), " . $adodb->qstr($event) . "," . $adodb->qstr($user) .
12 "," . $adodb->qstr($groupname) . "," . $adodb->qstr($success) . "," .
13 $adodb->qstr($comments) ."," .
14 $adodb->qstr($crt_user) ."," . $adodb->qstr($patient_id). ")";
16 $ret = sqlInsertClean_audit($sql);
17 if(($patient_id=="NULL") || ($patient_id==null))$patient_id=0;
19 send_atna_audit_msg($user, $groupname, $event, $patient_id, $success, $comments);
22 function getEventByDate($date, $user="", $cols="DISTINCT date, event, user, groupname, patient_id, success, comments, checksum")
24 $sql = "SELECT $cols FROM log WHERE date >= '$date 00:00:00' AND date <= '$date 23:59:59'";
25 if ($user) $sql .= " AND user LIKE '$user'";
26 $sql .= " ORDER BY date DESC LIMIT 5000";
27 $res = sqlStatement($sql);
28 for($iter=0; $row=sqlFetchArray($res); $iter++) {
35 * Get records from the LOG and Extended_Log table
36 * using the optional parameters:
37 * date : a specific date (defaults to today)
38 * user : a specific user (defaults to none)
39 * cols : gather specific columns (defaults to date,event,user,groupname,comments)
40 * sortby : sort the results by (defaults to none)
44 function getEvents($params)
46 // parse the parameters
47 $cols = "DISTINCT date, event, user, groupname, patient_id, success, comments,checksum,crt_user, id ";
48 if (isset($params['cols']) && $params['cols'] != "") $cols = $params['cols'];
50 $date1 = date("Y-m-d H:i:s", time());
51 if (isset($params['sdate']) && $params['sdate'] != "") $date1= $params['sdate'];
53 $date2 = date("Y-m-d H:i:s", time());
54 if (isset($params['edate']) && $params['edate'] != "") $date2= $params['edate'];
57 if (isset($params['user']) && $params['user'] != "") $user= $params['user'];
59 //VicarePlus :: For Generating log with patient id.
61 if (isset($params['patient']) && $params['patient'] != "") $patient= $params['patient'];
64 if (isset($params['sortby']) && $params['sortby'] != "") $sortby = $params['sortby'];
67 if (isset($params['levent']) && $params['levent'] != "") $levent = $params['levent'];
70 if (isset($params['tevent']) && $params['tevent'] != "") $tevent = $params['tevent'];
73 if (isset($params['event']) && $params['event'] != "") $event = $params['event'];
75 if ($sortby == "comments") $sortby = "description";
76 if ($sortby == "groupname") $sortby = ""; //VicarePlus :: since there is no groupname in extended_log
77 if ($sortby == "success") $sortby = ""; //VicarePlus :: since there is no success field in extended_log
78 if ($sortby == "checksum") $sortby = ""; //VicarePlus :: since there is no checksum field in extended_log
79 $columns = "DISTINCT date, event, user, recipient,patient_id,description";
80 $sql = "SELECT $columns FROM extended_log WHERE date >= '$date1' AND date <= '$date2'";
81 if ($user != "") $sql .= " AND user LIKE '$user'";
82 if ($patient != "") $sql .= " AND patient_id LIKE '$patient'";
83 if ($levent != "") $sql .= " AND event LIKE '$levent%'";
84 if ($sortby != "") $sql .= " ORDER BY ".$sortby." DESC "; // descending order
85 $sql .= " LIMIT 5000";
90 $sql = "SELECT $cols FROM log WHERE date >= '$date1' AND date <= '$date2'";
91 if ($user != "") $sql .= " AND user LIKE '$user'";
92 if ($patient != "") $sql .= " AND patient_id LIKE '$patient'";
93 if ($levent != "") $sql .= " AND event LIKE '$levent%'";
94 if ($tevent != "") $sql .= " AND event LIKE '%$tevent'";
95 if ($sortby != "") $sql .= " ORDER BY ".$sortby." DESC "; // descending order
96 $sql .= " LIMIT 5000";
98 $res = sqlStatement($sql);
99 for($iter=0; $row=sqlFetchArray($res); $iter++) {
105 /* Given an SQL insert/update that was just performeds:
106 * - Find the table and primary id of the row that was created/modified
107 * - Calculate the SHA1 checksum of that row (with all the
108 * column values concatenated together).
109 * - Return the SHA1 checksum as a 40 char hex string.
110 * If this is not an insert/update query, return "".
111 * If multiple rows were modified, return "".
112 * If we're unable to determine the row modified, return "".
114 * TODO: May need to incorporate the binded stuff (still analyzing)
117 function sql_checksum_of_modified_row($statement)
122 $tokens = preg_split("/[\s,(\'\"]+/", $statement);
123 /* Identifying the id for insert/replace statements for calculating the checksum */
124 if((strcasecmp($tokens[0],"INSERT")==0) || (strcasecmp($tokens[0],"REPLACE")==0)){
126 $rid = mysql_insert_id($GLOBALS['dbh']);
127 /* For handling the table that doesn't have auto-increment column */
128 if ($rid === 0 || $rid === FALSE) {
129 if($table == "gacl_aco_map" || $table == "gacl_aro_groups_map" || $table == "gacl_aro_map" || $table == "gacl_axo_groups_map" || $table == "gacl_axo_map")
131 else if($table == "gacl_groups_aro_map" || $table == "gacl_groups_axo_map")
135 /* To handle insert statements */
136 if($tokens[3] == $id){
137 for($i=4;$i<count($tokens);$i++){
138 if(strcasecmp($tokens[$i],"VALUES")==0){
144 /* To handle replace statements */
145 else if(strcasecmp($tokens[3],"SET")==0){
146 if((strcasecmp($tokens[4],"ID")==0) || (strcasecmp($tokens[4],"`ID`")==0)){
156 /* Identifying the id for update statements for calculating the checksum */
157 else if(strcasecmp($tokens[0],"UPDATE")==0){
161 $total = count($tokens);
163 /* Identifying the primary key column for the updated record */
164 if ($table == "form_physical_exam") {
167 else if ($table == "claims"){
170 else if ($table == "openemr_postcalendar_events") {
173 else if ($table == "lang_languages"){
176 else if ($table == "openemr_postcalendar_categories" || $table == "openemr_postcalendar_topics"){
179 else if ($table == "openemr_postcalendar_limits"){
182 else if($table == "gacl_aco_map" || $table == "gacl_aro_groups_map" || $table == "gacl_aro_map" || $table == "gacl_axo_groups_map" || $table == "gacl_axo_map"){
185 else if($table == "gacl_groups_aro_map" || $table == "gacl_groups_axo_map"){
192 /* Identifying the primary key value for the updated record */
193 while ($offset < $total) {
194 /* There are 4 possible ways that the id=123 can be parsed:
202 if (($tokens[$offset] == "$id=") && ($offset + 1 < $total)) {
203 $rid = $tokens[$offset+1];
206 /* 'id', '=', '123' */
207 else if ($tokens[$offset] == "$id" && $tokens[$offset+1] == "=" && ($offset+2 < $total)) {
208 $rid = $tokens[$offset+2];
212 else if (strpos($tokens[$offset], "$id=") === 0) {
213 $tid = substr($tokens[$offset], strlen($id)+1);
219 else if($tokens[$offset] == "$id") {
220 $tid = substr($tokens[$offset+1],1);
226 }//while ($offset < $total)
227 }// else if ($tokens[0] == 'update' || $tokens[0] == 'UPDATE' )
229 if ($table == "" || $rid == "") {
232 /* Framing sql statements for calculating checksum */
233 if ($table == "form_physical_exam") {
234 $sql = "select * from $table where forms_id = $rid";
236 else if ($table == "claims"){
237 $sql = "select * from $table where patient_id = $rid";
239 else if ($table == "openemr_postcalendar_events") {
240 $sql = "select * from $table where pc_eid = $rid";
242 else if ($table == "lang_languages") {
243 $sql = "select * from $table where lang_id = $rid";
245 else if ($table == "openemr_postcalendar_categories" || $table == "openemr_postcalendar_topics"){
246 $sql = "select * from $table where pc_catid = $rid";
248 else if ($table == "openemr_postcalendar_limits"){
249 $sql = "select * from $table where pc_limitid = $rid";
251 else if ($table == "gacl_aco_map" || $table == "gacl_aro_groups_map" || $table == "gacl_aro_map" || $table == "gacl_axo_groups_map" || $table == "gacl_axo_map"){
252 $sql = "select * from $table where acl_id = $rid";
254 else if($table == "gacl_groups_aro_map" || $table == "gacl_groups_axo_map"){
255 $sql = "select * from $table where group_id = $rid";
258 $sql = "select * from $table where id = $rid";
260 // When this function is working perfectly, can then shift to the
261 // sqlQueryNoLog() function.
262 $results = sqlQueryNoLogIgnoreError($sql);
264 /* Concatenating the column values for the row inserted/updated */
265 if (is_array($results)) {
266 foreach ($results as $field_name => $field) {
267 $column_values .= $field;
270 // ViCarePlus: As per NIST standard, the encryption algorithm SHA1 is used
272 //error_log("COLUMN_VALUES: ".$column_values,0);
273 return sha1($column_values);
276 /* Create an XML audit record corresponding to RFC 3881.
277 * The parameters passed are the column values (from table 'log')
278 * for a single audit record.
280 function create_rfc3881_msg($user, $group, $event, $patient_id, $outcome, $comments)
283 /* Event action codes indicate whether the event is read/write.
284 * C = create, R = read, U = update, D = delete, E = execute
286 $eventActionCode = 'E';
287 if (substr($event, -7) == "-create") {
288 $eventActionCode = 'C';
290 else if (substr($event, -7) == "-insert") {
291 $eventActionCode = 'C';
293 else if (substr($event, -7) == "-select") {
294 $eventActionCode = 'R';
296 else if (substr($event, -7) == "-update") {
297 $eventActionCode = 'U';
299 else if (substr($event, -7) == "-delete") {
300 $eventActionCode = 'D';
303 $date_obj = new DateTime();
304 $eventDateTime = $date_obj->format(DATE_ATOM);
306 /* For EventOutcomeIndicator, 0 = success and 4 = minor error */
307 $eventOutcome = ($outcome === 1) ? 0 : 4;
309 /* The choice of event codes is up to OpenEMR.
310 * We're using the same event codes as
311 * https://iheprofiles.projects.openhealthtools.org/
313 $eventIDcodeSystemName = "DCM";
315 $eventIDdisplayName = $event;
317 if (strpos($event, 'patient-record') !== FALSE) {
318 $eventIDcode = 110110;
319 $eventIDdisplayName = 'Patient Record';
321 else if (strpos($event, 'view') !== FALSE) {
322 $eventIDCode = 110110;
323 $eventIDdisplayName = 'Patient Record';
325 else if (strpos($event, 'login') !== FALSE) {
326 $eventIDcode = 110122;
327 $eventIDdisplayName = 'Login';
329 else if (strpos($event, 'logout') !== FALSE) {
330 $eventIDcode = 110123;
331 $eventIDdisplayName = 'Logout';
333 else if (strpos($event, 'scheduling') !== FALSE) {
334 $eventIDcode = 110111;
335 $eventIDdisplayName = 'Patient Care Assignment';
337 else if (strpos($event, 'security-administration') !== FALSE) {
338 $eventIDcode = 110129;
339 $eventIDdisplayName = 'Security Administration';
345 /* Variables used in ActiveParticipant section, which identifies
346 * the IP address and application of the source and destination.
348 $srcUserID = $_SERVER['SERVER_NAME'] . '|OpenEMR';
349 $srcNetwork = $_SERVER['SERVER_ADDR'];
350 $destUserID = $GLOBALS['atna_audit_host'];
351 $destNetwork = $GLOBALS['atna_audit_host'];
357 $userDisplayName = 'User Identifier';
360 $patientTypeCode = "";
363 $patientDisplayName = "";
365 if ($eventIdDisplayName == 'Patient Record') {
366 $patientID = $patient_id;
367 $pattientTypeCode = 1;
370 $patientDisplayName = 'Patient Number';
373 /* Construct the XML audit message, and save to $msg */
374 $msg = '<?xml version="1.0" encoding="ASCII"?>';
375 $msg .= '<AuditMessage xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ';
376 $msg .= 'xsi:noNamespaceSchemaLocation="healthcare-security-audit.xsd">';
378 /* Indicate the event code, text name, read/write type, and date/time */
379 $msg .= "<EventIdentification EventActionCode=\"$eventActionCode\" ";
380 $msg .= "EventDateTime=\"$eventDateTime\" ";
381 $msg .= "EventOutcomeIndicator=\"$eventOutcome\">";
382 $msg .= "<EventID code=\"eventIDcode\" displayName=\"$eventIDdisplayName\" ";
383 $msg .= "codeSystemName=\"DCM\" />";
384 $msg .= "</EventIdentification>";
386 /* Indicate the IP address and application of the source and destination */
387 $msg .= "<ActiveParticipant UserID=\"$srcUserID\" UserIsRequestor=\"true\" ";
388 $msg .= "NetworkAccessPointID=\"$srcNetwork\" NetworkAccessPointTypeCode=\"2\" >";
389 $msg .= "<RoleIDCode code=\"110153\" displayName=\"Source\" codeSystemName=\"DCM\" />";
390 $msg .= "</ActiveParticipant>";
391 $msg .= "<ActiveParticipant UserID=\"$destUserID\" UserIsRequestor=\"false\" ";
392 $msg .= "NetworkAccessPointID=\"$destNetwork\" NetworkAccessPointTypeCode=\"2\" >";
393 $msg .= "<RoleIDCode code=\"110152\" displayName=\"Destination\" codeSystemName=\"DCM\" />";
394 $msg .= "</ActiveParticipant>";
396 $msg .= "<AuditSourceIdentification AuditSourceID=\"$srcUserID\" />";
398 /* Indicate the username who generated this audit record */
399 $msg .= "<ParticipantObjectIdentification ParticipantObjectID=\"$user\" ";
400 $msg .= "ParticipantObjectTypeCode=\"1\" ";
401 $msg .= "ParticipantObjectTypeCodeRole=\"6\" >";
402 $msg .= "<ParticipantObjectIDTypeCode code=\"11\" ";
403 $msg .= "displayName=\"User Identifier\" ";
404 $msg .= "codeSystemName=\"RFC-3881\" /></ParticipantObjectIdentification>";
406 if ($eventIDdisplayName == 'Patient Record' && $patient_id != 0) {
407 $msg .= "<ParticipantObjectIdentification ParticipantObjectID=\"$patient_id\" ";
408 $msg .= "ParticipantObjectTypeCode=\"1\" ";
409 $msg .= "ParticipantObjectTypeCodeRole=\"1\" >";
410 $msg .= "<ParticipantObjectIDTypeCode code=\"2\" ";
411 $msg .= "displayName=\"Patient Number\" ";
412 $msg .= "codeSystemName=\"RFC-3881\" /></ParticipantObjectIdentification>";
414 $msg .= "</AuditMessage>";
416 /* Add the syslog header */
417 $date_obj = new DateTime($date);
418 $datestr= $date_obj->format(DATE_ATOM);
419 $msg = "<13> " . $datestr . " " . $_SERVER['SERVER_NAME'] . " " . $msg;
424 /* Create a TLS (SSLv3) connection to the given host/port.
425 * $localcert is the path to a PEM file with a client certificate and private key.
426 * $cafile is the path to the CA certificate file, for
427 * authenticating the remote machine's certificate.
428 * If $cafile is "", the remote machine's certificate is not verified.
429 * If $localcert is "", we don't pass a client certificate in the connection.
431 * Return a stream resource that can be used with fwrite(), fread(), etc.
432 * Returns FALSE on error.
434 function create_tls_conn($host, $port, $localcert, $cafile) {
436 if ($cafile !== null && $cafile != "") {
437 $sslopts['cafile'] = $cafile;
438 $sslopts['verify_peer'] = TRUE;
439 $sslopts['verify_depth'] = 10;
441 if ($localcert !== null && $localcert != "") {
442 $sslopts['local_cert'] = $localcert;
444 $opts = array('tls' => $sslopts, 'ssl' => $sslopts);
445 $ctx = stream_context_create($opts);
447 $flags = STREAM_CLIENT_CONNECT;
449 $olderr = error_reporting(0);
450 $conn = stream_socket_client('tls://' . $host . ":" . $port, $errno, $errstr,
451 $timeout, $flags, $ctx);
452 error_reporting($olderr);
457 /* This function is used to send audit records to an Audit Repository Server,
458 * as described in the Audit Trail and Node Authentication (ATNA) standard.
459 * Given the fields in a single audit record:
460 * - Create an XML audit message according to RFC 3881, including the RFC5425 syslog header.
461 * - Create a TLS connection that performs bi-directions certificate authentication,
462 * according to RFC 5425.
463 * - Send the XML message on the TLS connection.
465 function send_atna_audit_msg($user, $group, $event, $patient_id, $outcome, $comments)
467 /* If no ATNA repository server is configured, return */
468 if ($GLOBALS['atna_audit_host'] === null || $GLOBALS['atna_audit_host'] == "" || !($GLOBALS['enable_atna_audit'])) {
471 $host = $GLOBALS['atna_audit_host'];
472 $port = $GLOBALS['atna_audit_port'];
473 $localcert = $GLOBALS['atna_audit_localcert'];
474 $cacert = $GLOBALS['atna_audit_cacert'];
475 $conn = create_tls_conn($host, $port, $localcert, $cacert);
476 if ($conn !== FALSE) {
477 $msg = create_rfc3881_msg($user, $group, $event, $patient_id, $outcome, $comments);
485 /* Add an entry into the audit log table, indicating that an
486 * SQL query was performed. $outcome is true if the statement
487 * successfully completed. Determine the event type based on
488 * the tables present in the SQL query.
490 function auditSQLEvent($statement, $outcome, $binds=NULL)
493 $user = isset($_SESSION['authUser']) ? $_SESSION['authUser'] : "";
494 /* Don't log anything if the audit logging is not enabled. Exception for "emergency" users */
495 if (!isset($GLOBALS['enable_auditlog']) || !($GLOBALS['enable_auditlog']))
497 if ((soundex($user) != soundex("emergency")) && (soundex($user) != soundex("breakglass")))
502 $statement = trim($statement);
504 /* Don't audit SQL statements done to the audit log,
505 * or we'll have an infinite loop.
507 if ((stripos($statement, "insert into log") !== FALSE) ||
508 (stripos($statement, "FROM log ") !== FALSE) ) {
512 $group = isset($_SESSION['authGroup']) ? $_SESSION['authGroup'] : "";
513 $comments = $statement;
515 $processed_binds = "";
516 if (is_array($binds)) {
517 // Need to include the binded variable elements in the logging
519 foreach ($binds as $value_bind) {
522 $processed_binds .= "'" . add_escape_custom($value_bind) . "'";
527 $processed_binds .= ",'" . add_escape_custom($value_bind) . "'";
530 if (!empty($processed_binds)) {
531 $processed_binds = "(" . $processed_binds . ")";
532 $comments .= " " . $processed_binds;
538 if ($outcome === FALSE) {
541 if ($outcome !== FALSE) {
542 // Should use the $statement rather than the processed
543 // variables, which includes the binded stuff. If do
544 // indeed need the binded values, then will need
545 // to include this as a separate array.
547 //error_log("STATEMENT: ".$statement,0);
548 //error_log("BINDS: ".$processed_binds,0);
549 $checksum = sql_checksum_of_modified_row($statement);
550 //error_log("CHECKSUM: ".$checksum,0);
552 /* Determine the query type (select, update, insert, delete) */
553 $querytype = "select";
554 $querytypes = array("select", "update", "insert", "delete","replace");
555 foreach ($querytypes as $qtype) {
556 if (stripos($statement, $qtype) === 0) {
561 /* Determine the audit event based on the database tables */
563 $tables = array("billing" => "patient-record",
564 "claims" => "patient-record",
565 "employer_data" => "patient-record",
566 "forms" => "patient-record",
567 "form_encounter" => "patient-record",
568 "form_dictation" => "patient-record",
569 "form_misc_billing_options" => "patient-record",
570 "form_reviewofs" => "patient-record",
571 "form_ros" => "patient-record",
572 "form_soap" => "patient-record",
573 "form_vitals" => "patient-record",
574 "history_data" => "patient-record",
575 "immunizations" => "patient-record",
576 "insurance_data" => "patient-record",
577 "issue_encounter" => "patient-record",
578 "lists" => "patient-record",
579 "patient_data" => "patient-record",
580 "payments" => "patient-record",
581 "pnotes" => "patient-record",
582 "onotes" => "patient-record",
583 "prescriptions" => "order",
584 "transactions" => "patient-record",
585 "amendments" => "patient-record",
586 "amendments_history" => "patient-record",
587 "facility" => "security-administration",
588 "pharmacies" => "security-administration",
589 "addresses" => "security-administration",
590 "phone_numbers" => "security-administration",
591 "x12_partners" => "security-administration",
592 "insurance_companies" => "security-administration",
593 "codes" => "security-administration",
594 "registry" => "security-administration",
595 "users" => "security-administration",
596 "groups" => "security-administration",
597 "openemr_postcalendar_events" => "scheduling",
598 "openemr_postcalendar_categories" => "security-administration",
599 "openemr_postcalendar_limits" => "security-administration",
600 "openemr_postcalendar_topics" => "security-administration",
601 "gacl_acl" => "security-administration",
602 "gacl_acl_sections" => "security-administration",
603 "gacl_acl_seq" => "security-administration",
604 "gacl_aco" => "security-administration",
605 "gacl_aco_map" => "security-administration",
606 "gacl_aco_sections" => "security-administration",
607 "gacl_aco_sections_seq" => "security-administration",
608 "gacl_aco_seq" => "security-administration",
609 "gacl_aro" => "security-administration",
610 "gacl_aro_groups" => "security-administration",
611 "gacl_aro_groups_id_seq" => "security-administration",
612 "gacl_aro_groups_map" => "security-administration",
613 "gacl_aro_map" => "security-administration",
614 "gacl_aro_sections" => "security-administration",
615 "gacl_aro_sections_seq" => "security-administration",
616 "gacl_aro_seq" => "security-administration",
617 "gacl_axo" => "security-administration",
618 "gacl_axo_groups" => "security-administration",
619 "gacl_axo_groups_map" => "security-administration",
620 "gacl_axo_map" => "security-administration",
621 "gacl_axo_sections" => "security-administration",
622 "gacl_groups_aro_map" => "security-administration",
623 "gacl_groups_axo_map" => "security-administration",
624 "gacl_phpgacl" => "security-administration"
627 /* When searching for table names, truncate the SQL statement,
628 * removing any WHERE, SET, or VALUE clauses.
630 $truncated_sql = $statement;
631 $truncated_sql = str_replace("\n", " ", $truncated_sql);
632 if ($querytype == "select") {
633 $startwhere = stripos($truncated_sql, " where ");
634 if ($startwhere > 0) {
635 $truncated_sql = substr($truncated_sql, 0, $startwhere);
639 $startparen = stripos($truncated_sql, "(" );
640 $startset = stripos($truncated_sql, " set ");
641 $startvalues = stripos($truncated_sql, " values ");
643 if ($startparen > 0) {
644 $truncated_sql = substr($truncated_sql, 0, $startparen);
646 if ($startvalues > 0) {
647 $truncated_sql = substr($truncated_sql, 0, $startvalues);
650 $truncated_sql = substr($truncated_sql, 0, $startset);
653 foreach ($tables as $table => $value) {
654 if (strpos($truncated_sql, $table) !== FALSE) {
658 else if (strpos($truncated_sql, "form_") !== FALSE) {
659 $event = "patient-record";
664 /* Avoid filling the audit log with trivial SELECT statements.
665 * Skip SELECTs from unknown tables.
666 * Skip SELECT count() statements.
667 * Skip the SELECT made by the authCheckSession() function.
669 if ($querytype == "select") {
670 if ($event == "other")
672 if (stripos($statement, "SELECT count(" ) === 0)
674 if (stripos($statement, "select username, password from users") === 0)
679 /* If the event is a patient-record, then note the patient id */
681 if ($event == "patient-record") {
682 if (array_key_exists('pid', $_SESSION) && $_SESSION['pid'] != '') {
683 $pid = $_SESSION['pid'];
687 /* If query events are not enabled, don't log them */
688 if (($querytype == "select") && !($GLOBALS['audit_events_query']))
690 if ((soundex($user) != soundex("emergency")) && (soundex($user) != soundex("breakglass")))
694 if (!($GLOBALS["audit_events_${event}"]))
696 if ((soundex($user) != soundex("emergency")) && (soundex($user) != soundex("breakglass")))
701 $event = $event . "-" . $querytype;
703 $adodb = $GLOBALS['adodb']['db'];
705 // ViSolve : Don't log sequences - to avoid the affect due to GenID calls
706 if (strpos($comments, "sequences") !== FALSE) return;
708 $encrypt_comment = 'No';
709 //July 1, 2014: Ensoftek: Check and encrypt audit logging
710 if ($GLOBALS["enable_auditlog_encryption"]) {
711 $comments = aes256Encrypt($comments);
712 $encrypt_comment = 'Yes';
715 $current_datetime = date("Y-m-d H:i:s");
716 $SSL_CLIENT_S_DN_CN=isset($_SERVER['SSL_CLIENT_S_DN_CN']) ? $_SERVER['SSL_CLIENT_S_DN_CN'] : '';
717 $sql = "insert into log (date, event, user, groupname, comments, patient_id, success, checksum,crt_user) " .
719 $adodb->qstr($current_datetime). ", ".
720 $adodb->qstr($event) . ", " .
721 $adodb->qstr($user) . "," .
722 $adodb->qstr($group) . "," .
723 $adodb->qstr($comments) . "," .
724 $adodb->qstr($pid) . "," .
725 $adodb->qstr($success) . "," .
726 $adodb->qstr($checksum) . "," .
727 $adodb->qstr($SSL_CLIENT_S_DN_CN) .")";
728 sqlInsertClean_audit($sql);
730 $last_log_id = $GLOBALS['adodb']['db']->Insert_ID();
731 $checksumGenerate = '';
732 //July 1, 2014: Ensoftek: Record the encryption checksum in a secondary table(log_comment_encrypt)
733 if ($querytype == 'update') {
734 $concatLogColumns = $current_datetime.$event.$user.$group.$comments.$pid.$success.$checksum.$SSL_CLIENT_S_DN_CN;
735 $checksumGenerate = sha1($concatLogColumns);
737 $encryptLogQry = "INSERT INTO log_comment_encrypt (log_id, encrypt, checksum) ".
739 $adodb->qstr($last_log_id) . "," .
740 $adodb->qstr($encrypt_comment) . "," .
741 $adodb->qstr($checksumGenerate) .")";
742 sqlInsertClean_audit($encryptLogQry);
744 send_atna_audit_msg($user, $group, $event, $pid, $success, $comments);
748 // May-29-2014: Ensoftek: For Auditable events and tamper-resistance (MU2)
749 // Insert Audit Logging Status into the LOG table.
750 function auditSQLAuditTamper($enable)
752 $user = isset($_SESSION['authUser']) ? $_SESSION['authUser'] : "";
753 $group = isset($_SESSION['authGroup']) ? $_SESSION['authGroup'] : "";
757 $event = "security-administration" . "-" . "insert";
760 $adodb = $GLOBALS['adodb']['db'];
764 $comments = "Audit Logging Enabled.";
768 $comments = "Audit Logging Disabled.";
771 $SSL_CLIENT_S_DN_CN=isset($_SERVER['SSL_CLIENT_S_DN_CN']) ? $_SERVER['SSL_CLIENT_S_DN_CN'] : '';
772 $sql = "insert into log (date, event, user, groupname, comments, patient_id, success, checksum,crt_user) " .
774 $adodb->qstr($event) . ", " .
775 $adodb->qstr($user) . "," .
776 $adodb->qstr($group) . "," .
777 $adodb->qstr($comments) . "," .
778 $adodb->qstr($pid) . "," .
779 $adodb->qstr($success) . "," .
780 $adodb->qstr($checksum) . "," .
781 $adodb->qstr($SSL_CLIENT_S_DN_CN) .")";
783 sqlInsertClean_audit($sql);
784 send_atna_audit_msg($user, $group, $event, $pid, $success, $comments);
788 * Record the patient disclosures.
789 * @param $dates - The date when the disclosures are sent to the thrid party.
790 * @param $event - The type of the disclosure.
791 * @param $pid - The id of the patient for whom the disclosures are recorded.
792 * @param $comment - The recipient name and description of the disclosure.
793 * @uname - The username who is recording the disclosure.
795 function recordDisclosure($dates,$event,$pid,$recipient,$description,$user)
797 $adodb = $GLOBALS['adodb']['db'];
798 $crt_user= $_SERVER['SSL_CLIENT_S_DN_CN'];
799 $groupname=$_SESSION['authProvider'];
801 $sql = "insert into extended_log ( date, event, user, recipient, patient_id, description) " .
802 "values (" . $adodb->qstr($dates) . "," . $adodb->qstr($event) . "," . $adodb->qstr($user) .
803 "," . $adodb->qstr($recipient) . ",".
804 $adodb->qstr($pid) ."," .
805 $adodb->qstr($description) .")";
806 $ret = sqlInsertClean_audit($sql);
809 * Edit the disclosures that is recorded.
810 * @param $dates - The date when the disclosures are sent to the thrid party.
811 * @param $event - The type of the disclosure.
812 * param $comment - The recipient and the description of the disclosure are appended.
813 * $logeventid - The id of the record which is to be edited.
815 function updateRecordedDisclosure($dates,$event,$recipient,$description,$disclosure_id)
817 $adodb = $GLOBALS['adodb']['db'];
818 $sql="update extended_log set
819 event=" . $adodb->qstr($event) . ",
820 date=" . $adodb->qstr($dates) . ",
821 recipient=" . $adodb->qstr($recipient) . ",
822 description=" . $adodb->qstr($description) . "
823 where id=" . $adodb->qstr($disclosure_id) . "";
824 $ret = sqlInsertClean_audit($sql);
827 * Delete the disclosures that is recorded.
828 * $deleteid - The id of the record which is to be deleted.
830 function deleteDisclosure($deletelid)
832 $sql="delete from extended_log where id='" . add_escape_custom($deletelid) . "'";
833 $ret = sqlInsertClean_audit($sql);
836 //July 1, 2014: Ensoftek: Function to AES256 encrypt a given string
837 function aes256Encrypt($sValue){
838 $sSecretKey = pack('H*', "bcb04b7e103a0cd8b54763051cef08bc55abe029fdebae5e1d417e2ffb2a00a3");
843 $sSecretKey, $sValue,
856 //July 1, 2014: Ensoftek: Function to AES256 decrypt a given string
857 function aes256Decrypt($sValue){
858 $sSecretKey = pack('H*', "bcb04b7e103a0cd8b54763051cef08bc55abe029fdebae5e1d417e2ffb2a00a3");
863 base64_decode($sValue),
876 //July 1, 2014: Ensoftek: Utility function to get data from table(log_comment_encrypt)
877 function logCommentEncryptData($log_id){
878 $encryptRow = array();
879 $logRes = sqlStatement("SELECT * FROM log_comment_encrypt WHERE log_id=?", array($log_id));
880 while($logRow = sqlFetchArray($logRes)){
881 $encryptRow['encrypt'] = $logRow['encrypt'];
882 $encryptRow['checksum'] = $logRow['checksum'];