r16014: Correctly set the group RID in init_sam_from_buffer.
[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                 ptr->key.dsize = key.dsize;
906                 
907                 DLIST_ADD( tdbsam_pwent_list, ptr );
908         
909         }
910         
911         
912         return 0;
913 }
914
915 /***************************************************************
916  Open the TDB passwd database for SAM account enumeration.
917  Save a list of user keys for iteration.
918 ****************************************************************/
919
920 static NTSTATUS tdbsam_setsampwent(struct pdb_methods *my_methods, BOOL update, uint32 acb_mask)
921 {
922         if ( !tdbsam_open( tdbsam_filename ) ) {
923                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
924                 return NT_STATUS_ACCESS_DENIED;
925         }
926
927         tdb_traverse( tdbsam, tdbsam_traverse_setpwent, NULL );
928         pwent_initialized = True;
929
930         return NT_STATUS_OK;
931 }
932
933
934 /***************************************************************
935  End enumeration of the TDB passwd list.
936 ****************************************************************/
937
938 static void tdbsam_endsampwent(struct pdb_methods *my_methods)
939 {
940         struct pwent_list *ptr, *ptr_next;
941         
942         /* close the tdb only if we have a valid pwent state */
943         
944         if ( pwent_initialized ) {
945                 DEBUG(7, ("endtdbpwent: closed sam database.\n"));
946                 tdbsam_close();
947         }
948         
949         /* clear out any remaining entries in the list */
950         
951         for ( ptr=tdbsam_pwent_list; ptr; ptr = ptr_next ) {
952                 ptr_next = ptr->next;
953                 DLIST_REMOVE( tdbsam_pwent_list, ptr );
954                 SAFE_FREE( ptr->key.dptr);
955                 SAFE_FREE( ptr );
956         }       
957         
958         pwent_initialized = False;
959 }
960
961 /*****************************************************************
962  Get one struct samu from the TDB (next in line)
963 *****************************************************************/
964
965 static NTSTATUS tdbsam_getsampwent(struct pdb_methods *my_methods, struct samu *user)
966 {
967         NTSTATUS                nt_status = NT_STATUS_UNSUCCESSFUL;
968         TDB_DATA                data;
969         struct pwent_list       *pkey;
970
971         if ( !user ) {
972                 DEBUG(0,("tdbsam_getsampwent: struct samu is NULL.\n"));
973                 return nt_status;
974         }
975
976         if ( !tdbsam_pwent_list ) {
977                 DEBUG(4,("tdbsam_getsampwent: end of list\n"));
978                 return nt_status;
979         }
980         
981         /* pull the next entry */
982                 
983         pkey = tdbsam_pwent_list;
984         DLIST_REMOVE( tdbsam_pwent_list, pkey );
985         
986         data = tdb_fetch(tdbsam, pkey->key);
987
988         SAFE_FREE( pkey->key.dptr);
989         SAFE_FREE( pkey);
990         
991         if ( !data.dptr ) {
992                 DEBUG(5,("pdb_getsampwent: database entry not found.  Was the user deleted?\n"));
993                 return nt_status;
994         }
995   
996         if ( !init_sam_from_buffer(user, (unsigned char *)data.dptr, data.dsize) ) {
997                 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
998         }
999         
1000         SAFE_FREE( data.dptr );
1001
1002         return NT_STATUS_OK;
1003 }
1004
1005 /******************************************************************
1006  Lookup a name in the SAM TDB
1007 ******************************************************************/
1008
1009 static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods, struct samu *user, const char *sname)
1010 {
1011         TDB_DATA        data, key;
1012         fstring         keystr;
1013         fstring         name;
1014
1015         if ( !user ) {
1016                 DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
1017                 return NT_STATUS_NO_MEMORY;
1018         }
1019
1020         /* Data is stored in all lower-case */
1021         fstrcpy(name, sname);
1022         strlower_m(name);
1023
1024         /* set search key */
1025         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
1026         key.dptr = keystr;
1027         key.dsize = strlen(keystr) + 1;
1028
1029         /* open the database */
1030                 
1031         if ( !tdbsam_open( tdbsam_filename ) ) {
1032                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
1033                 return NT_STATUS_ACCESS_DENIED;
1034         }
1035         
1036         /* get the record */
1037         
1038         data = tdb_fetch(tdbsam, key);
1039         if (!data.dptr) {
1040                 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
1041                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
1042                 DEBUGADD(5, (" Key: %s\n", keystr));
1043                 tdbsam_close();
1044                 return NT_STATUS_NO_SUCH_USER;
1045         }
1046   
1047         /* unpack the buffer */
1048         
1049         if (!init_sam_from_buffer(user, (unsigned char *)data.dptr, data.dsize)) {
1050                 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
1051                 SAFE_FREE(data.dptr);
1052                 tdbsam_close();
1053                 return NT_STATUS_NO_MEMORY;
1054         }
1055         
1056         /* success */
1057         
1058         SAFE_FREE(data.dptr);
1059         tdbsam_close();
1060         
1061         return NT_STATUS_OK;
1062 }
1063
1064 /***************************************************************************
1065  Search by rid
1066  **************************************************************************/
1067
1068 static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods, struct samu *user, uint32 rid)
1069 {
1070         NTSTATUS                nt_status = NT_STATUS_UNSUCCESSFUL;
1071         TDB_DATA                data, key;
1072         fstring                 keystr;
1073         fstring                 name;
1074
1075         if ( !user ) {
1076                 DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
1077                 return nt_status;
1078         }
1079         
1080         /* set search key */
1081         
1082         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
1083         key.dptr = keystr;
1084         key.dsize = strlen (keystr) + 1;
1085
1086         /* open the database */
1087                 
1088         if ( !tdbsam_open( tdbsam_filename ) ) {
1089                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
1090                 return NT_STATUS_ACCESS_DENIED;
1091         }
1092
1093         /* get the record */
1094         
1095         data = tdb_fetch (tdbsam, key);
1096         if (!data.dptr) {
1097                 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
1098                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
1099                 nt_status = NT_STATUS_UNSUCCESSFUL;
1100                 goto done;
1101         }
1102
1103         fstrcpy(name, data.dptr);
1104         SAFE_FREE(data.dptr);
1105         
1106         nt_status = tdbsam_getsampwnam (my_methods, user, name);
1107
1108  done:
1109         /* cleanup */
1110         
1111         tdbsam_close();
1112                 
1113         return nt_status;
1114 }
1115
1116 static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods, struct samu * user, const DOM_SID *sid)
1117 {
1118         uint32 rid;
1119         
1120         if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) )
1121                 return NT_STATUS_UNSUCCESSFUL;
1122
1123         return tdbsam_getsampwrid(my_methods, user, rid);
1124 }
1125
1126 static BOOL tdb_delete_samacct_only( struct samu *sam_pass )
1127 {
1128         TDB_DATA        key;
1129         fstring         keystr;
1130         fstring         name;
1131
1132         fstrcpy(name, pdb_get_username(sam_pass));
1133         strlower_m(name);
1134         
1135         /* set the search key */
1136         
1137         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
1138         key.dptr = keystr;
1139         key.dsize = strlen (keystr) + 1;
1140         
1141         /* it's outaa here!  8^) */
1142         
1143         if (tdb_delete(tdbsam, key) != TDB_SUCCESS) {
1144                 DEBUG(5, ("Error deleting entry from tdb passwd database!\n"));
1145                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
1146                 return False;
1147         }
1148         
1149         return True;
1150 }
1151
1152 /***************************************************************************
1153  Delete a struct samu records for the username and RID key
1154 ****************************************************************************/
1155
1156 static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods, struct samu *sam_pass)
1157 {
1158         NTSTATUS        nt_status = NT_STATUS_UNSUCCESSFUL;
1159         TDB_DATA        key;
1160         fstring         keystr;
1161         uint32          rid;
1162         fstring         name;
1163         
1164         /* open the database */
1165                 
1166         if ( !tdbsam_open( tdbsam_filename ) ) {
1167                 DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
1168                          tdbsam_filename));
1169                 return NT_STATUS_ACCESS_DENIED;
1170         }
1171
1172         fstrcpy(name, pdb_get_username(sam_pass));
1173         strlower_m(name);
1174         
1175         /* set the search key */
1176
1177         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
1178         key.dptr = keystr;
1179         key.dsize = strlen (keystr) + 1;
1180         
1181         rid = pdb_get_user_rid(sam_pass);
1182
1183         /* it's outaa here!  8^) */
1184
1185         if ( tdb_delete(tdbsam, key) != TDB_SUCCESS ) {
1186                 DEBUG(5, ("Error deleting entry from tdb passwd database!\n"));
1187                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
1188                 nt_status = NT_STATUS_UNSUCCESSFUL;
1189                 goto done;
1190         }
1191
1192         /* set the search key */
1193         
1194         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
1195         key.dptr = keystr;
1196         key.dsize = strlen (keystr) + 1;
1197
1198         /* it's outaa here!  8^) */
1199         
1200         if ( tdb_delete(tdbsam, key) != TDB_SUCCESS ) {
1201                 DEBUG(5, ("Error deleting entry from tdb rid database!\n"));
1202                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
1203                 nt_status = NT_STATUS_UNSUCCESSFUL;
1204                 goto done;
1205         }
1206
1207         nt_status = NT_STATUS_OK;
1208         
1209  done:
1210         tdbsam_close();
1211         
1212         return nt_status;
1213 }
1214
1215
1216 /***************************************************************************
1217  Update the TDB SAM account record only
1218  Assumes that the tdbsam is already open 
1219 ****************************************************************************/
1220 static BOOL tdb_update_samacct_only( struct samu* newpwd, int flag )
1221 {
1222         TDB_DATA        key, data;
1223         uint8           *buf = NULL;
1224         fstring         keystr;
1225         fstring         name;
1226         BOOL            ret = True;
1227
1228         /* copy the struct samu struct into a BYTE buffer for storage */
1229         
1230         if ( (data.dsize=init_buffer_from_sam (&buf, newpwd, False)) == -1 ) {
1231                 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
1232                 ret = False;
1233                 goto done;
1234         }
1235         data.dptr = (char *)buf;
1236
1237         fstrcpy(name, pdb_get_username(newpwd));
1238         strlower_m(name);
1239         
1240         DEBUG(5, ("Storing %saccount %s with RID %d\n", 
1241                   flag == TDB_INSERT ? "(new) " : "", name, 
1242                   pdb_get_user_rid(newpwd)));
1243
1244         /* setup the USER index key */
1245         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
1246         key.dptr = keystr;
1247         key.dsize = strlen(keystr) + 1;
1248
1249         /* add the account */
1250         
1251         if ( tdb_store(tdbsam, key, data, flag) != TDB_SUCCESS ) {
1252                 DEBUG(0, ("Unable to modify passwd TDB!"));
1253                 DEBUGADD(0, (" Error: %s", tdb_errorstr(tdbsam)));
1254                 DEBUGADD(0, (" occured while storing the main record (%s)\n",
1255                              keystr));
1256                 ret = False;
1257                 goto done;
1258         }
1259
1260 done:   
1261         /* cleanup */
1262         SAFE_FREE(buf);
1263         
1264         return ret;
1265 }
1266
1267 /***************************************************************************
1268  Update the TDB SAM RID record only
1269  Assumes that the tdbsam is already open 
1270 ****************************************************************************/
1271 static BOOL tdb_update_ridrec_only( struct samu* newpwd, int flag )
1272 {
1273         TDB_DATA        key, data;
1274         fstring         keystr;
1275         fstring         name;
1276
1277         fstrcpy(name, pdb_get_username(newpwd));
1278         strlower_m(name);
1279
1280         /* setup RID data */
1281         data.dsize = strlen(name) + 1;
1282         data.dptr = name;
1283
1284         /* setup the RID index key */
1285         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX,  pdb_get_user_rid(newpwd));
1286         key.dptr = keystr;
1287         key.dsize = strlen (keystr) + 1;
1288         
1289         /* add the reference */
1290         if (tdb_store(tdbsam, key, data, flag) != TDB_SUCCESS) {
1291                 DEBUG(0, ("Unable to modify TDB passwd !"));
1292                 DEBUGADD(0, (" Error: %s\n", tdb_errorstr(tdbsam)));
1293                 DEBUGADD(0, (" occured while storing the RID index (%s)\n", keystr));
1294                 return False;
1295         }
1296
1297         return True;
1298
1299 }
1300
1301 /***************************************************************************
1302  Update the TDB SAM
1303 ****************************************************************************/
1304
1305 static BOOL tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd, int flag)
1306 {
1307         uint32          user_rid;
1308         BOOL            result = True;
1309
1310         /* invalidate the existing TDB iterator if it is open */
1311         
1312         tdbsam_endsampwent( my_methods );
1313         
1314 #if 0 
1315         if ( !pdb_get_group_rid(newpwd) ) {
1316                 DEBUG (0,("tdb_update_sam: Failing to store a struct samu for [%s] "
1317                         "without a primary group RID\n", pdb_get_username(newpwd)));
1318                 return False;
1319         }
1320 #endif
1321
1322         if ( !(user_rid = pdb_get_user_rid(newpwd)) ) {
1323                 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n", pdb_get_username(newpwd)));
1324                 return False;
1325         }
1326
1327         /* open the database */
1328                 
1329         if ( !tdbsam_open( tdbsam_filename ) ) {
1330                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
1331                 return False;
1332         }
1333         
1334         if ( !tdb_update_samacct_only(newpwd, flag) || !tdb_update_ridrec_only(newpwd, flag)) {
1335                 result = False;
1336         }
1337
1338         /* cleanup */
1339
1340         tdbsam_close();
1341         
1342         return result;  
1343 }
1344
1345 /***************************************************************************
1346  Modifies an existing struct samu
1347 ****************************************************************************/
1348
1349 static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
1350 {
1351         if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
1352                 return NT_STATUS_UNSUCCESSFUL;
1353         
1354         return NT_STATUS_OK;
1355 }
1356
1357 /***************************************************************************
1358  Adds an existing struct samu
1359 ****************************************************************************/
1360
1361 static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
1362 {
1363         if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
1364                 return NT_STATUS_UNSUCCESSFUL;
1365                 
1366         return NT_STATUS_OK;
1367 }
1368
1369 /***************************************************************************
1370  Renames a struct samu
1371  - check for the posix user/rename user script
1372  - Add and lock the new user record
1373  - rename the posix user
1374  - rewrite the rid->username record
1375  - delete the old user
1376  - unlock the new user record
1377 ***************************************************************************/
1378 static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
1379                                           struct samu *old_acct, 
1380                                           const char *newname)
1381 {
1382         struct samu      *new_acct = NULL;
1383         pstring          rename_script;
1384         BOOL             interim_account = False;
1385         int              rename_ret;
1386
1387         /* can't do anything without an external script */
1388         
1389         pstrcpy(rename_script, lp_renameuser_script() );
1390         if ( ! *rename_script ) {
1391                 return NT_STATUS_ACCESS_DENIED;
1392         }
1393
1394         /* invalidate the existing TDB iterator if it is open */
1395         
1396         tdbsam_endsampwent( my_methods );
1397
1398         if ( !(new_acct = samu_new( NULL )) ) {
1399                 return NT_STATUS_NO_MEMORY;
1400         }
1401         
1402         if ( !pdb_copy_sam_account(new_acct, old_acct) 
1403                 || !pdb_set_username(new_acct, newname, PDB_CHANGED)) 
1404         {
1405                 TALLOC_FREE(new_acct );
1406                 return NT_STATUS_NO_MEMORY;
1407         }
1408
1409         /* open the database */
1410                 
1411         if ( !tdbsam_open( tdbsam_filename ) ) {
1412                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
1413                 TALLOC_FREE(new_acct );
1414                 return NT_STATUS_ACCESS_DENIED;
1415         }
1416
1417         /* add the new account and lock it */
1418         
1419         if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
1420                 goto done;
1421         }
1422         
1423         interim_account = True;
1424
1425         if ( tdb_lock_bystring_with_timeout(tdbsam, newname, 30) == -1 ) {
1426                 goto done;
1427         }
1428
1429         /* rename the posix user */
1430         string_sub2(rename_script, "%unew", newname, sizeof(pstring), 
1431                     True, False, True);
1432         string_sub2(rename_script, "%uold", pdb_get_username(old_acct), 
1433                     sizeof(pstring), True, False, True);
1434         rename_ret = smbrun(rename_script, NULL);
1435
1436         DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n", rename_script, rename_ret));
1437
1438         if (rename_ret) {
1439                 goto done; 
1440         }
1441
1442         /* rewrite the rid->username record */
1443         
1444         if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
1445                 goto done;
1446         }
1447         interim_account = False;
1448         tdb_unlock_bystring( tdbsam, newname );
1449
1450         tdb_delete_samacct_only( old_acct );
1451         
1452         tdbsam_close();
1453         
1454         TALLOC_FREE(new_acct );
1455         return NT_STATUS_OK;
1456
1457 done:   
1458         /* cleanup */
1459         if (interim_account) {
1460                 tdb_unlock_bystring(tdbsam, newname);
1461                 tdb_delete_samacct_only(new_acct);
1462         }
1463         
1464         tdbsam_close();
1465         
1466         if (new_acct)
1467                 TALLOC_FREE(new_acct);
1468         
1469         return NT_STATUS_ACCESS_DENIED; 
1470 }
1471
1472 static BOOL tdbsam_rid_algorithm(struct pdb_methods *methods)
1473 {
1474         return False;
1475 }
1476
1477 /*
1478  * Historically, winbind was responsible for allocating RIDs, so the next RID
1479  * value was stored in winbindd_idmap.tdb. It has been moved to passdb now,
1480  * but for compatibility reasons we still keep the the next RID counter in
1481  * winbindd_idmap.tdb.
1482  */
1483
1484 /*****************************************************************************
1485  Initialise idmap database. For now (Dec 2005) this is a copy of the code in
1486  sam/idmap_tdb.c. Maybe at a later stage we can remove that capability from
1487  winbind completely and store the RID counter in passdb.tdb.
1488
1489  Dont' fully initialize with the HWM values, if it's new, we're only
1490  interested in the RID counter.
1491 *****************************************************************************/
1492
1493 static BOOL init_idmap_tdb(TDB_CONTEXT *tdb)
1494 {
1495         int32 version;
1496
1497         if (tdb_lock_bystring(tdb, "IDMAP_VERSION") != 0) {
1498                 DEBUG(0, ("Could not lock IDMAP_VERSION\n"));
1499                 return False;
1500         }
1501
1502         version = tdb_fetch_int32(tdb, "IDMAP_VERSION");
1503
1504         if (version == -1) {
1505                 /* No key found, must be a new db */
1506                 if (tdb_store_int32(tdb, "IDMAP_VERSION",
1507                                     IDMAP_VERSION) != 0) {
1508                         DEBUG(0, ("Could not store IDMAP_VERSION\n"));
1509                         tdb_unlock_bystring(tdb, "IDMAP_VERSION");
1510                         return False;
1511                 }
1512                 version = IDMAP_VERSION;
1513         }
1514
1515         if (version != IDMAP_VERSION) {
1516                 DEBUG(0, ("Expected IDMAP_VERSION=%d, found %d. Please "
1517                           "start winbind once\n", IDMAP_VERSION, version));
1518                 tdb_unlock_bystring(tdb, "IDMAP_VERSION");
1519                 return False;
1520         }
1521
1522         tdb_unlock_bystring(tdb, "IDMAP_VERSION");
1523         return True;
1524 }
1525
1526 static BOOL tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid)
1527 {
1528         TDB_CONTEXT *tdb;
1529         uint32 rid;
1530         BOOL ret = False;
1531
1532         tdb = tdb_open_log(lock_path("winbindd_idmap.tdb"), 0,
1533                            TDB_DEFAULT, O_RDWR | O_CREAT, 0644);
1534
1535         if (tdb == NULL) {
1536                 DEBUG(1, ("Could not open idmap: %s\n", strerror(errno)));
1537                 goto done;
1538         }
1539
1540         if (!init_idmap_tdb(tdb)) {
1541                 DEBUG(1, ("Could not init idmap\n"));
1542                 goto done;
1543         }
1544
1545         rid = BASE_RID;         /* Default if not set */
1546
1547         if (!tdb_change_uint32_atomic(tdb, "RID_COUNTER", &rid, 1)) {
1548                 DEBUG(3, ("tdbsam_new_rid: Failed to increase RID_COUNTER\n"));
1549                 goto done;
1550         }
1551
1552         *prid = rid;
1553         ret = True;
1554
1555  done:
1556         if ((tdb != NULL) && (tdb_close(tdb) != 0)) {
1557                 smb_panic("tdb_close(idmap_tdb) failed\n");
1558         }
1559
1560         return ret;
1561 }
1562
1563 /*********************************************************************
1564  Initialize the tdb sam backend.  Setup the dispath table of methods,
1565  open the tdb, etc...
1566 *********************************************************************/
1567
1568 static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
1569 {
1570         NTSTATUS nt_status;
1571         pstring tdbfile;
1572         const char *pfile = location;
1573
1574         if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
1575                 return nt_status;
1576         }
1577
1578         (*pdb_method)->name = "tdbsam";
1579
1580         (*pdb_method)->setsampwent = tdbsam_setsampwent;
1581         (*pdb_method)->endsampwent = tdbsam_endsampwent;
1582         (*pdb_method)->getsampwent = tdbsam_getsampwent;
1583         (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
1584         (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
1585         (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
1586         (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
1587         (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
1588         (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
1589
1590         (*pdb_method)->rid_algorithm = tdbsam_rid_algorithm;
1591         (*pdb_method)->new_rid = tdbsam_new_rid;
1592
1593         /* save the path for later */
1594                            
1595         if ( !location ) {
1596                 pstr_sprintf( tdbfile, "%s/%s", lp_private_dir(), PASSDB_FILE_NAME );
1597                 pfile = tdbfile;
1598         }
1599         pstrcpy( tdbsam_filename, pfile );
1600
1601         /* no private data */
1602         
1603         (*pdb_method)->private_data      = NULL;
1604         (*pdb_method)->free_private_data = NULL;
1605
1606         return NT_STATUS_OK;
1607 }
1608
1609 NTSTATUS pdb_tdbsam_init(void)
1610 {
1611         return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);
1612 }