1/* $NetBSD: auditlog.c,v 1.3 2021/08/14 16:15:02 christos Exp $ */ 2 3/* auditlog.c - log modifications for audit/history purposes */ 4/* $OpenLDAP$ */ 5/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2005-2021 The OpenLDAP Foundation. 8 * Portions copyright 2004-2005 Symas Corporation. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted only as authorized by the OpenLDAP 13 * Public License. 14 * 15 * A copy of this license is available in the file LICENSE in the 16 * top-level directory of the distribution or, alternatively, at 17 * <http://www.OpenLDAP.org/license.html>. 18 */ 19/* ACKNOWLEDGEMENTS: 20 * This work was initially developed by Symas Corp. for inclusion in 21 * OpenLDAP Software. This work was sponsored by Hewlett-Packard. 22 */ 23 24#include <sys/cdefs.h> 25__RCSID("$NetBSD: auditlog.c,v 1.3 2021/08/14 16:15:02 christos Exp $"); 26 27#include "portable.h" 28 29#ifdef SLAPD_OVER_AUDITLOG 30 31#include <stdio.h> 32 33#include <ac/string.h> 34#include <ac/ctype.h> 35 36#include "slap.h" 37#include "slap-config.h" 38#include "ldif.h" 39 40typedef struct auditlog_data { 41 ldap_pvt_thread_mutex_t ad_mutex; 42 char *ad_logfile; 43} auditlog_data; 44 45static ConfigTable auditlogcfg[] = { 46 { "auditlog", "filename", 2, 2, 0, 47 ARG_STRING|ARG_OFFSET, 48 (void *)offsetof(auditlog_data, ad_logfile), 49 "( OLcfgOvAt:15.1 NAME 'olcAuditlogFile' " 50 "DESC 'Filename for auditlogging' " 51 "EQUALITY caseExactMatch " 52 "SYNTAX OMsDirectoryString )", NULL, NULL }, 53 { NULL, NULL, 0, 0, 0, ARG_IGNORED } 54}; 55 56static ConfigOCs auditlogocs[] = { 57 { "( OLcfgOvOc:15.1 " 58 "NAME 'olcAuditlogConfig' " 59 "DESC 'Auditlog configuration' " 60 "SUP olcOverlayConfig " 61 "MAY ( olcAuditlogFile ) )", 62 Cft_Overlay, auditlogcfg }, 63 { NULL, 0, NULL } 64}; 65 66static int fprint_ldif(FILE *f, char *name, char *val, ber_len_t len) { 67 char *s; 68 if((s = ldif_put(LDIF_PUT_VALUE, name, val, len)) == NULL) 69 return(-1); 70 fputs(s, f); 71 ber_memfree(s); 72 return(0); 73} 74 75static int auditlog_response(Operation *op, SlapReply *rs) { 76 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 77 auditlog_data *ad = on->on_bi.bi_private; 78 FILE *f; 79 Attribute *a; 80 Modifications *m; 81 struct berval *b, *who = NULL, peername; 82 char *what, *whatm, *suffix; 83 time_t stamp; 84 int i; 85 86 if ( rs->sr_err != LDAP_SUCCESS ) return SLAP_CB_CONTINUE; 87 88 if ( !ad->ad_logfile ) return SLAP_CB_CONTINUE; 89 90/* 91** add or modify: use modifiersName if present 92** 93*/ 94 switch(op->o_tag) { 95 case LDAP_REQ_MODRDN: what = "modrdn"; break; 96 case LDAP_REQ_DELETE: what = "delete"; break; 97 case LDAP_REQ_ADD: 98 what = "add"; 99 for(a = op->ora_e->e_attrs; a; a = a->a_next) 100 if( a->a_desc == slap_schema.si_ad_modifiersName ) { 101 who = &a->a_vals[0]; 102 break; 103 } 104 break; 105 case LDAP_REQ_MODIFY: 106 what = "modify"; 107 for(m = op->orm_modlist; m; m = m->sml_next) 108 if( m->sml_desc == slap_schema.si_ad_modifiersName && 109 ( m->sml_op == LDAP_MOD_ADD || 110 m->sml_op == LDAP_MOD_REPLACE )) { 111 who = &m->sml_values[0]; 112 break; 113 } 114 break; 115 default: 116 return SLAP_CB_CONTINUE; 117 } 118 119 suffix = op->o_bd->be_suffix[0].bv_len ? op->o_bd->be_suffix[0].bv_val : 120 "global"; 121 122/* 123** note: this means requestor's dn when modifiersName is null 124*/ 125 if ( !who ) 126 who = &op->o_dn; 127 128 peername = op->o_conn->c_peer_name; 129 ldap_pvt_thread_mutex_lock(&ad->ad_mutex); 130 if((f = fopen(ad->ad_logfile, "a")) == NULL) { 131 ldap_pvt_thread_mutex_unlock(&ad->ad_mutex); 132 return SLAP_CB_CONTINUE; 133 } 134 135 stamp = slap_get_time(); 136 fprintf(f, "# %s %ld %s%s%s %s conn=%ld\n", 137 what, (long)stamp, suffix, who ? " " : "", who ? who->bv_val : "", 138 peername.bv_val ? peername.bv_val: "", op->o_conn->c_connid); 139 140 if ( !BER_BVISEMPTY( &op->o_conn->c_dn ) && 141 (!who || !dn_match( who, &op->o_conn->c_dn ))) 142 fprintf(f, "# realdn: %s\n", op->o_conn->c_dn.bv_val ); 143 144 fprintf(f, "dn: %s\nchangetype: %s\n", 145 op->o_req_dn.bv_val, what); 146 147 switch(op->o_tag) { 148 case LDAP_REQ_ADD: 149 for(a = op->ora_e->e_attrs; a; a = a->a_next) 150 if((b = a->a_vals) != NULL) 151 for(i = 0; b[i].bv_val; i++) 152 fprint_ldif(f, a->a_desc->ad_cname.bv_val, b[i].bv_val, b[i].bv_len); 153 break; 154 155 case LDAP_REQ_MODIFY: 156 for(m = op->orm_modlist; m; m = m->sml_next) { 157 switch(m->sml_op & LDAP_MOD_OP) { 158 case LDAP_MOD_ADD: whatm = "add"; break; 159 case LDAP_MOD_REPLACE: whatm = "replace"; break; 160 case LDAP_MOD_DELETE: whatm = "delete"; break; 161 case LDAP_MOD_INCREMENT: whatm = "increment"; break; 162 default: 163 fprintf(f, "# MOD_TYPE_UNKNOWN:%02x\n", m->sml_op & LDAP_MOD_OP); 164 continue; 165 } 166 fprintf(f, "%s: %s\n", whatm, m->sml_desc->ad_cname.bv_val); 167 if((b = m->sml_values) != NULL) 168 for(i = 0; b[i].bv_val; i++) 169 fprint_ldif(f, m->sml_desc->ad_cname.bv_val, b[i].bv_val, b[i].bv_len); 170 fprintf(f, "-\n"); 171 } 172 break; 173 174 case LDAP_REQ_MODRDN: 175 fprintf(f, "newrdn: %s\ndeleteoldrdn: %s\n", 176 op->orr_newrdn.bv_val, op->orr_deleteoldrdn ? "1" : "0"); 177 if(op->orr_newSup) fprintf(f, "newsuperior: %s\n", op->orr_newSup->bv_val); 178 break; 179 180 case LDAP_REQ_DELETE: 181 /* nothing else needed */ 182 break; 183 } 184 185 fprintf(f, "# end %s %ld\n\n", what, (long)stamp); 186 187 fclose(f); 188 ldap_pvt_thread_mutex_unlock(&ad->ad_mutex); 189 return SLAP_CB_CONTINUE; 190} 191 192static slap_overinst auditlog; 193 194static int 195auditlog_db_init( 196 BackendDB *be, 197 ConfigReply *cr 198) 199{ 200 slap_overinst *on = (slap_overinst *)be->bd_info; 201 auditlog_data *ad = ch_calloc(1, sizeof(auditlog_data)); 202 203 on->on_bi.bi_private = ad; 204 ldap_pvt_thread_mutex_init( &ad->ad_mutex ); 205 return 0; 206} 207 208static int 209auditlog_db_destroy( 210 BackendDB *be, 211 ConfigReply *cr 212) 213{ 214 slap_overinst *on = (slap_overinst *)be->bd_info; 215 auditlog_data *ad = on->on_bi.bi_private; 216 217 ldap_pvt_thread_mutex_destroy( &ad->ad_mutex ); 218 free( ad->ad_logfile ); 219 free( ad ); 220 return 0; 221} 222 223int auditlog_initialize() { 224 int rc; 225 226 auditlog.on_bi.bi_type = "auditlog"; 227 auditlog.on_bi.bi_flags = SLAPO_BFLAG_SINGLE; 228 auditlog.on_bi.bi_db_init = auditlog_db_init; 229 auditlog.on_bi.bi_db_destroy = auditlog_db_destroy; 230 auditlog.on_response = auditlog_response; 231 232 auditlog.on_bi.bi_cf_ocs = auditlogocs; 233 rc = config_register_schema( auditlogcfg, auditlogocs ); 234 if ( rc ) return rc; 235 236 return overlay_register(&auditlog); 237} 238 239#if SLAPD_OVER_AUDITLOG == SLAPD_MOD_DYNAMIC && defined(PIC) 240int 241init_module( int argc, char *argv[] ) 242{ 243 return auditlog_initialize(); 244} 245#endif 246 247#endif /* SLAPD_OVER_AUDITLOG */ 248