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