r16582: Fix Klocwork #1997 and all generic class of problems
[ira/wip.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  3       /* 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  Marshall/unmarshall struct samu structs.
63  *********************************************************************/
64
65 #define TDB_FORMAT_STRING_V0       "ddddddBBBBBBBBBBBBddBBwdwdBwwd"
66 #define TDB_FORMAT_STRING_V1       "dddddddBBBBBBBBBBBBddBBwdwdBwwd"
67 #define TDB_FORMAT_STRING_V2       "dddddddBBBBBBBBBBBBddBBBwwdBwwd"
68
69 /*********************************************************************
70 *********************************************************************/
71
72 static BOOL init_sam_from_buffer_v0(struct samu *sampass, uint8 *buf, uint32 buflen)
73 {
74
75         /* times are stored as 32bit integer
76            take care on system with 64bit wide time_t
77            --SSS */
78         uint32  logon_time,
79                 logoff_time,
80                 kickoff_time,
81                 pass_last_set_time,
82                 pass_can_change_time,
83                 pass_must_change_time;
84         char *username = NULL;
85         char *domain = NULL;
86         char *nt_username = NULL;
87         char *dir_drive = NULL;
88         char *unknown_str = NULL;
89         char *munged_dial = NULL;
90         char *fullname = NULL;
91         char *homedir = NULL;
92         char *logon_script = NULL;
93         char *profile_path = NULL;
94         char *acct_desc = NULL;
95         char *workstations = NULL;
96         uint32  username_len, domain_len, nt_username_len,
97                 dir_drive_len, unknown_str_len, munged_dial_len,
98                 fullname_len, homedir_len, logon_script_len,
99                 profile_path_len, acct_desc_len, workstations_len;
100                 
101         uint32  user_rid, group_rid, remove_me, hours_len, unknown_6;
102         uint16  acct_ctrl, logon_divs;
103         uint16  bad_password_count, logon_count;
104         uint8   *hours = NULL;
105         uint8   *lm_pw_ptr = NULL, *nt_pw_ptr = NULL;
106         uint32          len = 0;
107         uint32          lm_pw_len, nt_pw_len, hourslen;
108         BOOL ret = True;
109         
110         if(sampass == NULL || buf == NULL) {
111                 DEBUG(0, ("init_sam_from_buffer_v0: NULL parameters found!\n"));
112                 return False;
113         }
114
115 /* TDB_FORMAT_STRING_V0       "ddddddBBBBBBBBBBBBddBBwdwdBwwd" */
116
117         /* unpack the buffer into variables */
118         len = tdb_unpack ((char *)buf, buflen, TDB_FORMAT_STRING_V0,
119                 &logon_time,                                            /* d */
120                 &logoff_time,                                           /* d */
121                 &kickoff_time,                                          /* d */
122                 &pass_last_set_time,                                    /* d */
123                 &pass_can_change_time,                                  /* d */
124                 &pass_must_change_time,                                 /* d */
125                 &username_len, &username,                               /* B */
126                 &domain_len, &domain,                                   /* B */
127                 &nt_username_len, &nt_username,                         /* B */
128                 &fullname_len, &fullname,                               /* B */
129                 &homedir_len, &homedir,                                 /* B */
130                 &dir_drive_len, &dir_drive,                             /* B */
131                 &logon_script_len, &logon_script,                       /* B */
132                 &profile_path_len, &profile_path,                       /* B */
133                 &acct_desc_len, &acct_desc,                             /* B */
134                 &workstations_len, &workstations,                       /* B */
135                 &unknown_str_len, &unknown_str,                         /* B */
136                 &munged_dial_len, &munged_dial,                         /* B */
137                 &user_rid,                                              /* d */
138                 &group_rid,                                             /* d */
139                 &lm_pw_len, &lm_pw_ptr,                                 /* B */
140                 &nt_pw_len, &nt_pw_ptr,                                 /* B */
141                 &acct_ctrl,                                             /* w */
142                 &remove_me, /* remove on the next TDB_FORMAT upgarde */ /* d */
143                 &logon_divs,                                            /* w */
144                 &hours_len,                                             /* d */
145                 &hourslen, &hours,                                      /* B */
146                 &bad_password_count,                                    /* w */
147                 &logon_count,                                           /* w */
148                 &unknown_6);                                            /* d */
149                 
150         if (len == (uint32) -1)  {
151                 ret = False;
152                 goto done;
153         }
154
155         pdb_set_logon_time(sampass, logon_time, PDB_SET);
156         pdb_set_logoff_time(sampass, logoff_time, PDB_SET);
157         pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET);
158         pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET);
159         pdb_set_pass_must_change_time(sampass, pass_must_change_time, PDB_SET);
160         pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET);
161
162         pdb_set_username(sampass, username, PDB_SET); 
163         pdb_set_domain(sampass, domain, PDB_SET);
164         pdb_set_nt_username(sampass, nt_username, PDB_SET);
165         pdb_set_fullname(sampass, fullname, PDB_SET);
166
167         if (homedir) {
168                 pdb_set_homedir(sampass, homedir, PDB_SET);
169         }
170         else {
171                 pdb_set_homedir(sampass, 
172                         talloc_sub_basic(sampass, username, lp_logon_home()),
173                         PDB_DEFAULT);
174         }
175
176         if (dir_drive)  
177                 pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
178         else {
179                 pdb_set_dir_drive(sampass, 
180                         talloc_sub_basic(sampass,  username, lp_logon_drive()),
181                         PDB_DEFAULT);
182         }
183
184         if (logon_script) 
185                 pdb_set_logon_script(sampass, logon_script, PDB_SET);
186         else {
187                 pdb_set_logon_script(sampass, 
188                         talloc_sub_basic(sampass, username, lp_logon_script()),
189                         PDB_DEFAULT);
190         }
191         
192         if (profile_path) {     
193                 pdb_set_profile_path(sampass, profile_path, PDB_SET);
194         } else {
195                 pdb_set_profile_path(sampass, 
196                         talloc_sub_basic(sampass, username, lp_logon_path()),
197                         PDB_DEFAULT);
198         }
199
200         pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
201         pdb_set_workstations(sampass, workstations, PDB_SET);
202         pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
203
204         if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) {
205                 if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) {
206                         ret = False;
207                         goto done;
208                 }
209         }
210
211         if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) {
212                 if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) {
213                         ret = False;
214                         goto done;
215                 }
216         }
217
218         pdb_set_pw_history(sampass, NULL, 0, PDB_SET);
219         pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
220         pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET);
221         pdb_set_hours_len(sampass, hours_len, PDB_SET);
222         pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET);
223         pdb_set_logon_count(sampass, logon_count, PDB_SET);
224         pdb_set_unknown_6(sampass, unknown_6, PDB_SET);
225         pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
226         pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
227         pdb_set_hours(sampass, hours, PDB_SET);
228
229 done:
230
231         SAFE_FREE(username);
232         SAFE_FREE(domain);
233         SAFE_FREE(nt_username);
234         SAFE_FREE(fullname);
235         SAFE_FREE(homedir);
236         SAFE_FREE(dir_drive);
237         SAFE_FREE(logon_script);
238         SAFE_FREE(profile_path);
239         SAFE_FREE(acct_desc);
240         SAFE_FREE(workstations);
241         SAFE_FREE(munged_dial);
242         SAFE_FREE(unknown_str);
243         SAFE_FREE(lm_pw_ptr);
244         SAFE_FREE(nt_pw_ptr);
245         SAFE_FREE(hours);
246
247         return ret;
248 }
249
250 /*********************************************************************
251 *********************************************************************/
252
253 static BOOL init_sam_from_buffer_v1(struct samu *sampass, uint8 *buf, uint32 buflen)
254 {
255
256         /* times are stored as 32bit integer
257            take care on system with 64bit wide time_t
258            --SSS */
259         uint32  logon_time,
260                 logoff_time,
261                 kickoff_time,
262                 bad_password_time,
263                 pass_last_set_time,
264                 pass_can_change_time,
265                 pass_must_change_time;
266         char *username = NULL;
267         char *domain = NULL;
268         char *nt_username = NULL;
269         char *dir_drive = NULL;
270         char *unknown_str = NULL;
271         char *munged_dial = NULL;
272         char *fullname = NULL;
273         char *homedir = NULL;
274         char *logon_script = NULL;
275         char *profile_path = NULL;
276         char *acct_desc = NULL;
277         char *workstations = NULL;
278         uint32  username_len, domain_len, nt_username_len,
279                 dir_drive_len, unknown_str_len, munged_dial_len,
280                 fullname_len, homedir_len, logon_script_len,
281                 profile_path_len, acct_desc_len, workstations_len;
282                 
283         uint32  user_rid, group_rid, remove_me, hours_len, unknown_6;
284         uint16  acct_ctrl, logon_divs;
285         uint16  bad_password_count, logon_count;
286         uint8   *hours = NULL;
287         uint8   *lm_pw_ptr = NULL, *nt_pw_ptr = NULL;
288         uint32          len = 0;
289         uint32          lm_pw_len, nt_pw_len, hourslen;
290         BOOL ret = True;
291         
292         if(sampass == NULL || buf == NULL) {
293                 DEBUG(0, ("init_sam_from_buffer_v1: NULL parameters found!\n"));
294                 return False;
295         }
296
297 /* TDB_FORMAT_STRING_V1       "dddddddBBBBBBBBBBBBddBBwdwdBwwd" */
298
299         /* unpack the buffer into variables */
300         len = tdb_unpack ((char *)buf, buflen, TDB_FORMAT_STRING_V1,
301                 &logon_time,                                            /* d */
302                 &logoff_time,                                           /* d */
303                 &kickoff_time,                                          /* d */
304                 /* Change from V0 is addition of bad_password_time field. */
305                 &bad_password_time,                                     /* d */
306                 &pass_last_set_time,                                    /* d */
307                 &pass_can_change_time,                                  /* d */
308                 &pass_must_change_time,                                 /* d */
309                 &username_len, &username,                               /* B */
310                 &domain_len, &domain,                                   /* B */
311                 &nt_username_len, &nt_username,                         /* B */
312                 &fullname_len, &fullname,                               /* B */
313                 &homedir_len, &homedir,                                 /* B */
314                 &dir_drive_len, &dir_drive,                             /* B */
315                 &logon_script_len, &logon_script,                       /* B */
316                 &profile_path_len, &profile_path,                       /* B */
317                 &acct_desc_len, &acct_desc,                             /* B */
318                 &workstations_len, &workstations,                       /* B */
319                 &unknown_str_len, &unknown_str,                         /* B */
320                 &munged_dial_len, &munged_dial,                         /* B */
321                 &user_rid,                                              /* d */
322                 &group_rid,                                             /* d */
323                 &lm_pw_len, &lm_pw_ptr,                                 /* B */
324                 &nt_pw_len, &nt_pw_ptr,                                 /* B */
325                 &acct_ctrl,                                             /* w */
326                 &remove_me,                                             /* d */
327                 &logon_divs,                                            /* w */
328                 &hours_len,                                             /* d */
329                 &hourslen, &hours,                                      /* B */
330                 &bad_password_count,                                    /* w */
331                 &logon_count,                                           /* w */
332                 &unknown_6);                                            /* d */
333                 
334         if (len == (uint32) -1)  {
335                 ret = False;
336                 goto done;
337         }
338
339         pdb_set_logon_time(sampass, logon_time, PDB_SET);
340         pdb_set_logoff_time(sampass, logoff_time, PDB_SET);
341         pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET);
342
343         /* Change from V0 is addition of bad_password_time field. */
344         pdb_set_bad_password_time(sampass, bad_password_time, PDB_SET);
345         pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET);
346         pdb_set_pass_must_change_time(sampass, pass_must_change_time, PDB_SET);
347         pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET);
348
349         pdb_set_username(sampass, username, PDB_SET); 
350         pdb_set_domain(sampass, domain, PDB_SET);
351         pdb_set_nt_username(sampass, nt_username, PDB_SET);
352         pdb_set_fullname(sampass, fullname, PDB_SET);
353
354         if (homedir) {
355                 pdb_set_homedir(sampass, homedir, PDB_SET);
356         }
357         else {
358                 pdb_set_homedir(sampass, 
359                         talloc_sub_basic(sampass, username, lp_logon_home()),
360                         PDB_DEFAULT);
361         }
362
363         if (dir_drive)  
364                 pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
365         else {
366                 pdb_set_dir_drive(sampass, 
367                         talloc_sub_basic(sampass,  username, lp_logon_drive()),
368                         PDB_DEFAULT);
369         }
370
371         if (logon_script) 
372                 pdb_set_logon_script(sampass, logon_script, PDB_SET);
373         else {
374                 pdb_set_logon_script(sampass, 
375                         talloc_sub_basic(sampass, username, lp_logon_script()),
376                         PDB_DEFAULT);
377         }
378         
379         if (profile_path) {     
380                 pdb_set_profile_path(sampass, profile_path, PDB_SET);
381         } else {
382                 pdb_set_profile_path(sampass, 
383                         talloc_sub_basic(sampass, username, lp_logon_path()),
384                         PDB_DEFAULT);
385         }
386
387         pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
388         pdb_set_workstations(sampass, workstations, PDB_SET);
389         pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
390
391         if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) {
392                 if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) {
393                         ret = False;
394                         goto done;
395                 }
396         }
397
398         if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) {
399                 if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) {
400                         ret = False;
401                         goto done;
402                 }
403         }
404
405         pdb_set_pw_history(sampass, NULL, 0, PDB_SET);
406
407         pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
408         pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET);
409         pdb_set_hours_len(sampass, hours_len, PDB_SET);
410         pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET);
411         pdb_set_logon_count(sampass, logon_count, PDB_SET);
412         pdb_set_unknown_6(sampass, unknown_6, PDB_SET);
413         pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
414         pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
415         pdb_set_hours(sampass, hours, PDB_SET);
416
417 done:
418
419         SAFE_FREE(username);
420         SAFE_FREE(domain);
421         SAFE_FREE(nt_username);
422         SAFE_FREE(fullname);
423         SAFE_FREE(homedir);
424         SAFE_FREE(dir_drive);
425         SAFE_FREE(logon_script);
426         SAFE_FREE(profile_path);
427         SAFE_FREE(acct_desc);
428         SAFE_FREE(workstations);
429         SAFE_FREE(munged_dial);
430         SAFE_FREE(unknown_str);
431         SAFE_FREE(lm_pw_ptr);
432         SAFE_FREE(nt_pw_ptr);
433         SAFE_FREE(hours);
434
435         return ret;
436 }
437
438 BOOL init_sam_from_buffer_v2(struct samu *sampass, uint8 *buf, uint32 buflen)
439 {
440
441         /* times are stored as 32bit integer
442            take care on system with 64bit wide time_t
443            --SSS */
444         uint32  logon_time,
445                 logoff_time,
446                 kickoff_time,
447                 bad_password_time,
448                 pass_last_set_time,
449                 pass_can_change_time,
450                 pass_must_change_time;
451         char *username = NULL;
452         char *domain = NULL;
453         char *nt_username = NULL;
454         char *dir_drive = NULL;
455         char *unknown_str = NULL;
456         char *munged_dial = NULL;
457         char *fullname = NULL;
458         char *homedir = NULL;
459         char *logon_script = NULL;
460         char *profile_path = NULL;
461         char *acct_desc = NULL;
462         char *workstations = NULL;
463         uint32  username_len, domain_len, nt_username_len,
464                 dir_drive_len, unknown_str_len, munged_dial_len,
465                 fullname_len, homedir_len, logon_script_len,
466                 profile_path_len, acct_desc_len, workstations_len;
467                 
468         uint32  user_rid, group_rid, hours_len, unknown_6;
469         uint16  acct_ctrl, logon_divs;
470         uint16  bad_password_count, logon_count;
471         uint8   *hours = NULL;
472         uint8   *lm_pw_ptr = NULL, *nt_pw_ptr = NULL, *nt_pw_hist_ptr = NULL;
473         uint32          len = 0;
474         uint32          lm_pw_len, nt_pw_len, nt_pw_hist_len, hourslen;
475         uint32 pwHistLen = 0;
476         BOOL ret = True;
477         fstring tmpstring;
478         BOOL expand_explicit = lp_passdb_expand_explicit();
479         
480         if(sampass == NULL || buf == NULL) {
481                 DEBUG(0, ("init_sam_from_buffer_v2: NULL parameters found!\n"));
482                 return False;
483         }
484                                                                         
485 /* TDB_FORMAT_STRING_V2       "dddddddBBBBBBBBBBBBddBBBwwdBwwd" */
486
487         /* unpack the buffer into variables */
488         len = tdb_unpack ((char *)buf, buflen, TDB_FORMAT_STRING_V2,
489                 &logon_time,                                            /* d */
490                 &logoff_time,                                           /* d */
491                 &kickoff_time,                                          /* d */
492                 &bad_password_time,                                     /* d */
493                 &pass_last_set_time,                                    /* d */
494                 &pass_can_change_time,                                  /* d */
495                 &pass_must_change_time,                                 /* d */
496                 &username_len, &username,                               /* B */
497                 &domain_len, &domain,                                   /* B */
498                 &nt_username_len, &nt_username,                         /* B */
499                 &fullname_len, &fullname,                               /* B */
500                 &homedir_len, &homedir,                                 /* B */
501                 &dir_drive_len, &dir_drive,                             /* B */
502                 &logon_script_len, &logon_script,                       /* B */
503                 &profile_path_len, &profile_path,                       /* B */
504                 &acct_desc_len, &acct_desc,                             /* B */
505                 &workstations_len, &workstations,                       /* B */
506                 &unknown_str_len, &unknown_str,                         /* B */
507                 &munged_dial_len, &munged_dial,                         /* B */
508                 &user_rid,                                              /* d */
509                 &group_rid,                                             /* d */
510                 &lm_pw_len, &lm_pw_ptr,                                 /* B */
511                 &nt_pw_len, &nt_pw_ptr,                                 /* B */
512                 /* Change from V1 is addition of password history field. */
513                 &nt_pw_hist_len, &nt_pw_hist_ptr,                       /* B */
514                 &acct_ctrl,                                             /* w */
515                 /* Also "remove_me" field was removed. */
516                 &logon_divs,                                            /* w */
517                 &hours_len,                                             /* d */
518                 &hourslen, &hours,                                      /* B */
519                 &bad_password_count,                                    /* w */
520                 &logon_count,                                           /* w */
521                 &unknown_6);                                            /* d */
522                 
523         if (len == (uint32) -1)  {
524                 ret = False;
525                 goto done;
526         }
527
528         pdb_set_logon_time(sampass, logon_time, PDB_SET);
529         pdb_set_logoff_time(sampass, logoff_time, PDB_SET);
530         pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET);
531         pdb_set_bad_password_time(sampass, bad_password_time, PDB_SET);
532         pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET);
533         pdb_set_pass_must_change_time(sampass, pass_must_change_time, PDB_SET);
534         pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET);
535
536         pdb_set_username(sampass, username, PDB_SET); 
537         pdb_set_domain(sampass, domain, PDB_SET);
538         pdb_set_nt_username(sampass, nt_username, PDB_SET);
539         pdb_set_fullname(sampass, fullname, PDB_SET);
540
541         if (homedir) {
542                 fstrcpy( tmpstring, homedir );
543                 if (expand_explicit) {
544                         standard_sub_basic( username, tmpstring,
545                                             sizeof(tmpstring) );
546                 }
547                 pdb_set_homedir(sampass, tmpstring, PDB_SET);
548         }
549         else {
550                 pdb_set_homedir(sampass, 
551                         talloc_sub_basic(sampass, username, lp_logon_home()),
552                         PDB_DEFAULT);
553         }
554
555         if (dir_drive)  
556                 pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
557         else
558                 pdb_set_dir_drive(sampass, lp_logon_drive(), PDB_DEFAULT );
559
560         if (logon_script) {
561                 fstrcpy( tmpstring, logon_script );
562                 if (expand_explicit) {
563                         standard_sub_basic( username, tmpstring,
564                                             sizeof(tmpstring) );
565                 }
566                 pdb_set_logon_script(sampass, tmpstring, PDB_SET);
567         }
568         else {
569                 pdb_set_logon_script(sampass, 
570                         talloc_sub_basic(sampass, username, lp_logon_script()),
571                         PDB_DEFAULT);
572         }
573         
574         if (profile_path) {     
575                 fstrcpy( tmpstring, profile_path );
576                 if (expand_explicit) {
577                         standard_sub_basic( username, tmpstring,
578                                             sizeof(tmpstring) );
579                 }
580                 pdb_set_profile_path(sampass, tmpstring, PDB_SET);
581         } 
582         else {
583                 pdb_set_profile_path(sampass, 
584                         talloc_sub_basic(sampass, username, lp_logon_path()),
585                         PDB_DEFAULT);
586         }
587
588         pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
589         pdb_set_workstations(sampass, workstations, PDB_SET);
590         pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
591
592         if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) {
593                 if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) {
594                         ret = False;
595                         goto done;
596                 }
597         }
598
599         if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) {
600                 if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) {
601                         ret = False;
602                         goto done;
603                 }
604         }
605
606         /* Change from V1 is addition of password history field. */
607         pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHistLen);
608         if (pwHistLen) {
609                 uint8 *pw_hist = SMB_MALLOC(pwHistLen * PW_HISTORY_ENTRY_LEN);
610                 if (!pw_hist) {
611                         ret = False;
612                         goto done;
613                 }
614                 memset(pw_hist, '\0', pwHistLen * PW_HISTORY_ENTRY_LEN);
615                 if (nt_pw_hist_ptr && nt_pw_hist_len) {
616                         int i;
617                         SMB_ASSERT((nt_pw_hist_len % PW_HISTORY_ENTRY_LEN) == 0);
618                         nt_pw_hist_len /= PW_HISTORY_ENTRY_LEN;
619                         for (i = 0; (i < pwHistLen) && (i < nt_pw_hist_len); i++) {
620                                 memcpy(&pw_hist[i*PW_HISTORY_ENTRY_LEN],
621                                         &nt_pw_hist_ptr[i*PW_HISTORY_ENTRY_LEN],
622                                         PW_HISTORY_ENTRY_LEN);
623                         }
624                 }
625                 if (!pdb_set_pw_history(sampass, pw_hist, pwHistLen, PDB_SET)) {
626                         SAFE_FREE(pw_hist);
627                         ret = False;
628                         goto done;
629                 }
630                 SAFE_FREE(pw_hist);
631         } else {
632                 pdb_set_pw_history(sampass, NULL, 0, PDB_SET);
633         }
634
635         pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
636         pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET);
637         pdb_set_hours_len(sampass, hours_len, PDB_SET);
638         pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET);
639         pdb_set_logon_count(sampass, logon_count, PDB_SET);
640         pdb_set_unknown_6(sampass, unknown_6, PDB_SET);
641         pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
642         pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
643         pdb_set_hours(sampass, hours, PDB_SET);
644
645 done:
646
647         SAFE_FREE(username);
648         SAFE_FREE(domain);
649         SAFE_FREE(nt_username);
650         SAFE_FREE(fullname);
651         SAFE_FREE(homedir);
652         SAFE_FREE(dir_drive);
653         SAFE_FREE(logon_script);
654         SAFE_FREE(profile_path);
655         SAFE_FREE(acct_desc);
656         SAFE_FREE(workstations);
657         SAFE_FREE(munged_dial);
658         SAFE_FREE(unknown_str);
659         SAFE_FREE(lm_pw_ptr);
660         SAFE_FREE(nt_pw_ptr);
661         SAFE_FREE(nt_pw_hist_ptr);
662         SAFE_FREE(hours);
663
664         return ret;
665 }
666
667
668 /**********************************************************************
669  Intialize a struct samu struct from a BYTE buffer of size len
670  *********************************************************************/
671
672 static BOOL init_sam_from_buffer(struct samu *sampass, uint8 *buf, uint32 buflen)
673 {
674         return init_sam_from_buffer_v3(sampass, buf, buflen);
675 }
676
677 /**********************************************************************
678  Intialize a BYTE buffer from a struct samu struct
679  *********************************************************************/
680
681 static uint32 init_buffer_from_sam (uint8 **buf, struct samu *sampass, BOOL size_only)
682 {
683         return init_buffer_from_sam_v3(buf, sampass, size_only);
684 }
685
686 /**********************************************************************
687  Intialize a BYTE buffer from a struct samu struct
688  *********************************************************************/
689
690 static BOOL tdbsam_convert(int32 from) 
691 {
692         const char      *vstring = TDBSAM_VERSION_STRING;
693         const char      *prefix = USERPREFIX;
694         TDB_DATA        data, key, old_key;
695         uint8           *buf = NULL;
696         BOOL            ret;
697
698         /* handle a Samba upgrade */
699         tdb_lock_bystring(tdbsam, vstring);
700         
701         /* Enumerate all records and convert them */
702         key = tdb_firstkey(tdbsam);
703
704         while (key.dptr) {
705         
706                 /* skip all non-USER entries (eg. RIDs) */
707                 while ((key.dsize != 0) && (strncmp(key.dptr, prefix, strlen (prefix)))) {
708                         old_key = key;
709                         /* increment to next in line */
710                         key = tdb_nextkey(tdbsam, key);
711                         SAFE_FREE(old_key.dptr);
712                 }
713         
714                 if (key.dptr) {
715                         struct samu *user = NULL;
716
717                         /* read from tdbsam */
718                         data = tdb_fetch(tdbsam, key);
719                         if (!data.dptr) {
720                                 DEBUG(0,("tdbsam_convert: database entry not found: %s.\n",key.dptr));
721                                 return False;
722                         }
723         
724                         /* unpack the buffer from the former format */
725                         if ( !(user = samu_new( NULL )) ) {
726                                 DEBUG(0,("tdbsam_convert: samu_new() failed!\n"));
727                                 SAFE_FREE( data.dptr );
728                                 return False;
729                         }
730                         DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) (version:%d)\n", key.dptr, from));
731                         switch (from) {
732                                 case 0:
733                                         ret = init_sam_from_buffer_v0(user, (uint8 *)data.dptr, data.dsize);
734                                         break;
735                                 case 1:
736                                         ret = init_sam_from_buffer_v1(user, (uint8 *)data.dptr, data.dsize);
737                                         break;
738                                 case 2:
739                                         ret = init_sam_from_buffer_v2(user, (uint8 *)data.dptr, data.dsize);
740                                         break;
741                                 case 3:
742                                         ret = init_sam_from_buffer_v3(user, (uint8 *)data.dptr, data.dsize);
743                                         break;
744                                 default:
745                                         /* unknown tdbsam version */
746                                         ret = False;
747                         }
748                         if (!ret) {
749                                 DEBUG(0,("tdbsam_convert: Bad struct samu entry returned from TDB (key:%s) (version:%d)\n", key.dptr, from));
750                                 SAFE_FREE(data.dptr);
751                                 TALLOC_FREE(user );
752                                 return False;
753                         }
754         
755                         /* We're finished with the old data. */
756                         SAFE_FREE(data.dptr);
757
758                         /* pack from the buffer into the new format */
759                         
760                         DEBUG(10,("tdbsam_convert: Try packing a record (key:%s) (version:%d)\n", key.dptr, from));
761                         data.dsize = init_buffer_from_sam (&buf, user, False);
762                         TALLOC_FREE(user );
763                         
764                         if ( data.dsize == -1 ) {
765                                 DEBUG(0,("tdbsam_convert: cannot pack the struct samu into the new format\n"));
766                                 return False;
767                         }
768                         data.dptr = (char *)buf;
769                         
770                         /* Store the buffer inside the TDBSAM */
771                         if (tdb_store(tdbsam, key, data, TDB_MODIFY) != TDB_SUCCESS) {
772                                 DEBUG(0,("tdbsam_convert: cannot store the struct samu (key:%s) in new format\n",key.dptr));
773                                 SAFE_FREE(data.dptr);
774                                 return False;
775                         }
776                         
777                         SAFE_FREE(data.dptr);
778                         
779                         /* increment to next in line */
780                         old_key = key;
781                         key = tdb_nextkey(tdbsam, key);
782                         SAFE_FREE(old_key.dptr);
783                 }
784                 
785         }
786
787         
788         /* upgrade finished */
789         tdb_store_int32(tdbsam, vstring, TDBSAM_VERSION);
790         tdb_unlock_bystring(tdbsam, vstring);
791
792         return(True);   
793 }
794
795 /*********************************************************************
796  Open the tdbsam file based on the absolute path specified.
797  Uses a reference count to allow multiple open calls.
798 *********************************************************************/
799
800 static BOOL tdbsam_open( const char *name )
801 {
802         int32   version;
803         
804         /* check if we are already open */
805         
806         if ( tdbsam ) {
807                 ref_count++;
808                 DEBUG(8,("tdbsam_open: Incrementing open reference count.  Ref count is now %d\n", 
809                         ref_count));
810                 return True;
811         }
812         
813         SMB_ASSERT( ref_count == 0 );
814         
815         /* Try to open tdb passwd.  Create a new one if necessary */
816         
817         if (!(tdbsam = tdb_open_log(name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600))) {
818                 DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd [%s]\n", name));
819                 return False;
820         }
821
822         /* set the initial reference count - must be done before tdbsam_convert
823            as that calls tdbsam_open()/tdbsam_close(). */
824
825         ref_count = 1;
826
827         /* Check the version */
828         version = tdb_fetch_int32( tdbsam, TDBSAM_VERSION_STRING );
829         
830         if (version == -1) {
831                 version = 0;    /* Version not found, assume version 0 */
832         }
833         
834         /* Compare the version */
835         if (version > TDBSAM_VERSION) {
836                 /* Version more recent than the latest known */ 
837                 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
838                 tdb_close( tdbsam );
839                 ref_count = 0;
840                 return False;
841         } 
842         
843         
844         if ( version < TDBSAM_VERSION ) {       
845                 DEBUG(1, ("tdbsam_open: Converting version %d database to version %d.\n", 
846                         version, TDBSAM_VERSION));
847                 
848                 if ( !tdbsam_convert(version) ) {
849                         DEBUG(0, ("tdbsam_open: Error when trying to convert tdbsam [%s]\n",name));
850                         tdb_close(tdbsam);
851                         ref_count = 0;
852                         return False;
853                 }
854                         
855                 DEBUG(3, ("TDBSAM converted successfully.\n"));
856         }
857         
858         DEBUG(4,("tdbsam_open: successfully opened %s\n", name ));      
859         
860         return True;
861 }
862
863 /****************************************************************************
864  wrapper atound tdb_close() to handle the reference count
865 ****************************************************************************/
866
867 void tdbsam_close( void )
868 {
869         ref_count--;
870         
871         DEBUG(8,("tdbsam_close: Reference count is now %d.\n", ref_count));
872
873         SMB_ASSERT(ref_count >= 0 );
874         
875         if ( ref_count == 0 ) {
876                 tdb_close( tdbsam );
877                 tdbsam = NULL;
878         }
879         
880         return;
881 }
882
883 /****************************************************************************
884  creates a list of user keys
885 ****************************************************************************/
886
887 static int tdbsam_traverse_setpwent(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state)
888 {
889         const char *prefix = USERPREFIX;
890         int  prefixlen = strlen (prefix);
891         struct pwent_list *ptr;
892         
893         if ( strncmp(key.dptr, prefix, prefixlen) == 0 ) {
894                 if ( !(ptr=SMB_MALLOC_P(struct pwent_list)) ) {
895                         DEBUG(0,("tdbsam_traverse_setpwent: Failed to malloc new entry for list\n"));
896                         
897                         /* just return 0 and let the traversal continue */
898                         return 0;
899                 }
900                 ZERO_STRUCTP(ptr);
901                 
902                 /* save a copy of the key */
903                 
904                 ptr->key.dptr = memdup( key.dptr, key.dsize );
905                 if (!ptr->key.dptr) {
906                         DEBUG(0,("tdbsam_traverse_setpwent: memdup failed\n"));
907                         /* just return 0 and let the traversal continue */
908                         return 0;
909                 }
910
911                 ptr->key.dsize = key.dsize;
912                 
913                 DLIST_ADD( tdbsam_pwent_list, ptr );
914         
915         }
916         
917         
918         return 0;
919 }
920
921 /***************************************************************
922  Open the TDB passwd database for SAM account enumeration.
923  Save a list of user keys for iteration.
924 ****************************************************************/
925
926 static NTSTATUS tdbsam_setsampwent(struct pdb_methods *my_methods, BOOL update, uint32 acb_mask)
927 {
928         if ( !tdbsam_open( tdbsam_filename ) ) {
929                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
930                 return NT_STATUS_ACCESS_DENIED;
931         }
932
933         tdb_traverse( tdbsam, tdbsam_traverse_setpwent, NULL );
934         pwent_initialized = True;
935
936         return NT_STATUS_OK;
937 }
938
939
940 /***************************************************************
941  End enumeration of the TDB passwd list.
942 ****************************************************************/
943
944 static void tdbsam_endsampwent(struct pdb_methods *my_methods)
945 {
946         struct pwent_list *ptr, *ptr_next;
947         
948         /* close the tdb only if we have a valid pwent state */
949         
950         if ( pwent_initialized ) {
951                 DEBUG(7, ("endtdbpwent: closed sam database.\n"));
952                 tdbsam_close();
953         }
954         
955         /* clear out any remaining entries in the list */
956         
957         for ( ptr=tdbsam_pwent_list; ptr; ptr = ptr_next ) {
958                 ptr_next = ptr->next;
959                 DLIST_REMOVE( tdbsam_pwent_list, ptr );
960                 SAFE_FREE( ptr->key.dptr);
961                 SAFE_FREE( ptr );
962         }       
963         
964         pwent_initialized = False;
965 }
966
967 /*****************************************************************
968  Get one struct samu from the TDB (next in line)
969 *****************************************************************/
970
971 static NTSTATUS tdbsam_getsampwent(struct pdb_methods *my_methods, struct samu *user)
972 {
973         NTSTATUS                nt_status = NT_STATUS_UNSUCCESSFUL;
974         TDB_DATA                data;
975         struct pwent_list       *pkey;
976
977         if ( !user ) {
978                 DEBUG(0,("tdbsam_getsampwent: struct samu is NULL.\n"));
979                 return nt_status;
980         }
981
982         if ( !tdbsam_pwent_list ) {
983                 DEBUG(4,("tdbsam_getsampwent: end of list\n"));
984                 return nt_status;
985         }
986         
987         /* pull the next entry */
988                 
989         pkey = tdbsam_pwent_list;
990         DLIST_REMOVE( tdbsam_pwent_list, pkey );
991         
992         data = tdb_fetch(tdbsam, pkey->key);
993
994         SAFE_FREE( pkey->key.dptr);
995         SAFE_FREE( pkey);
996         
997         if ( !data.dptr ) {
998                 DEBUG(5,("pdb_getsampwent: database entry not found.  Was the user deleted?\n"));
999                 return nt_status;
1000         }
1001   
1002         if ( !init_sam_from_buffer(user, (unsigned char *)data.dptr, data.dsize) ) {
1003                 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
1004         }
1005         
1006         SAFE_FREE( data.dptr );
1007
1008         return NT_STATUS_OK;
1009 }
1010
1011 /******************************************************************
1012  Lookup a name in the SAM TDB
1013 ******************************************************************/
1014
1015 static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods, struct samu *user, const char *sname)
1016 {
1017         TDB_DATA        data, key;
1018         fstring         keystr;
1019         fstring         name;
1020
1021         if ( !user ) {
1022                 DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
1023                 return NT_STATUS_NO_MEMORY;
1024         }
1025
1026         /* Data is stored in all lower-case */
1027         fstrcpy(name, sname);
1028         strlower_m(name);
1029
1030         /* set search key */
1031         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
1032         key.dptr = keystr;
1033         key.dsize = strlen(keystr) + 1;
1034
1035         /* open the database */
1036                 
1037         if ( !tdbsam_open( tdbsam_filename ) ) {
1038                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
1039                 return NT_STATUS_ACCESS_DENIED;
1040         }
1041         
1042         /* get the record */
1043         
1044         data = tdb_fetch(tdbsam, key);
1045         if (!data.dptr) {
1046                 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
1047                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
1048                 DEBUGADD(5, (" Key: %s\n", keystr));
1049                 tdbsam_close();
1050                 return NT_STATUS_NO_SUCH_USER;
1051         }
1052   
1053         /* unpack the buffer */
1054         
1055         if (!init_sam_from_buffer(user, (unsigned char *)data.dptr, data.dsize)) {
1056                 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
1057                 SAFE_FREE(data.dptr);
1058                 tdbsam_close();
1059                 return NT_STATUS_NO_MEMORY;
1060         }
1061         
1062         /* success */
1063         
1064         SAFE_FREE(data.dptr);
1065         tdbsam_close();
1066         
1067         return NT_STATUS_OK;
1068 }
1069
1070 /***************************************************************************
1071  Search by rid
1072  **************************************************************************/
1073
1074 static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods, struct samu *user, uint32 rid)
1075 {
1076         NTSTATUS                nt_status = NT_STATUS_UNSUCCESSFUL;
1077         TDB_DATA                data, key;
1078         fstring                 keystr;
1079         fstring                 name;
1080
1081         if ( !user ) {
1082                 DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
1083                 return nt_status;
1084         }
1085         
1086         /* set search key */
1087         
1088         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
1089         key.dptr = keystr;
1090         key.dsize = strlen (keystr) + 1;
1091
1092         /* open the database */
1093                 
1094         if ( !tdbsam_open( tdbsam_filename ) ) {
1095                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
1096                 return NT_STATUS_ACCESS_DENIED;
1097         }
1098
1099         /* get the record */
1100         
1101         data = tdb_fetch (tdbsam, key);
1102         if (!data.dptr) {
1103                 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
1104                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
1105                 nt_status = NT_STATUS_UNSUCCESSFUL;
1106                 goto done;
1107         }
1108
1109         fstrcpy(name, data.dptr);
1110         SAFE_FREE(data.dptr);
1111         
1112         nt_status = tdbsam_getsampwnam (my_methods, user, name);
1113
1114  done:
1115         /* cleanup */
1116         
1117         tdbsam_close();
1118                 
1119         return nt_status;
1120 }
1121
1122 static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods, struct samu * user, const DOM_SID *sid)
1123 {
1124         uint32 rid;
1125         
1126         if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) )
1127                 return NT_STATUS_UNSUCCESSFUL;
1128
1129         return tdbsam_getsampwrid(my_methods, user, rid);
1130 }
1131
1132 static BOOL tdb_delete_samacct_only( struct samu *sam_pass )
1133 {
1134         TDB_DATA        key;
1135         fstring         keystr;
1136         fstring         name;
1137
1138         fstrcpy(name, pdb_get_username(sam_pass));
1139         strlower_m(name);
1140         
1141         /* set the search key */
1142         
1143         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
1144         key.dptr = keystr;
1145         key.dsize = strlen (keystr) + 1;
1146         
1147         /* it's outaa here!  8^) */
1148         
1149         if (tdb_delete(tdbsam, key) != TDB_SUCCESS) {
1150                 DEBUG(5, ("Error deleting entry from tdb passwd database!\n"));
1151                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
1152                 return False;
1153         }
1154         
1155         return True;
1156 }
1157
1158 /***************************************************************************
1159  Delete a struct samu records for the username and RID key
1160 ****************************************************************************/
1161
1162 static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods, struct samu *sam_pass)
1163 {
1164         NTSTATUS        nt_status = NT_STATUS_UNSUCCESSFUL;
1165         TDB_DATA        key;
1166         fstring         keystr;
1167         uint32          rid;
1168         fstring         name;
1169         
1170         /* open the database */
1171                 
1172         if ( !tdbsam_open( tdbsam_filename ) ) {
1173                 DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
1174                          tdbsam_filename));
1175                 return NT_STATUS_ACCESS_DENIED;
1176         }
1177
1178         fstrcpy(name, pdb_get_username(sam_pass));
1179         strlower_m(name);
1180         
1181         /* set the search key */
1182
1183         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
1184         key.dptr = keystr;
1185         key.dsize = strlen (keystr) + 1;
1186         
1187         rid = pdb_get_user_rid(sam_pass);
1188
1189         /* it's outaa here!  8^) */
1190
1191         if ( tdb_delete(tdbsam, key) != TDB_SUCCESS ) {
1192                 DEBUG(5, ("Error deleting entry from tdb passwd database!\n"));
1193                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
1194                 nt_status = NT_STATUS_UNSUCCESSFUL;
1195                 goto done;
1196         }
1197
1198         /* set the search key */
1199         
1200         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
1201         key.dptr = keystr;
1202         key.dsize = strlen (keystr) + 1;
1203
1204         /* it's outaa here!  8^) */
1205         
1206         if ( tdb_delete(tdbsam, key) != TDB_SUCCESS ) {
1207                 DEBUG(5, ("Error deleting entry from tdb rid database!\n"));
1208                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
1209                 nt_status = NT_STATUS_UNSUCCESSFUL;
1210                 goto done;
1211         }
1212
1213         nt_status = NT_STATUS_OK;
1214         
1215  done:
1216         tdbsam_close();
1217         
1218         return nt_status;
1219 }
1220
1221
1222 /***************************************************************************
1223  Update the TDB SAM account record only
1224  Assumes that the tdbsam is already open 
1225 ****************************************************************************/
1226 static BOOL tdb_update_samacct_only( struct samu* newpwd, int flag )
1227 {
1228         TDB_DATA        key, data;
1229         uint8           *buf = NULL;
1230         fstring         keystr;
1231         fstring         name;
1232         BOOL            ret = True;
1233
1234         /* copy the struct samu struct into a BYTE buffer for storage */
1235         
1236         if ( (data.dsize=init_buffer_from_sam (&buf, newpwd, False)) == -1 ) {
1237                 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
1238                 ret = False;
1239                 goto done;
1240         }
1241         data.dptr = (char *)buf;
1242
1243         fstrcpy(name, pdb_get_username(newpwd));
1244         strlower_m(name);
1245         
1246         DEBUG(5, ("Storing %saccount %s with RID %d\n", 
1247                   flag == TDB_INSERT ? "(new) " : "", name, 
1248                   pdb_get_user_rid(newpwd)));
1249
1250         /* setup the USER index key */
1251         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
1252         key.dptr = keystr;
1253         key.dsize = strlen(keystr) + 1;
1254
1255         /* add the account */
1256         
1257         if ( tdb_store(tdbsam, key, data, flag) != TDB_SUCCESS ) {
1258                 DEBUG(0, ("Unable to modify passwd TDB!"));
1259                 DEBUGADD(0, (" Error: %s", tdb_errorstr(tdbsam)));
1260                 DEBUGADD(0, (" occured while storing the main record (%s)\n",
1261                              keystr));
1262                 ret = False;
1263                 goto done;
1264         }
1265
1266 done:   
1267         /* cleanup */
1268         SAFE_FREE(buf);
1269         
1270         return ret;
1271 }
1272
1273 /***************************************************************************
1274  Update the TDB SAM RID record only
1275  Assumes that the tdbsam is already open 
1276 ****************************************************************************/
1277 static BOOL tdb_update_ridrec_only( struct samu* newpwd, int flag )
1278 {
1279         TDB_DATA        key, data;
1280         fstring         keystr;
1281         fstring         name;
1282
1283         fstrcpy(name, pdb_get_username(newpwd));
1284         strlower_m(name);
1285
1286         /* setup RID data */
1287         data.dsize = strlen(name) + 1;
1288         data.dptr = name;
1289
1290         /* setup the RID index key */
1291         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX,  pdb_get_user_rid(newpwd));
1292         key.dptr = keystr;
1293         key.dsize = strlen (keystr) + 1;
1294         
1295         /* add the reference */
1296         if (tdb_store(tdbsam, key, data, flag) != TDB_SUCCESS) {
1297                 DEBUG(0, ("Unable to modify TDB passwd !"));
1298                 DEBUGADD(0, (" Error: %s\n", tdb_errorstr(tdbsam)));
1299                 DEBUGADD(0, (" occured while storing the RID index (%s)\n", keystr));
1300                 return False;
1301         }
1302
1303         return True;
1304
1305 }
1306
1307 /***************************************************************************
1308  Update the TDB SAM
1309 ****************************************************************************/
1310
1311 static BOOL tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd, int flag)
1312 {
1313         uint32          user_rid;
1314         BOOL            result = True;
1315
1316         /* invalidate the existing TDB iterator if it is open */
1317         
1318         tdbsam_endsampwent( my_methods );
1319         
1320 #if 0 
1321         if ( !pdb_get_group_rid(newpwd) ) {
1322                 DEBUG (0,("tdb_update_sam: Failing to store a struct samu for [%s] "
1323                         "without a primary group RID\n", pdb_get_username(newpwd)));
1324                 return False;
1325         }
1326 #endif
1327
1328         if ( !(user_rid = pdb_get_user_rid(newpwd)) ) {
1329                 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n", pdb_get_username(newpwd)));
1330                 return False;
1331         }
1332
1333         /* open the database */
1334                 
1335         if ( !tdbsam_open( tdbsam_filename ) ) {
1336                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
1337                 return False;
1338         }
1339         
1340         if ( !tdb_update_samacct_only(newpwd, flag) || !tdb_update_ridrec_only(newpwd, flag)) {
1341                 result = False;
1342         }
1343
1344         /* cleanup */
1345
1346         tdbsam_close();
1347         
1348         return result;  
1349 }
1350
1351 /***************************************************************************
1352  Modifies an existing struct samu
1353 ****************************************************************************/
1354
1355 static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
1356 {
1357         if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
1358                 return NT_STATUS_UNSUCCESSFUL;
1359         
1360         return NT_STATUS_OK;
1361 }
1362
1363 /***************************************************************************
1364  Adds an existing struct samu
1365 ****************************************************************************/
1366
1367 static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
1368 {
1369         if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
1370                 return NT_STATUS_UNSUCCESSFUL;
1371                 
1372         return NT_STATUS_OK;
1373 }
1374
1375 /***************************************************************************
1376  Renames a struct samu
1377  - check for the posix user/rename user script
1378  - Add and lock the new user record
1379  - rename the posix user
1380  - rewrite the rid->username record
1381  - delete the old user
1382  - unlock the new user record
1383 ***************************************************************************/
1384 static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
1385                                           struct samu *old_acct, 
1386                                           const char *newname)
1387 {
1388         struct samu      *new_acct = NULL;
1389         pstring          rename_script;
1390         BOOL             interim_account = False;
1391         int              rename_ret;
1392
1393         /* can't do anything without an external script */
1394         
1395         pstrcpy(rename_script, lp_renameuser_script() );
1396         if ( ! *rename_script ) {
1397                 return NT_STATUS_ACCESS_DENIED;
1398         }
1399
1400         /* invalidate the existing TDB iterator if it is open */
1401         
1402         tdbsam_endsampwent( my_methods );
1403
1404         if ( !(new_acct = samu_new( NULL )) ) {
1405                 return NT_STATUS_NO_MEMORY;
1406         }
1407         
1408         if ( !pdb_copy_sam_account(new_acct, old_acct) 
1409                 || !pdb_set_username(new_acct, newname, PDB_CHANGED)) 
1410         {
1411                 TALLOC_FREE(new_acct );
1412                 return NT_STATUS_NO_MEMORY;
1413         }
1414
1415         /* open the database */
1416                 
1417         if ( !tdbsam_open( tdbsam_filename ) ) {
1418                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
1419                 TALLOC_FREE(new_acct );
1420                 return NT_STATUS_ACCESS_DENIED;
1421         }
1422
1423         /* add the new account and lock it */
1424         
1425         if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
1426                 goto done;
1427         }
1428         
1429         interim_account = True;
1430
1431         if ( tdb_lock_bystring_with_timeout(tdbsam, newname, 30) == -1 ) {
1432                 goto done;
1433         }
1434
1435         /* rename the posix user */
1436         string_sub2(rename_script, "%unew", newname, sizeof(pstring), 
1437                     True, False, True);
1438         string_sub2(rename_script, "%uold", pdb_get_username(old_acct), 
1439                     sizeof(pstring), True, False, True);
1440         rename_ret = smbrun(rename_script, NULL);
1441
1442         DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n", rename_script, rename_ret));
1443
1444         if (rename_ret) {
1445                 goto done; 
1446         }
1447
1448         /* rewrite the rid->username record */
1449         
1450         if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
1451                 goto done;
1452         }
1453         interim_account = False;
1454         tdb_unlock_bystring( tdbsam, newname );
1455
1456         tdb_delete_samacct_only( old_acct );
1457         
1458         tdbsam_close();
1459         
1460         TALLOC_FREE(new_acct );
1461         return NT_STATUS_OK;
1462
1463 done:   
1464         /* cleanup */
1465         if (interim_account) {
1466                 tdb_unlock_bystring(tdbsam, newname);
1467                 tdb_delete_samacct_only(new_acct);
1468         }
1469         
1470         tdbsam_close();
1471         
1472         if (new_acct)
1473                 TALLOC_FREE(new_acct);
1474         
1475         return NT_STATUS_ACCESS_DENIED; 
1476 }
1477
1478 static BOOL tdbsam_rid_algorithm(struct pdb_methods *methods)
1479 {
1480         return False;
1481 }
1482
1483 /*
1484  * Historically, winbind was responsible for allocating RIDs, so the next RID
1485  * value was stored in winbindd_idmap.tdb. It has been moved to passdb now,
1486  * but for compatibility reasons we still keep the the next RID counter in
1487  * winbindd_idmap.tdb.
1488  */
1489
1490 /*****************************************************************************
1491  Initialise idmap database. For now (Dec 2005) this is a copy of the code in
1492  sam/idmap_tdb.c. Maybe at a later stage we can remove that capability from
1493  winbind completely and store the RID counter in passdb.tdb.
1494
1495  Dont' fully initialize with the HWM values, if it's new, we're only
1496  interested in the RID counter.
1497 *****************************************************************************/
1498
1499 static BOOL init_idmap_tdb(TDB_CONTEXT *tdb)
1500 {
1501         int32 version;
1502
1503         if (tdb_lock_bystring(tdb, "IDMAP_VERSION") != 0) {
1504                 DEBUG(0, ("Could not lock IDMAP_VERSION\n"));
1505                 return False;
1506         }
1507
1508         version = tdb_fetch_int32(tdb, "IDMAP_VERSION");
1509
1510         if (version == -1) {
1511                 /* No key found, must be a new db */
1512                 if (tdb_store_int32(tdb, "IDMAP_VERSION",
1513                                     IDMAP_VERSION) != 0) {
1514                         DEBUG(0, ("Could not store IDMAP_VERSION\n"));
1515                         tdb_unlock_bystring(tdb, "IDMAP_VERSION");
1516                         return False;
1517                 }
1518                 version = IDMAP_VERSION;
1519         }
1520
1521         if (version != IDMAP_VERSION) {
1522                 DEBUG(0, ("Expected IDMAP_VERSION=%d, found %d. Please "
1523                           "start winbind once\n", IDMAP_VERSION, version));
1524                 tdb_unlock_bystring(tdb, "IDMAP_VERSION");
1525                 return False;
1526         }
1527
1528         tdb_unlock_bystring(tdb, "IDMAP_VERSION");
1529         return True;
1530 }
1531
1532 static BOOL tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid)
1533 {
1534         TDB_CONTEXT *tdb;
1535         uint32 rid;
1536         BOOL ret = False;
1537
1538         tdb = tdb_open_log(lock_path("winbindd_idmap.tdb"), 0,
1539                            TDB_DEFAULT, O_RDWR | O_CREAT, 0644);
1540
1541         if (tdb == NULL) {
1542                 DEBUG(1, ("Could not open idmap: %s\n", strerror(errno)));
1543                 goto done;
1544         }
1545
1546         if (!init_idmap_tdb(tdb)) {
1547                 DEBUG(1, ("Could not init idmap\n"));
1548                 goto done;
1549         }
1550
1551         rid = BASE_RID;         /* Default if not set */
1552
1553         if (!tdb_change_uint32_atomic(tdb, "RID_COUNTER", &rid, 1)) {
1554                 DEBUG(3, ("tdbsam_new_rid: Failed to increase RID_COUNTER\n"));
1555                 goto done;
1556         }
1557
1558         *prid = rid;
1559         ret = True;
1560
1561  done:
1562         if ((tdb != NULL) && (tdb_close(tdb) != 0)) {
1563                 smb_panic("tdb_close(idmap_tdb) failed\n");
1564         }
1565
1566         return ret;
1567 }
1568
1569 /*********************************************************************
1570  Initialize the tdb sam backend.  Setup the dispath table of methods,
1571  open the tdb, etc...
1572 *********************************************************************/
1573
1574 static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
1575 {
1576         NTSTATUS nt_status;
1577         pstring tdbfile;
1578         const char *pfile = location;
1579
1580         if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
1581                 return nt_status;
1582         }
1583
1584         (*pdb_method)->name = "tdbsam";
1585
1586         (*pdb_method)->setsampwent = tdbsam_setsampwent;
1587         (*pdb_method)->endsampwent = tdbsam_endsampwent;
1588         (*pdb_method)->getsampwent = tdbsam_getsampwent;
1589         (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
1590         (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
1591         (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
1592         (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
1593         (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
1594         (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
1595
1596         (*pdb_method)->rid_algorithm = tdbsam_rid_algorithm;
1597         (*pdb_method)->new_rid = tdbsam_new_rid;
1598
1599         /* save the path for later */
1600                            
1601         if ( !location ) {
1602                 pstr_sprintf( tdbfile, "%s/%s", lp_private_dir(), PASSDB_FILE_NAME );
1603                 pfile = tdbfile;
1604         }
1605         pstrcpy( tdbsam_filename, pfile );
1606
1607         /* no private data */
1608         
1609         (*pdb_method)->private_data      = NULL;
1610         (*pdb_method)->free_private_data = NULL;
1611
1612         return NT_STATUS_OK;
1613 }
1614
1615 NTSTATUS pdb_tdbsam_init(void)
1616 {
1617         return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);
1618 }