📄 accesslog.c
字号:
/* accesslog.c - log operations for audit/history purposes *//* $OpenLDAP: pkg/ldap/servers/slapd/overlays/accesslog.c,v 1.2.2.23 2007/01/25 12:42:01 hyc Exp $ *//* This work is part of OpenLDAP Software <http://www.openldap.org/>. * * Copyright 2005-2007 The OpenLDAP Foundation. * Portions copyright 2004-2005 Symas Corporation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * <http://www.OpenLDAP.org/license.html>. *//* ACKNOWLEDGEMENTS: * This work was initially developed by Howard Chu for inclusion in * OpenLDAP Software. */#include "portable.h"#ifdef SLAPD_OVER_ACCESSLOG#include <stdio.h>#include <ac/string.h>#include <ac/ctype.h>#include "slap.h"#include "config.h"#include "lutil.h"#include "ldap_rq.h"#define LOG_OP_ADD 0x001#define LOG_OP_DELETE 0x002#define LOG_OP_MODIFY 0x004#define LOG_OP_MODRDN 0x008#define LOG_OP_COMPARE 0x010#define LOG_OP_SEARCH 0x020#define LOG_OP_BIND 0x040#define LOG_OP_UNBIND 0x080#define LOG_OP_ABANDON 0x100#define LOG_OP_EXTENDED 0x200#define LOG_OP_UNKNOWN 0x400#define LOG_OP_WRITES (LOG_OP_ADD|LOG_OP_DELETE|LOG_OP_MODIFY|LOG_OP_MODRDN)#define LOG_OP_READS (LOG_OP_COMPARE|LOG_OP_SEARCH)#define LOG_OP_SESSION (LOG_OP_BIND|LOG_OP_UNBIND|LOG_OP_ABANDON)#define LOG_OP_ALL (LOG_OP_READS|LOG_OP_WRITES|LOG_OP_SESSION| \ LOG_OP_EXTENDED|LOG_OP_UNKNOWN)typedef struct log_info { BackendDB *li_db; slap_mask_t li_ops; int li_age; int li_cycle; struct re_s *li_task; Filter *li_oldf; Entry *li_old; int li_success; ldap_pvt_thread_mutex_t li_op_mutex; ldap_pvt_thread_mutex_t li_log_mutex;} log_info;static ConfigDriver log_cf_gen;enum { LOG_DB = 1, LOG_OPS, LOG_PURGE, LOG_SUCCESS, LOG_OLD};static ConfigTable log_cfats[] = { { "logdb", "suffix", 2, 2, 0, ARG_DN|ARG_MAGIC|LOG_DB, log_cf_gen, "( OLcfgOvAt:4.1 NAME 'olcAccessLogDB' " "DESC 'Suffix of database for log content' " "SUP distinguishedName SINGLE-VALUE )", NULL, NULL }, { "logops", "op|writes|reads|session|all", 2, 0, 0, ARG_MAGIC|LOG_OPS, log_cf_gen, "( OLcfgOvAt:4.2 NAME 'olcAccessLogOps' " "DESC 'Operation types to log' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString )", NULL, NULL }, { "logpurge", "age> <interval", 3, 3, 0, ARG_MAGIC|LOG_PURGE, log_cf_gen, "( OLcfgOvAt:4.3 NAME 'olcAccessLogPurge' " "DESC 'Log cleanup parameters' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { "logsuccess", NULL, 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|LOG_SUCCESS, log_cf_gen, "( OLcfgOvAt:4.4 NAME 'olcAccessLogSuccess' " "DESC 'Log successful ops only' " "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, { "logold", "filter", 2, 2, 0, ARG_MAGIC|LOG_OLD, log_cf_gen, "( OLcfgOvAt:4.5 NAME 'olcAccessLogOld' " "DESC 'Log old values when modifying entries matching the filter' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { NULL }};static ConfigOCs log_cfocs[] = { { "( OLcfgOvOc:4.1 " "NAME 'olcAccessLogConfig' " "DESC 'Access log configuration' " "SUP olcOverlayConfig " "MUST olcAccessLogDB " "MAY ( olcAccessLogOps $ olcAccessLogPurge $ olcAccessLogSuccess $ " "olcAccessLogOld ) )", Cft_Overlay, log_cfats }, { NULL }};static slap_verbmasks logops[] = { { BER_BVC("all"), LOG_OP_ALL }, { BER_BVC("writes"), LOG_OP_WRITES }, { BER_BVC("session"), LOG_OP_SESSION }, { BER_BVC("reads"), LOG_OP_READS }, { BER_BVC("add"), LOG_OP_ADD }, { BER_BVC("delete"), LOG_OP_DELETE }, { BER_BVC("modify"), LOG_OP_MODIFY }, { BER_BVC("modrdn"), LOG_OP_MODRDN }, { BER_BVC("compare"), LOG_OP_COMPARE }, { BER_BVC("search"), LOG_OP_SEARCH }, { BER_BVC("bind"), LOG_OP_BIND }, { BER_BVC("unbind"), LOG_OP_UNBIND }, { BER_BVC("abandon"), LOG_OP_ABANDON }, { BER_BVC("extended"), LOG_OP_EXTENDED }, { BER_BVC("unknown"), LOG_OP_UNKNOWN }, { BER_BVNULL, 0 }};/* Start with "add" in logops */#define EN_OFFSET 4enum { LOG_EN_ADD = 0, LOG_EN_DELETE, LOG_EN_MODIFY, LOG_EN_MODRDN, LOG_EN_COMPARE, LOG_EN_SEARCH, LOG_EN_BIND, LOG_EN_UNBIND, LOG_EN_ABANDON, LOG_EN_EXTENDED, LOG_EN_UNKNOWN, LOG_EN__COUNT};static ObjectClass *log_ocs[LOG_EN__COUNT], *log_container;#define LOG_SCHEMA_ROOT "1.3.6.1.4.1.4203.666.11.5"#define LOG_SCHEMA_AT LOG_SCHEMA_ROOT ".1"#define LOG_SCHEMA_OC LOG_SCHEMA_ROOT ".2"static AttributeDescription *ad_reqDN, *ad_reqStart, *ad_reqEnd, *ad_reqType, *ad_reqSession, *ad_reqResult, *ad_reqAuthzID, *ad_reqControls, *ad_reqRespControls, *ad_reqMethod, *ad_reqAssertion, *ad_reqNewRDN, *ad_reqNewSuperior, *ad_reqDeleteOldRDN, *ad_reqMod, *ad_reqScope, *ad_reqFilter, *ad_reqAttr, *ad_reqEntries, *ad_reqSizeLimit, *ad_reqTimeLimit, *ad_reqAttrsOnly, *ad_reqData, *ad_reqId, *ad_reqMessage, *ad_reqVersion, *ad_reqDerefAliases, *ad_reqReferral, *ad_reqOld;static struct { char *at; AttributeDescription **ad;} lattrs[] = { { "( " LOG_SCHEMA_AT ".1 NAME 'reqDN' " "DESC 'Target DN of request' " "EQUALITY distinguishedNameMatch " "SYNTAX OMsDN " "SINGLE-VALUE )", &ad_reqDN }, { "( " LOG_SCHEMA_AT ".2 NAME 'reqStart' " "DESC 'Start time of request' " "EQUALITY generalizedTimeMatch " "ORDERING generalizedTimeOrderingMatch " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 " "SINGLE-VALUE )", &ad_reqStart }, { "( " LOG_SCHEMA_AT ".3 NAME 'reqEnd' " "DESC 'End time of request' " "EQUALITY generalizedTimeMatch " "ORDERING generalizedTimeOrderingMatch " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 " "SINGLE-VALUE )", &ad_reqEnd }, { "( " LOG_SCHEMA_AT ".4 NAME 'reqType' " "DESC 'Type of request' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", &ad_reqType }, { "( " LOG_SCHEMA_AT ".5 NAME 'reqSession' " "DESC 'Session ID of request' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", &ad_reqSession }, { "( " LOG_SCHEMA_AT ".6 NAME 'reqAuthzID' " "DESC 'Authorization ID of requestor' " "EQUALITY distinguishedNameMatch " "SYNTAX OMsDN " "SINGLE-VALUE )", &ad_reqAuthzID }, { "( " LOG_SCHEMA_AT ".7 NAME 'reqResult' " "DESC 'Result code of request' " "EQUALITY integerMatch " "ORDERING integerOrderingMatch " "SYNTAX OMsInteger " "SINGLE-VALUE )", &ad_reqResult }, { "( " LOG_SCHEMA_AT ".8 NAME 'reqMessage' " "DESC 'Error text of request' " "EQUALITY caseIgnoreMatch " "SUBSTR caseIgnoreSubstringsMatch " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", &ad_reqMessage }, { "( " LOG_SCHEMA_AT ".9 NAME 'reqReferral' " "DESC 'Referrals returned for request' " "SUP labeledURI )", &ad_reqReferral }, { "( " LOG_SCHEMA_AT ".10 NAME 'reqControls' " "DESC 'Request controls' " "SYNTAX OMsOctetString )", &ad_reqControls }, { "( " LOG_SCHEMA_AT ".11 NAME 'reqRespControls' " "DESC 'Response controls of request' " "SYNTAX OMsOctetString )", &ad_reqRespControls }, { "( " LOG_SCHEMA_AT ".12 NAME 'reqId' " "DESC 'ID of Request to Abandon' " "EQUALITY integerMatch " "ORDERING integerOrderingMatch " "SYNTAX OMsInteger " "SINGLE-VALUE )", &ad_reqId }, { "( " LOG_SCHEMA_AT ".13 NAME 'reqVersion' " "DESC 'Protocol version of Bind request' " "EQUALITY integerMatch " "ORDERING integerOrderingMatch " "SYNTAX OMsInteger " "SINGLE-VALUE )", &ad_reqVersion }, { "( " LOG_SCHEMA_AT ".14 NAME 'reqMethod' " "DESC 'Bind method of request' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", &ad_reqMethod }, { "( " LOG_SCHEMA_AT ".15 NAME 'reqAssertion' " "DESC 'Compare Assertion of request' " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", &ad_reqAssertion }, { "( " LOG_SCHEMA_AT ".16 NAME 'reqMod' " "DESC 'Modifications of request' " "EQUALITY octetStringMatch " "SUBSTR octetStringSubstringsMatch " "SYNTAX OMsOctetString )", &ad_reqMod }, { "( " LOG_SCHEMA_AT ".17 NAME 'reqOld' " "DESC 'Old values of entry before request completed' " "EQUALITY octetStringMatch " "SUBSTR octetStringSubstringsMatch " "SYNTAX OMsOctetString )", &ad_reqOld }, { "( " LOG_SCHEMA_AT ".18 NAME 'reqNewRDN' " "DESC 'New RDN of request' " "EQUALITY distinguishedNameMatch " "SYNTAX OMsDN " "SINGLE-VALUE )", &ad_reqNewRDN }, { "( " LOG_SCHEMA_AT ".19 NAME 'reqDeleteOldRDN' " "DESC 'Delete old RDN' " "EQUALITY booleanMatch " "SYNTAX OMsBoolean " "SINGLE-VALUE )", &ad_reqDeleteOldRDN }, { "( " LOG_SCHEMA_AT ".20 NAME 'reqNewSuperior' " "DESC 'New superior DN of request' " "EQUALITY distinguishedNameMatch " "SYNTAX OMsDN " "SINGLE-VALUE )", &ad_reqNewSuperior }, { "( " LOG_SCHEMA_AT ".21 NAME 'reqScope' " "DESC 'Scope of request' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", &ad_reqScope }, { "( " LOG_SCHEMA_AT ".22 NAME 'reqDerefAliases' " "DESC 'Disposition of Aliases in request' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", &ad_reqDerefAliases }, { "( " LOG_SCHEMA_AT ".23 NAME 'reqAttrsOnly' " "DESC 'Attributes and values of request' " "EQUALITY booleanMatch " "SYNTAX OMsBoolean " "SINGLE-VALUE )", &ad_reqAttrsOnly }, { "( " LOG_SCHEMA_AT ".24 NAME 'reqFilter' " "DESC 'Filter of request' " "EQUALITY caseIgnoreMatch " "SUBSTR caseIgnoreSubstringsMatch " "SYNTAX OMsDirectoryString " "SINGLE-VALUE )", &ad_reqFilter }, { "( " LOG_SCHEMA_AT ".25 NAME 'reqAttr' " "DESC 'Attributes of request' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString )", &ad_reqAttr }, { "( " LOG_SCHEMA_AT ".26 NAME 'reqSizeLimit' " "DESC 'Size limit of request' " "EQUALITY integerMatch " "ORDERING integerOrderingMatch " "SYNTAX OMsInteger " "SINGLE-VALUE )", &ad_reqSizeLimit }, { "( " LOG_SCHEMA_AT ".27 NAME 'reqTimeLimit' " "DESC 'Time limit of request' " "EQUALITY integerMatch " "ORDERING integerOrderingMatch " "SYNTAX OMsInteger " "SINGLE-VALUE )", &ad_reqTimeLimit }, { "( " LOG_SCHEMA_AT ".28 NAME 'reqEntries' " "DESC 'Number of entries returned' " "EQUALITY integerMatch " "ORDERING integerOrderingMatch " "SYNTAX OMsInteger " "SINGLE-VALUE )", &ad_reqEntries }, { "( " LOG_SCHEMA_AT ".29 NAME 'reqData' " "DESC 'Data of extended request' " "EQUALITY octetStringMatch " "SUBSTR octetStringSubstringsMatch " "SYNTAX OMsOctetString " "SINGLE-VALUE )", &ad_reqData }, { NULL, NULL }};static struct { char *ot; ObjectClass **oc;} locs[] = { { "( " LOG_SCHEMA_OC ".0 NAME 'auditContainer' " "DESC 'AuditLog container' " "SUP top STRUCTURAL " "MAY ( cn $ reqStart $ reqEnd ) )", &log_container }, { "( " LOG_SCHEMA_OC ".1 NAME 'auditObject' " "DESC 'OpenLDAP request auditing' " "SUP top STRUCTURAL " "MUST ( reqStart $ reqType $ reqSession ) " "MAY ( reqDN $ reqAuthzID $ reqControls $ reqRespControls $ reqEnd $ " "reqResult $ reqMessage $ reqReferral ) )", &log_ocs[LOG_EN_UNBIND] }, { "( " LOG_SCHEMA_OC ".2 NAME 'auditReadObject' " "DESC 'OpenLDAP read request record' " "SUP auditObject STRUCTURAL )", NULL }, { "( " LOG_SCHEMA_OC ".3 NAME 'auditWriteObject' " "DESC 'OpenLDAP write request record' " "SUP auditObject STRUCTURAL )", NULL }, { "( " LOG_SCHEMA_OC ".4 NAME 'auditAbandon' " "DESC 'Abandon operation' " "SUP auditObject STRUCTURAL " "MUST reqId )", &log_ocs[LOG_EN_ABANDON] }, { "( " LOG_SCHEMA_OC ".5 NAME 'auditAdd' " "DESC 'Add operation' " "SUP auditWriteObject STRUCTURAL " "MUST reqMod )", &log_ocs[LOG_EN_ADD] }, { "( " LOG_SCHEMA_OC ".6 NAME 'auditBind' " "DESC 'Bind operation' " "SUP auditObject STRUCTURAL " "MUST ( reqVersion $ reqMethod ) )", &log_ocs[LOG_EN_BIND] }, { "( " LOG_SCHEMA_OC ".7 NAME 'auditCompare' " "DESC 'Compare operation' " "SUP auditReadObject STRUCTURAL " "MUST reqAssertion )", &log_ocs[LOG_EN_COMPARE] }, { "( " LOG_SCHEMA_OC ".8 NAME 'auditDelete' " "DESC 'Delete operation' " "SUP auditWriteObject STRUCTURAL " "MAY reqOld )", &log_ocs[LOG_EN_DELETE] }, { "( " LOG_SCHEMA_OC ".9 NAME 'auditModify' " "DESC 'Modify operation' " "SUP auditWriteObject STRUCTURAL " "MAY reqOld MUST reqMod )", &log_ocs[LOG_EN_MODIFY] }, { "( " LOG_SCHEMA_OC ".10 NAME 'auditModRDN' " "DESC 'ModRDN operation' " "SUP auditWriteObject STRUCTURAL " "MUST ( reqNewRDN $ reqDeleteOldRDN ) " "MAY reqNewSuperior )", &log_ocs[LOG_EN_MODRDN] }, { "( " LOG_SCHEMA_OC ".11 NAME 'auditSearch' " "DESC 'Search operation' " "SUP auditReadObject STRUCTURAL " "MUST ( reqScope $ reqDerefAliases $ reqAttrsonly ) " "MAY ( reqFilter $ reqAttr $ reqEntries $ reqSizeLimit $ " "reqTimeLimit ) )", &log_ocs[LOG_EN_SEARCH] }, { "( " LOG_SCHEMA_OC ".12 NAME 'auditExtended' " "DESC 'Extended operation' " "SUP auditObject STRUCTURAL " "MAY reqData )", &log_ocs[LOG_EN_EXTENDED] }, { NULL, NULL }};#define RDNEQ "reqStart="/* Our time intervals are of the form [ddd+]hh:mm[:ss] * If a field is present, it must be two digits. (Except for * days, which can be arbitrary width.) */static intlog_age_parse(char *agestr){ int t1, t2; int gotdays = 0; char *endptr; t1 = strtol( agestr, &endptr, 10 ); /* Is there a days delimiter? */ if ( *endptr == '+' ) { /* 32 bit time only covers about 68 years */ if ( t1 < 0 || t1 > 25000 ) return -1; t1 *= 24; gotdays = 1; agestr = endptr + 1; } else { if ( agestr[2] != ':' ) { /* No valid delimiter found, fail */ return -1; } t1 *= 60; agestr += 3; } t2 = atoi( agestr ); t1 += t2; if ( agestr[2] ) { /* if there's a delimiter, it can only be a colon */ if ( agestr[2] != ':' ) return -1; } else { /* If we're at the end of the string, and we started with days, * fail because we expected to find minutes too. */ return gotdays ? -1 : t1 * 60; } agestr += 3; t2 = atoi( agestr ); /* last field can only be seconds */ if ( agestr[2] && ( agestr[2] != ':' || !gotdays )) return -1; t1 *= 60; t1 += t2; if ( agestr[2] ) { agestr += 3; if ( agestr[2] ) return -1; t1 *= 60; t1 += atoi( agestr ); } else if ( gotdays ) { /* only got days+hh:mm */ t1 *= 60; } return t1;}static voidlog_age_unparse( int age, struct berval *agebv ){ int dd, hh, mm, ss; char *ptr; ss = age % 60; age /= 60; mm = age % 60; age /= 60; hh = age % 24; age /= 24; dd = age; ptr = agebv->bv_val; if ( dd ) ptr += sprintf( ptr, "%d+", dd ); ptr += sprintf( ptr, "%02d:%02d", hh, mm ); if ( ss ) ptr += sprintf( ptr, ":%02d", ss ); agebv->bv_len = ptr - agebv->bv_val;}static slap_callback nullsc = { NULL, NULL, NULL, NULL };#define PURGE_INCREMENT 100typedef struct purge_data { int slots; int used; BerVarray dn; BerVarray ndn; struct berval csn; /* an arbitrary old CSN */} purge_data;static intlog_old_lookup( Operation *op, SlapReply *rs ){ purge_data *pd = op->o_callback->sc_private; if ( rs->sr_type != REP_SEARCH) return 0; if ( slapd_shutdown ) return 0; /* Remember old CSN */ if ( pd->csn.bv_val[0] == '\0' ) { Attribute *a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryCSN ); if ( a ) { int len = a->a_vals[0].bv_len; if ( len > pd->csn.bv_len ) len = pd->csn.bv_len; AC_MEMCPY( pd->csn.bv_val, a->a_vals[0].bv_val, len ); pd->csn.bv_len = len; } } if ( pd->used >= pd->slots ) { pd->slots += PURGE_INCREMENT; pd->dn = ch_realloc( pd->dn, pd->slots * sizeof( struct berval )); pd->ndn = ch_realloc( pd->ndn, pd->slots * sizeof( struct berval )); } ber_dupbv( &pd->dn[pd->used], &rs->sr_entry->e_name ); ber_dupbv( &pd->ndn[pd->used], &rs->sr_entry->e_nname ); pd->used++; return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -