]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/passwd.c
ITS#2449, broken NOT filters
[openldap] / servers / slapd / back-bdb / passwd.c
1 /* passwd.c - bdb backend password routines */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11 #include <ac/string.h>
12
13 #include "back-bdb.h"
14 #include "external.h"
15 #include "lber_pvt.h"
16
17 int
18 bdb_exop_passwd( Operation *op, SlapReply *rs )
19 {
20         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
21         int rc;
22         Entry *e = NULL;
23         EntryInfo *ei;
24         struct berval hash = { 0, NULL };
25         DB_TXN *ltid = NULL, *lt2;
26         struct bdb_op_info opinfo;
27         char textbuf[SLAP_TEXT_BUFLEN];
28         size_t textlen = sizeof textbuf;
29
30         struct berval id = { 0, NULL };
31         struct berval new = { 0, NULL };
32
33         struct berval dn = { 0, NULL };
34         struct berval ndn = { 0, NULL };
35
36         u_int32_t       locker = 0;
37         DB_LOCK         lock;
38
39         assert( ber_bvcmp( &slap_EXOP_MODIFY_PASSWD, &op->oq_extended.rs_reqoid ) == 0 );
40
41         rc = slap_passwd_parse( op->oq_extended.rs_reqdata,
42                 &id, NULL, &new, &rs->sr_text );
43
44 #ifdef NEW_LOGGING
45         LDAP_LOG ( ACL, ENTRY, 
46                 "==>bdb_exop_passwd: \"%s\"\n", id.bv_val ? id.bv_val : "", 0, 0  );
47 #else
48         Debug( LDAP_DEBUG_ARGS, "==> bdb_exop_passwd: \"%s\"\n",
49                 id.bv_val ? id.bv_val : "", 0, 0 );
50 #endif
51
52         if( rc != LDAP_SUCCESS ) {
53                 goto done;
54         }
55
56         if( new.bv_len == 0 ) {
57                 slap_passwd_generate(&new);
58
59                 if( new.bv_len == 0 ) {
60                         rs->sr_text = "password generation failed.";
61                         rc = LDAP_OTHER;
62                         goto done;
63                 }
64                 
65                 rs->sr_rspdata = slap_passwd_return( &new );
66         }
67
68         slap_passwd_hash( &new, &hash );
69
70         if( hash.bv_len == 0 ) {
71                 rs->sr_text = "password hash failed";
72                 rc = LDAP_OTHER;
73                 goto done;
74         }
75
76         if( id.bv_len ) {
77                 dn = id;
78         } else {
79                 dn = op->o_dn;
80         }
81
82 #ifdef NEW_LOGGING
83         LDAP_LOG ( ACL, DETAIL1, "bdb_exop_passwd: \"%s\"%s\"\n",
84                 dn.bv_val, id.bv_len ? " (proxy)" : "", 0 );
85 #else
86         Debug( LDAP_DEBUG_TRACE, "bdb_exop_passwd: \"%s\"%s\n",
87                 dn.bv_val, id.bv_len ? " (proxy)" : "", 0 );
88 #endif
89
90         if( dn.bv_len == 0 ) {
91                 rs->sr_text = "No password is associated with the Root DSE";
92                 rc = LDAP_UNWILLING_TO_PERFORM;
93                 goto done;
94         }
95
96         rc = dnNormalize2( NULL, &dn, &ndn, op->o_tmpmemctx );
97         if( rc != LDAP_SUCCESS ) {
98                 rs->sr_text = "Invalid DN";
99                 goto done;
100         }
101
102         if( 0 ) {
103 retry:  /* transaction retry */
104                 if ( e != NULL ) {
105                         bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e);
106                 }
107 #ifdef NEW_LOGGING
108                 LDAP_LOG ( ACL, DETAIL1, "bdb_exop_passwd: retrying...\n", 0, 0, 0 );
109 #else
110                 Debug( LDAP_DEBUG_TRACE, "bdb_exop_passwd: retrying...\n", 0, 0, 0 );
111 #endif
112                 rc = TXN_ABORT( ltid );
113                 ltid = NULL;
114                 op->o_private = NULL;
115                 op->o_do_not_cache = opinfo.boi_acl_cache;
116                 if( rc != 0 ) {
117                         rc = LDAP_OTHER;
118                         rs->sr_text = "internal error";
119                         goto done;
120                 }
121                 ldap_pvt_thread_yield();
122         }
123
124         /* begin transaction */
125         rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &ltid, 
126                 bdb->bi_db_opflags );
127         rs->sr_text = NULL;
128         if( rc != 0 ) {
129 #ifdef NEW_LOGGING
130                 LDAP_LOG ( ACL, ERR, 
131                         "bdb_exop_passwd: txn_begin failed: %s (%d)\n", 
132                         db_strerror(rc), rc, 0 );
133 #else
134                 Debug( LDAP_DEBUG_TRACE,
135                         "bdb_exop_passwd: txn_begin failed: %s (%d)\n",
136                         db_strerror(rc), rc, 0 );
137 #endif
138                 rc = LDAP_OTHER;
139                 rs->sr_text = "internal error";
140                 goto done;
141         }
142
143         locker = TXN_ID ( ltid );
144
145         opinfo.boi_bdb = op->o_bd;
146         opinfo.boi_txn = ltid;
147         opinfo.boi_locker = locker;
148         opinfo.boi_err = 0;
149         opinfo.boi_acl_cache = op->o_do_not_cache;
150         op->o_private = &opinfo;
151
152         /* get entry */
153         rc = bdb_dn2entry( op->o_bd, ltid, &ndn, &ei, 0 , locker, &lock, op->o_tmpmemctx );
154
155         switch(rc) {
156         case DB_LOCK_DEADLOCK:
157         case DB_LOCK_NOTGRANTED:
158                 goto retry;
159         case DB_NOTFOUND:
160         case 0:
161                 break;
162         case LDAP_BUSY:
163                 rs->sr_text = "ldap server busy";
164                 goto done;
165         default:
166                 rc = LDAP_OTHER;
167                 rs->sr_text = "internal error";
168                 goto done;
169         }
170
171         if ( ei ) e = ei->bei_e;
172
173         if( e == NULL ) {
174                 rs->sr_text = "could not locate authorization entry";
175                 rc = LDAP_NO_SUCH_OBJECT;
176                 goto done;
177         }
178
179 #ifdef BDB_SUBENTRIES
180         if( is_entry_subentry( e ) ) {
181                 /* entry is an alias, don't allow operation */
182                 rs->sr_text = "authorization entry is subentry";
183                 rc = LDAP_OTHER;
184                 goto done;
185         }
186 #endif
187 #ifdef BDB_ALIASES
188         if( is_entry_alias( e ) ) {
189                 /* entry is an alias, don't allow operation */
190                 rs->sr_text = "authorization entry is alias";
191                 rc = LDAP_ALIAS_PROBLEM;
192                 goto done;
193         }
194 #endif
195
196         if( is_entry_referral( e ) ) {
197                 /* entry is an referral, don't allow operation */
198                 rs->sr_text = "authorization entry is referral";
199                 rc = LDAP_OTHER;
200                 goto done;
201         }
202
203         /* nested transaction */
204         rc = TXN_BEGIN( bdb->bi_dbenv, ltid, &lt2, 
205                 bdb->bi_db_opflags );
206         rs->sr_text = NULL;
207         if( rc != 0 ) {
208 #ifdef NEW_LOGGING
209                 LDAP_LOG ( OPERATION, ERR, 
210                         "bdb_exop_passwd: txn_begin(2) failed: %s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 );
211 #else
212                 Debug( LDAP_DEBUG_TRACE,
213                         "bdb_exop_passwd: txn_begin(2) failed: %s (%d)\n",
214                         db_strerror(rs->sr_err), rs->sr_err, 0 );
215 #endif
216                 rc = LDAP_OTHER;
217                 rs->sr_text = "internal error";
218                 goto done;
219         }
220         {
221                 Modifications ml;
222                 struct berval vals[2];
223                 Entry dummy, *save;
224
225                 save = e;
226                 dummy = *e;
227                 e = &dummy;
228
229                 vals[0] = hash;
230                 vals[1].bv_val = NULL;
231
232                 ml.sml_desc = slap_schema.si_ad_userPassword;
233                 ml.sml_values = vals;
234                 ml.sml_nvalues = NULL;
235                 ml.sml_op = LDAP_MOD_REPLACE;
236                 ml.sml_next = NULL;
237
238                 rc = bdb_modify_internal( op, lt2,
239                         &ml, e, &rs->sr_text, textbuf, textlen );
240
241                 if ( (rc == LDAP_INSUFFICIENT_ACCESS) && opinfo.boi_err ) {
242                         rc = opinfo.boi_err;
243                 }
244                 switch(rc) {
245                 case DB_LOCK_DEADLOCK:
246                 case DB_LOCK_NOTGRANTED:
247                         rs->sr_text = NULL;
248                         goto retry;
249                 case 0:
250                         rs->sr_text = NULL;
251                         break;
252                 default:
253                         rc = LDAP_OTHER;
254                         rs->sr_text = "entry modify failed";
255                         goto done;
256                 }
257
258                 /* change the entry itself */
259                 rc = bdb_id2entry_update( op->o_bd, lt2, e );
260                 if( rc != 0 ) {
261                         switch(rc) {
262                         case DB_LOCK_DEADLOCK:
263                         case DB_LOCK_NOTGRANTED:
264                                 goto retry;
265                         }
266                         rs->sr_text = "entry update failed";
267                         rc = LDAP_OTHER;
268                 }
269                 if ( TXN_COMMIT( lt2, 0 ) != 0 ) {
270                         rc = LDAP_OTHER;
271                         rs->sr_text = "txn_commit(2) failed";
272                 }
273
274                 if( rc == 0 ) {
275                         if( op->o_noop ) {
276                                 rc = TXN_ABORT( ltid );
277                         } else {
278                                 bdb_cache_modify( save, e->e_attrs,
279                                         bdb->bi_dbenv, locker, &lock );
280                                 rc = TXN_COMMIT( ltid, 0 );
281                         }
282                         ltid = NULL;
283                 }
284                 op->o_private = NULL;
285
286                 if( rc == LDAP_SUCCESS ) {
287                         op->o_req_dn = e->e_name;
288                         op->o_req_ndn = e->e_nname;
289                         op->oq_modify.rs_modlist = &ml;
290                         replog( op );
291                         op->oq_extended.rs_reqoid = slap_EXOP_MODIFY_PASSWD;
292                 }
293         }
294
295 done:
296         if( e != NULL ) {
297                 bdb_unlocked_cache_return_entry_w( &bdb->bi_cache, e );
298         }
299                 
300         if( hash.bv_val != NULL ) {
301                 free( hash.bv_val );
302         }
303
304         if( ndn.bv_val != NULL ) {
305                 op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
306         }
307
308         if( ltid != NULL ) {
309                 TXN_ABORT( ltid );
310                 op->o_private = NULL;
311         }
312
313         return rc;
314 }