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