]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/passwd.c
33803ff633ce0684c92523c6e236fbc42953caf1
[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
16 int
17 bdb_exop_passwd(
18         Backend         *be,
19         Connection              *conn,
20         Operation               *op,
21         const char              *reqoid,
22         struct berval   *reqdata,
23         char                    **rspoid,
24         struct berval   **rspdata,
25         LDAPControl             *** rspctrls,
26         const char              **text,
27         BerVarray *refs )
28 {
29         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
30         int rc;
31         Entry *e = NULL;
32         struct berval hash = { 0, NULL };
33         DB_TXN *ltid = NULL;
34         struct bdb_op_info opinfo;
35         char textbuf[SLAP_TEXT_BUFLEN];
36         size_t textlen = sizeof textbuf;
37
38         struct berval id = { 0, NULL };
39         struct berval new = { 0, NULL };
40
41         struct berval dn;
42         struct berval ndn;
43
44         u_int32_t       locker = 0;
45         DB_LOCK         lock;
46
47         assert( reqoid != NULL );
48         assert( strcmp( LDAP_EXOP_MODIFY_PASSWD, reqoid ) == 0 );
49
50         rc = slap_passwd_parse( reqdata,
51                 &id, NULL, &new, text );
52
53 #ifdef NEW_LOGGING
54         LDAP_LOG ( ACL, ENTRY, 
55                 "==>bdb_exop_passwd: \"%s\"\n", id.bv_val ? id.bv_val : "", 0, 0  );
56 #else
57         Debug( LDAP_DEBUG_ARGS, "==> bdb_exop_passwd: \"%s\"\n",
58                 id.bv_val ? id.bv_val : "", 0, 0 );
59 #endif
60
61         if( rc != LDAP_SUCCESS ) {
62                 goto done;
63         }
64
65         if( new.bv_len == 0 ) {
66                 slap_passwd_generate(&new);
67
68                 if( new.bv_len == 0 ) {
69                         *text = "password generation failed.";
70                         rc = LDAP_OTHER;
71                         goto done;
72                 }
73                 
74                 *rspdata = slap_passwd_return( &new );
75         }
76
77         slap_passwd_hash( &new, &hash );
78
79         if( hash.bv_len == 0 ) {
80                 *text = "password hash failed";
81                 rc = LDAP_OTHER;
82                 goto done;
83         }
84
85         if( id.bv_len ) {
86                 dn = id;
87         } else {
88                 dn = op->o_dn;
89         }
90
91 #ifdef NEW_LOGGING
92         LDAP_LOG ( ACL, DETAIL1, "bdb_exop_passwd: \"%s\"%s\"\n",
93                 dn.bv_val, id.bv_len ? " (proxy)" : "", 0 );
94 #else
95         Debug( LDAP_DEBUG_TRACE, "bdb_exop_passwd: \"%s\"%s\n",
96                 dn.bv_val, id.bv_len ? " (proxy)" : "", 0 );
97 #endif
98
99         if( dn.bv_len == 0 ) {
100                 *text = "No password is associated with the Root DSE";
101                 rc = LDAP_UNWILLING_TO_PERFORM;
102                 goto done;
103         }
104
105         rc = dnNormalize2( NULL, &dn, &ndn );
106         if( rc != LDAP_SUCCESS ) {
107                 *text = "Invalid DN";
108                 goto done;
109         }
110
111         if( 0 ) {
112 retry:  /* transaction retry */
113                 if ( e != NULL ) {
114                         bdb_cache_delete_entry(&bdb->bi_cache, e);
115                         bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e);
116                 }
117 #ifdef NEW_LOGGING
118                 LDAP_LOG ( ACL, DETAIL1, "bdb_exop_passwd: retrying...\n", 0, 0, 0 );
119 #else
120                 Debug( LDAP_DEBUG_TRACE, "bdb_exop_passwd: retrying...\n", 0, 0, 0 );
121 #endif
122                 rc = TXN_ABORT( ltid );
123                 ltid = NULL;
124                 op->o_private = NULL;
125                 op->o_do_not_cache = opinfo.boi_acl_cache;
126                 if( rc != 0 ) {
127                         rc = LDAP_OTHER;
128                         *text = "internal error";
129                         goto done;
130                 }
131                 ldap_pvt_thread_yield();
132         }
133
134         /* begin transaction */
135         rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &ltid, 
136                 bdb->bi_db_opflags );
137         *text = NULL;
138         if( rc != 0 ) {
139 #ifdef NEW_LOGGING
140                 LDAP_LOG ( ACL, ERR, 
141                         "bdb_exop_passwd: txn_begin failed: %s (%d)\n", 
142                         db_strerror(rc), rc, 0 );
143 #else
144                 Debug( LDAP_DEBUG_TRACE,
145                         "bdb_exop_passwd: txn_begin failed: %s (%d)\n",
146                         db_strerror(rc), rc, 0 );
147 #endif
148                 rc = LDAP_OTHER;
149                 *text = "internal error";
150                 goto done;
151         }
152
153         locker = TXN_ID ( ltid );
154
155         opinfo.boi_bdb = be;
156         opinfo.boi_txn = ltid;
157         opinfo.boi_locker = locker;
158         opinfo.boi_err = 0;
159         opinfo.boi_acl_cache = op->o_do_not_cache;
160         op->o_private = &opinfo;
161
162         /* get entry */
163         rc = bdb_dn2entry_w( be, ltid, &ndn, &e, NULL, 0 , locker, &lock);
164
165         switch(rc) {
166         case DB_LOCK_DEADLOCK:
167         case DB_LOCK_NOTGRANTED:
168                 goto retry;
169         case DB_NOTFOUND:
170         case 0:
171                 break;
172         case LDAP_BUSY:
173                 *text = "ldap server busy";
174                 goto done;
175         default:
176                 rc = LDAP_OTHER;
177                 *text = "internal error";
178                 goto done;
179         }
180
181         if( e == NULL ) {
182                 *text = "could not locate authorization entry";
183                 rc = LDAP_NO_SUCH_OBJECT;
184                 goto done;
185         }
186
187 #ifdef BDB_SUBENTRIES
188         if( is_entry_subentry( e ) ) {
189                 /* entry is an alias, don't allow operation */
190                 *text = "authorization entry is subentry";
191                 rc = LDAP_OTHER;
192                 goto done;
193         }
194 #endif
195 #ifdef BDB_ALIASES
196         if( is_entry_alias( e ) ) {
197                 /* entry is an alias, don't allow operation */
198                 *text = "authorization entry is alias";
199                 rc = LDAP_ALIAS_PROBLEM;
200                 goto done;
201         }
202 #endif
203
204         if( is_entry_referral( e ) ) {
205                 /* entry is an referral, don't allow operation */
206                 *text = "authorization entry is referral";
207                 rc = LDAP_OTHER;
208                 goto done;
209         }
210
211         {
212                 Modifications ml;
213                 struct berval vals[2];
214
215                 vals[0] = hash;
216                 vals[1].bv_val = NULL;
217
218                 ml.sml_desc = slap_schema.si_ad_userPassword;
219                 ml.sml_bvalues = vals;
220                 ml.sml_op = LDAP_MOD_REPLACE;
221                 ml.sml_next = NULL;
222
223                 rc = bdb_modify_internal( be, conn, op, ltid,
224                         &ml, e, text, textbuf, textlen );
225
226                 if ( (rc == LDAP_INSUFFICIENT_ACCESS) && opinfo.boi_err ) {
227                         rc = opinfo.boi_err;
228                 }
229                 switch(rc) {
230                 case DB_LOCK_DEADLOCK:
231                 case DB_LOCK_NOTGRANTED:
232                         *text = NULL;
233                         goto retry;
234                 case 0:
235                         *text = NULL;
236                         break;
237                 default:
238                         rc = LDAP_OTHER;
239                         *text = "entry modify failed";
240                         goto done;
241                 }
242
243                 /* change the entry itself */
244                 rc = bdb_id2entry_update( be, ltid, e );
245                 if( rc != 0 ) {
246                         switch(rc) {
247                         case DB_LOCK_DEADLOCK:
248                         case DB_LOCK_NOTGRANTED:
249                                 goto retry;
250                         }
251                         *text = "entry update failed";
252                         rc = LDAP_OTHER;
253                 }
254
255                 if( rc == 0 ) {
256                         if( op->o_noop ) {
257                                 rc = TXN_ABORT( ltid );
258                         } else {
259                                 rc = TXN_COMMIT( ltid, 0 );
260                         }
261                         ltid = NULL;
262                 }
263                 op->o_private = NULL;
264
265                 if( rc == LDAP_SUCCESS ) {
266                         replog( be, op, &e->e_name, &e->e_nname, &ml );
267                 }
268         }
269
270 done:
271         if( e != NULL ) {
272                 bdb_unlocked_cache_return_entry_w( &bdb->bi_cache, e );
273         }
274                 
275         if( hash.bv_val != NULL ) {
276                 free( hash.bv_val );
277         }
278
279         if( ltid != NULL ) {
280                 TXN_ABORT( ltid );
281                 op->o_private = NULL;
282         }
283
284         return rc;
285 }