Don't set an iterator to a piece of free'd memory, store it first.
[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-2002
6  * Copyright (C) Gerald Carter     2000
7  * Copyright (C) Jeremy Allison    2001
8  * Copyright (C) Andrew Bartlett   2002
9  * 
10  * This program is free software; you can redistribute it and/or modify it under
11  * the terms of the GNU General Public License as published by the Free
12  * Software Foundation; either version 2 of the License, or (at your option)
13  * any later version.
14  * 
15  * This program is distributed in the hope that it will be useful, but WITHOUT
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
18  * more details.
19  * 
20  * You should have received a copy of the GNU General Public License along with
21  * this program; if not, write to the Free Software Foundation, Inc., 675
22  * Mass Ave, Cambridge, MA 02139, USA.
23  */
24
25 #include "includes.h"
26
27 #if 0 /* when made a module use this */
28
29 static int tdbsam_debug_level = DBGC_ALL;
30 #undef DBGC_CLASS
31 #define DBGC_CLASS tdbsam_debug_level
32
33 #else
34
35 #undef DBGC_CLASS
36 #define DBGC_CLASS DBGC_PASSDB
37
38 #endif
39
40 #define PDB_VERSION             "20010830"
41 #define PASSDB_FILE_NAME        "passdb.tdb"
42 #define USERPREFIX              "USER_"
43 #define RIDPREFIX               "RID_"
44
45 struct tdbsam_privates {
46         TDB_CONTEXT     *passwd_tdb;
47
48         /* retrive-once info */
49         const char *tdbsam_location;
50 };
51
52 struct pwent_list {
53         struct pwent_list *prev, *next;
54         TDB_DATA key;
55 };
56 static struct pwent_list *tdbsam_pwent_list;
57
58
59 /****************************************************************************
60  creates a list of user keys
61 ****************************************************************************/
62
63 static int tdbsam_traverse_setpwent(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state)
64 {
65         const char *prefix = USERPREFIX;
66         int  prefixlen = strlen (prefix);
67         struct pwent_list *ptr;
68         
69         if ( strncmp(key.dptr, prefix, prefixlen) == 0 ) {
70                 if ( !(ptr=(struct pwent_list*)malloc(sizeof(struct pwent_list))) ) {
71                         DEBUG(0,("tdbsam_traverse_setpwent: Failed to malloc new entry for list\n"));
72                         
73                         /* just return 0 and let the traversal continue */
74                         return 0;
75                 }
76                 ZERO_STRUCTP(ptr);
77                 
78                 /* save a copy of the key */
79                 
80                 ptr->key.dptr = memdup( key.dptr, key.dsize );
81                 ptr->key.dsize = key.dsize;
82                 
83                 DLIST_ADD( tdbsam_pwent_list, ptr );
84         
85         }
86         
87         
88         return 0;
89 }
90
91 /*****************************************************************************
92  Utility functions to open and close the tdb sam database
93  ****************************************************************************/
94  
95 static BOOL open_tdbsam( struct tdbsam_privates *tdb_state, BOOL update )
96 {
97         /* check if we already have the tdbsam open */
98         
99         if ( tdb_state->passwd_tdb )
100                 return True;
101                 
102         if ( !(tdb_state->passwd_tdb = tdb_open_log(tdb_state->tdbsam_location, 
103                 0, TDB_DEFAULT, update?(O_RDWR|O_CREAT):O_RDONLY, 0600)) )
104         {
105                 DEBUG(0, ("Unable to open/create TDB passwd\n"));
106                 return False;
107         }
108
109         return True;
110 }
111
112 static void close_tdb(struct tdbsam_privates *tdb_state) 
113 {
114         if (tdb_state->passwd_tdb) {
115                 tdb_close(tdb_state->passwd_tdb);
116                 tdb_state->passwd_tdb = NULL;
117         }
118 }
119
120 /***************************************************************
121  Open the TDB passwd database for SAM account enumeration.
122  Save a list of user keys for iteration.
123 ****************************************************************/
124
125 static NTSTATUS tdbsam_setsampwent(struct pdb_methods *my_methods, BOOL update)
126 {
127         struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data;
128         
129         /* Open tdb passwd */
130         if ( !open_tdbsam(tdb_state, update) ) 
131                 return NT_STATUS_UNSUCCESSFUL;
132
133         tdb_traverse( tdb_state->passwd_tdb, tdbsam_traverse_setpwent, NULL );
134
135         return NT_STATUS_OK;
136 }
137
138
139 /***************************************************************
140  End enumeration of the TDB passwd list.
141 ****************************************************************/
142
143 static void tdbsam_endsampwent(struct pdb_methods *my_methods)
144 {
145         struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data;
146         struct pwent_list *ptr, *ptr_next;
147         
148         close_tdb(tdb_state);
149         
150         /* clear out any remaining entries in the list */
151         
152         for ( ptr=tdbsam_pwent_list; ptr; ptr = ptr_next ) {
153                 ptr_next = ptr->next;
154                 DLIST_REMOVE( tdbsam_pwent_list, ptr );
155                 SAFE_FREE( ptr->key.dptr);
156                 SAFE_FREE( ptr );
157         }
158         
159         DEBUG(7, ("endtdbpwent: closed sam database.\n"));
160 }
161
162 /*****************************************************************
163  Get one SAM_ACCOUNT from the TDB (next in line)
164 *****************************************************************/
165
166 static NTSTATUS tdbsam_getsampwent(struct pdb_methods *my_methods, SAM_ACCOUNT *user)
167 {
168         NTSTATUS                nt_status = NT_STATUS_UNSUCCESSFUL;
169         struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data;
170         TDB_DATA                data;
171         struct pwent_list       *pkey;
172
173         if ( !user ) {
174                 DEBUG(0,("tdbsam_getsampwent: SAM_ACCOUNT is NULL.\n"));
175                 return nt_status;
176         }
177
178         if( !open_tdbsam(tdb_state, True) )
179                 return nt_status;
180
181         if ( !tdbsam_pwent_list ) {
182                 DEBUG(4,("tdbsam_getsampwent: end of list\n"));
183                 return nt_status;
184         }
185
186         /* pull the next entry */
187                 
188         pkey = tdbsam_pwent_list;
189         DLIST_REMOVE( tdbsam_pwent_list, pkey );
190         
191         data = tdb_fetch(tdb_state->passwd_tdb, pkey->key);
192
193         SAFE_FREE( pkey->key.dptr);
194         SAFE_FREE( pkey);
195         
196         if (!data.dptr) {
197                 DEBUG(5,("pdb_getsampwent: database entry not found.  Was the user deleted?\n"));
198                 return nt_status;
199         }
200   
201         if (!init_sam_from_buffer(user, (unsigned char *)data.dptr, data.dsize)) {
202                 DEBUG(0,("pdb_getsampwent: Bad SAM_ACCOUNT entry returned from TDB!\n"));
203         }
204         
205         SAFE_FREE( data.dptr );
206         
207
208         return NT_STATUS_OK;
209 }
210
211 /******************************************************************
212  Lookup a name in the SAM TDB
213 ******************************************************************/
214
215 static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods, SAM_ACCOUNT *user, const char *sname)
216 {
217         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
218         struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data;
219         TDB_CONTEXT     *pwd_tdb;
220         TDB_DATA        data, key;
221         fstring         keystr;
222         fstring         name;
223
224         if (user==NULL) {
225                 DEBUG(0,("pdb_getsampwnam: SAM_ACCOUNT is NULL.\n"));
226                 return nt_status;
227         }
228
229         
230         /* Data is stored in all lower-case */
231         fstrcpy(name, sname);
232         strlower_m(name);
233
234         /* set search key */
235         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
236         key.dptr = keystr;
237         key.dsize = strlen(keystr) + 1;
238
239         /* open the accounts TDB */
240         if (!(pwd_tdb = tdb_open_log(tdb_state->tdbsam_location, 0, TDB_DEFAULT, O_RDONLY, 0600))) {
241         
242                 if (errno == ENOENT) {
243                         /*
244                          * TDB file doesn't exist, so try to create new one. This is useful to avoid
245                          * confusing error msg when adding user account first time
246                          */
247                         if (!(pwd_tdb = tdb_open_log(tdb_state->tdbsam_location, 0, TDB_DEFAULT, O_CREAT, 0600))) {
248                                 DEBUG(0, ("pdb_getsampwnam: TDB passwd (%s) did not exist. File successfully created.\n",
249                                           tdb_state->tdbsam_location));
250                         } else {
251                                 DEBUG(0, ("pdb_getsampwnam: TDB passwd (%s) does not exist. Couldn't create new one. Error was: %s\n",
252                                           tdb_state->tdbsam_location, strerror(errno)));
253                         }
254                         
255                         /* requested user isn't there anyway */
256                         nt_status = NT_STATUS_NO_SUCH_USER;
257                         return nt_status;
258                 }
259                 DEBUG(0, ("pdb_getsampwnam: Unable to open TDB passwd (%s)!\n", tdb_state->tdbsam_location));
260                 return nt_status;
261         }
262
263         /* get the record */
264         data = tdb_fetch(pwd_tdb, key);
265         if (!data.dptr) {
266                 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
267                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
268                 DEBUGADD(5, (" Key: %s\n", keystr));
269                 tdb_close(pwd_tdb);
270                 return nt_status;
271         }
272   
273         /* unpack the buffer */
274         if (!init_sam_from_buffer(user, (unsigned char *)data.dptr, data.dsize)) {
275                 DEBUG(0,("pdb_getsampwent: Bad SAM_ACCOUNT entry returned from TDB!\n"));
276                 SAFE_FREE(data.dptr);
277                 tdb_close(pwd_tdb);
278                 return nt_status;
279         }
280         SAFE_FREE(data.dptr);
281
282         /* no further use for database, close it now */
283         tdb_close(pwd_tdb);
284         
285         return NT_STATUS_OK;
286 }
287
288 /***************************************************************************
289  Search by rid
290  **************************************************************************/
291
292 static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods, SAM_ACCOUNT *user, uint32 rid)
293 {
294         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
295         struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data;
296         TDB_CONTEXT             *pwd_tdb;
297         TDB_DATA                data, key;
298         fstring                 keystr;
299         fstring                 name;
300         
301         if (user==NULL) {
302                 DEBUG(0,("pdb_getsampwrid: SAM_ACCOUNT is NULL.\n"));
303                 return nt_status;
304         }
305
306         /* set search key */
307         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
308         key.dptr = keystr;
309         key.dsize = strlen (keystr) + 1;
310
311         /* open the accounts TDB */
312         if (!(pwd_tdb = tdb_open_log(tdb_state->tdbsam_location, 0, TDB_DEFAULT, O_RDONLY, 0600))) {
313                 DEBUG(0, ("pdb_getsampwrid: Unable to open TDB rid database!\n"));
314                 return nt_status;
315         }
316
317         /* get the record */
318         data = tdb_fetch (pwd_tdb, key);
319         if (!data.dptr) {
320                 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
321                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
322                 tdb_close (pwd_tdb);
323                 return nt_status;
324         }
325
326         fstrcpy(name, data.dptr);
327         SAFE_FREE(data.dptr);
328         
329         tdb_close (pwd_tdb);
330         
331         return tdbsam_getsampwnam (my_methods, user, name);
332 }
333
334 static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods, SAM_ACCOUNT * user, const DOM_SID *sid)
335 {
336         uint32 rid;
337         if (!sid_peek_check_rid(get_global_sam_sid(), sid, &rid))
338                 return NT_STATUS_UNSUCCESSFUL;
339         return tdbsam_getsampwrid(my_methods, user, rid);
340 }
341
342 /***************************************************************************
343  Delete a SAM_ACCOUNT
344 ****************************************************************************/
345
346 static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT *sam_pass)
347 {
348         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
349         struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data;
350         TDB_CONTEXT     *pwd_tdb;
351         TDB_DATA        key;
352         fstring         keystr;
353         uint32          rid;
354         fstring         name;
355         
356         fstrcpy(name, pdb_get_username(sam_pass));
357         strlower_m(name);
358         
359         /* open the TDB */
360         if (!(pwd_tdb = tdb_open_log(tdb_state->tdbsam_location, 0, TDB_DEFAULT, O_RDWR, 0600))) {
361                 DEBUG(0, ("Unable to open TDB passwd!"));
362                 return nt_status;
363         }
364   
365         /* set the search key */
366         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
367         key.dptr = keystr;
368         key.dsize = strlen (keystr) + 1;
369         
370         rid = pdb_get_user_rid(sam_pass);
371
372         /* it's outaa here!  8^) */
373         if (tdb_delete(pwd_tdb, key) != TDB_SUCCESS) {
374                 DEBUG(5, ("Error deleting entry from tdb passwd database!\n"));
375                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
376                 tdb_close(pwd_tdb); 
377                 return nt_status;
378         }       
379
380         /* delete also the RID key */
381
382         /* set the search key */
383         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
384         key.dptr = keystr;
385         key.dsize = strlen (keystr) + 1;
386
387         /* it's outaa here!  8^) */
388         if (tdb_delete(pwd_tdb, key) != TDB_SUCCESS) {
389                 DEBUG(5, ("Error deleting entry from tdb rid database!\n"));
390                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
391                 tdb_close(pwd_tdb); 
392                 return nt_status;
393         }
394         
395         tdb_close(pwd_tdb);
396         
397         return NT_STATUS_OK;
398 }
399
400 /***************************************************************************
401  Update the TDB SAM
402 ****************************************************************************/
403
404 static BOOL tdb_update_sam(struct pdb_methods *my_methods, SAM_ACCOUNT* newpwd, int flag)
405 {
406         struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data;
407         TDB_CONTEXT     *pwd_tdb = NULL;
408         TDB_DATA        key, data;
409         uint8           *buf = NULL;
410         fstring         keystr;
411         fstring         name;
412         BOOL            ret = True;
413         uint32          user_rid;
414
415         /* invalidate the existing TDB iterator if it is open */
416         
417         if (tdb_state->passwd_tdb) {
418                 tdb_close(tdb_state->passwd_tdb);
419                 tdb_state->passwd_tdb = NULL;
420         }
421
422         /* open the account TDB passwd*/
423         
424         pwd_tdb = tdb_open_log(tdb_state->tdbsam_location, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0600);
425         
426         if (!pwd_tdb) {
427                 DEBUG(0, ("tdb_update_sam: Unable to open TDB passwd (%s)!\n", 
428                         tdb_state->tdbsam_location));
429                 return False;
430         }
431
432         if (!pdb_get_group_rid(newpwd)) {
433                 DEBUG (0,("tdb_update_sam: Failing to store a SAM_ACCOUNT for [%s] without a primary group RID\n",
434                         pdb_get_username(newpwd)));
435                 ret = False;
436                 goto done;
437         }
438
439         if ( !(user_rid = pdb_get_user_rid(newpwd)) ) {
440                 DEBUG(0,("tdb_update_sam: SAM_ACCOUNT (%s) with no RID!\n", pdb_get_username(newpwd)));
441                 ret = False;
442                 goto done;
443         }
444
445         /* copy the SAM_ACCOUNT struct into a BYTE buffer for storage */
446         if ((data.dsize=init_buffer_from_sam (&buf, newpwd, False)) == -1) {
447                 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy SAM_ACCOUNT info BYTE buffer!\n"));
448                 ret = False;
449                 goto done;
450         }
451         data.dptr = (char *)buf;
452
453         fstrcpy(name, pdb_get_username(newpwd));
454         strlower_m(name);
455         
456         DEBUG(5, ("Storing %saccount %s with RID %d\n", flag == TDB_INSERT ? "(new) " : "", name, user_rid));
457
458         /* setup the USER index key */
459         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
460         key.dptr = keystr;
461         key.dsize = strlen(keystr) + 1;
462
463         /* add the account */
464         if (tdb_store(pwd_tdb, key, data, flag) != TDB_SUCCESS) {
465                 DEBUG(0, ("Unable to modify passwd TDB!"));
466                 DEBUGADD(0, (" Error: %s", tdb_errorstr(pwd_tdb)));
467                 DEBUGADD(0, (" occured while storing the main record (%s)\n", keystr));
468                 ret = False;
469                 goto done;
470         }
471         
472         /* setup RID data */
473         data.dsize = strlen(name) + 1;
474         data.dptr = name;
475
476         /* setup the RID index key */
477         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, user_rid);
478         key.dptr = keystr;
479         key.dsize = strlen (keystr) + 1;
480         
481         /* add the reference */
482         if (tdb_store(pwd_tdb, key, data, flag) != TDB_SUCCESS) {
483                 DEBUG(0, ("Unable to modify TDB passwd !"));
484                 DEBUGADD(0, (" Error: %s\n", tdb_errorstr(pwd_tdb)));
485                 DEBUGADD(0, (" occured while storing the RID index (%s)\n", keystr));
486                 ret = False;
487                 goto done;
488         }
489
490 done:   
491         /* cleanup */
492         tdb_close (pwd_tdb);
493         SAFE_FREE(buf);
494         
495         return (ret);   
496 }
497
498 /***************************************************************************
499  Modifies an existing SAM_ACCOUNT
500 ****************************************************************************/
501
502 static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, SAM_ACCOUNT *newpwd)
503 {
504         if (tdb_update_sam(my_methods, newpwd, TDB_MODIFY))
505                 return NT_STATUS_OK;
506         else
507                 return NT_STATUS_UNSUCCESSFUL;
508 }
509
510 /***************************************************************************
511  Adds an existing SAM_ACCOUNT
512 ****************************************************************************/
513
514 static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, SAM_ACCOUNT *newpwd)
515 {
516         if (tdb_update_sam(my_methods, newpwd, TDB_INSERT))
517                 return NT_STATUS_OK;
518         else
519                 return NT_STATUS_UNSUCCESSFUL;
520 }
521
522 static void free_private_data(void **vp) 
523 {
524         struct tdbsam_privates **tdb_state = (struct tdbsam_privates **)vp;
525         close_tdb(*tdb_state);
526         *tdb_state = NULL;
527
528         /* No need to free any further, as it is talloc()ed */
529 }
530
531
532 static NTSTATUS pdb_init_tdbsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
533 {
534         NTSTATUS nt_status;
535         struct tdbsam_privates *tdb_state;
536
537         if (!NT_STATUS_IS_OK(nt_status = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) {
538                 return nt_status;
539         }
540
541         (*pdb_method)->name = "tdbsam";
542
543         (*pdb_method)->setsampwent = tdbsam_setsampwent;
544         (*pdb_method)->endsampwent = tdbsam_endsampwent;
545         (*pdb_method)->getsampwent = tdbsam_getsampwent;
546         (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
547         (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
548         (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
549         (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
550         (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
551
552         tdb_state = talloc_zero(pdb_context->mem_ctx, sizeof(struct tdbsam_privates));
553
554         if (!tdb_state) {
555                 DEBUG(0, ("talloc() failed for tdbsam private_data!\n"));
556                 return NT_STATUS_NO_MEMORY;
557         }
558
559         if (location) {
560                 tdb_state->tdbsam_location = talloc_strdup(pdb_context->mem_ctx, location);
561         } else {
562                 pstring tdbfile;
563                 get_private_directory(tdbfile);
564                 pstrcat(tdbfile, "/");
565                 pstrcat(tdbfile, PASSDB_FILE_NAME);
566                 tdb_state->tdbsam_location = talloc_strdup(pdb_context->mem_ctx, tdbfile);
567         }
568
569         (*pdb_method)->private_data = tdb_state;
570
571         (*pdb_method)->free_private_data = free_private_data;
572
573         return NT_STATUS_OK;
574 }
575
576 NTSTATUS pdb_tdbsam_init(void)
577 {
578         return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);
579 }
580