accesslog.c revision 1.1.1.5
1/* $NetBSD: accesslog.c,v 1.1.1.5 2017/02/09 01:47:02 christos Exp $ */ 2 3/* accesslog.c - log operations for audit/history purposes */ 4/* $OpenLDAP$ */ 5/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2005-2016 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 Howard Chu for inclusion in 21 * OpenLDAP Software. 22 */ 23 24#include <sys/cdefs.h> 25__RCSID("$NetBSD: accesslog.c,v 1.1.1.5 2017/02/09 01:47:02 christos Exp $"); 26 27#include "portable.h" 28 29#ifdef SLAPD_OVER_ACCESSLOG 30 31#include <stdio.h> 32 33#include <ac/string.h> 34#include <ac/ctype.h> 35 36#include "slap.h" 37#include "config.h" 38#include "lutil.h" 39#include "ldap_rq.h" 40 41#define LOG_OP_ADD 0x001 42#define LOG_OP_DELETE 0x002 43#define LOG_OP_MODIFY 0x004 44#define LOG_OP_MODRDN 0x008 45#define LOG_OP_COMPARE 0x010 46#define LOG_OP_SEARCH 0x020 47#define LOG_OP_BIND 0x040 48#define LOG_OP_UNBIND 0x080 49#define LOG_OP_ABANDON 0x100 50#define LOG_OP_EXTENDED 0x200 51#define LOG_OP_UNKNOWN 0x400 52 53#define LOG_OP_WRITES (LOG_OP_ADD|LOG_OP_DELETE|LOG_OP_MODIFY|LOG_OP_MODRDN) 54#define LOG_OP_READS (LOG_OP_COMPARE|LOG_OP_SEARCH) 55#define LOG_OP_SESSION (LOG_OP_BIND|LOG_OP_UNBIND|LOG_OP_ABANDON) 56#define LOG_OP_ALL (LOG_OP_READS|LOG_OP_WRITES|LOG_OP_SESSION| \ 57 LOG_OP_EXTENDED|LOG_OP_UNKNOWN) 58 59typedef struct log_attr { 60 struct log_attr *next; 61 AttributeDescription *attr; 62} log_attr; 63 64typedef struct log_base { 65 struct log_base *lb_next; 66 slap_mask_t lb_ops; 67 struct berval lb_base; 68 struct berval lb_line; 69} log_base; 70 71typedef struct log_info { 72 BackendDB *li_db; 73 struct berval li_db_suffix; 74 slap_mask_t li_ops; 75 int li_age; 76 int li_cycle; 77 struct re_s *li_task; 78 Filter *li_oldf; 79 Entry *li_old; 80 log_attr *li_oldattrs; 81 struct berval li_uuid; 82 int li_success; 83 log_base *li_bases; 84 ldap_pvt_thread_rmutex_t li_op_rmutex; 85 ldap_pvt_thread_mutex_t li_log_mutex; 86} log_info; 87 88static ConfigDriver log_cf_gen; 89 90enum { 91 LOG_DB = 1, 92 LOG_OPS, 93 LOG_PURGE, 94 LOG_SUCCESS, 95 LOG_OLD, 96 LOG_OLDATTR, 97 LOG_BASE 98}; 99 100static ConfigTable log_cfats[] = { 101 { "logdb", "suffix", 2, 2, 0, ARG_DN|ARG_MAGIC|LOG_DB, 102 log_cf_gen, "( OLcfgOvAt:4.1 NAME 'olcAccessLogDB' " 103 "DESC 'Suffix of database for log content' " 104 "SUP distinguishedName SINGLE-VALUE )", NULL, NULL }, 105 { "logops", "op|writes|reads|session|all", 2, 0, 0, 106 ARG_MAGIC|LOG_OPS, 107 log_cf_gen, "( OLcfgOvAt:4.2 NAME 'olcAccessLogOps' " 108 "DESC 'Operation types to log' " 109 "EQUALITY caseIgnoreMatch " 110 "SYNTAX OMsDirectoryString )", NULL, NULL }, 111 { "logpurge", "age> <interval", 3, 3, 0, ARG_MAGIC|LOG_PURGE, 112 log_cf_gen, "( OLcfgOvAt:4.3 NAME 'olcAccessLogPurge' " 113 "DESC 'Log cleanup parameters' " 114 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, 115 { "logsuccess", NULL, 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|LOG_SUCCESS, 116 log_cf_gen, "( OLcfgOvAt:4.4 NAME 'olcAccessLogSuccess' " 117 "DESC 'Log successful ops only' " 118 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, 119 { "logold", "filter", 2, 2, 0, ARG_MAGIC|LOG_OLD, 120 log_cf_gen, "( OLcfgOvAt:4.5 NAME 'olcAccessLogOld' " 121 "DESC 'Log old values when modifying entries matching the filter' " 122 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, 123 { "logoldattr", "attrs", 2, 0, 0, ARG_MAGIC|LOG_OLDATTR, 124 log_cf_gen, "( OLcfgOvAt:4.6 NAME 'olcAccessLogOldAttr' " 125 "DESC 'Log old values of these attributes even if unmodified' " 126 "EQUALITY caseIgnoreMatch " 127 "SYNTAX OMsDirectoryString )", NULL, NULL }, 128 { "logbase", "op|writes|reads|session|all< <baseDN", 3, 3, 0, 129 ARG_MAGIC|LOG_BASE, 130 log_cf_gen, "( OLcfgOvAt:4.7 NAME 'olcAccessLogBase' " 131 "DESC 'Operation types to log under a specific branch' " 132 "EQUALITY caseIgnoreMatch " 133 "SYNTAX OMsDirectoryString )", NULL, NULL }, 134 { NULL } 135}; 136 137static ConfigOCs log_cfocs[] = { 138 { "( OLcfgOvOc:4.1 " 139 "NAME 'olcAccessLogConfig' " 140 "DESC 'Access log configuration' " 141 "SUP olcOverlayConfig " 142 "MUST olcAccessLogDB " 143 "MAY ( olcAccessLogOps $ olcAccessLogPurge $ olcAccessLogSuccess $ " 144 "olcAccessLogOld $ olcAccessLogOldAttr $ olcAccessLogBase ) )", 145 Cft_Overlay, log_cfats }, 146 { NULL } 147}; 148 149static slap_verbmasks logops[] = { 150 { BER_BVC("all"), LOG_OP_ALL }, 151 { BER_BVC("writes"), LOG_OP_WRITES }, 152 { BER_BVC("session"), LOG_OP_SESSION }, 153 { BER_BVC("reads"), LOG_OP_READS }, 154 { BER_BVC("add"), LOG_OP_ADD }, 155 { BER_BVC("delete"), LOG_OP_DELETE }, 156 { BER_BVC("modify"), LOG_OP_MODIFY }, 157 { BER_BVC("modrdn"), LOG_OP_MODRDN }, 158 { BER_BVC("compare"), LOG_OP_COMPARE }, 159 { BER_BVC("search"), LOG_OP_SEARCH }, 160 { BER_BVC("bind"), LOG_OP_BIND }, 161 { BER_BVC("unbind"), LOG_OP_UNBIND }, 162 { BER_BVC("abandon"), LOG_OP_ABANDON }, 163 { BER_BVC("extended"), LOG_OP_EXTENDED }, 164 { BER_BVC("unknown"), LOG_OP_UNKNOWN }, 165 { BER_BVNULL, 0 } 166}; 167 168/* Start with "add" in logops */ 169#define EN_OFFSET 4 170 171enum { 172 LOG_EN_ADD = 0, 173 LOG_EN_DELETE, 174 LOG_EN_MODIFY, 175 LOG_EN_MODRDN, 176 LOG_EN_COMPARE, 177 LOG_EN_SEARCH, 178 LOG_EN_BIND, 179 LOG_EN_UNBIND, 180 LOG_EN_ABANDON, 181 LOG_EN_EXTENDED, 182 LOG_EN_UNKNOWN, 183 LOG_EN__COUNT 184}; 185 186static ObjectClass *log_ocs[LOG_EN__COUNT], *log_container, 187 *log_oc_read, *log_oc_write; 188 189#define LOG_SCHEMA_ROOT "1.3.6.1.4.1.4203.666.11.5" 190 191#define LOG_SCHEMA_AT LOG_SCHEMA_ROOT ".1" 192#define LOG_SCHEMA_OC LOG_SCHEMA_ROOT ".2" 193#define LOG_SCHEMA_SYN LOG_SCHEMA_ROOT ".3" 194 195static AttributeDescription *ad_reqDN, *ad_reqStart, *ad_reqEnd, *ad_reqType, 196 *ad_reqSession, *ad_reqResult, *ad_reqAuthzID, *ad_reqControls, 197 *ad_reqRespControls, *ad_reqMethod, *ad_reqAssertion, *ad_reqNewRDN, 198 *ad_reqNewSuperior, *ad_reqDeleteOldRDN, *ad_reqMod, 199 *ad_reqScope, *ad_reqFilter, *ad_reqAttr, *ad_reqEntries, 200 *ad_reqSizeLimit, *ad_reqTimeLimit, *ad_reqAttrsOnly, *ad_reqData, 201 *ad_reqId, *ad_reqMessage, *ad_reqVersion, *ad_reqDerefAliases, 202 *ad_reqReferral, *ad_reqOld, *ad_auditContext, *ad_reqEntryUUID; 203 204static int 205logSchemaControlValidate( 206 Syntax *syntax, 207 struct berval *val ); 208 209char *mrControl[] = { 210 "objectIdentifierFirstComponentMatch", 211 NULL 212}; 213 214static struct { 215 char *oid; 216 slap_syntax_defs_rec syn; 217 char **mrs; 218} lsyntaxes[] = { 219 { LOG_SCHEMA_SYN ".1" , 220 { "( " LOG_SCHEMA_SYN ".1 DESC 'Control' )", 221 SLAP_SYNTAX_HIDE, 222 NULL, 223 logSchemaControlValidate, 224 NULL }, 225 mrControl }, 226 { NULL } 227}; 228 229static struct { 230 char *at; 231 AttributeDescription **ad; 232} lattrs[] = { 233 { "( " LOG_SCHEMA_AT ".1 NAME 'reqDN' " 234 "DESC 'Target DN of request' " 235 "EQUALITY distinguishedNameMatch " 236 "SYNTAX OMsDN " 237 "SINGLE-VALUE )", &ad_reqDN }, 238 { "( " LOG_SCHEMA_AT ".2 NAME 'reqStart' " 239 "DESC 'Start time of request' " 240 "EQUALITY generalizedTimeMatch " 241 "ORDERING generalizedTimeOrderingMatch " 242 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 " 243 "SINGLE-VALUE )", &ad_reqStart }, 244 { "( " LOG_SCHEMA_AT ".3 NAME 'reqEnd' " 245 "DESC 'End time of request' " 246 "EQUALITY generalizedTimeMatch " 247 "ORDERING generalizedTimeOrderingMatch " 248 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 " 249 "SINGLE-VALUE )", &ad_reqEnd }, 250 { "( " LOG_SCHEMA_AT ".4 NAME 'reqType' " 251 "DESC 'Type of request' " 252 "EQUALITY caseIgnoreMatch " 253 "SYNTAX OMsDirectoryString " 254 "SINGLE-VALUE )", &ad_reqType }, 255 { "( " LOG_SCHEMA_AT ".5 NAME 'reqSession' " 256 "DESC 'Session ID of request' " 257 "EQUALITY caseIgnoreMatch " 258 "SYNTAX OMsDirectoryString " 259 "SINGLE-VALUE )", &ad_reqSession }, 260 { "( " LOG_SCHEMA_AT ".6 NAME 'reqAuthzID' " 261 "DESC 'Authorization ID of requestor' " 262 "EQUALITY distinguishedNameMatch " 263 "SYNTAX OMsDN " 264 "SINGLE-VALUE )", &ad_reqAuthzID }, 265 { "( " LOG_SCHEMA_AT ".7 NAME 'reqResult' " 266 "DESC 'Result code of request' " 267 "EQUALITY integerMatch " 268 "ORDERING integerOrderingMatch " 269 "SYNTAX OMsInteger " 270 "SINGLE-VALUE )", &ad_reqResult }, 271 { "( " LOG_SCHEMA_AT ".8 NAME 'reqMessage' " 272 "DESC 'Error text of request' " 273 "EQUALITY caseIgnoreMatch " 274 "SUBSTR caseIgnoreSubstringsMatch " 275 "SYNTAX OMsDirectoryString " 276 "SINGLE-VALUE )", &ad_reqMessage }, 277 { "( " LOG_SCHEMA_AT ".9 NAME 'reqReferral' " 278 "DESC 'Referrals returned for request' " 279 "SUP labeledURI )", &ad_reqReferral }, 280 { "( " LOG_SCHEMA_AT ".10 NAME 'reqControls' " 281 "DESC 'Request controls' " 282 "EQUALITY objectIdentifierFirstComponentMatch " 283 "SYNTAX " LOG_SCHEMA_SYN ".1 " 284 "X-ORDERED 'VALUES' )", &ad_reqControls }, 285 { "( " LOG_SCHEMA_AT ".11 NAME 'reqRespControls' " 286 "DESC 'Response controls of request' " 287 "EQUALITY objectIdentifierFirstComponentMatch " 288 "SYNTAX " LOG_SCHEMA_SYN ".1 " 289 "X-ORDERED 'VALUES' )", &ad_reqRespControls }, 290 { "( " LOG_SCHEMA_AT ".12 NAME 'reqId' " 291 "DESC 'ID of Request to Abandon' " 292 "EQUALITY integerMatch " 293 "ORDERING integerOrderingMatch " 294 "SYNTAX OMsInteger " 295 "SINGLE-VALUE )", &ad_reqId }, 296 { "( " LOG_SCHEMA_AT ".13 NAME 'reqVersion' " 297 "DESC 'Protocol version of Bind request' " 298 "EQUALITY integerMatch " 299 "ORDERING integerOrderingMatch " 300 "SYNTAX OMsInteger " 301 "SINGLE-VALUE )", &ad_reqVersion }, 302 { "( " LOG_SCHEMA_AT ".14 NAME 'reqMethod' " 303 "DESC 'Bind method of request' " 304 "EQUALITY caseIgnoreMatch " 305 "SYNTAX OMsDirectoryString " 306 "SINGLE-VALUE )", &ad_reqMethod }, 307 { "( " LOG_SCHEMA_AT ".15 NAME 'reqAssertion' " 308 "DESC 'Compare Assertion of request' " 309 "SYNTAX OMsDirectoryString " 310 "SINGLE-VALUE )", &ad_reqAssertion }, 311 { "( " LOG_SCHEMA_AT ".16 NAME 'reqMod' " 312 "DESC 'Modifications of request' " 313 "EQUALITY octetStringMatch " 314 "SUBSTR octetStringSubstringsMatch " 315 "SYNTAX OMsOctetString )", &ad_reqMod }, 316 { "( " LOG_SCHEMA_AT ".17 NAME 'reqOld' " 317 "DESC 'Old values of entry before request completed' " 318 "EQUALITY octetStringMatch " 319 "SUBSTR octetStringSubstringsMatch " 320 "SYNTAX OMsOctetString )", &ad_reqOld }, 321 { "( " LOG_SCHEMA_AT ".18 NAME 'reqNewRDN' " 322 "DESC 'New RDN of request' " 323 "EQUALITY distinguishedNameMatch " 324 "SYNTAX OMsDN " 325 "SINGLE-VALUE )", &ad_reqNewRDN }, 326 { "( " LOG_SCHEMA_AT ".19 NAME 'reqDeleteOldRDN' " 327 "DESC 'Delete old RDN' " 328 "EQUALITY booleanMatch " 329 "SYNTAX OMsBoolean " 330 "SINGLE-VALUE )", &ad_reqDeleteOldRDN }, 331 { "( " LOG_SCHEMA_AT ".20 NAME 'reqNewSuperior' " 332 "DESC 'New superior DN of request' " 333 "EQUALITY distinguishedNameMatch " 334 "SYNTAX OMsDN " 335 "SINGLE-VALUE )", &ad_reqNewSuperior }, 336 { "( " LOG_SCHEMA_AT ".21 NAME 'reqScope' " 337 "DESC 'Scope of request' " 338 "EQUALITY caseIgnoreMatch " 339 "SYNTAX OMsDirectoryString " 340 "SINGLE-VALUE )", &ad_reqScope }, 341 { "( " LOG_SCHEMA_AT ".22 NAME 'reqDerefAliases' " 342 "DESC 'Disposition of Aliases in request' " 343 "EQUALITY caseIgnoreMatch " 344 "SYNTAX OMsDirectoryString " 345 "SINGLE-VALUE )", &ad_reqDerefAliases }, 346 { "( " LOG_SCHEMA_AT ".23 NAME 'reqAttrsOnly' " 347 "DESC 'Attributes and values of request' " 348 "EQUALITY booleanMatch " 349 "SYNTAX OMsBoolean " 350 "SINGLE-VALUE )", &ad_reqAttrsOnly }, 351 { "( " LOG_SCHEMA_AT ".24 NAME 'reqFilter' " 352 "DESC 'Filter of request' " 353 "EQUALITY caseIgnoreMatch " 354 "SUBSTR caseIgnoreSubstringsMatch " 355 "SYNTAX OMsDirectoryString " 356 "SINGLE-VALUE )", &ad_reqFilter }, 357 { "( " LOG_SCHEMA_AT ".25 NAME 'reqAttr' " 358 "DESC 'Attributes of request' " 359 "EQUALITY caseIgnoreMatch " 360 "SYNTAX OMsDirectoryString )", &ad_reqAttr }, 361 { "( " LOG_SCHEMA_AT ".26 NAME 'reqSizeLimit' " 362 "DESC 'Size limit of request' " 363 "EQUALITY integerMatch " 364 "ORDERING integerOrderingMatch " 365 "SYNTAX OMsInteger " 366 "SINGLE-VALUE )", &ad_reqSizeLimit }, 367 { "( " LOG_SCHEMA_AT ".27 NAME 'reqTimeLimit' " 368 "DESC 'Time limit of request' " 369 "EQUALITY integerMatch " 370 "ORDERING integerOrderingMatch " 371 "SYNTAX OMsInteger " 372 "SINGLE-VALUE )", &ad_reqTimeLimit }, 373 { "( " LOG_SCHEMA_AT ".28 NAME 'reqEntries' " 374 "DESC 'Number of entries returned' " 375 "EQUALITY integerMatch " 376 "ORDERING integerOrderingMatch " 377 "SYNTAX OMsInteger " 378 "SINGLE-VALUE )", &ad_reqEntries }, 379 { "( " LOG_SCHEMA_AT ".29 NAME 'reqData' " 380 "DESC 'Data of extended request' " 381 "EQUALITY octetStringMatch " 382 "SUBSTR octetStringSubstringsMatch " 383 "SYNTAX OMsOctetString " 384 "SINGLE-VALUE )", &ad_reqData }, 385 386 /* 387 * from <draft-chu-ldap-logschema-01.txt>: 388 * 389 390 ( LOG_SCHEMA_AT .30 NAME 'auditContext' 391 DESC 'DN of auditContainer' 392 EQUALITY distinguishedNameMatch 393 SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 394 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation ) 395 396 * - removed EQUALITY matchingRule 397 * - changed directoryOperation in dSAOperation 398 */ 399 { "( " LOG_SCHEMA_AT ".30 NAME 'auditContext' " 400 "DESC 'DN of auditContainer' " 401 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 " 402 "SINGLE-VALUE " 403 "NO-USER-MODIFICATION " 404 "USAGE dSAOperation )", &ad_auditContext }, 405 406 /* 407 * ITS#6656 408 */ 409 { "( " LOG_SCHEMA_AT ".31 NAME 'reqEntryUUID' " 410 "DESC 'UUID of entry' " 411 "EQUALITY UUIDMatch " 412 "ORDERING UUIDOrderingMatch " 413 "SYNTAX 1.3.6.1.1.16.1 " 414 "SINGLE-VALUE )", &ad_reqEntryUUID }, 415 { NULL, NULL } 416}; 417 418static struct { 419 char *ot; 420 ObjectClass **oc; 421} locs[] = { 422 { "( " LOG_SCHEMA_OC ".0 NAME 'auditContainer' " 423 "DESC 'AuditLog container' " 424 "SUP top STRUCTURAL " 425 "MAY ( cn $ reqStart $ reqEnd ) )", &log_container }, 426 { "( " LOG_SCHEMA_OC ".1 NAME 'auditObject' " 427 "DESC 'OpenLDAP request auditing' " 428 "SUP top STRUCTURAL " 429 "MUST ( reqStart $ reqType $ reqSession ) " 430 "MAY ( reqDN $ reqAuthzID $ reqControls $ reqRespControls $ reqEnd $ " 431 "reqResult $ reqMessage $ reqReferral $ reqEntryUUID ) )", 432 &log_ocs[LOG_EN_UNBIND] }, 433 { "( " LOG_SCHEMA_OC ".2 NAME 'auditReadObject' " 434 "DESC 'OpenLDAP read request record' " 435 "SUP auditObject STRUCTURAL )", &log_oc_read }, 436 { "( " LOG_SCHEMA_OC ".3 NAME 'auditWriteObject' " 437 "DESC 'OpenLDAP write request record' " 438 "SUP auditObject STRUCTURAL )", &log_oc_write }, 439 { "( " LOG_SCHEMA_OC ".4 NAME 'auditAbandon' " 440 "DESC 'Abandon operation' " 441 "SUP auditObject STRUCTURAL " 442 "MUST reqId )", &log_ocs[LOG_EN_ABANDON] }, 443 { "( " LOG_SCHEMA_OC ".5 NAME 'auditAdd' " 444 "DESC 'Add operation' " 445 "SUP auditWriteObject STRUCTURAL " 446 "MUST reqMod )", &log_ocs[LOG_EN_ADD] }, 447 { "( " LOG_SCHEMA_OC ".6 NAME 'auditBind' " 448 "DESC 'Bind operation' " 449 "SUP auditObject STRUCTURAL " 450 "MUST ( reqVersion $ reqMethod ) )", &log_ocs[LOG_EN_BIND] }, 451 { "( " LOG_SCHEMA_OC ".7 NAME 'auditCompare' " 452 "DESC 'Compare operation' " 453 "SUP auditReadObject STRUCTURAL " 454 "MUST reqAssertion )", &log_ocs[LOG_EN_COMPARE] }, 455 { "( " LOG_SCHEMA_OC ".8 NAME 'auditDelete' " 456 "DESC 'Delete operation' " 457 "SUP auditWriteObject STRUCTURAL " 458 "MAY reqOld )", &log_ocs[LOG_EN_DELETE] }, 459 { "( " LOG_SCHEMA_OC ".9 NAME 'auditModify' " 460 "DESC 'Modify operation' " 461 "SUP auditWriteObject STRUCTURAL " 462 "MAY reqOld MUST reqMod )", &log_ocs[LOG_EN_MODIFY] }, 463 { "( " LOG_SCHEMA_OC ".10 NAME 'auditModRDN' " 464 "DESC 'ModRDN operation' " 465 "SUP auditWriteObject STRUCTURAL " 466 "MUST ( reqNewRDN $ reqDeleteOldRDN ) " 467 "MAY ( reqNewSuperior $ reqMod $ reqOld ) )", &log_ocs[LOG_EN_MODRDN] }, 468 { "( " LOG_SCHEMA_OC ".11 NAME 'auditSearch' " 469 "DESC 'Search operation' " 470 "SUP auditReadObject STRUCTURAL " 471 "MUST ( reqScope $ reqDerefAliases $ reqAttrsonly ) " 472 "MAY ( reqFilter $ reqAttr $ reqEntries $ reqSizeLimit $ " 473 "reqTimeLimit ) )", &log_ocs[LOG_EN_SEARCH] }, 474 { "( " LOG_SCHEMA_OC ".12 NAME 'auditExtended' " 475 "DESC 'Extended operation' " 476 "SUP auditObject STRUCTURAL " 477 "MAY reqData )", &log_ocs[LOG_EN_EXTENDED] }, 478 { NULL, NULL } 479}; 480 481#define RDNEQ "reqStart=" 482 483/* Our time intervals are of the form [ddd+]hh:mm[:ss] 484 * If a field is present, it must be two digits. (Except for 485 * days, which can be arbitrary width.) 486 */ 487static int 488log_age_parse(char *agestr) 489{ 490 int t1, t2; 491 int gotdays = 0; 492 char *endptr; 493 494 t1 = strtol( agestr, &endptr, 10 ); 495 /* Is there a days delimiter? */ 496 if ( *endptr == '+' ) { 497 /* 32 bit time only covers about 68 years */ 498 if ( t1 < 0 || t1 > 25000 ) 499 return -1; 500 t1 *= 24; 501 gotdays = 1; 502 agestr = endptr + 1; 503 } else { 504 if ( agestr[2] != ':' ) { 505 /* No valid delimiter found, fail */ 506 return -1; 507 } 508 t1 *= 60; 509 agestr += 3; 510 } 511 512 t2 = atoi( agestr ); 513 t1 += t2; 514 515 if ( agestr[2] ) { 516 /* if there's a delimiter, it can only be a colon */ 517 if ( agestr[2] != ':' ) 518 return -1; 519 } else { 520 /* If we're at the end of the string, and we started with days, 521 * fail because we expected to find minutes too. 522 */ 523 return gotdays ? -1 : t1 * 60; 524 } 525 526 agestr += 3; 527 t2 = atoi( agestr ); 528 529 /* last field can only be seconds */ 530 if ( agestr[2] && ( agestr[2] != ':' || !gotdays )) 531 return -1; 532 t1 *= 60; 533 t1 += t2; 534 535 if ( agestr[2] ) { 536 agestr += 3; 537 if ( agestr[2] ) 538 return -1; 539 t1 *= 60; 540 t1 += atoi( agestr ); 541 } else if ( gotdays ) { 542 /* only got days+hh:mm */ 543 t1 *= 60; 544 } 545 return t1; 546} 547 548static void 549log_age_unparse( int age, struct berval *agebv, size_t size ) 550{ 551 int dd, hh, mm, ss, len; 552 char *ptr; 553 554 assert( size > 0 ); 555 556 ss = age % 60; 557 age /= 60; 558 mm = age % 60; 559 age /= 60; 560 hh = age % 24; 561 age /= 24; 562 dd = age; 563 564 ptr = agebv->bv_val; 565 566 if ( dd ) { 567 len = snprintf( ptr, size, "%d+", dd ); 568 assert( len >= 0 && (unsigned) len < size ); 569 size -= len; 570 ptr += len; 571 } 572 len = snprintf( ptr, size, "%02d:%02d", hh, mm ); 573 assert( len >= 0 && (unsigned) len < size ); 574 size -= len; 575 ptr += len; 576 if ( ss ) { 577 len = snprintf( ptr, size, ":%02d", ss ); 578 assert( len >= 0 && (unsigned) len < size ); 579 size -= len; 580 ptr += len; 581 } 582 583 agebv->bv_len = ptr - agebv->bv_val; 584} 585 586static slap_callback nullsc; 587 588#define PURGE_INCREMENT 100 589 590typedef struct purge_data { 591 int slots; 592 int used; 593 BerVarray dn; 594 BerVarray ndn; 595 struct berval csn; /* an arbitrary old CSN */ 596} purge_data; 597 598static int 599log_old_lookup( Operation *op, SlapReply *rs ) 600{ 601 purge_data *pd = op->o_callback->sc_private; 602 Attribute *a; 603 604 if ( rs->sr_type != REP_SEARCH) return 0; 605 606 if ( slapd_shutdown ) return 0; 607 608 /* Remember max CSN: should always be the last entry 609 * seen, since log entries are ordered chronologically... 610 */ 611 a = attr_find( rs->sr_entry->e_attrs, 612 slap_schema.si_ad_entryCSN ); 613 if ( a ) { 614 ber_len_t len = a->a_nvals[0].bv_len; 615 /* Paranoid len check, normalized CSNs are always the same length */ 616 if ( len > LDAP_PVT_CSNSTR_BUFSIZE ) 617 len = LDAP_PVT_CSNSTR_BUFSIZE; 618 if ( memcmp( a->a_nvals[0].bv_val, pd->csn.bv_val, len ) > 0 ) { 619 AC_MEMCPY( pd->csn.bv_val, a->a_nvals[0].bv_val, len ); 620 pd->csn.bv_len = len; 621 } 622 } 623 if ( pd->used >= pd->slots ) { 624 pd->slots += PURGE_INCREMENT; 625 pd->dn = ch_realloc( pd->dn, pd->slots * sizeof( struct berval )); 626 pd->ndn = ch_realloc( pd->ndn, pd->slots * sizeof( struct berval )); 627 } 628 ber_dupbv( &pd->dn[pd->used], &rs->sr_entry->e_name ); 629 ber_dupbv( &pd->ndn[pd->used], &rs->sr_entry->e_nname ); 630 pd->used++; 631 return 0; 632} 633 634/* Periodically search for old entries in the log database and delete them */ 635static void * 636accesslog_purge( void *ctx, void *arg ) 637{ 638 struct re_s *rtask = arg; 639 struct log_info *li = rtask->arg; 640 641 Connection conn = {0}; 642 OperationBuffer opbuf; 643 Operation *op; 644 SlapReply rs = {REP_RESULT}; 645 slap_callback cb = { NULL, log_old_lookup, NULL, NULL, NULL }; 646 Filter f; 647 AttributeAssertion ava = ATTRIBUTEASSERTION_INIT; 648 purge_data pd = {0}; 649 char timebuf[LDAP_LUTIL_GENTIME_BUFSIZE]; 650 char csnbuf[LDAP_PVT_CSNSTR_BUFSIZE]; 651 time_t old = slap_get_time(); 652 653 connection_fake_init( &conn, &opbuf, ctx ); 654 op = &opbuf.ob_op; 655 656 f.f_choice = LDAP_FILTER_LE; 657 f.f_ava = &ava; 658 f.f_next = NULL; 659 660 ava.aa_desc = ad_reqStart; 661 ava.aa_value.bv_val = timebuf; 662 ava.aa_value.bv_len = sizeof(timebuf); 663 664 old -= li->li_age; 665 slap_timestamp( &old, &ava.aa_value ); 666 667 op->o_tag = LDAP_REQ_SEARCH; 668 op->o_bd = li->li_db; 669 op->o_dn = li->li_db->be_rootdn; 670 op->o_ndn = li->li_db->be_rootndn; 671 op->o_req_dn = li->li_db->be_suffix[0]; 672 op->o_req_ndn = li->li_db->be_nsuffix[0]; 673 op->o_callback = &cb; 674 op->ors_scope = LDAP_SCOPE_ONELEVEL; 675 op->ors_deref = LDAP_DEREF_NEVER; 676 op->ors_tlimit = SLAP_NO_LIMIT; 677 op->ors_slimit = SLAP_NO_LIMIT; 678 op->ors_filter = &f; 679 filter2bv_x( op, &f, &op->ors_filterstr ); 680 op->ors_attrs = slap_anlist_no_attrs; 681 op->ors_attrsonly = 1; 682 683 pd.csn.bv_len = sizeof( csnbuf ); 684 pd.csn.bv_val = csnbuf; 685 csnbuf[0] = '\0'; 686 cb.sc_private = &pd; 687 688 op->o_bd->be_search( op, &rs ); 689 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx ); 690 691 if ( pd.used ) { 692 int i; 693 694 /* delete the expired entries */ 695 op->o_tag = LDAP_REQ_DELETE; 696 op->o_callback = &nullsc; 697 op->o_csn = pd.csn; 698 op->o_dont_replicate = 1; 699 700 for (i=0; i<pd.used; i++) { 701 op->o_req_dn = pd.dn[i]; 702 op->o_req_ndn = pd.ndn[i]; 703 if ( !slapd_shutdown ) { 704 rs_reinit( &rs, REP_RESULT ); 705 op->o_bd->be_delete( op, &rs ); 706 } 707 ch_free( pd.ndn[i].bv_val ); 708 ch_free( pd.dn[i].bv_val ); 709 } 710 ch_free( pd.ndn ); 711 ch_free( pd.dn ); 712 713 { 714 Modifications mod; 715 struct berval bv[2]; 716 rs_reinit( &rs, REP_RESULT ); 717 /* update context's entryCSN to reflect oldest CSN */ 718 mod.sml_numvals = 1; 719 mod.sml_values = bv; 720 bv[0] = pd.csn; 721 BER_BVZERO(&bv[1]); 722 mod.sml_nvalues = NULL; 723 mod.sml_desc = slap_schema.si_ad_entryCSN; 724 mod.sml_op = LDAP_MOD_REPLACE; 725 mod.sml_flags = SLAP_MOD_INTERNAL; 726 mod.sml_next = NULL; 727 728 op->o_tag = LDAP_REQ_MODIFY; 729 op->orm_modlist = &mod; 730 op->orm_no_opattrs = 1; 731 op->o_req_dn = li->li_db->be_suffix[0]; 732 op->o_req_ndn = li->li_db->be_nsuffix[0]; 733 op->o_no_schema_check = 1; 734 op->o_managedsait = SLAP_CONTROL_NONCRITICAL; 735 op->o_bd->be_modify( op, &rs ); 736 if ( mod.sml_next ) { 737 slap_mods_free( mod.sml_next, 1 ); 738 } 739 } 740 } 741 742 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); 743 ldap_pvt_runqueue_stoptask( &slapd_rq, rtask ); 744 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); 745 746 return NULL; 747} 748 749static int 750log_cf_gen(ConfigArgs *c) 751{ 752 slap_overinst *on = (slap_overinst *)c->bi; 753 struct log_info *li = on->on_bi.bi_private; 754 int rc = 0; 755 slap_mask_t tmask = 0; 756 char agebuf[2*STRLENOF("ddddd+hh:mm:ss ")]; 757 struct berval agebv, cyclebv; 758 759 switch( c->op ) { 760 case SLAP_CONFIG_EMIT: 761 switch( c->type ) { 762 case LOG_DB: 763 if ( !BER_BVISEMPTY( &li->li_db_suffix )) { 764 value_add_one( &c->rvalue_vals, &li->li_db_suffix ); 765 value_add_one( &c->rvalue_nvals, &li->li_db_suffix ); 766 } else if ( li->li_db ) { 767 value_add_one( &c->rvalue_vals, li->li_db->be_suffix ); 768 value_add_one( &c->rvalue_nvals, li->li_db->be_nsuffix ); 769 } else { 770 snprintf( c->cr_msg, sizeof( c->cr_msg ), 771 "accesslog: \"logdb <suffix>\" must be specified" ); 772 Debug( LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", 773 c->log, c->cr_msg, c->value_dn.bv_val ); 774 rc = 1; 775 break; 776 } 777 break; 778 case LOG_OPS: 779 rc = mask_to_verbs( logops, li->li_ops, &c->rvalue_vals ); 780 break; 781 case LOG_PURGE: 782 if ( !li->li_age ) { 783 rc = 1; 784 break; 785 } 786 agebv.bv_val = agebuf; 787 log_age_unparse( li->li_age, &agebv, sizeof( agebuf ) ); 788 agebv.bv_val[agebv.bv_len] = ' '; 789 agebv.bv_len++; 790 cyclebv.bv_val = agebv.bv_val + agebv.bv_len; 791 log_age_unparse( li->li_cycle, &cyclebv, sizeof( agebuf ) - agebv.bv_len ); 792 agebv.bv_len += cyclebv.bv_len; 793 value_add_one( &c->rvalue_vals, &agebv ); 794 break; 795 case LOG_SUCCESS: 796 if ( li->li_success ) 797 c->value_int = li->li_success; 798 else 799 rc = 1; 800 break; 801 case LOG_OLD: 802 if ( li->li_oldf ) { 803 filter2bv( li->li_oldf, &agebv ); 804 ber_bvarray_add( &c->rvalue_vals, &agebv ); 805 } 806 else 807 rc = 1; 808 break; 809 case LOG_OLDATTR: 810 if ( li->li_oldattrs ) { 811 log_attr *la; 812 813 for ( la = li->li_oldattrs; la; la=la->next ) 814 value_add_one( &c->rvalue_vals, &la->attr->ad_cname ); 815 } 816 else 817 rc = 1; 818 break; 819 case LOG_BASE: 820 if ( li->li_bases ) { 821 log_base *lb; 822 823 for ( lb = li->li_bases; lb; lb=lb->lb_next ) 824 value_add_one( &c->rvalue_vals, &lb->lb_line ); 825 } 826 else 827 rc = 1; 828 break; 829 } 830 break; 831 case LDAP_MOD_DELETE: 832 switch( c->type ) { 833 case LOG_DB: 834 /* noop. this should always be a valid backend. */ 835 break; 836 case LOG_OPS: 837 if ( c->valx < 0 ) { 838 li->li_ops = 0; 839 } else { 840 rc = verbs_to_mask( 1, &c->line, logops, &tmask ); 841 if ( rc == 0 ) 842 li->li_ops &= ~tmask; 843 } 844 break; 845 case LOG_PURGE: 846 if ( li->li_task ) { 847 struct re_s *re = li->li_task; 848 li->li_task = NULL; 849 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); 850 if ( ldap_pvt_runqueue_isrunning( &slapd_rq, re )) 851 ldap_pvt_runqueue_stoptask( &slapd_rq, re ); 852 ldap_pvt_runqueue_remove( &slapd_rq, re ); 853 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); 854 } 855 li->li_age = 0; 856 li->li_cycle = 0; 857 break; 858 case LOG_SUCCESS: 859 li->li_success = 0; 860 break; 861 case LOG_OLD: 862 if ( li->li_oldf ) { 863 filter_free( li->li_oldf ); 864 li->li_oldf = NULL; 865 } 866 break; 867 case LOG_OLDATTR: 868 if ( c->valx < 0 ) { 869 log_attr *la, *ln; 870 871 for ( la = li->li_oldattrs; la; la = ln ) { 872 ln = la->next; 873 ch_free( la ); 874 } 875 } else { 876 log_attr *la = NULL, **lp; 877 int i; 878 879 for ( lp = &li->li_oldattrs, i=0; i < c->valx; i++ ) { 880 la = *lp; 881 lp = &la->next; 882 } 883 *lp = la->next; 884 ch_free( la ); 885 } 886 break; 887 case LOG_BASE: 888 if ( c->valx < 0 ) { 889 log_base *lb, *ln; 890 891 for ( lb = li->li_bases; lb; lb = ln ) { 892 ln = lb->lb_next; 893 ch_free( lb ); 894 } 895 } else { 896 log_base *lb = NULL, **lp; 897 int i; 898 899 for ( lp = &li->li_bases, i=0; i < c->valx; i++ ) { 900 lb = *lp; 901 lp = &lb->lb_next; 902 } 903 *lp = lb->lb_next; 904 ch_free( lb ); 905 } 906 break; 907 } 908 break; 909 default: 910 switch( c->type ) { 911 case LOG_DB: 912 if ( CONFIG_ONLINE_ADD( c )) { 913 li->li_db = select_backend( &c->value_ndn, 0 ); 914 if ( !li->li_db ) { 915 snprintf( c->cr_msg, sizeof( c->cr_msg ), 916 "<%s> no matching backend found for suffix", 917 c->argv[0] ); 918 Debug( LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", 919 c->log, c->cr_msg, c->value_dn.bv_val ); 920 rc = 1; 921 } 922 ch_free( c->value_ndn.bv_val ); 923 } else { 924 li->li_db_suffix = c->value_ndn; 925 } 926 ch_free( c->value_dn.bv_val ); 927 break; 928 case LOG_OPS: 929 rc = verbs_to_mask( c->argc, c->argv, logops, &tmask ); 930 if ( rc == 0 ) 931 li->li_ops |= tmask; 932 break; 933 case LOG_PURGE: 934 li->li_age = log_age_parse( c->argv[1] ); 935 if ( li->li_age < 1 ) { 936 rc = 1; 937 } else { 938 li->li_cycle = log_age_parse( c->argv[2] ); 939 if ( li->li_cycle < 1 ) { 940 rc = 1; 941 } else if ( slapMode & SLAP_SERVER_MODE ) { 942 struct re_s *re = li->li_task; 943 if ( re ) 944 re->interval.tv_sec = li->li_cycle; 945 else { 946 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); 947 li->li_task = ldap_pvt_runqueue_insert( &slapd_rq, 948 li->li_cycle, accesslog_purge, li, 949 "accesslog_purge", li->li_db ? 950 li->li_db->be_suffix[0].bv_val : 951 c->be->be_suffix[0].bv_val ); 952 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); 953 } 954 } 955 } 956 break; 957 case LOG_SUCCESS: 958 li->li_success = c->value_int; 959 break; 960 case LOG_OLD: 961 li->li_oldf = str2filter( c->argv[1] ); 962 if ( !li->li_oldf ) { 963 snprintf( c->cr_msg, sizeof( c->cr_msg ), "bad filter!" ); 964 rc = 1; 965 } 966 break; 967 case LOG_OLDATTR: { 968 int i; 969 AttributeDescription *ad; 970 const char *text; 971 972 for ( i=1; i< c->argc; i++ ) { 973 ad = NULL; 974 if ( slap_str2ad( c->argv[i], &ad, &text ) == LDAP_SUCCESS ) { 975 log_attr *la = ch_malloc( sizeof( log_attr )); 976 la->attr = ad; 977 la->next = li->li_oldattrs; 978 li->li_oldattrs = la; 979 } else { 980 snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s <%s>: %s", 981 c->argv[0], c->argv[i], text ); 982 Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, 983 "%s: %s\n", c->log, c->cr_msg, 0 ); 984 rc = ARG_BAD_CONF; 985 break; 986 } 987 } 988 } 989 break; 990 case LOG_BASE: { 991 slap_mask_t m = 0; 992 rc = verbstring_to_mask( logops, c->argv[1], '|', &m ); 993 if ( rc == 0 ) { 994 struct berval dn, ndn; 995 ber_str2bv( c->argv[2], 0, 0, &dn ); 996 rc = dnNormalize( 0, NULL, NULL, &dn, &ndn, NULL ); 997 if ( rc == 0 ) { 998 log_base *lb; 999 struct berval mbv; 1000 char *ptr; 1001 mask_to_verbstring( logops, m, '|', &mbv ); 1002 lb = ch_malloc( sizeof( log_base ) + mbv.bv_len + ndn.bv_len + 3 + 1 ); 1003 lb->lb_line.bv_val = (char *)(lb + 1); 1004 lb->lb_line.bv_len = mbv.bv_len + ndn.bv_len + 3; 1005 ptr = lutil_strcopy( lb->lb_line.bv_val, mbv.bv_val ); 1006 *ptr++ = ' '; 1007 *ptr++ = '"'; 1008 lb->lb_base.bv_val = ptr; 1009 lb->lb_base.bv_len = ndn.bv_len; 1010 ptr = lutil_strcopy( ptr, ndn.bv_val ); 1011 *ptr++ = '"'; 1012 lb->lb_ops = m; 1013 lb->lb_next = li->li_bases; 1014 li->li_bases = lb; 1015 } else { 1016 snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s invalid DN: %s", 1017 c->argv[0], c->argv[2] ); 1018 Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, 1019 "%s: %s\n", c->log, c->cr_msg, 0 ); 1020 rc = ARG_BAD_CONF; 1021 } 1022 } else { 1023 snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s invalid ops: %s", 1024 c->argv[0], c->argv[1] ); 1025 Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, 1026 "%s: %s\n", c->log, c->cr_msg, 0 ); 1027 rc = ARG_BAD_CONF; 1028 } 1029 } 1030 break; 1031 } 1032 break; 1033 } 1034 return rc; 1035} 1036 1037static int 1038logSchemaControlValidate( 1039 Syntax *syntax, 1040 struct berval *valp ) 1041{ 1042 struct berval val, bv; 1043 ber_len_t i; 1044 int rc = LDAP_SUCCESS; 1045 1046 assert( valp != NULL ); 1047 1048 val = *valp; 1049 1050 /* check minimal size */ 1051 if ( val.bv_len < STRLENOF( "{*}" ) ) { 1052 return LDAP_INVALID_SYNTAX; 1053 } 1054 1055 val.bv_len--; 1056 1057 /* check SEQUENCE boundaries */ 1058 if ( val.bv_val[ 0 ] != '{' /*}*/ || 1059 val.bv_val[ val.bv_len ] != /*{*/ '}' ) 1060 { 1061 return LDAP_INVALID_SYNTAX; 1062 } 1063 1064 /* extract and check OID */ 1065 for ( i = 1; i < val.bv_len; i++ ) { 1066 if ( !ASCII_SPACE( val.bv_val[ i ] ) ) { 1067 break; 1068 } 1069 } 1070 1071 bv.bv_val = &val.bv_val[ i ]; 1072 1073 for ( i++; i < val.bv_len; i++ ) { 1074 if ( ASCII_SPACE( val.bv_val[ i ] ) ) 1075 { 1076 break; 1077 } 1078 } 1079 1080 bv.bv_len = &val.bv_val[ i ] - bv.bv_val; 1081 1082 rc = numericoidValidate( NULL, &bv ); 1083 if ( rc != LDAP_SUCCESS ) { 1084 return rc; 1085 } 1086 1087 if ( i == val.bv_len ) { 1088 return LDAP_SUCCESS; 1089 } 1090 1091 if ( val.bv_val[ i ] != ' ' ) { 1092 return LDAP_INVALID_SYNTAX; 1093 } 1094 1095 for ( i++; i < val.bv_len; i++ ) { 1096 if ( !ASCII_SPACE( val.bv_val[ i ] ) ) { 1097 break; 1098 } 1099 } 1100 1101 if ( i == val.bv_len ) { 1102 return LDAP_SUCCESS; 1103 } 1104 1105 /* extract and check criticality */ 1106 if ( strncasecmp( &val.bv_val[ i ], "criticality ", STRLENOF( "criticality " ) ) == 0 ) 1107 { 1108 i += STRLENOF( "criticality " ); 1109 for ( ; i < val.bv_len; i++ ) { 1110 if ( !ASCII_SPACE( val.bv_val[ i ] ) ) { 1111 break; 1112 } 1113 } 1114 1115 if ( i == val.bv_len ) { 1116 return LDAP_INVALID_SYNTAX; 1117 } 1118 1119 bv.bv_val = &val.bv_val[ i ]; 1120 1121 for ( ; i < val.bv_len; i++ ) { 1122 if ( ASCII_SPACE( val.bv_val[ i ] ) ) { 1123 break; 1124 } 1125 } 1126 1127 bv.bv_len = &val.bv_val[ i ] - bv.bv_val; 1128 1129 if ( !bvmatch( &bv, &slap_true_bv ) && !bvmatch( &bv, &slap_false_bv ) ) 1130 { 1131 return LDAP_INVALID_SYNTAX; 1132 } 1133 1134 if ( i == val.bv_len ) { 1135 return LDAP_SUCCESS; 1136 } 1137 1138 if ( val.bv_val[ i ] != ' ' ) { 1139 return LDAP_INVALID_SYNTAX; 1140 } 1141 1142 for ( i++; i < val.bv_len; i++ ) { 1143 if ( !ASCII_SPACE( val.bv_val[ i ] ) ) { 1144 break; 1145 } 1146 } 1147 1148 if ( i == val.bv_len ) { 1149 return LDAP_SUCCESS; 1150 } 1151 } 1152 1153 /* extract and check controlValue */ 1154 if ( strncasecmp( &val.bv_val[ i ], "controlValue ", STRLENOF( "controlValue " ) ) == 0 ) 1155 { 1156 ber_len_t valueStart, valueLen; 1157 1158 i += STRLENOF( "controlValue " ); 1159 for ( ; i < val.bv_len; i++ ) { 1160 if ( !ASCII_SPACE( val.bv_val[ i ] ) ) { 1161 break; 1162 } 1163 } 1164 1165 if ( i == val.bv_len ) { 1166 return LDAP_INVALID_SYNTAX; 1167 } 1168 1169 if ( val.bv_val[ i ] != '"' ) { 1170 return LDAP_INVALID_SYNTAX; 1171 } 1172 1173 i++; 1174 valueStart = i; 1175 1176 for ( ; i < val.bv_len; i++ ) { 1177 if ( val.bv_val[ i ] == '"' ) { 1178 break; 1179 } 1180 1181 if ( !ASCII_HEX( val.bv_val[ i ] ) ) { 1182 return LDAP_INVALID_SYNTAX; 1183 } 1184 } 1185 1186 if ( val.bv_val[ i ] != '"' ) { 1187 return LDAP_INVALID_SYNTAX; 1188 } 1189 1190 valueLen = i - valueStart; 1191 if ( (valueLen/2)*2 != valueLen ) { 1192 return LDAP_INVALID_SYNTAX; 1193 } 1194 1195 for ( i++; i < val.bv_len; i++ ) { 1196 if ( !ASCII_SPACE( val.bv_val[ i ] ) ) { 1197 break; 1198 } 1199 } 1200 1201 if ( i == val.bv_len ) { 1202 return LDAP_SUCCESS; 1203 } 1204 } 1205 1206 return LDAP_INVALID_SYNTAX; 1207} 1208 1209static int 1210accesslog_ctrls( 1211 LDAPControl **ctrls, 1212 BerVarray *valsp, 1213 BerVarray *nvalsp, 1214 void *memctx ) 1215{ 1216 long i, rc = 0; 1217 1218 assert( valsp != NULL ); 1219 assert( ctrls != NULL ); 1220 1221 *valsp = NULL; 1222 *nvalsp = NULL; 1223 1224 for ( i = 0; ctrls[ i ] != NULL; i++ ) { 1225 struct berval idx, 1226 oid, 1227 noid, 1228 bv; 1229 char *ptr, 1230 buf[ 32 ]; 1231 1232 if ( ctrls[ i ]->ldctl_oid == NULL ) { 1233 return LDAP_PROTOCOL_ERROR; 1234 } 1235 1236 idx.bv_len = snprintf( buf, sizeof( buf ), "{%ld}", i ); 1237 idx.bv_val = buf; 1238 1239 ber_str2bv( ctrls[ i ]->ldctl_oid, 0, 0, &oid ); 1240 noid.bv_len = idx.bv_len + oid.bv_len; 1241 ptr = noid.bv_val = ber_memalloc_x( noid.bv_len + 1, memctx ); 1242 ptr = lutil_strcopy( ptr, idx.bv_val ); 1243 ptr = lutil_strcopy( ptr, oid.bv_val ); 1244 1245 bv.bv_len = idx.bv_len + STRLENOF( "{}" ) + oid.bv_len; 1246 1247 if ( ctrls[ i ]->ldctl_iscritical ) { 1248 bv.bv_len += STRLENOF( " criticality TRUE" ); 1249 } 1250 1251 if ( !BER_BVISNULL( &ctrls[ i ]->ldctl_value ) ) { 1252 bv.bv_len += STRLENOF( " controlValue \"\"" ) 1253 + 2 * ctrls[ i ]->ldctl_value.bv_len; 1254 } 1255 1256 ptr = bv.bv_val = ber_memalloc_x( bv.bv_len + 1, memctx ); 1257 if ( ptr == NULL ) { 1258 ber_bvarray_free( *valsp ); 1259 *valsp = NULL; 1260 ber_bvarray_free( *nvalsp ); 1261 *nvalsp = NULL; 1262 return LDAP_OTHER; 1263 } 1264 1265 ptr = lutil_strcopy( ptr, idx.bv_val ); 1266 1267 *ptr++ = '{' /*}*/ ; 1268 ptr = lutil_strcopy( ptr, oid.bv_val ); 1269 1270 if ( ctrls[ i ]->ldctl_iscritical ) { 1271 ptr = lutil_strcopy( ptr, " criticality TRUE" ); 1272 } 1273 1274 if ( !BER_BVISNULL( &ctrls[ i ]->ldctl_value ) ) { 1275 ber_len_t j; 1276 1277 ptr = lutil_strcopy( ptr, " controlValue \"" ); 1278 for ( j = 0; j < ctrls[ i ]->ldctl_value.bv_len; j++ ) { 1279 *ptr++ = SLAP_ESCAPE_HI(ctrls[ i ]->ldctl_value.bv_val[ j ]); 1280 *ptr++ = SLAP_ESCAPE_LO(ctrls[ i ]->ldctl_value.bv_val[ j ]); 1281 } 1282 1283 *ptr++ = '"'; 1284 } 1285 1286 *ptr++ = '}'; 1287 *ptr = '\0'; 1288 1289 ber_bvarray_add_x( valsp, &bv, memctx ); 1290 ber_bvarray_add_x( nvalsp, &noid, memctx ); 1291 } 1292 1293 return rc; 1294 1295} 1296 1297static Entry *accesslog_entry( Operation *op, SlapReply *rs, int logop, 1298 Operation *op2 ) { 1299 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 1300 log_info *li = on->on_bi.bi_private; 1301 1302 char rdnbuf[STRLENOF(RDNEQ)+LDAP_LUTIL_GENTIME_BUFSIZE+8]; 1303 char nrdnbuf[STRLENOF(RDNEQ)+LDAP_LUTIL_GENTIME_BUFSIZE+8]; 1304 1305 struct berval rdn, nrdn, timestamp, ntimestamp, bv; 1306 slap_verbmasks *lo = logops+logop+EN_OFFSET; 1307 1308 Entry *e = entry_alloc(); 1309 1310 strcpy( rdnbuf, RDNEQ ); 1311 rdn.bv_val = rdnbuf; 1312 strcpy( nrdnbuf, RDNEQ ); 1313 nrdn.bv_val = nrdnbuf; 1314 1315 timestamp.bv_val = rdnbuf+STRLENOF(RDNEQ); 1316 timestamp.bv_len = sizeof(rdnbuf) - STRLENOF(RDNEQ); 1317 slap_timestamp( &op->o_time, ×tamp ); 1318 snprintf( timestamp.bv_val + timestamp.bv_len-1, sizeof(".123456Z"), ".%06dZ", op->o_tincr ); 1319 timestamp.bv_len += STRLENOF(".123456"); 1320 1321 rdn.bv_len = STRLENOF(RDNEQ)+timestamp.bv_len; 1322 ad_reqStart->ad_type->sat_equality->smr_normalize( 1323 SLAP_MR_VALUE_OF_ASSERTION_SYNTAX, ad_reqStart->ad_type->sat_syntax, 1324 ad_reqStart->ad_type->sat_equality, ×tamp, &ntimestamp, 1325 op->o_tmpmemctx ); 1326 1327 strcpy( nrdn.bv_val + STRLENOF(RDNEQ), ntimestamp.bv_val ); 1328 nrdn.bv_len = STRLENOF(RDNEQ)+ntimestamp.bv_len; 1329 build_new_dn( &e->e_name, li->li_db->be_suffix, &rdn, NULL ); 1330 build_new_dn( &e->e_nname, li->li_db->be_nsuffix, &nrdn, NULL ); 1331 1332 attr_merge_one( e, slap_schema.si_ad_objectClass, 1333 &log_ocs[logop]->soc_cname, NULL ); 1334 attr_merge_one( e, slap_schema.si_ad_structuralObjectClass, 1335 &log_ocs[logop]->soc_cname, NULL ); 1336 attr_merge_one( e, ad_reqStart, ×tamp, &ntimestamp ); 1337 op->o_tmpfree( ntimestamp.bv_val, op->o_tmpmemctx ); 1338 1339 slap_op_time( &op2->o_time, &op2->o_tincr ); 1340 1341 timestamp.bv_len = sizeof(rdnbuf) - STRLENOF(RDNEQ); 1342 slap_timestamp( &op2->o_time, ×tamp ); 1343 snprintf( timestamp.bv_val + timestamp.bv_len-1, sizeof(".123456Z"), ".%06dZ", op2->o_tincr ); 1344 timestamp.bv_len += STRLENOF(".123456"); 1345 1346 attr_merge_normalize_one( e, ad_reqEnd, ×tamp, op->o_tmpmemctx ); 1347 1348 /* Exops have OID appended */ 1349 if ( logop == LOG_EN_EXTENDED ) { 1350 bv.bv_len = lo->word.bv_len + op->ore_reqoid.bv_len + 2; 1351 bv.bv_val = ch_malloc( bv.bv_len + 1 ); 1352 AC_MEMCPY( bv.bv_val, lo->word.bv_val, lo->word.bv_len ); 1353 bv.bv_val[lo->word.bv_len] = '{'; 1354 AC_MEMCPY( bv.bv_val+lo->word.bv_len+1, op->ore_reqoid.bv_val, 1355 op->ore_reqoid.bv_len ); 1356 bv.bv_val[bv.bv_len-1] = '}'; 1357 bv.bv_val[bv.bv_len] = '\0'; 1358 attr_merge_one( e, ad_reqType, &bv, NULL ); 1359 } else { 1360 attr_merge_one( e, ad_reqType, &lo->word, NULL ); 1361 } 1362 1363 rdn.bv_len = snprintf( rdn.bv_val, sizeof( rdnbuf ), "%lu", op->o_connid ); 1364 if ( rdn.bv_len < sizeof( rdnbuf ) ) { 1365 attr_merge_one( e, ad_reqSession, &rdn, NULL ); 1366 } /* else? */ 1367 1368 if ( BER_BVISNULL( &op->o_dn ) ) { 1369 attr_merge_one( e, ad_reqAuthzID, (struct berval *)&slap_empty_bv, 1370 (struct berval *)&slap_empty_bv ); 1371 } else { 1372 attr_merge_one( e, ad_reqAuthzID, &op->o_dn, &op->o_ndn ); 1373 } 1374 1375 /* FIXME: need to add reqControls and reqRespControls */ 1376 if ( op->o_ctrls ) { 1377 BerVarray vals = NULL, 1378 nvals = NULL; 1379 1380 if ( accesslog_ctrls( op->o_ctrls, &vals, &nvals, 1381 op->o_tmpmemctx ) == LDAP_SUCCESS && vals ) 1382 { 1383 attr_merge( e, ad_reqControls, vals, nvals ); 1384 ber_bvarray_free_x( vals, op->o_tmpmemctx ); 1385 ber_bvarray_free_x( nvals, op->o_tmpmemctx ); 1386 } 1387 } 1388 1389 if ( rs->sr_ctrls ) { 1390 BerVarray vals = NULL, 1391 nvals = NULL; 1392 1393 if ( accesslog_ctrls( rs->sr_ctrls, &vals, &nvals, 1394 op->o_tmpmemctx ) == LDAP_SUCCESS && vals ) 1395 { 1396 attr_merge( e, ad_reqRespControls, vals, nvals ); 1397 ber_bvarray_free_x( vals, op->o_tmpmemctx ); 1398 ber_bvarray_free_x( nvals, op->o_tmpmemctx ); 1399 } 1400 1401 } 1402 1403 return e; 1404} 1405 1406static struct berval scopes[] = { 1407 BER_BVC("base"), 1408 BER_BVC("one"), 1409 BER_BVC("sub"), 1410 BER_BVC("subord") 1411}; 1412 1413static struct berval derefs[] = { 1414 BER_BVC("never"), 1415 BER_BVC("searching"), 1416 BER_BVC("finding"), 1417 BER_BVC("always") 1418}; 1419 1420static struct berval simple = BER_BVC("SIMPLE"); 1421 1422static void accesslog_val2val(AttributeDescription *ad, struct berval *val, 1423 char c_op, struct berval *dst) { 1424 char *ptr; 1425 1426 dst->bv_len = ad->ad_cname.bv_len + val->bv_len + 2; 1427 if ( c_op ) dst->bv_len++; 1428 1429 dst->bv_val = ch_malloc( dst->bv_len+1 ); 1430 1431 ptr = lutil_strcopy( dst->bv_val, ad->ad_cname.bv_val ); 1432 *ptr++ = ':'; 1433 if ( c_op ) 1434 *ptr++ = c_op; 1435 *ptr++ = ' '; 1436 AC_MEMCPY( ptr, val->bv_val, val->bv_len ); 1437 dst->bv_val[dst->bv_len] = '\0'; 1438} 1439 1440static int 1441accesslog_op2logop( Operation *op ) 1442{ 1443 switch ( op->o_tag ) { 1444 case LDAP_REQ_ADD: return LOG_EN_ADD; 1445 case LDAP_REQ_DELETE: return LOG_EN_DELETE; 1446 case LDAP_REQ_MODIFY: return LOG_EN_MODIFY; 1447 case LDAP_REQ_MODRDN: return LOG_EN_MODRDN; 1448 case LDAP_REQ_COMPARE: return LOG_EN_COMPARE; 1449 case LDAP_REQ_SEARCH: return LOG_EN_SEARCH; 1450 case LDAP_REQ_BIND: return LOG_EN_BIND; 1451 case LDAP_REQ_EXTENDED: return LOG_EN_EXTENDED; 1452 default: /* unknown operation type */ 1453 break; 1454 } /* Unbind and Abandon never reach here */ 1455 return LOG_EN_UNKNOWN; 1456} 1457 1458static int accesslog_response(Operation *op, SlapReply *rs) { 1459 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 1460 log_info *li = on->on_bi.bi_private; 1461 Attribute *a, *last_attr; 1462 Modifications *m; 1463 struct berval *b, uuid = BER_BVNULL; 1464 int i; 1465 int logop, do_graduate = 0; 1466 slap_verbmasks *lo; 1467 Entry *e = NULL, *old = NULL, *e_uuid = NULL; 1468 char timebuf[LDAP_LUTIL_GENTIME_BUFSIZE+8]; 1469 struct berval bv; 1470 char *ptr; 1471 BerVarray vals; 1472 Operation op2 = {0}; 1473 SlapReply rs2 = {REP_RESULT}; 1474 1475 if ( rs->sr_type != REP_RESULT && rs->sr_type != REP_EXTENDED ) 1476 return SLAP_CB_CONTINUE; 1477 1478 logop = accesslog_op2logop( op ); 1479 lo = logops+logop+EN_OFFSET; 1480 if ( !( li->li_ops & lo->mask )) { 1481 log_base *lb; 1482 1483 i = 0; 1484 for ( lb = li->li_bases; lb; lb=lb->lb_next ) 1485 if (( lb->lb_ops & lo->mask ) && dnIsSuffix( &op->o_req_ndn, &lb->lb_base )) { 1486 i = 1; 1487 break; 1488 } 1489 if ( !i ) 1490 return SLAP_CB_CONTINUE; 1491 } 1492 1493 /* mutex and so were only set for write operations; 1494 * if we got here, the operation must be logged */ 1495 if ( lo->mask & LOG_OP_WRITES ) { 1496 slap_callback *cb; 1497 1498 /* Most internal ops are not logged */ 1499 if ( op->o_dont_replicate) { 1500 /* Let contextCSN updates from syncrepl thru; the underlying 1501 * syncprov needs to see them. Skip others. 1502 */ 1503 if (( op->o_tag != LDAP_REQ_MODIFY || 1504 op->orm_modlist->sml_op != LDAP_MOD_REPLACE || 1505 op->orm_modlist->sml_desc != slap_schema.si_ad_contextCSN ) && 1506 op->orm_no_opattrs ) 1507 return SLAP_CB_CONTINUE; 1508 } 1509 1510 ldap_pvt_thread_mutex_lock( &li->li_log_mutex ); 1511 old = li->li_old; 1512 uuid = li->li_uuid; 1513 li->li_old = NULL; 1514 BER_BVZERO( &li->li_uuid ); 1515 /* Disarm mod_cleanup */ 1516 for ( cb = op->o_callback; cb; cb = cb->sc_next ) { 1517 if ( cb->sc_private == (void *)on ) { 1518 cb->sc_private = NULL; 1519 break; 1520 } 1521 } 1522 ldap_pvt_thread_rmutex_unlock( &li->li_op_rmutex, op->o_tid ); 1523 } 1524 1525 /* ignore these internal reads */ 1526 if (( lo->mask & LOG_OP_READS ) && op->o_do_not_cache ) { 1527 return SLAP_CB_CONTINUE; 1528 } 1529 1530 if ( li->li_success && rs->sr_err != LDAP_SUCCESS ) 1531 goto done; 1532 1533 e = accesslog_entry( op, rs, logop, &op2 ); 1534 1535 attr_merge_one( e, ad_reqDN, &op->o_req_dn, &op->o_req_ndn ); 1536 1537 if ( rs->sr_text ) { 1538 ber_str2bv( rs->sr_text, 0, 0, &bv ); 1539 attr_merge_normalize_one( e, ad_reqMessage, &bv, op->o_tmpmemctx ); 1540 } 1541 bv.bv_len = snprintf( timebuf, sizeof( timebuf ), "%d", rs->sr_err ); 1542 if ( bv.bv_len < sizeof( timebuf ) ) { 1543 bv.bv_val = timebuf; 1544 attr_merge_one( e, ad_reqResult, &bv, NULL ); 1545 } 1546 1547 last_attr = attr_find( e->e_attrs, ad_reqResult ); 1548 1549 e_uuid = old; 1550 switch( logop ) { 1551 case LOG_EN_ADD: 1552 case LOG_EN_DELETE: { 1553 char c_op; 1554 Entry *e2; 1555 1556 if ( logop == LOG_EN_ADD ) { 1557 e2 = op->ora_e; 1558 e_uuid = op->ora_e; 1559 c_op = '+'; 1560 1561 } else { 1562 if ( !old ) 1563 break; 1564 e2 = old; 1565 c_op = 0; 1566 } 1567 /* count all the vals */ 1568 i = 0; 1569 for ( a=e2->e_attrs; a; a=a->a_next ) { 1570 i += a->a_numvals; 1571 } 1572 vals = ch_malloc( (i+1) * sizeof( struct berval )); 1573 i = 0; 1574 for ( a=e2->e_attrs; a; a=a->a_next ) { 1575 if ( a->a_vals ) { 1576 for (b=a->a_vals; !BER_BVISNULL( b ); b++,i++) { 1577 accesslog_val2val( a->a_desc, b, c_op, &vals[i] ); 1578 } 1579 } 1580 } 1581 vals[i].bv_val = NULL; 1582 vals[i].bv_len = 0; 1583 a = attr_alloc( logop == LOG_EN_ADD ? ad_reqMod : ad_reqOld ); 1584 a->a_numvals = i; 1585 a->a_vals = vals; 1586 a->a_nvals = vals; 1587 last_attr->a_next = a; 1588 break; 1589 } 1590 1591 case LOG_EN_MODRDN: 1592 case LOG_EN_MODIFY: 1593 /* count all the mods */ 1594 i = 0; 1595 for ( m = op->orm_modlist; m; m = m->sml_next ) { 1596 if ( m->sml_values ) { 1597 i += m->sml_numvals; 1598 } else if ( m->sml_op == LDAP_MOD_DELETE || 1599 m->sml_op == LDAP_MOD_REPLACE ) 1600 { 1601 i++; 1602 } 1603 } 1604 vals = ch_malloc( (i+1) * sizeof( struct berval )); 1605 i = 0; 1606 1607 /* init flags on old entry */ 1608 if ( old ) { 1609 for ( a = old->e_attrs; a; a = a->a_next ) { 1610 log_attr *la; 1611 a->a_flags = 0; 1612 1613 /* look for attrs that are always logged */ 1614 for ( la = li->li_oldattrs; la; la = la->next ) { 1615 if ( a->a_desc == la->attr ) { 1616 a->a_flags = 1; 1617 } 1618 } 1619 } 1620 } 1621 1622 for ( m = op->orm_modlist; m; m = m->sml_next ) { 1623 /* Mark this attribute as modified */ 1624 if ( old ) { 1625 a = attr_find( old->e_attrs, m->sml_desc ); 1626 if ( a ) { 1627 a->a_flags = 1; 1628 } 1629 } 1630 1631 /* don't log the RDN mods; they're explicitly logged later */ 1632 if ( logop == LOG_EN_MODRDN && 1633 ( m->sml_op == SLAP_MOD_SOFTADD || 1634 m->sml_op == LDAP_MOD_DELETE ) ) 1635 { 1636 continue; 1637 } 1638 1639 if ( m->sml_values ) { 1640 for ( b = m->sml_values; !BER_BVISNULL( b ); b++, i++ ) { 1641 char c_op; 1642 1643 switch ( m->sml_op ) { 1644 case LDAP_MOD_ADD: c_op = '+'; break; 1645 case LDAP_MOD_DELETE: c_op = '-'; break; 1646 case LDAP_MOD_REPLACE: c_op = '='; break; 1647 case LDAP_MOD_INCREMENT: c_op = '#'; break; 1648 1649 /* unknown op. there shouldn't be any of these. we 1650 * don't know what to do with it, but we shouldn't just 1651 * ignore it. 1652 */ 1653 default: c_op = '?'; break; 1654 } 1655 accesslog_val2val( m->sml_desc, b, c_op, &vals[i] ); 1656 } 1657 } else if ( m->sml_op == LDAP_MOD_DELETE || 1658 m->sml_op == LDAP_MOD_REPLACE ) 1659 { 1660 vals[i].bv_len = m->sml_desc->ad_cname.bv_len + 2; 1661 vals[i].bv_val = ch_malloc( vals[i].bv_len + 1 ); 1662 ptr = lutil_strcopy( vals[i].bv_val, 1663 m->sml_desc->ad_cname.bv_val ); 1664 *ptr++ = ':'; 1665 if ( m->sml_op == LDAP_MOD_DELETE ) { 1666 *ptr++ = '-'; 1667 } else { 1668 *ptr++ = '='; 1669 } 1670 *ptr = '\0'; 1671 i++; 1672 } 1673 } 1674 1675 if ( i > 0 ) { 1676 BER_BVZERO( &vals[i] ); 1677 a = attr_alloc( ad_reqMod ); 1678 a->a_numvals = i; 1679 a->a_vals = vals; 1680 a->a_nvals = vals; 1681 last_attr->a_next = a; 1682 last_attr = a; 1683 1684 } else { 1685 ch_free( vals ); 1686 } 1687 1688 if ( old ) { 1689 /* count all the vals */ 1690 i = 0; 1691 for ( a = old->e_attrs; a != NULL; a = a->a_next ) { 1692 if ( a->a_vals && a->a_flags ) { 1693 i += a->a_numvals; 1694 } 1695 } 1696 if ( i ) { 1697 vals = ch_malloc( (i + 1) * sizeof( struct berval ) ); 1698 i = 0; 1699 for ( a=old->e_attrs; a; a=a->a_next ) { 1700 if ( a->a_vals && a->a_flags ) { 1701 for (b=a->a_vals; !BER_BVISNULL( b ); b++,i++) { 1702 accesslog_val2val( a->a_desc, b, 0, &vals[i] ); 1703 } 1704 } 1705 } 1706 vals[i].bv_val = NULL; 1707 vals[i].bv_len = 0; 1708 a = attr_alloc( ad_reqOld ); 1709 a->a_numvals = i; 1710 a->a_vals = vals; 1711 a->a_nvals = vals; 1712 last_attr->a_next = a; 1713 } 1714 } 1715 if ( logop == LOG_EN_MODIFY ) { 1716 break; 1717 } 1718 1719 /* Now log the actual modRDN info */ 1720 attr_merge_one( e, ad_reqNewRDN, &op->orr_newrdn, &op->orr_nnewrdn ); 1721 attr_merge_one( e, ad_reqDeleteOldRDN, op->orr_deleteoldrdn ? 1722 (struct berval *)&slap_true_bv : (struct berval *)&slap_false_bv, 1723 NULL ); 1724 if ( op->orr_newSup ) { 1725 attr_merge_one( e, ad_reqNewSuperior, op->orr_newSup, op->orr_nnewSup ); 1726 } 1727 break; 1728 1729 case LOG_EN_COMPARE: 1730 bv.bv_len = op->orc_ava->aa_desc->ad_cname.bv_len + 1 + 1731 op->orc_ava->aa_value.bv_len; 1732 bv.bv_val = op->o_tmpalloc( bv.bv_len+1, op->o_tmpmemctx ); 1733 ptr = lutil_strcopy( bv.bv_val, op->orc_ava->aa_desc->ad_cname.bv_val ); 1734 *ptr++ = '='; 1735 AC_MEMCPY( ptr, op->orc_ava->aa_value.bv_val, op->orc_ava->aa_value.bv_len ); 1736 bv.bv_val[bv.bv_len] = '\0'; 1737 attr_merge_one( e, ad_reqAssertion, &bv, NULL ); 1738 op->o_tmpfree( bv.bv_val, op->o_tmpmemctx ); 1739 break; 1740 1741 case LOG_EN_SEARCH: 1742 attr_merge_one( e, ad_reqScope, &scopes[op->ors_scope], NULL ); 1743 attr_merge_one( e, ad_reqDerefAliases, &derefs[op->ors_deref], NULL ); 1744 attr_merge_one( e, ad_reqAttrsOnly, op->ors_attrsonly ? 1745 (struct berval *)&slap_true_bv : (struct berval *)&slap_false_bv, 1746 NULL ); 1747 if ( !BER_BVISEMPTY( &op->ors_filterstr )) 1748 attr_merge_normalize_one( e, ad_reqFilter, &op->ors_filterstr, op->o_tmpmemctx ); 1749 if ( op->ors_attrs ) { 1750 int j; 1751 /* count them */ 1752 for (i=0; !BER_BVISNULL(&op->ors_attrs[i].an_name );i++) 1753 ; 1754 vals = op->o_tmpalloc( (i+1) * sizeof(struct berval), 1755 op->o_tmpmemctx ); 1756 for (i=0, j=0; !BER_BVISNULL(&op->ors_attrs[i].an_name );i++) { 1757 if (!BER_BVISEMPTY(&op->ors_attrs[i].an_name)) { 1758 vals[j] = op->ors_attrs[i].an_name; 1759 j++; 1760 } 1761 } 1762 BER_BVZERO(&vals[j]); 1763 attr_merge_normalize( e, ad_reqAttr, vals, op->o_tmpmemctx ); 1764 op->o_tmpfree( vals, op->o_tmpmemctx ); 1765 } 1766 bv.bv_val = timebuf; 1767 bv.bv_len = snprintf( bv.bv_val, sizeof( timebuf ), "%d", rs->sr_nentries ); 1768 if ( bv.bv_len < sizeof( timebuf ) ) { 1769 attr_merge_one( e, ad_reqEntries, &bv, NULL ); 1770 } /* else? */ 1771 1772 bv.bv_len = snprintf( bv.bv_val, sizeof( timebuf ), "%d", op->ors_tlimit ); 1773 if ( bv.bv_len < sizeof( timebuf ) ) { 1774 attr_merge_one( e, ad_reqTimeLimit, &bv, NULL ); 1775 } /* else? */ 1776 1777 bv.bv_len = snprintf( bv.bv_val, sizeof( timebuf ), "%d", op->ors_slimit ); 1778 if ( bv.bv_len < sizeof( timebuf ) ) { 1779 attr_merge_one( e, ad_reqSizeLimit, &bv, NULL ); 1780 } /* else? */ 1781 break; 1782 1783 case LOG_EN_BIND: 1784 bv.bv_val = timebuf; 1785 bv.bv_len = snprintf( bv.bv_val, sizeof( timebuf ), "%d", op->o_protocol ); 1786 if ( bv.bv_len < sizeof( timebuf ) ) { 1787 attr_merge_one( e, ad_reqVersion, &bv, NULL ); 1788 } /* else? */ 1789 if ( op->orb_method == LDAP_AUTH_SIMPLE ) { 1790 attr_merge_normalize_one( e, ad_reqMethod, &simple, op->o_tmpmemctx ); 1791 } else { 1792 bv.bv_len = STRLENOF("SASL()") + op->orb_mech.bv_len; 1793 bv.bv_val = op->o_tmpalloc( bv.bv_len + 1, op->o_tmpmemctx ); 1794 ptr = lutil_strcopy( bv.bv_val, "SASL(" ); 1795 ptr = lutil_strcopy( ptr, op->orb_mech.bv_val ); 1796 *ptr++ = ')'; 1797 *ptr = '\0'; 1798 attr_merge_normalize_one( e, ad_reqMethod, &bv, op->o_tmpmemctx ); 1799 op->o_tmpfree( bv.bv_val, op->o_tmpmemctx ); 1800 } 1801 1802 break; 1803 1804 case LOG_EN_EXTENDED: 1805 if ( op->ore_reqdata ) { 1806 attr_merge_one( e, ad_reqData, op->ore_reqdata, NULL ); 1807 } 1808 break; 1809 1810 case LOG_EN_UNKNOWN: 1811 /* we don't know its parameters, don't add any */ 1812 break; 1813 } 1814 1815 if ( e_uuid || !BER_BVISNULL( &uuid ) ) { 1816 struct berval *pbv = NULL; 1817 1818 if ( !BER_BVISNULL( &uuid ) ) { 1819 pbv = &uuid; 1820 1821 } else { 1822 a = attr_find( e_uuid->e_attrs, slap_schema.si_ad_entryUUID ); 1823 if ( a ) { 1824 pbv = &a->a_vals[0]; 1825 } 1826 } 1827 1828 if ( pbv ) { 1829 attr_merge_normalize_one( e, ad_reqEntryUUID, pbv, op->o_tmpmemctx ); 1830 } 1831 1832 if ( !BER_BVISNULL( &uuid ) ) { 1833 ber_memfree( uuid.bv_val ); 1834 BER_BVZERO( &uuid ); 1835 } 1836 } 1837 1838 op2.o_hdr = op->o_hdr; 1839 op2.o_tag = LDAP_REQ_ADD; 1840 op2.o_bd = li->li_db; 1841 op2.o_dn = li->li_db->be_rootdn; 1842 op2.o_ndn = li->li_db->be_rootndn; 1843 op2.o_req_dn = e->e_name; 1844 op2.o_req_ndn = e->e_nname; 1845 op2.ora_e = e; 1846 op2.o_callback = &nullsc; 1847 op2.o_csn = op->o_csn; 1848 /* contextCSN updates may still reach here */ 1849 op2.o_dont_replicate = op->o_dont_replicate; 1850 1851 if (( lo->mask & LOG_OP_WRITES ) && !BER_BVISEMPTY( &op->o_csn )) { 1852 struct berval maxcsn; 1853 char cbuf[LDAP_PVT_CSNSTR_BUFSIZE]; 1854 int foundit; 1855 cbuf[0] = '\0'; 1856 maxcsn.bv_val = cbuf; 1857 maxcsn.bv_len = sizeof(cbuf); 1858 /* If there was a commit CSN on the main DB, 1859 * we must propagate it to the log DB for its 1860 * own syncprov. Otherwise, don't generate one. 1861 */ 1862 slap_get_commit_csn( op, &maxcsn, &foundit ); 1863 if ( !BER_BVISEMPTY( &maxcsn ) ) { 1864 slap_queue_csn( &op2, &op->o_csn ); 1865 do_graduate = 1; 1866 } else { 1867 attr_merge_normalize_one( e, slap_schema.si_ad_entryCSN, 1868 &op->o_csn, op->o_tmpmemctx ); 1869 } 1870 } 1871 1872 op2.o_bd->be_add( &op2, &rs2 ); 1873 if ( e == op2.ora_e ) entry_free( e ); 1874 e = NULL; 1875 if ( do_graduate ) { 1876 slap_graduate_commit_csn( &op2 ); 1877 } 1878 1879done: 1880 if ( lo->mask & LOG_OP_WRITES ) 1881 ldap_pvt_thread_mutex_unlock( &li->li_log_mutex ); 1882 if ( old ) entry_free( old ); 1883 return SLAP_CB_CONTINUE; 1884} 1885 1886/* Since Bind success is sent by the frontend, it won't normally enter 1887 * the overlay response callback. Add another callback to make sure it 1888 * gets here. 1889 */ 1890static int 1891accesslog_bind_resp( Operation *op, SlapReply *rs ) 1892{ 1893 BackendDB *be, db; 1894 int rc; 1895 slap_callback *sc; 1896 1897 be = op->o_bd; 1898 db = *be; 1899 op->o_bd = &db; 1900 db.bd_info = op->o_callback->sc_private; 1901 rc = accesslog_response( op, rs ); 1902 op->o_bd = be; 1903 sc = op->o_callback; 1904 op->o_callback = sc->sc_next; 1905 op->o_tmpfree( sc, op->o_tmpmemctx ); 1906 return rc; 1907} 1908 1909static int 1910accesslog_op_bind( Operation *op, SlapReply *rs ) 1911{ 1912 slap_callback *sc; 1913 1914 sc = op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx ); 1915 sc->sc_response = accesslog_bind_resp; 1916 sc->sc_private = op->o_bd->bd_info; 1917 1918 if ( op->o_callback ) { 1919 sc->sc_next = op->o_callback->sc_next; 1920 op->o_callback->sc_next = sc; 1921 } else { 1922 op->o_callback = sc; 1923 } 1924 return SLAP_CB_CONTINUE; 1925} 1926 1927static int 1928accesslog_mod_cleanup( Operation *op, SlapReply *rs ) 1929{ 1930 slap_callback *sc = op->o_callback; 1931 slap_overinst *on = sc->sc_private; 1932 op->o_callback = sc->sc_next; 1933 1934 op->o_tmpfree( sc, op->o_tmpmemctx ); 1935 1936 if ( on ) { 1937 BackendInfo *bi = op->o_bd->bd_info; 1938 op->o_bd->bd_info = (BackendInfo *)on; 1939 accesslog_response( op, rs ); 1940 op->o_bd->bd_info = bi; 1941 } 1942 return 0; 1943} 1944 1945static int 1946accesslog_op_mod( Operation *op, SlapReply *rs ) 1947{ 1948 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 1949 log_info *li = on->on_bi.bi_private; 1950 slap_verbmasks *lo; 1951 int logop; 1952 int doit = 0; 1953 1954 /* These internal ops are not logged */ 1955 if ( op->o_dont_replicate ) { 1956 /* Let contextCSN updates from syncrepl thru; the underlying 1957 * syncprov needs to see them. Skip others. 1958 */ 1959 if (( op->o_tag != LDAP_REQ_MODIFY || 1960 op->orm_modlist->sml_op != LDAP_MOD_REPLACE || 1961 op->orm_modlist->sml_desc != slap_schema.si_ad_contextCSN ) && 1962 op->orm_no_opattrs ) 1963 return SLAP_CB_CONTINUE; 1964 /* give this a unique timestamp */ 1965 op->o_tincr++; 1966 } 1967 1968 logop = accesslog_op2logop( op ); 1969 lo = logops+logop+EN_OFFSET; 1970 1971 if ( li->li_ops & lo->mask ) { 1972 doit = 1; 1973 } else { 1974 log_base *lb; 1975 for ( lb = li->li_bases; lb; lb = lb->lb_next ) 1976 if (( lb->lb_ops & lo->mask ) && dnIsSuffix( &op->o_req_ndn, &lb->lb_base )) { 1977 doit = 1; 1978 break; 1979 } 1980 } 1981 1982 if ( doit ) { 1983 slap_callback *cb = op->o_tmpcalloc( 1, sizeof( slap_callback ), op->o_tmpmemctx ), *cb2; 1984 cb->sc_cleanup = accesslog_mod_cleanup; 1985 cb->sc_private = on; 1986 for ( cb2 = op->o_callback; cb2->sc_next; cb2 = cb2->sc_next ); 1987 cb2->sc_next = cb; 1988 1989 ldap_pvt_thread_rmutex_lock( &li->li_op_rmutex, op->o_tid ); 1990 if ( li->li_oldf && ( op->o_tag == LDAP_REQ_DELETE || 1991 op->o_tag == LDAP_REQ_MODIFY || 1992 ( op->o_tag == LDAP_REQ_MODRDN && li->li_oldattrs ))) 1993 { 1994 int rc; 1995 Entry *e; 1996 1997 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1998 rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e ); 1999 if ( e ) { 2000 if ( test_filter( op, e, li->li_oldf ) == LDAP_COMPARE_TRUE ) 2001 li->li_old = entry_dup( e ); 2002 be_entry_release_rw( op, e, 0 ); 2003 } 2004 op->o_bd->bd_info = (BackendInfo *)on; 2005 2006 } else { 2007 int rc; 2008 Entry *e; 2009 2010 op->o_bd->bd_info = (BackendInfo *)on->on_info; 2011 rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e ); 2012 if ( e ) { 2013 Attribute *a = attr_find( e->e_attrs, slap_schema.si_ad_entryUUID ); 2014 if ( a ) { 2015 ber_dupbv( &li->li_uuid, &a->a_vals[0] ); 2016 } 2017 be_entry_release_rw( op, e, 0 ); 2018 } 2019 op->o_bd->bd_info = (BackendInfo *)on; 2020 } 2021 } 2022 return SLAP_CB_CONTINUE; 2023} 2024 2025/* unbinds are broadcast to all backends; we only log it if this 2026 * backend was used for the original bind. 2027 */ 2028static int 2029accesslog_unbind( Operation *op, SlapReply *rs ) 2030{ 2031 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 2032 if ( op->o_conn->c_authz_backend == on->on_info->oi_origdb ) { 2033 log_info *li = on->on_bi.bi_private; 2034 Operation op2 = {0}; 2035 void *cids[SLAP_MAX_CIDS]; 2036 SlapReply rs2 = {REP_RESULT}; 2037 Entry *e; 2038 2039 if ( !( li->li_ops & LOG_OP_UNBIND )) { 2040 log_base *lb; 2041 int i = 0; 2042 2043 for ( lb = li->li_bases; lb; lb=lb->lb_next ) 2044 if (( lb->lb_ops & LOG_OP_UNBIND ) && dnIsSuffix( &op->o_ndn, &lb->lb_base )) { 2045 i = 1; 2046 break; 2047 } 2048 if ( !i ) 2049 return SLAP_CB_CONTINUE; 2050 } 2051 2052 e = accesslog_entry( op, rs, LOG_EN_UNBIND, &op2 ); 2053 op2.o_hdr = op->o_hdr; 2054 op2.o_tag = LDAP_REQ_ADD; 2055 op2.o_bd = li->li_db; 2056 op2.o_dn = li->li_db->be_rootdn; 2057 op2.o_ndn = li->li_db->be_rootndn; 2058 op2.o_req_dn = e->e_name; 2059 op2.o_req_ndn = e->e_nname; 2060 op2.ora_e = e; 2061 op2.o_callback = &nullsc; 2062 op2.o_controls = cids; 2063 memset(cids, 0, sizeof( cids )); 2064 2065 op2.o_bd->be_add( &op2, &rs2 ); 2066 if ( e == op2.ora_e ) 2067 entry_free( e ); 2068 } 2069 return SLAP_CB_CONTINUE; 2070} 2071 2072static int 2073accesslog_abandon( Operation *op, SlapReply *rs ) 2074{ 2075 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 2076 log_info *li = on->on_bi.bi_private; 2077 Operation op2 = {0}; 2078 void *cids[SLAP_MAX_CIDS]; 2079 SlapReply rs2 = {REP_RESULT}; 2080 Entry *e; 2081 char buf[64]; 2082 struct berval bv; 2083 2084 if ( !op->o_time ) 2085 return SLAP_CB_CONTINUE; 2086 2087 if ( !( li->li_ops & LOG_OP_ABANDON )) { 2088 log_base *lb; 2089 int i = 0; 2090 2091 for ( lb = li->li_bases; lb; lb=lb->lb_next ) 2092 if (( lb->lb_ops & LOG_OP_ABANDON ) && dnIsSuffix( &op->o_ndn, &lb->lb_base )) { 2093 i = 1; 2094 break; 2095 } 2096 if ( !i ) 2097 return SLAP_CB_CONTINUE; 2098 } 2099 2100 e = accesslog_entry( op, rs, LOG_EN_ABANDON, &op2 ); 2101 bv.bv_val = buf; 2102 bv.bv_len = snprintf( buf, sizeof( buf ), "%d", op->orn_msgid ); 2103 if ( bv.bv_len < sizeof( buf ) ) { 2104 attr_merge_one( e, ad_reqId, &bv, NULL ); 2105 } /* else? */ 2106 2107 op2.o_hdr = op->o_hdr; 2108 op2.o_tag = LDAP_REQ_ADD; 2109 op2.o_bd = li->li_db; 2110 op2.o_dn = li->li_db->be_rootdn; 2111 op2.o_ndn = li->li_db->be_rootndn; 2112 op2.o_req_dn = e->e_name; 2113 op2.o_req_ndn = e->e_nname; 2114 op2.ora_e = e; 2115 op2.o_callback = &nullsc; 2116 op2.o_controls = cids; 2117 memset(cids, 0, sizeof( cids )); 2118 2119 op2.o_bd->be_add( &op2, &rs2 ); 2120 if ( e == op2.ora_e ) 2121 entry_free( e ); 2122 2123 return SLAP_CB_CONTINUE; 2124} 2125 2126static int 2127accesslog_operational( Operation *op, SlapReply *rs ) 2128{ 2129 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 2130 log_info *li = on->on_bi.bi_private; 2131 2132 if ( op->o_sync != SLAP_CONTROL_NONE ) 2133 return SLAP_CB_CONTINUE; 2134 2135 if ( rs->sr_entry != NULL 2136 && dn_match( &op->o_bd->be_nsuffix[0], &rs->sr_entry->e_nname ) ) 2137 { 2138 Attribute **ap; 2139 2140 for ( ap = &rs->sr_operational_attrs; *ap; ap = &(*ap)->a_next ) 2141 /* just count */ ; 2142 2143 if ( SLAP_OPATTRS( rs->sr_attr_flags ) || 2144 ad_inlist( ad_auditContext, rs->sr_attrs ) ) 2145 { 2146 *ap = attr_alloc( ad_auditContext ); 2147 attr_valadd( *ap, 2148 &li->li_db->be_suffix[0], 2149 &li->li_db->be_nsuffix[0], 1 ); 2150 } 2151 } 2152 2153 return SLAP_CB_CONTINUE; 2154} 2155 2156static slap_overinst accesslog; 2157 2158static int 2159accesslog_db_init( 2160 BackendDB *be, 2161 ConfigReply *cr 2162) 2163{ 2164 slap_overinst *on = (slap_overinst *)be->bd_info; 2165 log_info *li = ch_calloc(1, sizeof(log_info)); 2166 2167 on->on_bi.bi_private = li; 2168 ldap_pvt_thread_rmutex_init( &li->li_op_rmutex ); 2169 ldap_pvt_thread_mutex_init( &li->li_log_mutex ); 2170 return 0; 2171} 2172 2173static int 2174accesslog_db_destroy( 2175 BackendDB *be, 2176 ConfigReply *cr 2177) 2178{ 2179 slap_overinst *on = (slap_overinst *)be->bd_info; 2180 log_info *li = on->on_bi.bi_private; 2181 log_attr *la; 2182 2183 if ( li->li_oldf ) 2184 filter_free( li->li_oldf ); 2185 for ( la=li->li_oldattrs; la; la=li->li_oldattrs ) { 2186 li->li_oldattrs = la->next; 2187 ch_free( la ); 2188 } 2189 ldap_pvt_thread_mutex_destroy( &li->li_log_mutex ); 2190 ldap_pvt_thread_rmutex_destroy( &li->li_op_rmutex ); 2191 free( li ); 2192 return LDAP_SUCCESS; 2193} 2194 2195/* Create the logdb's root entry if it's missing */ 2196static void * 2197accesslog_db_root( 2198 void *ctx, 2199 void *arg ) 2200{ 2201 struct re_s *rtask = arg; 2202 slap_overinst *on = rtask->arg; 2203 log_info *li = on->on_bi.bi_private; 2204 2205 Connection conn = {0}; 2206 OperationBuffer opbuf; 2207 Operation *op; 2208 2209 Entry *e; 2210 int rc; 2211 2212 connection_fake_init( &conn, &opbuf, ctx ); 2213 op = &opbuf.ob_op; 2214 op->o_bd = li->li_db; 2215 op->o_dn = li->li_db->be_rootdn; 2216 op->o_ndn = li->li_db->be_rootndn; 2217 rc = be_entry_get_rw( op, li->li_db->be_nsuffix, NULL, NULL, 0, &e ); 2218 2219 if ( e ) { 2220 be_entry_release_rw( op, e, 0 ); 2221 2222 } else { 2223 SlapReply rs = {REP_RESULT}; 2224 struct berval rdn, nrdn, attr; 2225 char *ptr; 2226 AttributeDescription *ad = NULL; 2227 const char *text = NULL; 2228 Entry *e_ctx; 2229 BackendDB db; 2230 2231 e = entry_alloc(); 2232 ber_dupbv( &e->e_name, li->li_db->be_suffix ); 2233 ber_dupbv( &e->e_nname, li->li_db->be_nsuffix ); 2234 2235 attr_merge_one( e, slap_schema.si_ad_objectClass, 2236 &log_container->soc_cname, NULL ); 2237 2238 dnRdn( &e->e_name, &rdn ); 2239 dnRdn( &e->e_nname, &nrdn ); 2240 ptr = ber_bvchr( &rdn, '=' ); 2241 2242 assert( ptr != NULL ); 2243 2244 attr.bv_val = rdn.bv_val; 2245 attr.bv_len = ptr - rdn.bv_val; 2246 2247 slap_bv2ad( &attr, &ad, &text ); 2248 2249 rdn.bv_val = ptr+1; 2250 rdn.bv_len -= attr.bv_len + 1; 2251 ptr = ber_bvchr( &nrdn, '=' ); 2252 nrdn.bv_len -= ptr - nrdn.bv_val + 1; 2253 nrdn.bv_val = ptr+1; 2254 attr_merge_one( e, ad, &rdn, &nrdn ); 2255 2256 /* Get contextCSN from main DB */ 2257 op->o_bd = on->on_info->oi_origdb; 2258 rc = be_entry_get_rw( op, op->o_bd->be_nsuffix, NULL, 2259 slap_schema.si_ad_contextCSN, 0, &e_ctx ); 2260 2261 if ( e_ctx ) { 2262 Attribute *a; 2263 2264 a = attr_find( e_ctx->e_attrs, slap_schema.si_ad_contextCSN ); 2265 if ( a ) { 2266 /* FIXME: contextCSN could have multiple values! 2267 * should select the one with the server's SID */ 2268 attr_merge_one( e, slap_schema.si_ad_entryCSN, 2269 &a->a_vals[0], &a->a_nvals[0] ); 2270 attr_merge( e, a->a_desc, a->a_vals, a->a_nvals ); 2271 } 2272 be_entry_release_rw( op, e_ctx, 0 ); 2273 } 2274 db = *li->li_db; 2275 op->o_bd = &db; 2276 2277 op->ora_e = e; 2278 op->o_req_dn = e->e_name; 2279 op->o_req_ndn = e->e_nname; 2280 op->o_callback = &nullsc; 2281 SLAP_DBFLAGS( op->o_bd ) |= SLAP_DBFLAG_NOLASTMOD; 2282 rc = op->o_bd->be_add( op, &rs ); 2283 if ( e == op->ora_e ) 2284 entry_free( e ); 2285 } 2286 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); 2287 ldap_pvt_runqueue_stoptask( &slapd_rq, rtask ); 2288 ldap_pvt_runqueue_remove( &slapd_rq, rtask ); 2289 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); 2290 2291 return NULL; 2292} 2293 2294static int 2295accesslog_db_open( 2296 BackendDB *be, 2297 ConfigReply *cr 2298) 2299{ 2300 slap_overinst *on = (slap_overinst *)be->bd_info; 2301 log_info *li = on->on_bi.bi_private; 2302 2303 2304 if ( !BER_BVISEMPTY( &li->li_db_suffix )) { 2305 li->li_db = select_backend( &li->li_db_suffix, 0 ); 2306 ch_free( li->li_db_suffix.bv_val ); 2307 BER_BVZERO( &li->li_db_suffix ); 2308 } 2309 if ( li->li_db == NULL ) { 2310 Debug( LDAP_DEBUG_ANY, 2311 "accesslog: \"logdb <suffix>\" missing or invalid.\n", 2312 0, 0, 0 ); 2313 return 1; 2314 } 2315 2316 if ( slapMode & SLAP_TOOL_MODE ) 2317 return 0; 2318 2319 if ( BER_BVISEMPTY( &li->li_db->be_rootndn )) { 2320 ber_dupbv( &li->li_db->be_rootdn, li->li_db->be_suffix ); 2321 ber_dupbv( &li->li_db->be_rootndn, li->li_db->be_nsuffix ); 2322 } 2323 2324 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); 2325 ldap_pvt_runqueue_insert( &slapd_rq, 3600, accesslog_db_root, on, 2326 "accesslog_db_root", li->li_db->be_suffix[0].bv_val ); 2327 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); 2328 2329 return 0; 2330} 2331 2332int accesslog_initialize() 2333{ 2334 int i, rc; 2335 2336 accesslog.on_bi.bi_type = "accesslog"; 2337 accesslog.on_bi.bi_db_init = accesslog_db_init; 2338 accesslog.on_bi.bi_db_destroy = accesslog_db_destroy; 2339 accesslog.on_bi.bi_db_open = accesslog_db_open; 2340 2341 accesslog.on_bi.bi_op_add = accesslog_op_mod; 2342 accesslog.on_bi.bi_op_bind = accesslog_op_bind; 2343 accesslog.on_bi.bi_op_delete = accesslog_op_mod; 2344 accesslog.on_bi.bi_op_modify = accesslog_op_mod; 2345 accesslog.on_bi.bi_op_modrdn = accesslog_op_mod; 2346 accesslog.on_bi.bi_op_unbind = accesslog_unbind; 2347 accesslog.on_bi.bi_op_abandon = accesslog_abandon; 2348 accesslog.on_bi.bi_operational = accesslog_operational; 2349 accesslog.on_response = accesslog_response; 2350 2351 accesslog.on_bi.bi_cf_ocs = log_cfocs; 2352 2353 nullsc.sc_response = slap_null_cb; 2354 2355 rc = config_register_schema( log_cfats, log_cfocs ); 2356 if ( rc ) return rc; 2357 2358 /* log schema integration */ 2359 for ( i=0; lsyntaxes[i].oid; i++ ) { 2360 int code; 2361 2362 code = register_syntax( &lsyntaxes[ i ].syn ); 2363 if ( code != 0 ) { 2364 Debug( LDAP_DEBUG_ANY, 2365 "accesslog_init: register_syntax failed\n", 2366 0, 0, 0 ); 2367 return code; 2368 } 2369 2370 if ( lsyntaxes[i].mrs != NULL ) { 2371 code = mr_make_syntax_compat_with_mrs( 2372 lsyntaxes[i].oid, lsyntaxes[i].mrs ); 2373 if ( code < 0 ) { 2374 Debug( LDAP_DEBUG_ANY, 2375 "accesslog_init: " 2376 "mr_make_syntax_compat_with_mrs " 2377 "failed\n", 2378 0, 0, 0 ); 2379 return code; 2380 } 2381 } 2382 } 2383 2384 for ( i=0; lattrs[i].at; i++ ) { 2385 int code; 2386 2387 code = register_at( lattrs[i].at, lattrs[i].ad, 0 ); 2388 if ( code ) { 2389 Debug( LDAP_DEBUG_ANY, 2390 "accesslog_init: register_at failed\n", 2391 0, 0, 0 ); 2392 return -1; 2393 } 2394#ifndef LDAP_DEVEL 2395 (*lattrs[i].ad)->ad_type->sat_flags |= SLAP_AT_HIDE; 2396#endif 2397 } 2398 2399 for ( i=0; locs[i].ot; i++ ) { 2400 int code; 2401 2402 code = register_oc( locs[i].ot, locs[i].oc, 0 ); 2403 if ( code ) { 2404 Debug( LDAP_DEBUG_ANY, 2405 "accesslog_init: register_oc failed\n", 2406 0, 0, 0 ); 2407 return -1; 2408 } 2409#ifndef LDAP_DEVEL 2410 (*locs[i].oc)->soc_flags |= SLAP_OC_HIDE; 2411#endif 2412 } 2413 2414 return overlay_register(&accesslog); 2415} 2416 2417#if SLAPD_OVER_ACCESSLOG == SLAPD_MOD_DYNAMIC 2418int 2419init_module( int argc, char *argv[] ) 2420{ 2421 return accesslog_initialize(); 2422} 2423#endif 2424 2425#endif /* SLAPD_OVER_ACCESSLOG */ 2426