r13589: Make sure we only try to close the tdbsam file in endsampwent() when we
[tprouty/samba.git] / source3 / passdb / pdb_tdb.c
1 /*
2  * Unix SMB/CIFS implementation. 
3  * SMB parameters and setup
4  * Copyright (C) Andrew Tridgell   1992-1998
5  * Copyright (C) Simo Sorce        2000-2003
6  * Copyright (C) Gerald Carter     2000-2006
7  * Copyright (C) Jeremy Allison    2001
8  * Copyright (C) Andrew Bartlett   2002
9  * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2005
10  * 
11  * This program is free software; you can redistribute it and/or modify it under
12  * the terms of the GNU General Public License as published by the Free
13  * Software Foundation; either version 2 of the License, or (at your option)
14  * any later version.
15  * 
16  * This program is distributed in the hope that it will be useful, but WITHOUT
17  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
19  * more details.
20  * 
21  * You should have received a copy of the GNU General Public License along with
22  * this program; if not, write to the Free Software Foundation, Inc., 675
23  * Mass Ave, Cambridge, MA 02139, USA.
24  */
25
26 #include "includes.h"
27
28 #if 0 /* when made a module use this */
29
30 static int tdbsam_debug_level = DBGC_ALL;
31 #undef DBGC_CLASS
32 #define DBGC_CLASS tdbsam_debug_level
33
34 #else
35
36 #undef DBGC_CLASS
37 #define DBGC_CLASS DBGC_PASSDB
38
39 #endif
40
41 #define TDBSAM_VERSION  2       /* Most recent TDBSAM version */
42 #define TDBSAM_VERSION_STRING   "INFO/version"
43 #define PASSDB_FILE_NAME        "passdb.tdb"
44 #define USERPREFIX              "USER_"
45 #define RIDPREFIX               "RID_"
46 #define PRIVPREFIX              "PRIV_"
47
48 struct pwent_list {
49         struct pwent_list *prev, *next;
50         TDB_DATA key;
51 };
52 static struct pwent_list *tdbsam_pwent_list;
53 static BOOL pwent_initialized;
54
55 /* GLOBAL TDB SAM CONTEXT */
56
57 static TDB_CONTEXT *tdbsam;
58 static int ref_count = 0;
59 static pstring tdbsam_filename;
60
61 /**
62  * Convert old TDBSAM to the latest version.
63  * @param pdb_tdb A pointer to the opened TDBSAM file which must be converted. 
64  *                This file must be opened with read/write access.
65  * @param from Current version of the TDBSAM file.
66  * @return True if the conversion has been successful, false otherwise. 
67  **/
68
69 static BOOL tdbsam_convert(int32 from) 
70 {
71         const char      *vstring = TDBSAM_VERSION_STRING;
72         const char      *prefix = USERPREFIX;
73         TDB_DATA        data, key, old_key;
74         uint8           *buf = NULL;
75         BOOL            ret;
76
77         /* handle a Samba upgrade */
78         tdb_lock_bystring(tdbsam, vstring, 0);
79         
80         /* Enumerate all records and convert them */
81         key = tdb_firstkey(tdbsam);
82
83         while (key.dptr) {
84         
85                 /* skip all non-USER entries (eg. RIDs) */
86                 while ((key.dsize != 0) && (strncmp(key.dptr, prefix, strlen (prefix)))) {
87                         old_key = key;
88                         /* increment to next in line */
89                         key = tdb_nextkey(tdbsam, key);
90                         SAFE_FREE(old_key.dptr);
91                 }
92         
93                 if (key.dptr) {
94                         struct samu *user = NULL;
95
96                         /* read from tdbsam */
97                         data = tdb_fetch(tdbsam, key);
98                         if (!data.dptr) {
99                                 DEBUG(0,("tdbsam_convert: database entry not found: %s.\n",key.dptr));
100                                 return False;
101                         }
102         
103                         /* unpack the buffer from the former format */
104                         pdb_init_sam( &user );
105                         DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) (version:%d)\n", key.dptr, from));
106                         switch (from) {
107                                 case 0:
108                                         ret = init_sam_from_buffer_v0(user, (uint8 *)data.dptr, data.dsize);
109                                         break;
110                                 case 1:
111                                         ret = init_sam_from_buffer_v1(user, (uint8 *)data.dptr, data.dsize);
112                                         break;
113                                 case 2:
114                                         ret = init_sam_from_buffer_v2(user, (uint8 *)data.dptr, data.dsize);
115                                         break;
116                                 default:
117                                         /* unknown tdbsam version */
118                                         ret = False;
119                         }
120                         if (!ret) {
121                                 DEBUG(0,("tdbsam_convert: Bad struct samu entry returned from TDB (key:%s) (version:%d)\n", key.dptr, from));
122                                 SAFE_FREE(data.dptr);
123                                 TALLOC_FREE(user );
124                                 return False;
125                         }
126         
127                         /* We're finished with the old data. */
128                         SAFE_FREE(data.dptr);
129
130                         /* pack from the buffer into the new format */
131                         
132                         DEBUG(10,("tdbsam_convert: Try packing a record (key:%s) (version:%d)\n", key.dptr, from));
133                         data.dsize = init_buffer_from_sam (&buf, user, False);
134                         TALLOC_FREE(user );
135                         
136                         if ( data.dsize == -1 ) {
137                                 DEBUG(0,("tdbsam_convert: cannot pack the struct samu into the new format\n"));
138                                 return False;
139                         }
140                         data.dptr = (char *)buf;
141                         
142                         /* Store the buffer inside the TDBSAM */
143                         if (tdb_store(tdbsam, key, data, TDB_MODIFY) != TDB_SUCCESS) {
144                                 DEBUG(0,("tdbsam_convert: cannot store the struct samu (key:%s) in new format\n",key.dptr));
145                                 SAFE_FREE(data.dptr);
146                                 return False;
147                         }
148                         
149                         SAFE_FREE(data.dptr);
150                         
151                         /* increment to next in line */
152                         old_key = key;
153                         key = tdb_nextkey(tdbsam, key);
154                         SAFE_FREE(old_key.dptr);
155                 }
156                 
157         }
158
159         
160         /* upgrade finished */
161         tdb_store_int32(tdbsam, vstring, TDBSAM_VERSION);
162         tdb_unlock_bystring(tdbsam, vstring);
163
164         return(True);   
165 }
166
167 /*********************************************************************
168  Open the tdbsam file based on the absolute path specified.
169  Uses a reference count to allow multiple open calls.
170 *********************************************************************/
171
172 static BOOL tdbsam_open( const char *name )
173 {
174         int32   version;
175         
176         /* check if we are already open */
177         
178         if ( tdbsam ) {
179                 ref_count++;
180                 DEBUG(8,("tdbsam_open: Incrementing open reference count.  Ref count is now %d\n", 
181                         ref_count));
182                 return True;
183         }
184         
185         SMB_ASSERT( ref_count == 0 );
186         
187         /* Try to open tdb passwd.  Create a new one if necessary */
188         
189         if (!(tdbsam = tdb_open_log(name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600))) {
190                 DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd [%s]\n", name));
191                 return False;
192         }
193
194         /* Check the version */
195         version = tdb_fetch_int32( tdbsam, TDBSAM_VERSION_STRING );
196         
197         if (version == -1)
198                 version = 0;    /* Version not found, assume version 0 */
199         
200         /* Compare the version */
201         if (version > TDBSAM_VERSION) {
202                 /* Version more recent than the latest known */ 
203                 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
204                 tdb_close( tdbsam );
205                 return False;
206         } 
207         
208         
209         if ( version < TDBSAM_VERSION ) {       
210                 DEBUG(1, ("tdbsam_open: Converting version %d database to version %d.\n", 
211                         version, TDBSAM_VERSION));
212                 
213                 if ( !tdbsam_convert(version) ) {
214                         DEBUG(0, ("tdbsam_open: Error when trying to convert tdbsam [%s]\n",name));
215                         tdb_close(tdbsam);
216                         return False;
217                 }
218                         
219                 DEBUG(3, ("TDBSAM converted successfully.\n"));
220         }
221         
222         /* set the initial reference count */
223
224         ref_count = 1;
225
226         DEBUG(4,("tdbsam_open: successfully opened %s\n", name ));      
227         
228         return True;
229 }
230
231 /****************************************************************************
232  wrapper atound tdb_close() to handle the reference count
233 ****************************************************************************/
234
235 void tdbsam_close( void )
236 {
237         ref_count--;
238         
239         DEBUG(8,("tdbsam_close: Reference count is now %d.\n", ref_count));
240
241         SMB_ASSERT(ref_count >= 0 );
242         
243         if ( ref_count == 0 ) {
244                 tdb_close( tdbsam );
245                 tdbsam = NULL;
246         }
247         
248         return;
249 }
250
251 /****************************************************************************
252  creates a list of user keys
253 ****************************************************************************/
254
255 static int tdbsam_traverse_setpwent(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state)
256 {
257         const char *prefix = USERPREFIX;
258         int  prefixlen = strlen (prefix);
259         struct pwent_list *ptr;
260         
261         if ( strncmp(key.dptr, prefix, prefixlen) == 0 ) {
262                 if ( !(ptr=SMB_MALLOC_P(struct pwent_list)) ) {
263                         DEBUG(0,("tdbsam_traverse_setpwent: Failed to malloc new entry for list\n"));
264                         
265                         /* just return 0 and let the traversal continue */
266                         return 0;
267                 }
268                 ZERO_STRUCTP(ptr);
269                 
270                 /* save a copy of the key */
271                 
272                 ptr->key.dptr = memdup( key.dptr, key.dsize );
273                 ptr->key.dsize = key.dsize;
274                 
275                 DLIST_ADD( tdbsam_pwent_list, ptr );
276         
277         }
278         
279         
280         return 0;
281 }
282
283 /***************************************************************
284  Open the TDB passwd database for SAM account enumeration.
285  Save a list of user keys for iteration.
286 ****************************************************************/
287
288 static NTSTATUS tdbsam_setsampwent(struct pdb_methods *my_methods, BOOL update, uint16 acb_mask)
289 {
290         if ( !tdbsam_open( tdbsam_filename ) ) {
291                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
292                 return NT_STATUS_ACCESS_DENIED;
293         }
294
295         tdb_traverse( tdbsam, tdbsam_traverse_setpwent, NULL );
296         pwent_initialized = True;
297
298         return NT_STATUS_OK;
299 }
300
301
302 /***************************************************************
303  End enumeration of the TDB passwd list.
304 ****************************************************************/
305
306 static void tdbsam_endsampwent(struct pdb_methods *my_methods)
307 {
308         struct pwent_list *ptr, *ptr_next;
309         
310         /* close the tdb only if we have a valid pwent state */
311         
312         if ( pwent_initialized ) {
313                 DEBUG(7, ("endtdbpwent: closed sam database.\n"));
314                 tdbsam_close();
315         }
316         
317         /* clear out any remaining entries in the list */
318         
319         for ( ptr=tdbsam_pwent_list; ptr; ptr = ptr_next ) {
320                 ptr_next = ptr->next;
321                 DLIST_REMOVE( tdbsam_pwent_list, ptr );
322                 SAFE_FREE( ptr->key.dptr);
323                 SAFE_FREE( ptr );
324         }       
325         
326         pwent_initialized = False;
327 }
328
329 /*****************************************************************
330  Get one struct samu from the TDB (next in line)
331 *****************************************************************/
332
333 static NTSTATUS tdbsam_getsampwent(struct pdb_methods *my_methods, struct samu *user)
334 {
335         NTSTATUS                nt_status = NT_STATUS_UNSUCCESSFUL;
336         TDB_DATA                data;
337         struct pwent_list       *pkey;
338
339         if ( !user ) {
340                 DEBUG(0,("tdbsam_getsampwent: struct samu is NULL.\n"));
341                 return nt_status;
342         }
343
344         if ( !tdbsam_pwent_list ) {
345                 DEBUG(4,("tdbsam_getsampwent: end of list\n"));
346                 return nt_status;
347         }
348         
349         /* pull the next entry */
350                 
351         pkey = tdbsam_pwent_list;
352         DLIST_REMOVE( tdbsam_pwent_list, pkey );
353         
354         data = tdb_fetch(tdbsam, pkey->key);
355
356         SAFE_FREE( pkey->key.dptr);
357         SAFE_FREE( pkey);
358         
359         if ( !data.dptr ) {
360                 DEBUG(5,("pdb_getsampwent: database entry not found.  Was the user deleted?\n"));
361                 return nt_status;
362         }
363   
364         if ( !init_sam_from_buffer(user, (unsigned char *)data.dptr, data.dsize) ) {
365                 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
366         }
367         
368         SAFE_FREE( data.dptr );
369
370         return NT_STATUS_OK;
371 }
372
373 /******************************************************************
374  Lookup a name in the SAM TDB
375 ******************************************************************/
376
377 static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods, struct samu *user, const char *sname)
378 {
379         NTSTATUS        result;
380         TDB_DATA        data, key;
381         fstring         keystr;
382         fstring         name;
383
384         if ( !user ) {
385                 DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
386                 return NT_STATUS_NO_MEMORY;
387         }
388
389         /* Data is stored in all lower-case */
390         fstrcpy(name, sname);
391         strlower_m(name);
392
393         /* set search key */
394         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
395         key.dptr = keystr;
396         key.dsize = strlen(keystr) + 1;
397
398         /* open the database */
399                 
400         if ( !tdbsam_open( tdbsam_filename ) ) {
401                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
402                 return NT_STATUS_ACCESS_DENIED;
403         }
404         
405         /* get the record */
406         
407         data = tdb_fetch(tdbsam, key);
408         if (!data.dptr) {
409                 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
410                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
411                 DEBUGADD(5, (" Key: %s\n", keystr));
412                 result = NT_STATUS_NO_SUCH_USER;
413                 goto done;
414         }
415   
416         /* unpack the buffer */
417         
418         if (!init_sam_from_buffer(user, (unsigned char *)data.dptr, data.dsize)) {
419                 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
420                 SAFE_FREE(data.dptr);
421                 result = NT_STATUS_NO_MEMORY;
422                 goto done;
423         }
424         
425         result = NT_STATUS_OK;
426         
427  done:
428         SAFE_FREE(data.dptr);
429         tdbsam_close();
430         
431         return result;
432 }
433
434 /***************************************************************************
435  Search by rid
436  **************************************************************************/
437
438 static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods, struct samu *user, uint32 rid)
439 {
440         NTSTATUS                nt_status = NT_STATUS_UNSUCCESSFUL;
441         TDB_DATA                data, key;
442         fstring                 keystr;
443         fstring                 name;
444
445         if ( !user ) {
446                 DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
447                 return nt_status;
448         }
449         
450         /* set search key */
451         
452         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
453         key.dptr = keystr;
454         key.dsize = strlen (keystr) + 1;
455
456         /* open the database */
457                 
458         if ( !tdbsam_open( tdbsam_filename ) ) {
459                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
460                 return NT_STATUS_ACCESS_DENIED;
461         }
462
463         /* get the record */
464         
465         data = tdb_fetch (tdbsam, key);
466         if (!data.dptr) {
467                 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
468                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
469                 nt_status = NT_STATUS_UNSUCCESSFUL;
470                 goto done;
471         }
472
473         fstrcpy(name, data.dptr);
474         SAFE_FREE(data.dptr);
475         
476         nt_status = tdbsam_getsampwnam (my_methods, user, name);
477
478  done:
479         /* cleanup */
480         
481         tdbsam_close();
482                 
483         return nt_status;
484 }
485
486 static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods, struct samu * user, const DOM_SID *sid)
487 {
488         uint32 rid;
489         
490         if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) )
491                 return NT_STATUS_UNSUCCESSFUL;
492
493         return tdbsam_getsampwrid(my_methods, user, rid);
494 }
495
496 static BOOL tdb_delete_samacct_only( struct samu *sam_pass )
497 {
498         TDB_DATA        key;
499         fstring         keystr;
500         fstring         name;
501
502         fstrcpy(name, pdb_get_username(sam_pass));
503         strlower_m(name);
504         
505         /* set the search key */
506         
507         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
508         key.dptr = keystr;
509         key.dsize = strlen (keystr) + 1;
510         
511         /* it's outaa here!  8^) */
512         
513         if (tdb_delete(tdbsam, key) != TDB_SUCCESS) {
514                 DEBUG(5, ("Error deleting entry from tdb passwd database!\n"));
515                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
516                 return False;
517         }
518         
519         return True;
520 }
521
522 /***************************************************************************
523  Delete a struct samu records for the username and RID key
524 ****************************************************************************/
525
526 static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods, struct samu *sam_pass)
527 {
528         NTSTATUS        nt_status = NT_STATUS_UNSUCCESSFUL;
529         TDB_DATA        key;
530         fstring         keystr;
531         uint32          rid;
532         fstring         name;
533         
534         /* make sure we have an open handle to the tdb.  Should have happened 
535            at module  initialization time */
536            
537         if ( !tdbsam ) {
538                 DEBUG(0,("tdbsam_getsampwrid: tdbsam not open!\n"));
539                 return NT_STATUS_NO_SUCH_USER;
540         }
541
542         fstrcpy(name, pdb_get_username(sam_pass));
543         strlower_m(name);
544         
545         /* set the search key */
546
547         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
548         key.dptr = keystr;
549         key.dsize = strlen (keystr) + 1;
550         
551         rid = pdb_get_user_rid(sam_pass);
552
553         /* open the database */
554                 
555         if ( !tdbsam_open( tdbsam_filename ) ) {
556                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
557                 return NT_STATUS_ACCESS_DENIED;
558         }
559         
560         /* it's outaa here!  8^) */
561
562         if ( tdb_delete(tdbsam, key) != TDB_SUCCESS ) {
563                 DEBUG(5, ("Error deleting entry from tdb passwd database!\n"));
564                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
565                 nt_status = NT_STATUS_UNSUCCESSFUL;
566                 goto done;
567         }
568
569         /* set the search key */
570         
571         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
572         key.dptr = keystr;
573         key.dsize = strlen (keystr) + 1;
574
575         /* it's outaa here!  8^) */
576         
577         if ( tdb_delete(tdbsam, key) != TDB_SUCCESS ) {
578                 DEBUG(5, ("Error deleting entry from tdb rid database!\n"));
579                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
580                 nt_status = NT_STATUS_UNSUCCESSFUL;
581                 goto done;
582         }
583
584         nt_status = NT_STATUS_OK;
585         
586  done:
587         tdbsam_close();
588         
589         return nt_status;
590 }
591
592
593 /***************************************************************************
594  Update the TDB SAM account record only
595  Assumes that the tdbsam is already open 
596 ****************************************************************************/
597 static BOOL tdb_update_samacct_only( struct samu* newpwd, int flag )
598 {
599         TDB_DATA        key, data;
600         uint8           *buf = NULL;
601         fstring         keystr;
602         fstring         name;
603         BOOL            ret = True;
604
605         /* copy the struct samu struct into a BYTE buffer for storage */
606         
607         if ( (data.dsize=init_buffer_from_sam (&buf, newpwd, False)) == -1 ) {
608                 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
609                 ret = False;
610                 goto done;
611         }
612         data.dptr = (char *)buf;
613
614         fstrcpy(name, pdb_get_username(newpwd));
615         strlower_m(name);
616         
617         DEBUG(5, ("Storing %saccount %s with RID %d\n", 
618                   flag == TDB_INSERT ? "(new) " : "", name, 
619                   pdb_get_user_rid(newpwd)));
620
621         /* setup the USER index key */
622         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
623         key.dptr = keystr;
624         key.dsize = strlen(keystr) + 1;
625
626         /* add the account */
627         
628         if ( tdb_store(tdbsam, key, data, flag) != TDB_SUCCESS ) {
629                 DEBUG(0, ("Unable to modify passwd TDB!"));
630                 DEBUGADD(0, (" Error: %s", tdb_errorstr(tdbsam)));
631                 DEBUGADD(0, (" occured while storing the main record (%s)\n",
632                              keystr));
633                 ret = False;
634                 goto done;
635         }
636
637 done:   
638         /* cleanup */
639         SAFE_FREE(buf);
640         
641         return ret;
642 }
643
644 /***************************************************************************
645  Update the TDB SAM RID record only
646  Assumes that the tdbsam is already open 
647 ****************************************************************************/
648 static BOOL tdb_update_ridrec_only( struct samu* newpwd, int flag )
649 {
650         TDB_DATA        key, data;
651         fstring         keystr;
652         fstring         name;
653
654         fstrcpy(name, pdb_get_username(newpwd));
655         strlower_m(name);
656
657         /* setup RID data */
658         data.dsize = strlen(name) + 1;
659         data.dptr = name;
660
661         /* setup the RID index key */
662         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX,  pdb_get_user_rid(newpwd));
663         key.dptr = keystr;
664         key.dsize = strlen (keystr) + 1;
665         
666         /* add the reference */
667         if (tdb_store(tdbsam, key, data, flag) != TDB_SUCCESS) {
668                 DEBUG(0, ("Unable to modify TDB passwd !"));
669                 DEBUGADD(0, (" Error: %s\n", tdb_errorstr(tdbsam)));
670                 DEBUGADD(0, (" occured while storing the RID index (%s)\n", keystr));
671                 return False;
672         }
673
674         return True;
675
676 }
677
678 /***************************************************************************
679  Update the TDB SAM
680 ****************************************************************************/
681
682 static BOOL tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd, int flag)
683 {
684         uint32          user_rid;
685         BOOL            result = True;
686
687         /* invalidate the existing TDB iterator if it is open */
688         
689         tdbsam_endsampwent( my_methods );
690         
691         if ( !pdb_get_group_rid(newpwd) ) {
692                 DEBUG (0,("tdb_update_sam: Failing to store a struct samu for [%s] "
693                         "without a primary group RID\n", pdb_get_username(newpwd)));
694                 return False;
695         }
696
697         if ( !(user_rid = pdb_get_user_rid(newpwd)) ) {
698                 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n", pdb_get_username(newpwd)));
699                 return False;
700         }
701
702         /* open the database */
703                 
704         if ( !tdbsam_open( tdbsam_filename ) ) {
705                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
706                 return False;
707         }
708         
709         if ( !tdb_update_samacct_only(newpwd, flag) || !tdb_update_ridrec_only(newpwd, flag)) {
710                 result = False;
711         }
712
713         /* cleanup */
714
715         tdbsam_close();
716         
717         return result;  
718 }
719
720 /***************************************************************************
721  Modifies an existing struct samu
722 ****************************************************************************/
723
724 static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
725 {
726         if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
727                 return NT_STATUS_UNSUCCESSFUL;
728         
729         return NT_STATUS_OK;
730 }
731
732 /***************************************************************************
733  Adds an existing struct samu
734 ****************************************************************************/
735
736 static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
737 {
738         if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
739                 return NT_STATUS_UNSUCCESSFUL;
740                 
741         return NT_STATUS_OK;
742 }
743
744 /***************************************************************************
745  Renames a struct samu
746  - check for the posix user/rename user script
747  - Add and lock the new user record
748  - rename the posix user
749  - rewrite the rid->username record
750  - delete the old user
751  - unlock the new user record
752 ***************************************************************************/
753 static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
754                                           struct samu *old_acct, 
755                                           const char *newname)
756 {
757         struct samu      *new_acct = NULL;
758         pstring          rename_script;
759         BOOL             interim_account = False;
760         int              rename_ret;
761
762         /* make sure we have an open handle to the tdb.  Should have happened 
763            at module  initialization time */
764            
765         if ( !tdbsam ) {
766                 DEBUG(0,("tdbsam_getsampwrid: tdbsam not open!\n"));
767                 return NT_STATUS_NO_SUCH_USER;
768         }
769         
770         /* can't do anything without an external script */
771         
772         pstrcpy(rename_script, lp_renameuser_script() );
773         if ( ! *rename_script )
774                 return NT_STATUS_ACCESS_DENIED;
775
776         /* invalidate the existing TDB iterator if it is open */
777         
778         tdbsam_endsampwent( my_methods );
779
780         if ( !pdb_copy_sam_account(old_acct, &new_acct) 
781                 || !pdb_set_username(new_acct, newname, PDB_CHANGED)) 
782         {
783                 TALLOC_FREE(new_acct );
784                 return NT_STATUS_NO_MEMORY;
785         }
786
787         /* open the database */
788                 
789         if ( !tdbsam_open( tdbsam_filename ) ) {
790                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
791                 TALLOC_FREE(new_acct );
792                 return NT_STATUS_ACCESS_DENIED;
793         }
794
795         /* add the new account and lock it */
796         
797         if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) 
798         {
799                 goto done;
800         }
801         
802         interim_account = True;
803
804         if ( tdb_lock_bystring(tdbsam, newname, 30) == -1 ) {
805                 goto done;
806         }
807
808         /* rename the posix user */
809         
810         pstring_sub(rename_script, "%unew", newname);
811         pstring_sub(rename_script, "%uold", pdb_get_username(old_acct));
812         rename_ret = smbrun(rename_script, NULL);
813
814         DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n", rename_script, rename_ret));
815
816         if (rename_ret) 
817                 goto done; 
818
819         /* rewrite the rid->username record */
820         
821         if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) )
822                 goto done;
823         interim_account = False;
824         tdb_unlock_bystring( tdbsam, newname );
825
826         tdb_delete_samacct_only( old_acct );
827         
828         tdbsam_close();
829         
830         TALLOC_FREE(new_acct );
831         return NT_STATUS_OK;
832
833 done:   
834         /* cleanup */
835         if (interim_account) {
836                 tdb_unlock_bystring(tdbsam, newname);
837                 tdb_delete_samacct_only(new_acct);
838         }
839         
840         tdbsam_close();
841         
842         if (new_acct)
843                 TALLOC_FREE(new_acct);
844         
845         return NT_STATUS_ACCESS_DENIED; 
846 }
847
848 static BOOL tdbsam_rid_algorithm(struct pdb_methods *methods)
849 {
850         return False;
851 }
852
853 /*
854  * Historically, winbind was responsible for allocating RIDs, so the next RID
855  * value was stored in winbindd_idmap.tdb. It has been moved to passdb now,
856  * but for compatibility reasons we still keep the the next RID counter in
857  * winbindd_idmap.tdb.
858  */
859
860 /*****************************************************************************
861  Initialise idmap database. For now (Dec 2005) this is a copy of the code in
862  sam/idmap_tdb.c. Maybe at a later stage we can remove that capability from
863  winbind completely and store the RID counter in passdb.tdb.
864
865  Dont' fully initialize with the HWM values, if it's new, we're only
866  interested in the RID counter.
867 *****************************************************************************/
868
869 static BOOL init_idmap_tdb(TDB_CONTEXT *tdb)
870 {
871         int32 version;
872
873         if (tdb_lock_bystring(tdb, "IDMAP_VERSION", 0) != 0) {
874                 DEBUG(0, ("Could not lock IDMAP_VERSION\n"));
875                 return False;
876         }
877
878         version = tdb_fetch_int32(tdb, "IDMAP_VERSION");
879
880         if (version == -1) {
881                 /* No key found, must be a new db */
882                 if (tdb_store_int32(tdb, "IDMAP_VERSION",
883                                     IDMAP_VERSION) != 0) {
884                         DEBUG(0, ("Could not store IDMAP_VERSION\n"));
885                         tdb_unlock_bystring(tdb, "IDMAP_VERSION");
886                         return False;
887                 }
888                 version = IDMAP_VERSION;
889         }
890
891         if (version != IDMAP_VERSION) {
892                 DEBUG(0, ("Expected IDMAP_VERSION=%d, found %d. Please "
893                           "start winbind once\n", IDMAP_VERSION, version));
894                 tdb_unlock_bystring(tdb, "IDMAP_VERSION");
895                 return False;
896         }
897
898         tdb_unlock_bystring(tdb, "IDMAP_VERSION");
899         return True;
900 }
901
902 static BOOL tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid)
903 {
904         TDB_CONTEXT *tdb;
905         uint32 rid;
906         BOOL ret = False;
907
908         tdb = tdb_open_log(lock_path("winbindd_idmap.tdb"), 0,
909                            TDB_DEFAULT, O_RDWR | O_CREAT, 0644);
910
911         if (tdb == NULL) {
912                 DEBUG(1, ("Could not open idmap: %s\n", strerror(errno)));
913                 goto done;
914         }
915
916         if (!init_idmap_tdb(tdb)) {
917                 DEBUG(1, ("Could not init idmap\n"));
918                 goto done;
919         }
920
921         rid = BASE_RID;         /* Default if not set */
922
923         if (!tdb_change_uint32_atomic(tdb, "RID_COUNTER", &rid, 1)) {
924                 DEBUG(3, ("tdbsam_new_rid: Failed to increase RID_COUNTER\n"));
925                 goto done;
926         }
927
928         *prid = rid;
929         ret = True;
930
931  done:
932         if ((tdb != NULL) && (tdb_close(tdb) != 0)) {
933                 smb_panic("tdb_close(idmap_tdb) failed\n");
934         }
935
936         return ret;
937 }
938
939 /*********************************************************************
940  Initialize the tdb sam backend.  Setup the dispath table of methods,
941  open the tdb, etc...
942 *********************************************************************/
943
944 static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
945 {
946         NTSTATUS nt_status;
947         pstring tdbfile;
948         const char *pfile = location;
949
950         if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
951                 return nt_status;
952         }
953
954         (*pdb_method)->name = "tdbsam";
955
956         (*pdb_method)->setsampwent = tdbsam_setsampwent;
957         (*pdb_method)->endsampwent = tdbsam_endsampwent;
958         (*pdb_method)->getsampwent = tdbsam_getsampwent;
959         (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
960         (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
961         (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
962         (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
963         (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
964         (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
965
966         (*pdb_method)->rid_algorithm = tdbsam_rid_algorithm;
967         (*pdb_method)->new_rid = tdbsam_new_rid;
968
969         /* save the path for later */
970                            
971         if ( !location ) {
972                 pstr_sprintf( tdbfile, "%s/%s", lp_private_dir(), PASSDB_FILE_NAME );
973                 pfile = tdbfile;
974         }
975         pstrcpy( tdbsam_filename, pfile );
976
977         /* no private data */
978         
979         (*pdb_method)->private_data      = NULL;
980         (*pdb_method)->free_private_data = NULL;
981
982         return NT_STATUS_OK;
983 }
984
985 NTSTATUS pdb_tdbsam_init(void)
986 {
987         return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);
988 }