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