accesslog.c revision 1.1.1.6
1/* $NetBSD: accesslog.c,v 1.1.1.6 2018/02/06 01:53:16 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-2017 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.6 2018/02/06 01:53:16 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 ldap_pvt_thread_pool_pausecheck( &connection_pool ); 710 } 711 ch_free( pd.ndn ); 712 ch_free( pd.dn ); 713 714 { 715 Modifications mod; 716 struct berval bv[2]; 717 rs_reinit( &rs, REP_RESULT ); 718 /* update context's entryCSN to reflect oldest CSN */ 719 mod.sml_numvals = 1; 720 mod.sml_values = bv; 721 bv[0] = pd.csn; 722 BER_BVZERO(&bv[1]); 723 mod.sml_nvalues = NULL; 724 mod.sml_desc = slap_schema.si_ad_entryCSN; 725 mod.sml_op = LDAP_MOD_REPLACE; 726 mod.sml_flags = SLAP_MOD_INTERNAL; 727 mod.sml_next = NULL; 728 729 op->o_tag = LDAP_REQ_MODIFY; 730 op->orm_modlist = &mod; 731 op->orm_no_opattrs = 1; 732 op->o_req_dn = li->li_db->be_suffix[0]; 733 op->o_req_ndn = li->li_db->be_nsuffix[0]; 734 op->o_no_schema_check = 1; 735 op->o_managedsait = SLAP_CONTROL_NONCRITICAL; 736 op->o_bd->be_modify( op, &rs ); 737 if ( mod.sml_next ) { 738 slap_mods_free( mod.sml_next, 1 ); 739 } 740 } 741 } 742 743 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); 744 ldap_pvt_runqueue_stoptask( &slapd_rq, rtask ); 745 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); 746 747 return NULL; 748} 749 750static int 751log_cf_gen(ConfigArgs *c) 752{ 753 slap_overinst *on = (slap_overinst *)c->bi; 754 struct log_info *li = on->on_bi.bi_private; 755 int rc = 0; 756 slap_mask_t tmask = 0; 757 char agebuf[2*STRLENOF("ddddd+hh:mm:ss ")]; 758 struct berval agebv, cyclebv; 759 760 switch( c->op ) { 761 case SLAP_CONFIG_EMIT: 762 switch( c->type ) { 763 case LOG_DB: 764 if ( !BER_BVISEMPTY( &li->li_db_suffix )) { 765 value_add_one( &c->rvalue_vals, &li->li_db_suffix ); 766 value_add_one( &c->rvalue_nvals, &li->li_db_suffix ); 767 } else if ( li->li_db ) { 768 value_add_one( &c->rvalue_vals, li->li_db->be_suffix ); 769 value_add_one( &c->rvalue_nvals, li->li_db->be_nsuffix ); 770 } else { 771 snprintf( c->cr_msg, sizeof( c->cr_msg ), 772 "accesslog: \"logdb <suffix>\" must be specified" ); 773 Debug( LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", 774 c->log, c->cr_msg, c->value_dn.bv_val ); 775 rc = 1; 776 break; 777 } 778 break; 779 case LOG_OPS: 780 rc = mask_to_verbs( logops, li->li_ops, &c->rvalue_vals ); 781 break; 782 case LOG_PURGE: 783 if ( !li->li_age ) { 784 rc = 1; 785 break; 786 } 787 agebv.bv_val = agebuf; 788 log_age_unparse( li->li_age, &agebv, sizeof( agebuf ) ); 789 agebv.bv_val[agebv.bv_len] = ' '; 790 agebv.bv_len++; 791 cyclebv.bv_val = agebv.bv_val + agebv.bv_len; 792 log_age_unparse( li->li_cycle, &cyclebv, sizeof( agebuf ) - agebv.bv_len ); 793 agebv.bv_len += cyclebv.bv_len; 794 value_add_one( &c->rvalue_vals, &agebv ); 795 break; 796 case LOG_SUCCESS: 797 if ( li->li_success ) 798 c->value_int = li->li_success; 799 else 800 rc = 1; 801 break; 802 case LOG_OLD: 803 if ( li->li_oldf ) { 804 filter2bv( li->li_oldf, &agebv ); 805 ber_bvarray_add( &c->rvalue_vals, &agebv ); 806 } 807 else 808 rc = 1; 809 break; 810 case LOG_OLDATTR: 811 if ( li->li_oldattrs ) { 812 log_attr *la; 813 814 for ( la = li->li_oldattrs; la; la=la->next ) 815 value_add_one( &c->rvalue_vals, &la->attr->ad_cname ); 816 } 817 else 818 rc = 1; 819 break; 820 case LOG_BASE: 821 if ( li->li_bases ) { 822 log_base *lb; 823 824 for ( lb = li->li_bases; lb; lb=lb->lb_next ) 825 value_add_one( &c->rvalue_vals, &lb->lb_line ); 826 } 827 else 828 rc = 1; 829 break; 830 } 831 break; 832 case LDAP_MOD_DELETE: 833 switch( c->type ) { 834 case LOG_DB: 835 /* noop. this should always be a valid backend. */ 836 break; 837 case LOG_OPS: 838 if ( c->valx < 0 ) { 839 li->li_ops = 0; 840 } else { 841 rc = verbs_to_mask( 1, &c->line, logops, &tmask ); 842 if ( rc == 0 ) 843 li->li_ops &= ~tmask; 844 } 845 break; 846 case LOG_PURGE: 847 if ( li->li_task ) { 848 struct re_s *re = li->li_task; 849 li->li_task = NULL; 850 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); 851 if ( ldap_pvt_runqueue_isrunning( &slapd_rq, re )) 852 ldap_pvt_runqueue_stoptask( &slapd_rq, re ); 853 ldap_pvt_runqueue_remove( &slapd_rq, re ); 854 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); 855 } 856 li->li_age = 0; 857 li->li_cycle = 0; 858 break; 859 case LOG_SUCCESS: 860 li->li_success = 0; 861 break; 862 case LOG_OLD: 863 if ( li->li_oldf ) { 864 filter_free( li->li_oldf ); 865 li->li_oldf = NULL; 866 } 867 break; 868 case LOG_OLDATTR: 869 if ( c->valx < 0 ) { 870 log_attr *la, *ln; 871 872 for ( la = li->li_oldattrs; la; la = ln ) { 873 ln = la->next; 874 ch_free( la ); 875 } 876 } else { 877 log_attr *la = NULL, **lp; 878 int i; 879 880 for ( lp = &li->li_oldattrs, i=0; i < c->valx; i++ ) { 881 la = *lp; 882 lp = &la->next; 883 } 884 *lp = la->next; 885 ch_free( la ); 886 } 887 break; 888 case LOG_BASE: 889 if ( c->valx < 0 ) { 890 log_base *lb, *ln; 891 892 for ( lb = li->li_bases; lb; lb = ln ) { 893 ln = lb->lb_next; 894 ch_free( lb ); 895 } 896 } else { 897 log_base *lb = NULL, **lp; 898 int i; 899 900 for ( lp = &li->li_bases, i=0; i < c->valx; i++ ) { 901 lb = *lp; 902 lp = &lb->lb_next; 903 } 904 *lp = lb->lb_next; 905 ch_free( lb ); 906 } 907 break; 908 } 909 break; 910 default: 911 switch( c->type ) { 912 case LOG_DB: 913 if ( CONFIG_ONLINE_ADD( c )) { 914 li->li_db = select_backend( &c->value_ndn, 0 ); 915 if ( !li->li_db ) { 916 snprintf( c->cr_msg, sizeof( c->cr_msg ), 917 "<%s> no matching backend found for suffix", 918 c->argv[0] ); 919 Debug( LDAP_DEBUG_ANY, "%s: %s \"%s\"\n", 920 c->log, c->cr_msg, c->value_dn.bv_val ); 921 rc = 1; 922 } 923 ch_free( c->value_ndn.bv_val ); 924 } else { 925 li->li_db_suffix = c->value_ndn; 926 } 927 ch_free( c->value_dn.bv_val ); 928 break; 929 case LOG_OPS: 930 rc = verbs_to_mask( c->argc, c->argv, logops, &tmask ); 931 if ( rc == 0 ) 932 li->li_ops |= tmask; 933 break; 934 case LOG_PURGE: 935 li->li_age = log_age_parse( c->argv[1] ); 936 if ( li->li_age < 1 ) { 937 rc = 1; 938 } else { 939 li->li_cycle = log_age_parse( c->argv[2] ); 940 if ( li->li_cycle < 1 ) { 941 rc = 1; 942 } else if ( slapMode & SLAP_SERVER_MODE ) { 943 struct re_s *re = li->li_task; 944 if ( re ) 945 re->interval.tv_sec = li->li_cycle; 946 else { 947 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); 948 li->li_task = ldap_pvt_runqueue_insert( &slapd_rq, 949 li->li_cycle, accesslog_purge, li, 950 "accesslog_purge", li->li_db ? 951 li->li_db->be_suffix[0].bv_val : 952 c->be->be_suffix[0].bv_val ); 953 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); 954 } 955 } 956 } 957 break; 958 case LOG_SUCCESS: 959 li->li_success = c->value_int; 960 break; 961 case LOG_OLD: 962 li->li_oldf = str2filter( c->argv[1] ); 963 if ( !li->li_oldf ) { 964 snprintf( c->cr_msg, sizeof( c->cr_msg ), "bad filter!" ); 965 rc = 1; 966 } 967 break; 968 case LOG_OLDATTR: { 969 int i; 970 AttributeDescription *ad; 971 const char *text; 972 973 for ( i=1; i< c->argc; i++ ) { 974 ad = NULL; 975 if ( slap_str2ad( c->argv[i], &ad, &text ) == LDAP_SUCCESS ) { 976 log_attr *la = ch_malloc( sizeof( log_attr )); 977 la->attr = ad; 978 la->next = li->li_oldattrs; 979 li->li_oldattrs = la; 980 } else { 981 snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s <%s>: %s", 982 c->argv[0], c->argv[i], text ); 983 Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, 984 "%s: %s\n", c->log, c->cr_msg, 0 ); 985 rc = ARG_BAD_CONF; 986 break; 987 } 988 } 989 } 990 break; 991 case LOG_BASE: { 992 slap_mask_t m = 0; 993 rc = verbstring_to_mask( logops, c->argv[1], '|', &m ); 994 if ( rc == 0 ) { 995 struct berval dn, ndn; 996 ber_str2bv( c->argv[2], 0, 0, &dn ); 997 rc = dnNormalize( 0, NULL, NULL, &dn, &ndn, NULL ); 998 if ( rc == 0 ) { 999 log_base *lb; 1000 struct berval mbv; 1001 char *ptr; 1002 mask_to_verbstring( logops, m, '|', &mbv ); 1003 lb = ch_malloc( sizeof( log_base ) + mbv.bv_len + ndn.bv_len + 3 + 1 ); 1004 lb->lb_line.bv_val = (char *)(lb + 1); 1005 lb->lb_line.bv_len = mbv.bv_len + ndn.bv_len + 3; 1006 ptr = lutil_strcopy( lb->lb_line.bv_val, mbv.bv_val ); 1007 *ptr++ = ' '; 1008 *ptr++ = '"'; 1009 lb->lb_base.bv_val = ptr; 1010 lb->lb_base.bv_len = ndn.bv_len; 1011 ptr = lutil_strcopy( ptr, ndn.bv_val ); 1012 *ptr++ = '"'; 1013 lb->lb_ops = m; 1014 lb->lb_next = li->li_bases; 1015 li->li_bases = lb; 1016 } else { 1017 snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s invalid DN: %s", 1018 c->argv[0], c->argv[2] ); 1019 Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, 1020 "%s: %s\n", c->log, c->cr_msg, 0 ); 1021 rc = ARG_BAD_CONF; 1022 } 1023 } else { 1024 snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s invalid ops: %s", 1025 c->argv[0], c->argv[1] ); 1026 Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, 1027 "%s: %s\n", c->log, c->cr_msg, 0 ); 1028 rc = ARG_BAD_CONF; 1029 } 1030 } 1031 break; 1032 } 1033 break; 1034 } 1035 return rc; 1036} 1037 1038static int 1039logSchemaControlValidate( 1040 Syntax *syntax, 1041 struct berval *valp ) 1042{ 1043 struct berval val, bv; 1044 ber_len_t i; 1045 int rc = LDAP_SUCCESS; 1046 1047 assert( valp != NULL ); 1048 1049 val = *valp; 1050 1051 /* check minimal size */ 1052 if ( val.bv_len < STRLENOF( "{*}" ) ) { 1053 return LDAP_INVALID_SYNTAX; 1054 } 1055 1056 val.bv_len--; 1057 1058 /* check SEQUENCE boundaries */ 1059 if ( val.bv_val[ 0 ] != '{' /*}*/ || 1060 val.bv_val[ val.bv_len ] != /*{*/ '}' ) 1061 { 1062 return LDAP_INVALID_SYNTAX; 1063 } 1064 1065 /* extract and check OID */ 1066 for ( i = 1; i < val.bv_len; i++ ) { 1067 if ( !ASCII_SPACE( val.bv_val[ i ] ) ) { 1068 break; 1069 } 1070 } 1071 1072 bv.bv_val = &val.bv_val[ i ]; 1073 1074 for ( i++; i < val.bv_len; i++ ) { 1075 if ( ASCII_SPACE( val.bv_val[ i ] ) ) 1076 { 1077 break; 1078 } 1079 } 1080 1081 bv.bv_len = &val.bv_val[ i ] - bv.bv_val; 1082 1083 rc = numericoidValidate( NULL, &bv ); 1084 if ( rc != LDAP_SUCCESS ) { 1085 return rc; 1086 } 1087 1088 if ( i == val.bv_len ) { 1089 return LDAP_SUCCESS; 1090 } 1091 1092 if ( val.bv_val[ i ] != ' ' ) { 1093 return LDAP_INVALID_SYNTAX; 1094 } 1095 1096 for ( i++; i < val.bv_len; i++ ) { 1097 if ( !ASCII_SPACE( val.bv_val[ i ] ) ) { 1098 break; 1099 } 1100 } 1101 1102 if ( i == val.bv_len ) { 1103 return LDAP_SUCCESS; 1104 } 1105 1106 /* extract and check criticality */ 1107 if ( strncasecmp( &val.bv_val[ i ], "criticality ", STRLENOF( "criticality " ) ) == 0 ) 1108 { 1109 i += STRLENOF( "criticality " ); 1110 for ( ; i < val.bv_len; i++ ) { 1111 if ( !ASCII_SPACE( val.bv_val[ i ] ) ) { 1112 break; 1113 } 1114 } 1115 1116 if ( i == val.bv_len ) { 1117 return LDAP_INVALID_SYNTAX; 1118 } 1119 1120 bv.bv_val = &val.bv_val[ i ]; 1121 1122 for ( ; i < val.bv_len; i++ ) { 1123 if ( ASCII_SPACE( val.bv_val[ i ] ) ) { 1124 break; 1125 } 1126 } 1127 1128 bv.bv_len = &val.bv_val[ i ] - bv.bv_val; 1129 1130 if ( !bvmatch( &bv, &slap_true_bv ) && !bvmatch( &bv, &slap_false_bv ) ) 1131 { 1132 return LDAP_INVALID_SYNTAX; 1133 } 1134 1135 if ( i == val.bv_len ) { 1136 return LDAP_SUCCESS; 1137 } 1138 1139 if ( val.bv_val[ i ] != ' ' ) { 1140 return LDAP_INVALID_SYNTAX; 1141 } 1142 1143 for ( i++; i < val.bv_len; i++ ) { 1144 if ( !ASCII_SPACE( val.bv_val[ i ] ) ) { 1145 break; 1146 } 1147 } 1148 1149 if ( i == val.bv_len ) { 1150 return LDAP_SUCCESS; 1151 } 1152 } 1153 1154 /* extract and check controlValue */ 1155 if ( strncasecmp( &val.bv_val[ i ], "controlValue ", STRLENOF( "controlValue " ) ) == 0 ) 1156 { 1157 ber_len_t valueStart, valueLen; 1158 1159 i += STRLENOF( "controlValue " ); 1160 for ( ; i < val.bv_len; i++ ) { 1161 if ( !ASCII_SPACE( val.bv_val[ i ] ) ) { 1162 break; 1163 } 1164 } 1165 1166 if ( i == val.bv_len ) { 1167 return LDAP_INVALID_SYNTAX; 1168 } 1169 1170 if ( val.bv_val[ i ] != '"' ) { 1171 return LDAP_INVALID_SYNTAX; 1172 } 1173 1174 i++; 1175 valueStart = i; 1176 1177 for ( ; i < val.bv_len; i++ ) { 1178 if ( val.bv_val[ i ] == '"' ) { 1179 break; 1180 } 1181 1182 if ( !ASCII_HEX( val.bv_val[ i ] ) ) { 1183 return LDAP_INVALID_SYNTAX; 1184 } 1185 } 1186 1187 if ( val.bv_val[ i ] != '"' ) { 1188 return LDAP_INVALID_SYNTAX; 1189 } 1190 1191 valueLen = i - valueStart; 1192 if ( (valueLen/2)*2 != valueLen ) { 1193 return LDAP_INVALID_SYNTAX; 1194 } 1195 1196 for ( i++; i < val.bv_len; i++ ) { 1197 if ( !ASCII_SPACE( val.bv_val[ i ] ) ) { 1198 break; 1199 } 1200 } 1201 1202 if ( i == val.bv_len ) { 1203 return LDAP_SUCCESS; 1204 } 1205 } 1206 1207 return LDAP_INVALID_SYNTAX; 1208} 1209 1210static int 1211accesslog_ctrls( 1212 LDAPControl **ctrls, 1213 BerVarray *valsp, 1214 BerVarray *nvalsp, 1215 void *memctx ) 1216{ 1217 long i, rc = 0; 1218 1219 assert( valsp != NULL ); 1220 assert( ctrls != NULL ); 1221 1222 *valsp = NULL; 1223 *nvalsp = NULL; 1224 1225 for ( i = 0; ctrls[ i ] != NULL; i++ ) { 1226 struct berval idx, 1227 oid, 1228 noid, 1229 bv; 1230 char *ptr, 1231 buf[ 32 ]; 1232 1233 if ( ctrls[ i ]->ldctl_oid == NULL ) { 1234 return LDAP_PROTOCOL_ERROR; 1235 } 1236 1237 idx.bv_len = snprintf( buf, sizeof( buf ), "{%ld}", i ); 1238 idx.bv_val = buf; 1239 1240 ber_str2bv( ctrls[ i ]->ldctl_oid, 0, 0, &oid ); 1241 noid.bv_len = idx.bv_len + oid.bv_len; 1242 ptr = noid.bv_val = ber_memalloc_x( noid.bv_len + 1, memctx ); 1243 ptr = lutil_strcopy( ptr, idx.bv_val ); 1244 ptr = lutil_strcopy( ptr, oid.bv_val ); 1245 1246 bv.bv_len = idx.bv_len + STRLENOF( "{}" ) + oid.bv_len; 1247 1248 if ( ctrls[ i ]->ldctl_iscritical ) { 1249 bv.bv_len += STRLENOF( " criticality TRUE" ); 1250 } 1251 1252 if ( !BER_BVISNULL( &ctrls[ i ]->ldctl_value ) ) { 1253 bv.bv_len += STRLENOF( " controlValue \"\"" ) 1254 + 2 * ctrls[ i ]->ldctl_value.bv_len; 1255 } 1256 1257 ptr = bv.bv_val = ber_memalloc_x( bv.bv_len + 1, memctx ); 1258 if ( ptr == NULL ) { 1259 ber_bvarray_free( *valsp ); 1260 *valsp = NULL; 1261 ber_bvarray_free( *nvalsp ); 1262 *nvalsp = NULL; 1263 return LDAP_OTHER; 1264 } 1265 1266 ptr = lutil_strcopy( ptr, idx.bv_val ); 1267 1268 *ptr++ = '{' /*}*/ ; 1269 ptr = lutil_strcopy( ptr, oid.bv_val ); 1270 1271 if ( ctrls[ i ]->ldctl_iscritical ) { 1272 ptr = lutil_strcopy( ptr, " criticality TRUE" ); 1273 } 1274 1275 if ( !BER_BVISNULL( &ctrls[ i ]->ldctl_value ) ) { 1276 ber_len_t j; 1277 1278 ptr = lutil_strcopy( ptr, " controlValue \"" ); 1279 for ( j = 0; j < ctrls[ i ]->ldctl_value.bv_len; j++ ) { 1280 *ptr++ = SLAP_ESCAPE_HI(ctrls[ i ]->ldctl_value.bv_val[ j ]); 1281 *ptr++ = SLAP_ESCAPE_LO(ctrls[ i ]->ldctl_value.bv_val[ j ]); 1282 } 1283 1284 *ptr++ = '"'; 1285 } 1286 1287 *ptr++ = '}'; 1288 *ptr = '\0'; 1289 1290 ber_bvarray_add_x( valsp, &bv, memctx ); 1291 ber_bvarray_add_x( nvalsp, &noid, memctx ); 1292 } 1293 1294 return rc; 1295 1296} 1297 1298static Entry *accesslog_entry( Operation *op, SlapReply *rs, int logop, 1299 Operation *op2 ) { 1300 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 1301 log_info *li = on->on_bi.bi_private; 1302 1303 char rdnbuf[STRLENOF(RDNEQ)+LDAP_LUTIL_GENTIME_BUFSIZE+8]; 1304 char nrdnbuf[STRLENOF(RDNEQ)+LDAP_LUTIL_GENTIME_BUFSIZE+8]; 1305 1306 struct berval rdn, nrdn, timestamp, ntimestamp, bv; 1307 slap_verbmasks *lo = logops+logop+EN_OFFSET; 1308 1309 Entry *e = entry_alloc(); 1310 1311 strcpy( rdnbuf, RDNEQ ); 1312 rdn.bv_val = rdnbuf; 1313 strcpy( nrdnbuf, RDNEQ ); 1314 nrdn.bv_val = nrdnbuf; 1315 1316 timestamp.bv_val = rdnbuf+STRLENOF(RDNEQ); 1317 timestamp.bv_len = sizeof(rdnbuf) - STRLENOF(RDNEQ); 1318 slap_timestamp( &op->o_time, ×tamp ); 1319 snprintf( timestamp.bv_val + timestamp.bv_len-1, sizeof(".123456Z"), ".%06dZ", op->o_tincr ); 1320 timestamp.bv_len += STRLENOF(".123456"); 1321 1322 rdn.bv_len = STRLENOF(RDNEQ)+timestamp.bv_len; 1323 ad_reqStart->ad_type->sat_equality->smr_normalize( 1324 SLAP_MR_VALUE_OF_ASSERTION_SYNTAX, ad_reqStart->ad_type->sat_syntax, 1325 ad_reqStart->ad_type->sat_equality, ×tamp, &ntimestamp, 1326 op->o_tmpmemctx ); 1327 1328 strcpy( nrdn.bv_val + STRLENOF(RDNEQ), ntimestamp.bv_val ); 1329 nrdn.bv_len = STRLENOF(RDNEQ)+ntimestamp.bv_len; 1330 build_new_dn( &e->e_name, li->li_db->be_suffix, &rdn, NULL ); 1331 build_new_dn( &e->e_nname, li->li_db->be_nsuffix, &nrdn, NULL ); 1332 1333 attr_merge_one( e, slap_schema.si_ad_objectClass, 1334 &log_ocs[logop]->soc_cname, NULL ); 1335 attr_merge_one( e, slap_schema.si_ad_structuralObjectClass, 1336 &log_ocs[logop]->soc_cname, NULL ); 1337 attr_merge_one( e, ad_reqStart, ×tamp, &ntimestamp ); 1338 op->o_tmpfree( ntimestamp.bv_val, op->o_tmpmemctx ); 1339 1340 slap_op_time( &op2->o_time, &op2->o_tincr ); 1341 1342 timestamp.bv_len = sizeof(rdnbuf) - STRLENOF(RDNEQ); 1343 slap_timestamp( &op2->o_time, ×tamp ); 1344 snprintf( timestamp.bv_val + timestamp.bv_len-1, sizeof(".123456Z"), ".%06dZ", op2->o_tincr ); 1345 timestamp.bv_len += STRLENOF(".123456"); 1346 1347 attr_merge_normalize_one( e, ad_reqEnd, ×tamp, op->o_tmpmemctx ); 1348 1349 /* Exops have OID appended */ 1350 if ( logop == LOG_EN_EXTENDED ) { 1351 bv.bv_len = lo->word.bv_len + op->ore_reqoid.bv_len + 2; 1352 bv.bv_val = ch_malloc( bv.bv_len + 1 ); 1353 AC_MEMCPY( bv.bv_val, lo->word.bv_val, lo->word.bv_len ); 1354 bv.bv_val[lo->word.bv_len] = '{'; 1355 AC_MEMCPY( bv.bv_val+lo->word.bv_len+1, op->ore_reqoid.bv_val, 1356 op->ore_reqoid.bv_len ); 1357 bv.bv_val[bv.bv_len-1] = '}'; 1358 bv.bv_val[bv.bv_len] = '\0'; 1359 attr_merge_one( e, ad_reqType, &bv, NULL ); 1360 } else { 1361 attr_merge_one( e, ad_reqType, &lo->word, NULL ); 1362 } 1363 1364 rdn.bv_len = snprintf( rdn.bv_val, sizeof( rdnbuf ), "%lu", op->o_connid ); 1365 if ( rdn.bv_len < sizeof( rdnbuf ) ) { 1366 attr_merge_one( e, ad_reqSession, &rdn, NULL ); 1367 } /* else? */ 1368 1369 if ( BER_BVISNULL( &op->o_dn ) ) { 1370 attr_merge_one( e, ad_reqAuthzID, (struct berval *)&slap_empty_bv, 1371 (struct berval *)&slap_empty_bv ); 1372 } else { 1373 attr_merge_one( e, ad_reqAuthzID, &op->o_dn, &op->o_ndn ); 1374 } 1375 1376 /* FIXME: need to add reqControls and reqRespControls */ 1377 if ( op->o_ctrls ) { 1378 BerVarray vals = NULL, 1379 nvals = NULL; 1380 1381 if ( accesslog_ctrls( op->o_ctrls, &vals, &nvals, 1382 op->o_tmpmemctx ) == LDAP_SUCCESS && vals ) 1383 { 1384 attr_merge( e, ad_reqControls, vals, nvals ); 1385 ber_bvarray_free_x( vals, op->o_tmpmemctx ); 1386 ber_bvarray_free_x( nvals, op->o_tmpmemctx ); 1387 } 1388 } 1389 1390 if ( rs->sr_ctrls ) { 1391 BerVarray vals = NULL, 1392 nvals = NULL; 1393 1394 if ( accesslog_ctrls( rs->sr_ctrls, &vals, &nvals, 1395 op->o_tmpmemctx ) == LDAP_SUCCESS && vals ) 1396 { 1397 attr_merge( e, ad_reqRespControls, vals, nvals ); 1398 ber_bvarray_free_x( vals, op->o_tmpmemctx ); 1399 ber_bvarray_free_x( nvals, op->o_tmpmemctx ); 1400 } 1401 1402 } 1403 1404 return e; 1405} 1406 1407static struct berval scopes[] = { 1408 BER_BVC("base"), 1409 BER_BVC("one"), 1410 BER_BVC("sub"), 1411 BER_BVC("subord") 1412}; 1413 1414static struct berval derefs[] = { 1415 BER_BVC("never"), 1416 BER_BVC("searching"), 1417 BER_BVC("finding"), 1418 BER_BVC("always") 1419}; 1420 1421static struct berval simple = BER_BVC("SIMPLE"); 1422 1423static void accesslog_val2val(AttributeDescription *ad, struct berval *val, 1424 char c_op, struct berval *dst) { 1425 char *ptr; 1426 1427 dst->bv_len = ad->ad_cname.bv_len + val->bv_len + 2; 1428 if ( c_op ) dst->bv_len++; 1429 1430 dst->bv_val = ch_malloc( dst->bv_len+1 ); 1431 1432 ptr = lutil_strcopy( dst->bv_val, ad->ad_cname.bv_val ); 1433 *ptr++ = ':'; 1434 if ( c_op ) 1435 *ptr++ = c_op; 1436 *ptr++ = ' '; 1437 AC_MEMCPY( ptr, val->bv_val, val->bv_len ); 1438 dst->bv_val[dst->bv_len] = '\0'; 1439} 1440 1441static int 1442accesslog_op2logop( Operation *op ) 1443{ 1444 switch ( op->o_tag ) { 1445 case LDAP_REQ_ADD: return LOG_EN_ADD; 1446 case LDAP_REQ_DELETE: return LOG_EN_DELETE; 1447 case LDAP_REQ_MODIFY: return LOG_EN_MODIFY; 1448 case LDAP_REQ_MODRDN: return LOG_EN_MODRDN; 1449 case LDAP_REQ_COMPARE: return LOG_EN_COMPARE; 1450 case LDAP_REQ_SEARCH: return LOG_EN_SEARCH; 1451 case LDAP_REQ_BIND: return LOG_EN_BIND; 1452 case LDAP_REQ_EXTENDED: return LOG_EN_EXTENDED; 1453 default: /* unknown operation type */ 1454 break; 1455 } /* Unbind and Abandon never reach here */ 1456 return LOG_EN_UNKNOWN; 1457} 1458 1459static int accesslog_response(Operation *op, SlapReply *rs) { 1460 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 1461 log_info *li = on->on_bi.bi_private; 1462 Attribute *a, *last_attr; 1463 Modifications *m; 1464 struct berval *b, uuid = BER_BVNULL; 1465 int i; 1466 int logop, do_graduate = 0; 1467 slap_verbmasks *lo; 1468 Entry *e = NULL, *old = NULL, *e_uuid = NULL; 1469 char timebuf[LDAP_LUTIL_GENTIME_BUFSIZE+8]; 1470 struct berval bv; 1471 char *ptr; 1472 BerVarray vals; 1473 Operation op2 = {0}; 1474 SlapReply rs2 = {REP_RESULT}; 1475 1476 if ( rs->sr_type != REP_RESULT && rs->sr_type != REP_EXTENDED ) 1477 return SLAP_CB_CONTINUE; 1478 1479 logop = accesslog_op2logop( op ); 1480 lo = logops+logop+EN_OFFSET; 1481 if ( !( li->li_ops & lo->mask )) { 1482 log_base *lb; 1483 1484 i = 0; 1485 for ( lb = li->li_bases; lb; lb=lb->lb_next ) 1486 if (( lb->lb_ops & lo->mask ) && dnIsSuffix( &op->o_req_ndn, &lb->lb_base )) { 1487 i = 1; 1488 break; 1489 } 1490 if ( !i ) 1491 return SLAP_CB_CONTINUE; 1492 } 1493 1494 /* mutex and so were only set for write operations; 1495 * if we got here, the operation must be logged */ 1496 if ( lo->mask & LOG_OP_WRITES ) { 1497 slap_callback *cb; 1498 1499 /* Most internal ops are not logged */ 1500 if ( op->o_dont_replicate) { 1501 /* Let contextCSN updates from syncrepl thru; the underlying 1502 * syncprov needs to see them. Skip others. 1503 */ 1504 if (( op->o_tag != LDAP_REQ_MODIFY || 1505 op->orm_modlist->sml_op != LDAP_MOD_REPLACE || 1506 op->orm_modlist->sml_desc != slap_schema.si_ad_contextCSN ) && 1507 op->orm_no_opattrs ) 1508 return SLAP_CB_CONTINUE; 1509 } 1510 1511 ldap_pvt_thread_mutex_lock( &li->li_log_mutex ); 1512 old = li->li_old; 1513 uuid = li->li_uuid; 1514 li->li_old = NULL; 1515 BER_BVZERO( &li->li_uuid ); 1516 /* Disarm mod_cleanup */ 1517 for ( cb = op->o_callback; cb; cb = cb->sc_next ) { 1518 if ( cb->sc_private == (void *)on ) { 1519 cb->sc_private = NULL; 1520 break; 1521 } 1522 } 1523 ldap_pvt_thread_rmutex_unlock( &li->li_op_rmutex, op->o_tid ); 1524 } 1525 1526 /* ignore these internal reads */ 1527 if (( lo->mask & LOG_OP_READS ) && op->o_do_not_cache ) { 1528 return SLAP_CB_CONTINUE; 1529 } 1530 1531 if ( li->li_success && rs->sr_err != LDAP_SUCCESS ) 1532 goto done; 1533 1534 e = accesslog_entry( op, rs, logop, &op2 ); 1535 1536 attr_merge_one( e, ad_reqDN, &op->o_req_dn, &op->o_req_ndn ); 1537 1538 if ( rs->sr_text ) { 1539 ber_str2bv( rs->sr_text, 0, 0, &bv ); 1540 attr_merge_normalize_one( e, ad_reqMessage, &bv, op->o_tmpmemctx ); 1541 } 1542 bv.bv_len = snprintf( timebuf, sizeof( timebuf ), "%d", rs->sr_err ); 1543 if ( bv.bv_len < sizeof( timebuf ) ) { 1544 bv.bv_val = timebuf; 1545 attr_merge_one( e, ad_reqResult, &bv, NULL ); 1546 } 1547 1548 last_attr = attr_find( e->e_attrs, ad_reqResult ); 1549 1550 e_uuid = old; 1551 switch( logop ) { 1552 case LOG_EN_ADD: 1553 case LOG_EN_DELETE: { 1554 char c_op; 1555 Entry *e2; 1556 1557 if ( logop == LOG_EN_ADD ) { 1558 e2 = op->ora_e; 1559 e_uuid = op->ora_e; 1560 c_op = '+'; 1561 1562 } else { 1563 if ( !old ) 1564 break; 1565 e2 = old; 1566 c_op = 0; 1567 } 1568 /* count all the vals */ 1569 i = 0; 1570 for ( a=e2->e_attrs; a; a=a->a_next ) { 1571 i += a->a_numvals; 1572 } 1573 vals = ch_malloc( (i+1) * sizeof( struct berval )); 1574 i = 0; 1575 for ( a=e2->e_attrs; a; a=a->a_next ) { 1576 if ( a->a_vals ) { 1577 for (b=a->a_vals; !BER_BVISNULL( b ); b++,i++) { 1578 accesslog_val2val( a->a_desc, b, c_op, &vals[i] ); 1579 } 1580 } 1581 } 1582 vals[i].bv_val = NULL; 1583 vals[i].bv_len = 0; 1584 a = attr_alloc( logop == LOG_EN_ADD ? ad_reqMod : ad_reqOld ); 1585 a->a_numvals = i; 1586 a->a_vals = vals; 1587 a->a_nvals = vals; 1588 last_attr->a_next = a; 1589 break; 1590 } 1591 1592 case LOG_EN_MODRDN: 1593 case LOG_EN_MODIFY: 1594 /* count all the mods + attributes (ITS#6545) */ 1595 i = 0; 1596 for ( m = op->orm_modlist; m; m = m->sml_next ) { 1597 if ( m->sml_values ) { 1598 i += m->sml_numvals; 1599 } else if ( m->sml_op == LDAP_MOD_DELETE || 1600 m->sml_op == LDAP_MOD_REPLACE ) 1601 { 1602 i++; 1603 } 1604 if ( m->sml_next && m->sml_desc == m->sml_next->sml_desc ) { 1605 i++; 1606 } 1607 } 1608 vals = ch_malloc( (i+1) * sizeof( struct berval )); 1609 i = 0; 1610 1611 /* init flags on old entry */ 1612 if ( old ) { 1613 for ( a = old->e_attrs; a; a = a->a_next ) { 1614 log_attr *la; 1615 a->a_flags = 0; 1616 1617 /* look for attrs that are always logged */ 1618 for ( la = li->li_oldattrs; la; la = la->next ) { 1619 if ( a->a_desc == la->attr ) { 1620 a->a_flags = 1; 1621 } 1622 } 1623 } 1624 } 1625 1626 for ( m = op->orm_modlist; m; m = m->sml_next ) { 1627 /* Mark this attribute as modified */ 1628 if ( old ) { 1629 a = attr_find( old->e_attrs, m->sml_desc ); 1630 if ( a ) { 1631 a->a_flags = 1; 1632 } 1633 } 1634 1635 /* don't log the RDN mods; they're explicitly logged later */ 1636 if ( logop == LOG_EN_MODRDN && 1637 ( m->sml_op == SLAP_MOD_SOFTADD || 1638 m->sml_op == LDAP_MOD_DELETE ) ) 1639 { 1640 continue; 1641 } 1642 1643 if ( m->sml_values ) { 1644 for ( b = m->sml_values; !BER_BVISNULL( b ); b++, i++ ) { 1645 char c_op; 1646 1647 switch ( m->sml_op ) { 1648 case LDAP_MOD_ADD: c_op = '+'; break; 1649 case LDAP_MOD_DELETE: c_op = '-'; break; 1650 case LDAP_MOD_REPLACE: c_op = '='; break; 1651 case LDAP_MOD_INCREMENT: c_op = '#'; break; 1652 1653 /* unknown op. there shouldn't be any of these. we 1654 * don't know what to do with it, but we shouldn't just 1655 * ignore it. 1656 */ 1657 default: c_op = '?'; break; 1658 } 1659 accesslog_val2val( m->sml_desc, b, c_op, &vals[i] ); 1660 } 1661 } else if ( m->sml_op == LDAP_MOD_DELETE || 1662 m->sml_op == LDAP_MOD_REPLACE ) 1663 { 1664 vals[i].bv_len = m->sml_desc->ad_cname.bv_len + 2; 1665 vals[i].bv_val = ch_malloc( vals[i].bv_len + 1 ); 1666 ptr = lutil_strcopy( vals[i].bv_val, 1667 m->sml_desc->ad_cname.bv_val ); 1668 *ptr++ = ':'; 1669 if ( m->sml_op == LDAP_MOD_DELETE ) { 1670 *ptr++ = '-'; 1671 } else { 1672 *ptr++ = '='; 1673 } 1674 *ptr = '\0'; 1675 i++; 1676 } 1677 /* ITS#6545: when the same attribute is edited multiple times, 1678 * record the transition */ 1679 if ( m->sml_next && m->sml_desc == m->sml_next->sml_desc ) { 1680 ber_str2bv( ":", STRLENOF(":"), 1, &vals[i] ); 1681 i++; 1682 } 1683 } 1684 1685 if ( i > 0 ) { 1686 BER_BVZERO( &vals[i] ); 1687 a = attr_alloc( ad_reqMod ); 1688 a->a_numvals = i; 1689 a->a_vals = vals; 1690 a->a_nvals = vals; 1691 last_attr->a_next = a; 1692 last_attr = a; 1693 1694 } else { 1695 ch_free( vals ); 1696 } 1697 1698 if ( old ) { 1699 /* count all the vals */ 1700 i = 0; 1701 for ( a = old->e_attrs; a != NULL; a = a->a_next ) { 1702 if ( a->a_vals && a->a_flags ) { 1703 i += a->a_numvals; 1704 } 1705 } 1706 if ( i ) { 1707 vals = ch_malloc( (i + 1) * sizeof( struct berval ) ); 1708 i = 0; 1709 for ( a=old->e_attrs; a; a=a->a_next ) { 1710 if ( a->a_vals && a->a_flags ) { 1711 for (b=a->a_vals; !BER_BVISNULL( b ); b++,i++) { 1712 accesslog_val2val( a->a_desc, b, 0, &vals[i] ); 1713 } 1714 } 1715 } 1716 vals[i].bv_val = NULL; 1717 vals[i].bv_len = 0; 1718 a = attr_alloc( ad_reqOld ); 1719 a->a_numvals = i; 1720 a->a_vals = vals; 1721 a->a_nvals = vals; 1722 last_attr->a_next = a; 1723 } 1724 } 1725 if ( logop == LOG_EN_MODIFY ) { 1726 break; 1727 } 1728 1729 /* Now log the actual modRDN info */ 1730 attr_merge_one( e, ad_reqNewRDN, &op->orr_newrdn, &op->orr_nnewrdn ); 1731 attr_merge_one( e, ad_reqDeleteOldRDN, op->orr_deleteoldrdn ? 1732 (struct berval *)&slap_true_bv : (struct berval *)&slap_false_bv, 1733 NULL ); 1734 if ( op->orr_newSup ) { 1735 attr_merge_one( e, ad_reqNewSuperior, op->orr_newSup, op->orr_nnewSup ); 1736 } 1737 break; 1738 1739 case LOG_EN_COMPARE: 1740 bv.bv_len = op->orc_ava->aa_desc->ad_cname.bv_len + 1 + 1741 op->orc_ava->aa_value.bv_len; 1742 bv.bv_val = op->o_tmpalloc( bv.bv_len+1, op->o_tmpmemctx ); 1743 ptr = lutil_strcopy( bv.bv_val, op->orc_ava->aa_desc->ad_cname.bv_val ); 1744 *ptr++ = '='; 1745 AC_MEMCPY( ptr, op->orc_ava->aa_value.bv_val, op->orc_ava->aa_value.bv_len ); 1746 bv.bv_val[bv.bv_len] = '\0'; 1747 attr_merge_one( e, ad_reqAssertion, &bv, NULL ); 1748 op->o_tmpfree( bv.bv_val, op->o_tmpmemctx ); 1749 break; 1750 1751 case LOG_EN_SEARCH: 1752 attr_merge_one( e, ad_reqScope, &scopes[op->ors_scope], NULL ); 1753 attr_merge_one( e, ad_reqDerefAliases, &derefs[op->ors_deref], NULL ); 1754 attr_merge_one( e, ad_reqAttrsOnly, op->ors_attrsonly ? 1755 (struct berval *)&slap_true_bv : (struct berval *)&slap_false_bv, 1756 NULL ); 1757 if ( !BER_BVISEMPTY( &op->ors_filterstr )) 1758 attr_merge_normalize_one( e, ad_reqFilter, &op->ors_filterstr, op->o_tmpmemctx ); 1759 if ( op->ors_attrs ) { 1760 int j; 1761 /* count them */ 1762 for (i=0; !BER_BVISNULL(&op->ors_attrs[i].an_name );i++) 1763 ; 1764 vals = op->o_tmpalloc( (i+1) * sizeof(struct berval), 1765 op->o_tmpmemctx ); 1766 for (i=0, j=0; !BER_BVISNULL(&op->ors_attrs[i].an_name );i++) { 1767 if (!BER_BVISEMPTY(&op->ors_attrs[i].an_name)) { 1768 vals[j] = op->ors_attrs[i].an_name; 1769 j++; 1770 } 1771 } 1772 BER_BVZERO(&vals[j]); 1773 attr_merge_normalize( e, ad_reqAttr, vals, op->o_tmpmemctx ); 1774 op->o_tmpfree( vals, op->o_tmpmemctx ); 1775 } 1776 bv.bv_val = timebuf; 1777 bv.bv_len = snprintf( bv.bv_val, sizeof( timebuf ), "%d", rs->sr_nentries ); 1778 if ( bv.bv_len < sizeof( timebuf ) ) { 1779 attr_merge_one( e, ad_reqEntries, &bv, NULL ); 1780 } /* else? */ 1781 1782 bv.bv_len = snprintf( bv.bv_val, sizeof( timebuf ), "%d", op->ors_tlimit ); 1783 if ( bv.bv_len < sizeof( timebuf ) ) { 1784 attr_merge_one( e, ad_reqTimeLimit, &bv, NULL ); 1785 } /* else? */ 1786 1787 bv.bv_len = snprintf( bv.bv_val, sizeof( timebuf ), "%d", op->ors_slimit ); 1788 if ( bv.bv_len < sizeof( timebuf ) ) { 1789 attr_merge_one( e, ad_reqSizeLimit, &bv, NULL ); 1790 } /* else? */ 1791 break; 1792 1793 case LOG_EN_BIND: 1794 bv.bv_val = timebuf; 1795 bv.bv_len = snprintf( bv.bv_val, sizeof( timebuf ), "%d", op->o_protocol ); 1796 if ( bv.bv_len < sizeof( timebuf ) ) { 1797 attr_merge_one( e, ad_reqVersion, &bv, NULL ); 1798 } /* else? */ 1799 if ( op->orb_method == LDAP_AUTH_SIMPLE ) { 1800 attr_merge_normalize_one( e, ad_reqMethod, &simple, op->o_tmpmemctx ); 1801 } else { 1802 bv.bv_len = STRLENOF("SASL()") + op->orb_mech.bv_len; 1803 bv.bv_val = op->o_tmpalloc( bv.bv_len + 1, op->o_tmpmemctx ); 1804 ptr = lutil_strcopy( bv.bv_val, "SASL(" ); 1805 ptr = lutil_strcopy( ptr, op->orb_mech.bv_val ); 1806 *ptr++ = ')'; 1807 *ptr = '\0'; 1808 attr_merge_normalize_one( e, ad_reqMethod, &bv, op->o_tmpmemctx ); 1809 op->o_tmpfree( bv.bv_val, op->o_tmpmemctx ); 1810 } 1811 1812 break; 1813 1814 case LOG_EN_EXTENDED: 1815 if ( op->ore_reqdata ) { 1816 attr_merge_one( e, ad_reqData, op->ore_reqdata, NULL ); 1817 } 1818 break; 1819 1820 case LOG_EN_UNKNOWN: 1821 /* we don't know its parameters, don't add any */ 1822 break; 1823 } 1824 1825 if ( e_uuid || !BER_BVISNULL( &uuid ) ) { 1826 struct berval *pbv = NULL; 1827 1828 if ( !BER_BVISNULL( &uuid ) ) { 1829 pbv = &uuid; 1830 1831 } else { 1832 a = attr_find( e_uuid->e_attrs, slap_schema.si_ad_entryUUID ); 1833 if ( a ) { 1834 pbv = &a->a_vals[0]; 1835 } 1836 } 1837 1838 if ( pbv ) { 1839 attr_merge_normalize_one( e, ad_reqEntryUUID, pbv, op->o_tmpmemctx ); 1840 } 1841 1842 if ( !BER_BVISNULL( &uuid ) ) { 1843 ber_memfree( uuid.bv_val ); 1844 BER_BVZERO( &uuid ); 1845 } 1846 } 1847 1848 op2.o_hdr = op->o_hdr; 1849 op2.o_tag = LDAP_REQ_ADD; 1850 op2.o_bd = li->li_db; 1851 op2.o_dn = li->li_db->be_rootdn; 1852 op2.o_ndn = li->li_db->be_rootndn; 1853 op2.o_req_dn = e->e_name; 1854 op2.o_req_ndn = e->e_nname; 1855 op2.ora_e = e; 1856 op2.o_callback = &nullsc; 1857 op2.o_csn = op->o_csn; 1858 /* contextCSN updates may still reach here */ 1859 op2.o_dont_replicate = op->o_dont_replicate; 1860 1861 if (( lo->mask & LOG_OP_WRITES ) && !BER_BVISEMPTY( &op->o_csn )) { 1862 struct berval maxcsn; 1863 char cbuf[LDAP_PVT_CSNSTR_BUFSIZE]; 1864 int foundit; 1865 cbuf[0] = '\0'; 1866 maxcsn.bv_val = cbuf; 1867 maxcsn.bv_len = sizeof(cbuf); 1868 /* If there was a commit CSN on the main DB, 1869 * we must propagate it to the log DB for its 1870 * own syncprov. Otherwise, don't generate one. 1871 */ 1872 slap_get_commit_csn( op, &maxcsn, &foundit ); 1873 if ( !BER_BVISEMPTY( &maxcsn ) ) { 1874 slap_queue_csn( &op2, &op->o_csn ); 1875 do_graduate = 1; 1876 } else { 1877 attr_merge_normalize_one( e, slap_schema.si_ad_entryCSN, 1878 &op->o_csn, op->o_tmpmemctx ); 1879 } 1880 } 1881 1882 op2.o_bd->be_add( &op2, &rs2 ); 1883 if ( e == op2.ora_e ) entry_free( e ); 1884 e = NULL; 1885 if ( do_graduate ) { 1886 slap_graduate_commit_csn( &op2 ); 1887 } 1888 1889done: 1890 if ( lo->mask & LOG_OP_WRITES ) 1891 ldap_pvt_thread_mutex_unlock( &li->li_log_mutex ); 1892 if ( old ) entry_free( old ); 1893 return SLAP_CB_CONTINUE; 1894} 1895 1896/* Since Bind success is sent by the frontend, it won't normally enter 1897 * the overlay response callback. Add another callback to make sure it 1898 * gets here. 1899 */ 1900static int 1901accesslog_bind_resp( Operation *op, SlapReply *rs ) 1902{ 1903 BackendDB *be, db; 1904 int rc; 1905 slap_callback *sc; 1906 1907 be = op->o_bd; 1908 db = *be; 1909 op->o_bd = &db; 1910 db.bd_info = op->o_callback->sc_private; 1911 rc = accesslog_response( op, rs ); 1912 op->o_bd = be; 1913 sc = op->o_callback; 1914 op->o_callback = sc->sc_next; 1915 op->o_tmpfree( sc, op->o_tmpmemctx ); 1916 return rc; 1917} 1918 1919static int 1920accesslog_op_bind( Operation *op, SlapReply *rs ) 1921{ 1922 slap_callback *sc; 1923 1924 sc = op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx ); 1925 sc->sc_response = accesslog_bind_resp; 1926 sc->sc_private = op->o_bd->bd_info; 1927 1928 if ( op->o_callback ) { 1929 sc->sc_next = op->o_callback->sc_next; 1930 op->o_callback->sc_next = sc; 1931 } else { 1932 op->o_callback = sc; 1933 } 1934 return SLAP_CB_CONTINUE; 1935} 1936 1937static int 1938accesslog_mod_cleanup( Operation *op, SlapReply *rs ) 1939{ 1940 slap_callback *sc = op->o_callback; 1941 slap_overinst *on = sc->sc_private; 1942 op->o_callback = sc->sc_next; 1943 1944 op->o_tmpfree( sc, op->o_tmpmemctx ); 1945 1946 if ( on ) { 1947 BackendInfo *bi = op->o_bd->bd_info; 1948 op->o_bd->bd_info = (BackendInfo *)on; 1949 accesslog_response( op, rs ); 1950 op->o_bd->bd_info = bi; 1951 } 1952 return 0; 1953} 1954 1955static int 1956accesslog_op_mod( Operation *op, SlapReply *rs ) 1957{ 1958 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 1959 log_info *li = on->on_bi.bi_private; 1960 slap_verbmasks *lo; 1961 int logop; 1962 int doit = 0; 1963 1964 /* These internal ops are not logged */ 1965 if ( op->o_dont_replicate ) { 1966 /* Let contextCSN updates from syncrepl thru; the underlying 1967 * syncprov needs to see them. Skip others. 1968 */ 1969 if (( op->o_tag != LDAP_REQ_MODIFY || 1970 op->orm_modlist->sml_op != LDAP_MOD_REPLACE || 1971 op->orm_modlist->sml_desc != slap_schema.si_ad_contextCSN ) && 1972 op->orm_no_opattrs ) 1973 return SLAP_CB_CONTINUE; 1974 /* give this a unique timestamp */ 1975 op->o_tincr++; 1976 } 1977 1978 logop = accesslog_op2logop( op ); 1979 lo = logops+logop+EN_OFFSET; 1980 1981 if ( li->li_ops & lo->mask ) { 1982 doit = 1; 1983 } else { 1984 log_base *lb; 1985 for ( lb = li->li_bases; lb; lb = lb->lb_next ) 1986 if (( lb->lb_ops & lo->mask ) && dnIsSuffix( &op->o_req_ndn, &lb->lb_base )) { 1987 doit = 1; 1988 break; 1989 } 1990 } 1991 1992 if ( doit ) { 1993 slap_callback *cb = op->o_tmpcalloc( 1, sizeof( slap_callback ), op->o_tmpmemctx ), *cb2; 1994 cb->sc_cleanup = accesslog_mod_cleanup; 1995 cb->sc_private = on; 1996 for ( cb2 = op->o_callback; cb2->sc_next; cb2 = cb2->sc_next ); 1997 cb2->sc_next = cb; 1998 1999 ldap_pvt_thread_rmutex_lock( &li->li_op_rmutex, op->o_tid ); 2000 if ( li->li_oldf && ( op->o_tag == LDAP_REQ_DELETE || 2001 op->o_tag == LDAP_REQ_MODIFY || 2002 ( op->o_tag == LDAP_REQ_MODRDN && li->li_oldattrs ))) 2003 { 2004 int rc; 2005 Entry *e; 2006 2007 op->o_bd->bd_info = (BackendInfo *)on->on_info; 2008 rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e ); 2009 if ( e ) { 2010 if ( test_filter( op, e, li->li_oldf ) == LDAP_COMPARE_TRUE ) 2011 li->li_old = entry_dup( e ); 2012 be_entry_release_rw( op, e, 0 ); 2013 } 2014 op->o_bd->bd_info = (BackendInfo *)on; 2015 2016 } else { 2017 int rc; 2018 Entry *e; 2019 2020 op->o_bd->bd_info = (BackendInfo *)on->on_info; 2021 rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e ); 2022 if ( e ) { 2023 Attribute *a = attr_find( e->e_attrs, slap_schema.si_ad_entryUUID ); 2024 if ( a ) { 2025 ber_dupbv( &li->li_uuid, &a->a_vals[0] ); 2026 } 2027 be_entry_release_rw( op, e, 0 ); 2028 } 2029 op->o_bd->bd_info = (BackendInfo *)on; 2030 } 2031 } 2032 return SLAP_CB_CONTINUE; 2033} 2034 2035/* unbinds are broadcast to all backends; we only log it if this 2036 * backend was used for the original bind. 2037 */ 2038static int 2039accesslog_unbind( Operation *op, SlapReply *rs ) 2040{ 2041 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 2042 if ( op->o_conn->c_authz_backend == on->on_info->oi_origdb ) { 2043 log_info *li = on->on_bi.bi_private; 2044 Operation op2 = {0}; 2045 void *cids[SLAP_MAX_CIDS]; 2046 SlapReply rs2 = {REP_RESULT}; 2047 Entry *e; 2048 2049 if ( !( li->li_ops & LOG_OP_UNBIND )) { 2050 log_base *lb; 2051 int i = 0; 2052 2053 for ( lb = li->li_bases; lb; lb=lb->lb_next ) 2054 if (( lb->lb_ops & LOG_OP_UNBIND ) && dnIsSuffix( &op->o_ndn, &lb->lb_base )) { 2055 i = 1; 2056 break; 2057 } 2058 if ( !i ) 2059 return SLAP_CB_CONTINUE; 2060 } 2061 2062 e = accesslog_entry( op, rs, LOG_EN_UNBIND, &op2 ); 2063 op2.o_hdr = op->o_hdr; 2064 op2.o_tag = LDAP_REQ_ADD; 2065 op2.o_bd = li->li_db; 2066 op2.o_dn = li->li_db->be_rootdn; 2067 op2.o_ndn = li->li_db->be_rootndn; 2068 op2.o_req_dn = e->e_name; 2069 op2.o_req_ndn = e->e_nname; 2070 op2.ora_e = e; 2071 op2.o_callback = &nullsc; 2072 op2.o_controls = cids; 2073 memset(cids, 0, sizeof( cids )); 2074 2075 op2.o_bd->be_add( &op2, &rs2 ); 2076 if ( e == op2.ora_e ) 2077 entry_free( e ); 2078 } 2079 return SLAP_CB_CONTINUE; 2080} 2081 2082static int 2083accesslog_abandon( Operation *op, SlapReply *rs ) 2084{ 2085 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 2086 log_info *li = on->on_bi.bi_private; 2087 Operation op2 = {0}; 2088 void *cids[SLAP_MAX_CIDS]; 2089 SlapReply rs2 = {REP_RESULT}; 2090 Entry *e; 2091 char buf[64]; 2092 struct berval bv; 2093 2094 if ( !op->o_time ) 2095 return SLAP_CB_CONTINUE; 2096 2097 if ( !( li->li_ops & LOG_OP_ABANDON )) { 2098 log_base *lb; 2099 int i = 0; 2100 2101 for ( lb = li->li_bases; lb; lb=lb->lb_next ) 2102 if (( lb->lb_ops & LOG_OP_ABANDON ) && dnIsSuffix( &op->o_ndn, &lb->lb_base )) { 2103 i = 1; 2104 break; 2105 } 2106 if ( !i ) 2107 return SLAP_CB_CONTINUE; 2108 } 2109 2110 e = accesslog_entry( op, rs, LOG_EN_ABANDON, &op2 ); 2111 bv.bv_val = buf; 2112 bv.bv_len = snprintf( buf, sizeof( buf ), "%d", op->orn_msgid ); 2113 if ( bv.bv_len < sizeof( buf ) ) { 2114 attr_merge_one( e, ad_reqId, &bv, NULL ); 2115 } /* else? */ 2116 2117 op2.o_hdr = op->o_hdr; 2118 op2.o_tag = LDAP_REQ_ADD; 2119 op2.o_bd = li->li_db; 2120 op2.o_dn = li->li_db->be_rootdn; 2121 op2.o_ndn = li->li_db->be_rootndn; 2122 op2.o_req_dn = e->e_name; 2123 op2.o_req_ndn = e->e_nname; 2124 op2.ora_e = e; 2125 op2.o_callback = &nullsc; 2126 op2.o_controls = cids; 2127 memset(cids, 0, sizeof( cids )); 2128 2129 op2.o_bd->be_add( &op2, &rs2 ); 2130 if ( e == op2.ora_e ) 2131 entry_free( e ); 2132 2133 return SLAP_CB_CONTINUE; 2134} 2135 2136static int 2137accesslog_operational( Operation *op, SlapReply *rs ) 2138{ 2139 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 2140 log_info *li = on->on_bi.bi_private; 2141 2142 if ( op->o_sync != SLAP_CONTROL_NONE ) 2143 return SLAP_CB_CONTINUE; 2144 2145 if ( rs->sr_entry != NULL 2146 && dn_match( &op->o_bd->be_nsuffix[0], &rs->sr_entry->e_nname ) ) 2147 { 2148 Attribute **ap; 2149 2150 for ( ap = &rs->sr_operational_attrs; *ap; ap = &(*ap)->a_next ) 2151 /* just count */ ; 2152 2153 if ( SLAP_OPATTRS( rs->sr_attr_flags ) || 2154 ad_inlist( ad_auditContext, rs->sr_attrs ) ) 2155 { 2156 *ap = attr_alloc( ad_auditContext ); 2157 attr_valadd( *ap, 2158 &li->li_db->be_suffix[0], 2159 &li->li_db->be_nsuffix[0], 1 ); 2160 } 2161 } 2162 2163 return SLAP_CB_CONTINUE; 2164} 2165 2166static slap_overinst accesslog; 2167 2168static int 2169accesslog_db_init( 2170 BackendDB *be, 2171 ConfigReply *cr 2172) 2173{ 2174 slap_overinst *on = (slap_overinst *)be->bd_info; 2175 log_info *li = ch_calloc(1, sizeof(log_info)); 2176 2177 on->on_bi.bi_private = li; 2178 ldap_pvt_thread_rmutex_init( &li->li_op_rmutex ); 2179 ldap_pvt_thread_mutex_init( &li->li_log_mutex ); 2180 return 0; 2181} 2182 2183static int 2184accesslog_db_destroy( 2185 BackendDB *be, 2186 ConfigReply *cr 2187) 2188{ 2189 slap_overinst *on = (slap_overinst *)be->bd_info; 2190 log_info *li = on->on_bi.bi_private; 2191 log_attr *la; 2192 2193 if ( li->li_oldf ) 2194 filter_free( li->li_oldf ); 2195 for ( la=li->li_oldattrs; la; la=li->li_oldattrs ) { 2196 li->li_oldattrs = la->next; 2197 ch_free( la ); 2198 } 2199 ldap_pvt_thread_mutex_destroy( &li->li_log_mutex ); 2200 ldap_pvt_thread_rmutex_destroy( &li->li_op_rmutex ); 2201 free( li ); 2202 return LDAP_SUCCESS; 2203} 2204 2205/* Create the logdb's root entry if it's missing */ 2206static void * 2207accesslog_db_root( 2208 void *ctx, 2209 void *arg ) 2210{ 2211 struct re_s *rtask = arg; 2212 slap_overinst *on = rtask->arg; 2213 log_info *li = on->on_bi.bi_private; 2214 2215 Connection conn = {0}; 2216 OperationBuffer opbuf; 2217 Operation *op; 2218 2219 Entry *e; 2220 int rc; 2221 2222 connection_fake_init( &conn, &opbuf, ctx ); 2223 op = &opbuf.ob_op; 2224 op->o_bd = li->li_db; 2225 op->o_dn = li->li_db->be_rootdn; 2226 op->o_ndn = li->li_db->be_rootndn; 2227 rc = be_entry_get_rw( op, li->li_db->be_nsuffix, NULL, NULL, 0, &e ); 2228 2229 if ( e ) { 2230 be_entry_release_rw( op, e, 0 ); 2231 2232 } else { 2233 SlapReply rs = {REP_RESULT}; 2234 struct berval rdn, nrdn, attr; 2235 char *ptr; 2236 AttributeDescription *ad = NULL; 2237 const char *text = NULL; 2238 Entry *e_ctx; 2239 BackendDB db; 2240 2241 e = entry_alloc(); 2242 ber_dupbv( &e->e_name, li->li_db->be_suffix ); 2243 ber_dupbv( &e->e_nname, li->li_db->be_nsuffix ); 2244 2245 attr_merge_one( e, slap_schema.si_ad_objectClass, 2246 &log_container->soc_cname, NULL ); 2247 2248 dnRdn( &e->e_name, &rdn ); 2249 dnRdn( &e->e_nname, &nrdn ); 2250 ptr = ber_bvchr( &rdn, '=' ); 2251 2252 assert( ptr != NULL ); 2253 2254 attr.bv_val = rdn.bv_val; 2255 attr.bv_len = ptr - rdn.bv_val; 2256 2257 slap_bv2ad( &attr, &ad, &text ); 2258 2259 rdn.bv_val = ptr+1; 2260 rdn.bv_len -= attr.bv_len + 1; 2261 ptr = ber_bvchr( &nrdn, '=' ); 2262 nrdn.bv_len -= ptr - nrdn.bv_val + 1; 2263 nrdn.bv_val = ptr+1; 2264 attr_merge_one( e, ad, &rdn, &nrdn ); 2265 2266 /* Get contextCSN from main DB */ 2267 op->o_bd = on->on_info->oi_origdb; 2268 rc = be_entry_get_rw( op, op->o_bd->be_nsuffix, NULL, 2269 slap_schema.si_ad_contextCSN, 0, &e_ctx ); 2270 2271 if ( e_ctx ) { 2272 Attribute *a; 2273 2274 a = attr_find( e_ctx->e_attrs, slap_schema.si_ad_contextCSN ); 2275 if ( a ) { 2276 /* FIXME: contextCSN could have multiple values! 2277 * should select the one with the server's SID */ 2278 attr_merge_one( e, slap_schema.si_ad_entryCSN, 2279 &a->a_vals[0], &a->a_nvals[0] ); 2280 attr_merge( e, a->a_desc, a->a_vals, a->a_nvals ); 2281 } 2282 be_entry_release_rw( op, e_ctx, 0 ); 2283 } 2284 db = *li->li_db; 2285 op->o_bd = &db; 2286 2287 op->ora_e = e; 2288 op->o_req_dn = e->e_name; 2289 op->o_req_ndn = e->e_nname; 2290 op->o_callback = &nullsc; 2291 SLAP_DBFLAGS( op->o_bd ) |= SLAP_DBFLAG_NOLASTMOD; 2292 rc = op->o_bd->be_add( op, &rs ); 2293 if ( e == op->ora_e ) 2294 entry_free( e ); 2295 } 2296 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); 2297 ldap_pvt_runqueue_stoptask( &slapd_rq, rtask ); 2298 ldap_pvt_runqueue_remove( &slapd_rq, rtask ); 2299 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); 2300 2301 return NULL; 2302} 2303 2304static int 2305accesslog_db_open( 2306 BackendDB *be, 2307 ConfigReply *cr 2308) 2309{ 2310 slap_overinst *on = (slap_overinst *)be->bd_info; 2311 log_info *li = on->on_bi.bi_private; 2312 2313 2314 if ( !BER_BVISEMPTY( &li->li_db_suffix )) { 2315 li->li_db = select_backend( &li->li_db_suffix, 0 ); 2316 ch_free( li->li_db_suffix.bv_val ); 2317 BER_BVZERO( &li->li_db_suffix ); 2318 } 2319 if ( li->li_db == NULL ) { 2320 Debug( LDAP_DEBUG_ANY, 2321 "accesslog: \"logdb <suffix>\" missing or invalid.\n", 2322 0, 0, 0 ); 2323 return 1; 2324 } 2325 2326 if ( slapMode & SLAP_TOOL_MODE ) 2327 return 0; 2328 2329 if ( BER_BVISEMPTY( &li->li_db->be_rootndn )) { 2330 ber_dupbv( &li->li_db->be_rootdn, li->li_db->be_suffix ); 2331 ber_dupbv( &li->li_db->be_rootndn, li->li_db->be_nsuffix ); 2332 } 2333 2334 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); 2335 ldap_pvt_runqueue_insert( &slapd_rq, 3600, accesslog_db_root, on, 2336 "accesslog_db_root", li->li_db->be_suffix[0].bv_val ); 2337 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); 2338 2339 return 0; 2340} 2341 2342int accesslog_initialize() 2343{ 2344 int i, rc; 2345 2346 accesslog.on_bi.bi_type = "accesslog"; 2347 accesslog.on_bi.bi_db_init = accesslog_db_init; 2348 accesslog.on_bi.bi_db_destroy = accesslog_db_destroy; 2349 accesslog.on_bi.bi_db_open = accesslog_db_open; 2350 2351 accesslog.on_bi.bi_op_add = accesslog_op_mod; 2352 accesslog.on_bi.bi_op_bind = accesslog_op_bind; 2353 accesslog.on_bi.bi_op_delete = accesslog_op_mod; 2354 accesslog.on_bi.bi_op_modify = accesslog_op_mod; 2355 accesslog.on_bi.bi_op_modrdn = accesslog_op_mod; 2356 accesslog.on_bi.bi_op_unbind = accesslog_unbind; 2357 accesslog.on_bi.bi_op_abandon = accesslog_abandon; 2358 accesslog.on_bi.bi_operational = accesslog_operational; 2359 accesslog.on_response = accesslog_response; 2360 2361 accesslog.on_bi.bi_cf_ocs = log_cfocs; 2362 2363 nullsc.sc_response = slap_null_cb; 2364 2365 rc = config_register_schema( log_cfats, log_cfocs ); 2366 if ( rc ) return rc; 2367 2368 /* log schema integration */ 2369 for ( i=0; lsyntaxes[i].oid; i++ ) { 2370 int code; 2371 2372 code = register_syntax( &lsyntaxes[ i ].syn ); 2373 if ( code != 0 ) { 2374 Debug( LDAP_DEBUG_ANY, 2375 "accesslog_init: register_syntax failed\n", 2376 0, 0, 0 ); 2377 return code; 2378 } 2379 2380 if ( lsyntaxes[i].mrs != NULL ) { 2381 code = mr_make_syntax_compat_with_mrs( 2382 lsyntaxes[i].oid, lsyntaxes[i].mrs ); 2383 if ( code < 0 ) { 2384 Debug( LDAP_DEBUG_ANY, 2385 "accesslog_init: " 2386 "mr_make_syntax_compat_with_mrs " 2387 "failed\n", 2388 0, 0, 0 ); 2389 return code; 2390 } 2391 } 2392 } 2393 2394 for ( i=0; lattrs[i].at; i++ ) { 2395 int code; 2396 2397 code = register_at( lattrs[i].at, lattrs[i].ad, 0 ); 2398 if ( code ) { 2399 Debug( LDAP_DEBUG_ANY, 2400 "accesslog_init: register_at failed\n", 2401 0, 0, 0 ); 2402 return -1; 2403 } 2404#ifndef LDAP_DEVEL 2405 (*lattrs[i].ad)->ad_type->sat_flags |= SLAP_AT_HIDE; 2406#endif 2407 } 2408 2409 for ( i=0; locs[i].ot; i++ ) { 2410 int code; 2411 2412 code = register_oc( locs[i].ot, locs[i].oc, 0 ); 2413 if ( code ) { 2414 Debug( LDAP_DEBUG_ANY, 2415 "accesslog_init: register_oc failed\n", 2416 0, 0, 0 ); 2417 return -1; 2418 } 2419#ifndef LDAP_DEVEL 2420 (*locs[i].oc)->soc_flags |= SLAP_OC_HIDE; 2421#endif 2422 } 2423 2424 return overlay_register(&accesslog); 2425} 2426 2427#if SLAPD_OVER_ACCESSLOG == SLAPD_MOD_DYNAMIC 2428int 2429init_module( int argc, char *argv[] ) 2430{ 2431 return accesslog_initialize(); 2432} 2433#endif 2434 2435#endif /* SLAPD_OVER_ACCESSLOG */ 2436