accesslog.c revision 1.4 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