]> git.sur5r.net Git - openldap/blob - servers/slapd/overlays/auditlog.c
streamline overlay configuration
[openldap] / servers / slapd / overlays / auditlog.c
1 /* auditlog.c - log modifications for audit/history purposes */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2005 The OpenLDAP Foundation.
6  * Portions copyright 2004-2005 Symas Corporation.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* ACKNOWLEDGEMENTS:
18  * This work was initially developed by Symas Corp. for inclusion in
19  * OpenLDAP Software.  This work was sponsored by Hewlett-Packard.
20  */
21
22 #include "portable.h"
23
24 #ifdef SLAPD_OVER_AUDITLOG
25
26 #include <stdio.h>
27
28 #include <ac/string.h>
29 #include <ac/ctype.h>
30
31 #include "slap.h"
32 #include "ldif.h"
33
34 typedef struct auditlog_data {
35         ldap_pvt_thread_mutex_t ad_mutex;
36         char *ad_logfile;
37 } auditlog_data;
38
39 int fprint_ldif(FILE *f, char *name, char *val, ber_len_t len) {
40         char *s;
41         if((s = ldif_put(LDIF_PUT_VALUE, name, val, len)) == NULL)
42                 return(-1);
43         fputs(s, f);
44         ber_memfree(s);
45         return(0);
46 }
47
48 int auditlog_response(Operation *op, SlapReply *rs) {
49         slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
50         auditlog_data *ad = on->on_bi.bi_private;
51         FILE *f;
52         Attribute *a;
53         Modifications *m;
54         struct berval *b;
55         char *what, *subop, *suffix, *who = NULL;
56         long stamp = slap_get_time();
57         int i;
58
59         if ( rs->sr_err != LDAP_SUCCESS ) return SLAP_CB_CONTINUE;
60
61         if ( !op->o_bd || !ad->ad_logfile ) return SLAP_CB_CONTINUE;
62
63 /*
64 ** add or modify: use modifiersName if present
65 **
66 */
67         switch(op->o_tag) {
68                 case LDAP_REQ_MODRDN:   what = "modrdn";        break;
69                 case LDAP_REQ_DELETE:   what = "delete";        break;
70                 case LDAP_REQ_ADD:
71                         what = "add";
72                         for(a = op->ora_e->e_attrs; a; a = a->a_next)
73                                 if( a->a_desc == slap_schema.si_ad_modifiersName ) {
74                                         who = a->a_vals[0].bv_val;
75                                         break;
76                                 }
77                         break;
78                 case LDAP_REQ_MODIFY:
79                         what = "modify";
80                         for(m = op->orm_modlist; m; m = m->sml_next)
81                                 if( m->sml_desc == slap_schema.si_ad_modifiersName ) {
82                                         who = m->sml_values[0].bv_val;
83                                         break;
84                                 }
85                         break;
86                 default:
87                         return SLAP_CB_CONTINUE;
88         }
89
90         suffix = op->o_bd->be_suffix[0].bv_len ? op->o_bd->be_suffix[0].bv_val :
91                 "global";
92
93 /*
94 ** note: this means requestor's dn when modifiersName is null
95 */
96         if ( !who )
97                 who = op->o_dn.bv_val;
98
99         ldap_pvt_thread_mutex_lock(&ad->ad_mutex);
100         if((f = fopen(ad->ad_logfile, "a")) == NULL) {
101                 ldap_pvt_thread_mutex_unlock(&ad->ad_mutex);
102                 return SLAP_CB_CONTINUE;
103         }
104
105         fprintf(f, "# %s %ld %s%s%s\ndn: %s\nchangetype: %s\n",
106                 what, stamp, suffix, who ? " " : "", who ? who : "",
107                 op->o_req_dn.bv_val, what);
108
109         switch(op->o_tag) {
110           case LDAP_REQ_ADD:
111                 for(a = op->ora_e->e_attrs; a; a = a->a_next)
112                     if(b = a->a_vals)
113                         for(i = 0; b[i].bv_val; i++)
114                                 fprint_ldif(f, a->a_desc->ad_cname.bv_val, b[i].bv_val, b[i].bv_len);
115                 break;
116
117           case LDAP_REQ_MODIFY:
118                 for(m = op->orm_modlist; m; m = m->sml_next) {
119                         switch(m->sml_op & LDAP_MOD_OP) {
120                                 case LDAP_MOD_ADD:       what = "add";          break;
121                                 case LDAP_MOD_REPLACE:   what = "replace";      break;
122                                 case LDAP_MOD_DELETE:    what = "delete";       break;
123                                 case LDAP_MOD_INCREMENT: what = "increment";    break;
124                                 default:
125                                         fprintf(f, "# MOD_TYPE_UNKNOWN:%02x\n", m->sml_op & LDAP_MOD_OP);
126                                         continue;
127                         }
128                         fprintf(f, "%s: %s\n", what, m->sml_desc->ad_cname.bv_val);
129                         if(b = m->sml_values) for(i = 0; b[i].bv_val; i++)
130                                 fprint_ldif(f, m->sml_desc->ad_cname.bv_val, b[i].bv_val, b[i].bv_len);
131                         fprintf(f, "-\n");
132                 }
133                 break;
134
135           case LDAP_REQ_MODRDN:
136                 fprintf(f, "newrdn: %s\ndeleteoldrdn: %s\n",
137                         op->orr_newrdn.bv_val, op->orr_deleteoldrdn ? "1" : "0");
138                 if(op->orr_newSup) fprintf(f, "newsuperior: %s\n", op->orr_newSup->bv_val);
139                 break;
140
141           case LDAP_REQ_DELETE:
142                 /* nothing else needed */
143                 break;
144         }
145
146         fprintf(f, "# end %s %ld\n\n", what, stamp);
147
148         fclose(f);
149         ldap_pvt_thread_mutex_unlock(&ad->ad_mutex);
150         return SLAP_CB_CONTINUE;
151 }
152
153 static slap_overinst auditlog;
154
155 static int
156 auditlog_db_init(
157         BackendDB *be
158 )
159 {
160         slap_overinst *on = (slap_overinst *)be->bd_info;
161         auditlog_data *ad = ch_malloc(sizeof(auditlog_data));
162
163         on->on_bi.bi_private = ad;
164         ldap_pvt_thread_mutex_init( &ad->ad_mutex );
165         return 0;
166 }
167
168 static int
169 auditlog_db_close(
170         BackendDB *be
171 )
172 {
173         slap_overinst *on = (slap_overinst *)be->bd_info;
174         auditlog_data *ad = on->on_bi.bi_private;
175
176         free( ad->ad_logfile );
177         ad->ad_logfile = NULL;
178 }
179
180 static int
181 auditlog_db_destroy(
182         BackendDB *be
183 )
184 {
185         slap_overinst *on = (slap_overinst *)be->bd_info;
186         auditlog_data *ad = on->on_bi.bi_private;
187
188         ldap_pvt_thread_mutex_destroy( &ad->ad_mutex );
189         free( ad );
190 }
191
192 static int
193 auditlog_config(
194         BackendDB       *be,
195         const char      *fname,
196         int             lineno,
197         int             argc,
198         char    **argv
199 )
200 {
201         slap_overinst *on = (slap_overinst *) be->bd_info;
202         auditlog_data *ad = on->on_bi.bi_private;
203
204         /* history log file */
205         if ( strcasecmp( argv[0], "auditlog" ) == 0 ) {
206                 if ( argc < 2 ) {
207                         Debug( LDAP_DEBUG_ANY,
208             "%s: line %d: missing filename in \"auditlog <filename>\" line\n",
209                             fname, lineno, 0 );
210                                 return( 1 );
211                 }
212                 ad->ad_logfile = ch_strdup( argv[1] );
213                 return 0;
214         }
215         return SLAP_CONF_UNKNOWN;
216 }
217
218 int auditlog_initialize() {
219
220         auditlog.on_bi.bi_type = "auditlog";
221         auditlog.on_bi.bi_db_init = auditlog_db_init;
222         auditlog.on_bi.bi_db_config = auditlog_config;
223         auditlog.on_bi.bi_db_close = auditlog_db_close;
224         auditlog.on_bi.bi_db_destroy = auditlog_db_destroy;
225         auditlog.on_response = auditlog_response;
226
227         return overlay_register(&auditlog);
228 }
229
230 #if SLAPD_OVER_AUDITLOG == SLAPD_MOD_DYNAMIC && defined(PIC)
231 int
232 init_module( int argc, char *argv[] )
233 {
234         return auditlog_initialize();
235 }
236 #endif
237
238 #endif /* SLAPD_OVER_AUDITLOG */