@@ -180,6 +180,27 @@ static AuditEventStackItem * auditEventStack = NULL;
180
180
*/
181
181
static int64 stackTotal = 0 ;
182
182
183
+ /*
184
+ * Check that an item is on the stack. If not, an error will be raised since
185
+ * this is a bad state to be in and it might mean audit records are being lost.
186
+ */
187
+ static void
188
+ stack_valid (int64 stackId )
189
+ {
190
+ AuditEventStackItem * nextItem = auditEventStack ;
191
+
192
+ /* Look through the stack for the stack entry */
193
+ while (nextItem != NULL && nextItem -> stackId != stackId )
194
+ nextItem = nextItem -> next ;
195
+
196
+ /* If we didn't find it, something went wrong. */
197
+ if (nextItem == NULL )
198
+ elog (ERROR , "plaudit stack item " INT64_FORMAT
199
+ " not found - top of stack is " INT64_FORMAT "" ,
200
+ stackId ,
201
+ auditEventStack == NULL ? (int64 ) - 1 : auditEventStack -> stackId );
202
+ }
203
+
183
204
/*
184
205
* Respond to callbacks registered with MemoryContextRegisterResetCallback().
185
206
* Removes the event(s) off the stack that have become obsolete once the
@@ -495,7 +516,118 @@ polar_audit_ProcessUtility_hook(PlannedStmt *pstmt,
495
516
DestReceiver * dest ,
496
517
QueryCompletion * qc )
497
518
{
498
- return ;
519
+ int64 stackId = 0 ;
520
+ AuditEventStackItem * stackItem = NULL ;
521
+
522
+ /*
523
+ * Don't audit substatements. All the substatements we care about should
524
+ * be covered by the event triggers.
525
+ */
526
+ if (context <= PROCESS_UTILITY_QUERY && !IsAbortedTransactionBlockState ())
527
+ {
528
+ /* Process top level utility statement */
529
+ if (context == PROCESS_UTILITY_TOPLEVEL )
530
+ {
531
+ /*
532
+ * If the stack is not empty then the only allowed entries are
533
+ * call statements or open, select, show, and explain cursors
534
+ */
535
+ if (auditEventStack != NULL )
536
+ {
537
+ AuditEventStackItem * nextItem = auditEventStack ;
538
+
539
+ do
540
+ {
541
+ if (nextItem -> auditEvent .commandTag != T_SelectStmt &&
542
+ nextItem -> auditEvent .commandTag != T_VariableShowStmt &&
543
+ nextItem -> auditEvent .commandTag != T_ExplainStmt &&
544
+ nextItem -> auditEvent .commandTag != T_CallStmt )
545
+ {
546
+ elog (ERROR , "plaudit stack is not empty" );
547
+ }
548
+
549
+ nextItem = nextItem -> next ;
550
+ }
551
+ while (nextItem != NULL );
552
+ }
553
+
554
+ stackItem = stack_push ();
555
+ stackItem -> auditEvent .paramList = copyParamList (params );
556
+ }
557
+ else
558
+ stackItem = stack_push ();
559
+
560
+ stackId = stackItem -> stackId ;
561
+ stackItem -> auditEvent .logStmtLevel = GetCommandLogLevel (pstmt -> utilityStmt );
562
+ stackItem -> auditEvent .commandTag = nodeTag (pstmt -> utilityStmt );
563
+ stackItem -> auditEvent .command = CreateCommandTag (pstmt -> utilityStmt );
564
+ stackItem -> auditEvent .commandText = queryString ;
565
+ stackItem -> auditEvent .auditOid = get_role_oid (auditRole , true);
566
+
567
+ /*
568
+ * If this is a DO block log it before calling the next ProcessUtility
569
+ * hook.
570
+ */
571
+ if (auditLogBitmap & LOG_FUNCTION &&
572
+ stackItem -> auditEvent .commandTag == T_DoStmt &&
573
+ !IsAbortedTransactionBlockState ())
574
+ log_audit_event (stackItem );
575
+
576
+ /*
577
+ * If this is a create/alter extension command log it before calling
578
+ * the next ProcessUtility hook. Otherwise, any warnings will be
579
+ * emitted before the create/alter is logged and errors will prevent
580
+ * it from being logged at all.
581
+ */
582
+ if (auditLogBitmap & LOG_DDL &&
583
+ (stackItem -> auditEvent .commandTag == T_CreateExtensionStmt ||
584
+ stackItem -> auditEvent .commandTag == T_AlterExtensionStmt ) &&
585
+ !IsAbortedTransactionBlockState ())
586
+ log_audit_event (stackItem );
587
+
588
+ /*
589
+ * A close will free the open cursor which will also free the close
590
+ * audit entry. Immediately log the close and set stackItem to NULL so
591
+ * it won't be logged later.
592
+ */
593
+ if (stackItem -> auditEvent .commandTag == T_ClosePortalStmt )
594
+ {
595
+ if (auditLogBitmap & LOG_MISC && !IsAbortedTransactionBlockState ())
596
+ log_audit_event (stackItem );
597
+
598
+ stackItem = NULL ;
599
+ }
600
+ }
601
+
602
+ /* Call the standard process utility chain. */
603
+ if (next_ProcessUtility_hook )
604
+ (* next_ProcessUtility_hook ) (pstmt , queryString , readOnlyTree , context ,
605
+ params , queryEnv , dest , qc );
606
+ else
607
+ standard_ProcessUtility (pstmt , queryString , readOnlyTree , context ,
608
+ params , queryEnv , dest , qc );
609
+
610
+ /*
611
+ * Process the audit event if there is one. Also check that this event
612
+ * was not popped off the stack by a memory context being free'd
613
+ * elsewhere.
614
+ */
615
+ if (stackItem && !IsAbortedTransactionBlockState ())
616
+ {
617
+ /*
618
+ * Make sure the item we want to log is still on the stack - if not
619
+ * then something has gone wrong and an error will be raised.
620
+ */
621
+ stack_valid (stackId );
622
+
623
+ /*
624
+ * Log the utility command if logging is on, the command has not
625
+ * already been logged by another hook, and the transaction is not
626
+ * aborted.
627
+ */
628
+ if (auditLogBitmap != 0 && !stackItem -> auditEvent .logged )
629
+ log_audit_event (stackItem );
630
+ }
499
631
}
500
632
501
633
/*
0 commit comments