first cut at adding full transactions for ctdb to samba3
[samba.git] / source3 / passdb / pdb_tdb.c
1 /*
2  * Unix SMB/CIFS implementation. 
3  * SMB parameters and setup
4  * Copyright (C) Andrew Tridgell   1992-1998
5  * Copyright (C) Simo Sorce        2000-2003
6  * Copyright (C) Gerald Carter     2000-2006
7  * Copyright (C) Jeremy Allison    2001
8  * Copyright (C) Andrew Bartlett   2002
9  * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2005
10  * 
11  * This program is free software; you can redistribute it and/or modify it under
12  * the terms of the GNU General Public License as published by the Free
13  * Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
23  */
24
25 #include "includes.h"
26
27 #if 0 /* when made a module use this */
28
29 static int tdbsam_debug_level = DBGC_ALL;
30 #undef DBGC_CLASS
31 #define DBGC_CLASS tdbsam_debug_level
32
33 #else
34
35 #undef DBGC_CLASS
36 #define DBGC_CLASS DBGC_PASSDB
37
38 #endif
39
40 #define TDBSAM_VERSION  3       /* Most recent TDBSAM version */
41 #define TDBSAM_VERSION_STRING   "INFO/version"
42 #define PASSDB_FILE_NAME        "passdb.tdb"
43 #define USERPREFIX              "USER_"
44 #define USERPREFIX_LEN          5
45 #define RIDPREFIX               "RID_"
46 #define PRIVPREFIX              "PRIV_"
47
48 /* GLOBAL TDB SAM CONTEXT */
49
50 static struct db_context *db_sam;
51 static char *tdbsam_filename;
52
53 /**********************************************************************
54  Marshall/unmarshall struct samu structs.
55  *********************************************************************/
56
57 #define TDB_FORMAT_STRING_V0       "ddddddBBBBBBBBBBBBddBBwdwdBwwd"
58 #define TDB_FORMAT_STRING_V1       "dddddddBBBBBBBBBBBBddBBwdwdBwwd"
59 #define TDB_FORMAT_STRING_V2       "dddddddBBBBBBBBBBBBddBBBwwdBwwd"
60
61 /*********************************************************************
62 *********************************************************************/
63
64 static bool init_sam_from_buffer_v0(struct samu *sampass, uint8 *buf, uint32 buflen)
65 {
66
67         /* times are stored as 32bit integer
68            take care on system with 64bit wide time_t
69            --SSS */
70         uint32  logon_time,
71                 logoff_time,
72                 kickoff_time,
73                 pass_last_set_time,
74                 pass_can_change_time,
75                 pass_must_change_time;
76         char *username = NULL;
77         char *domain = NULL;
78         char *nt_username = NULL;
79         char *dir_drive = NULL;
80         char *unknown_str = NULL;
81         char *munged_dial = NULL;
82         char *fullname = NULL;
83         char *homedir = NULL;
84         char *logon_script = NULL;
85         char *profile_path = NULL;
86         char *acct_desc = NULL;
87         char *workstations = NULL;
88         uint32  username_len, domain_len, nt_username_len,
89                 dir_drive_len, unknown_str_len, munged_dial_len,
90                 fullname_len, homedir_len, logon_script_len,
91                 profile_path_len, acct_desc_len, workstations_len;
92                 
93         uint32  user_rid, group_rid, remove_me, hours_len, unknown_6;
94         uint16  acct_ctrl, logon_divs;
95         uint16  bad_password_count, logon_count;
96         uint8   *hours = NULL;
97         uint8   *lm_pw_ptr = NULL, *nt_pw_ptr = NULL;
98         uint32          len = 0;
99         uint32          lm_pw_len, nt_pw_len, hourslen;
100         bool ret = True;
101         
102         if(sampass == NULL || buf == NULL) {
103                 DEBUG(0, ("init_sam_from_buffer_v0: NULL parameters found!\n"));
104                 return False;
105         }
106
107 /* TDB_FORMAT_STRING_V0       "ddddddBBBBBBBBBBBBddBBwdwdBwwd" */
108
109         /* unpack the buffer into variables */
110         len = tdb_unpack (buf, buflen, TDB_FORMAT_STRING_V0,
111                 &logon_time,                                            /* d */
112                 &logoff_time,                                           /* d */
113                 &kickoff_time,                                          /* d */
114                 &pass_last_set_time,                                    /* d */
115                 &pass_can_change_time,                                  /* d */
116                 &pass_must_change_time,                                 /* d */
117                 &username_len, &username,                               /* B */
118                 &domain_len, &domain,                                   /* B */
119                 &nt_username_len, &nt_username,                         /* B */
120                 &fullname_len, &fullname,                               /* B */
121                 &homedir_len, &homedir,                                 /* B */
122                 &dir_drive_len, &dir_drive,                             /* B */
123                 &logon_script_len, &logon_script,                       /* B */
124                 &profile_path_len, &profile_path,                       /* B */
125                 &acct_desc_len, &acct_desc,                             /* B */
126                 &workstations_len, &workstations,                       /* B */
127                 &unknown_str_len, &unknown_str,                         /* B */
128                 &munged_dial_len, &munged_dial,                         /* B */
129                 &user_rid,                                              /* d */
130                 &group_rid,                                             /* d */
131                 &lm_pw_len, &lm_pw_ptr,                                 /* B */
132                 &nt_pw_len, &nt_pw_ptr,                                 /* B */
133                 &acct_ctrl,                                             /* w */
134                 &remove_me, /* remove on the next TDB_FORMAT upgarde */ /* d */
135                 &logon_divs,                                            /* w */
136                 &hours_len,                                             /* d */
137                 &hourslen, &hours,                                      /* B */
138                 &bad_password_count,                                    /* w */
139                 &logon_count,                                           /* w */
140                 &unknown_6);                                            /* d */
141                 
142         if (len == (uint32) -1)  {
143                 ret = False;
144                 goto done;
145         }
146
147         pdb_set_logon_time(sampass, logon_time, PDB_SET);
148         pdb_set_logoff_time(sampass, logoff_time, PDB_SET);
149         pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET);
150         pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET);
151         pdb_set_pass_must_change_time(sampass, pass_must_change_time, PDB_SET);
152         pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET);
153
154         pdb_set_username(sampass, username, PDB_SET); 
155         pdb_set_domain(sampass, domain, PDB_SET);
156         pdb_set_nt_username(sampass, nt_username, PDB_SET);
157         pdb_set_fullname(sampass, fullname, PDB_SET);
158
159         if (homedir) {
160                 pdb_set_homedir(sampass, homedir, PDB_SET);
161         }
162         else {
163                 pdb_set_homedir(sampass, 
164                         talloc_sub_basic(sampass, username, domain,
165                                          lp_logon_home()),
166                         PDB_DEFAULT);
167         }
168
169         if (dir_drive)  
170                 pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
171         else {
172                 pdb_set_dir_drive(sampass, 
173                         talloc_sub_basic(sampass, username, domain,
174                                          lp_logon_drive()),
175                         PDB_DEFAULT);
176         }
177
178         if (logon_script) 
179                 pdb_set_logon_script(sampass, logon_script, PDB_SET);
180         else {
181                 pdb_set_logon_script(sampass, 
182                         talloc_sub_basic(sampass, username, domain,
183                                          lp_logon_script()),
184                         PDB_DEFAULT);
185         }
186         
187         if (profile_path) {     
188                 pdb_set_profile_path(sampass, profile_path, PDB_SET);
189         } else {
190                 pdb_set_profile_path(sampass, 
191                         talloc_sub_basic(sampass, username, domain,
192                                          lp_logon_path()),
193                         PDB_DEFAULT);
194         }
195
196         pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
197         pdb_set_workstations(sampass, workstations, PDB_SET);
198         pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
199
200         if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) {
201                 if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) {
202                         ret = False;
203                         goto done;
204                 }
205         }
206
207         if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) {
208                 if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) {
209                         ret = False;
210                         goto done;
211                 }
212         }
213
214         pdb_set_pw_history(sampass, NULL, 0, PDB_SET);
215         pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
216         pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET);
217         pdb_set_hours_len(sampass, hours_len, PDB_SET);
218         pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET);
219         pdb_set_logon_count(sampass, logon_count, PDB_SET);
220         pdb_set_unknown_6(sampass, unknown_6, PDB_SET);
221         pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
222         pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
223         pdb_set_hours(sampass, hours, PDB_SET);
224
225 done:
226
227         SAFE_FREE(username);
228         SAFE_FREE(domain);
229         SAFE_FREE(nt_username);
230         SAFE_FREE(fullname);
231         SAFE_FREE(homedir);
232         SAFE_FREE(dir_drive);
233         SAFE_FREE(logon_script);
234         SAFE_FREE(profile_path);
235         SAFE_FREE(acct_desc);
236         SAFE_FREE(workstations);
237         SAFE_FREE(munged_dial);
238         SAFE_FREE(unknown_str);
239         SAFE_FREE(lm_pw_ptr);
240         SAFE_FREE(nt_pw_ptr);
241         SAFE_FREE(hours);
242
243         return ret;
244 }
245
246 /*********************************************************************
247 *********************************************************************/
248
249 static bool init_sam_from_buffer_v1(struct samu *sampass, uint8 *buf, uint32 buflen)
250 {
251
252         /* times are stored as 32bit integer
253            take care on system with 64bit wide time_t
254            --SSS */
255         uint32  logon_time,
256                 logoff_time,
257                 kickoff_time,
258                 bad_password_time,
259                 pass_last_set_time,
260                 pass_can_change_time,
261                 pass_must_change_time;
262         char *username = NULL;
263         char *domain = NULL;
264         char *nt_username = NULL;
265         char *dir_drive = NULL;
266         char *unknown_str = NULL;
267         char *munged_dial = NULL;
268         char *fullname = NULL;
269         char *homedir = NULL;
270         char *logon_script = NULL;
271         char *profile_path = NULL;
272         char *acct_desc = NULL;
273         char *workstations = NULL;
274         uint32  username_len, domain_len, nt_username_len,
275                 dir_drive_len, unknown_str_len, munged_dial_len,
276                 fullname_len, homedir_len, logon_script_len,
277                 profile_path_len, acct_desc_len, workstations_len;
278                 
279         uint32  user_rid, group_rid, remove_me, hours_len, unknown_6;
280         uint16  acct_ctrl, logon_divs;
281         uint16  bad_password_count, logon_count;
282         uint8   *hours = NULL;
283         uint8   *lm_pw_ptr = NULL, *nt_pw_ptr = NULL;
284         uint32          len = 0;
285         uint32          lm_pw_len, nt_pw_len, hourslen;
286         bool ret = True;
287         
288         if(sampass == NULL || buf == NULL) {
289                 DEBUG(0, ("init_sam_from_buffer_v1: NULL parameters found!\n"));
290                 return False;
291         }
292
293 /* TDB_FORMAT_STRING_V1       "dddddddBBBBBBBBBBBBddBBwdwdBwwd" */
294
295         /* unpack the buffer into variables */
296         len = tdb_unpack (buf, buflen, TDB_FORMAT_STRING_V1,
297                 &logon_time,                                            /* d */
298                 &logoff_time,                                           /* d */
299                 &kickoff_time,                                          /* d */
300                 /* Change from V0 is addition of bad_password_time field. */
301                 &bad_password_time,                                     /* d */
302                 &pass_last_set_time,                                    /* d */
303                 &pass_can_change_time,                                  /* d */
304                 &pass_must_change_time,                                 /* d */
305                 &username_len, &username,                               /* B */
306                 &domain_len, &domain,                                   /* B */
307                 &nt_username_len, &nt_username,                         /* B */
308                 &fullname_len, &fullname,                               /* B */
309                 &homedir_len, &homedir,                                 /* B */
310                 &dir_drive_len, &dir_drive,                             /* B */
311                 &logon_script_len, &logon_script,                       /* B */
312                 &profile_path_len, &profile_path,                       /* B */
313                 &acct_desc_len, &acct_desc,                             /* B */
314                 &workstations_len, &workstations,                       /* B */
315                 &unknown_str_len, &unknown_str,                         /* B */
316                 &munged_dial_len, &munged_dial,                         /* B */
317                 &user_rid,                                              /* d */
318                 &group_rid,                                             /* d */
319                 &lm_pw_len, &lm_pw_ptr,                                 /* B */
320                 &nt_pw_len, &nt_pw_ptr,                                 /* B */
321                 &acct_ctrl,                                             /* w */
322                 &remove_me,                                             /* d */
323                 &logon_divs,                                            /* w */
324                 &hours_len,                                             /* d */
325                 &hourslen, &hours,                                      /* B */
326                 &bad_password_count,                                    /* w */
327                 &logon_count,                                           /* w */
328                 &unknown_6);                                            /* d */
329                 
330         if (len == (uint32) -1)  {
331                 ret = False;
332                 goto done;
333         }
334
335         pdb_set_logon_time(sampass, logon_time, PDB_SET);
336         pdb_set_logoff_time(sampass, logoff_time, PDB_SET);
337         pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET);
338
339         /* Change from V0 is addition of bad_password_time field. */
340         pdb_set_bad_password_time(sampass, bad_password_time, PDB_SET);
341         pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET);
342         pdb_set_pass_must_change_time(sampass, pass_must_change_time, PDB_SET);
343         pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET);
344
345         pdb_set_username(sampass, username, PDB_SET); 
346         pdb_set_domain(sampass, domain, PDB_SET);
347         pdb_set_nt_username(sampass, nt_username, PDB_SET);
348         pdb_set_fullname(sampass, fullname, PDB_SET);
349
350         if (homedir) {
351                 pdb_set_homedir(sampass, homedir, PDB_SET);
352         }
353         else {
354                 pdb_set_homedir(sampass, 
355                         talloc_sub_basic(sampass, username, domain,
356                                          lp_logon_home()),
357                         PDB_DEFAULT);
358         }
359
360         if (dir_drive)  
361                 pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
362         else {
363                 pdb_set_dir_drive(sampass, 
364                         talloc_sub_basic(sampass, username, domain,
365                                          lp_logon_drive()),
366                         PDB_DEFAULT);
367         }
368
369         if (logon_script) 
370                 pdb_set_logon_script(sampass, logon_script, PDB_SET);
371         else {
372                 pdb_set_logon_script(sampass, 
373                         talloc_sub_basic(sampass, username, domain,
374                                          lp_logon_script()),
375                         PDB_DEFAULT);
376         }
377         
378         if (profile_path) {     
379                 pdb_set_profile_path(sampass, profile_path, PDB_SET);
380         } else {
381                 pdb_set_profile_path(sampass, 
382                         talloc_sub_basic(sampass, username, domain,
383                                          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 tmp_string;
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 (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( tmp_string, homedir );
543                 if (expand_explicit) {
544                         standard_sub_basic( username, domain, tmp_string,
545                                             sizeof(tmp_string) );
546                 }
547                 pdb_set_homedir(sampass, tmp_string, PDB_SET);
548         }
549         else {
550                 pdb_set_homedir(sampass, 
551                         talloc_sub_basic(sampass, username, domain,
552                                          lp_logon_home()),
553                         PDB_DEFAULT);
554         }
555
556         if (dir_drive)  
557                 pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
558         else
559                 pdb_set_dir_drive(sampass, lp_logon_drive(), PDB_DEFAULT );
560
561         if (logon_script) {
562                 fstrcpy( tmp_string, logon_script );
563                 if (expand_explicit) {
564                         standard_sub_basic( username, domain, tmp_string,
565                                             sizeof(tmp_string) );
566                 }
567                 pdb_set_logon_script(sampass, tmp_string, PDB_SET);
568         }
569         else {
570                 pdb_set_logon_script(sampass, 
571                         talloc_sub_basic(sampass, username, domain,
572                                          lp_logon_script()),
573                         PDB_DEFAULT);
574         }
575         
576         if (profile_path) {     
577                 fstrcpy( tmp_string, profile_path );
578                 if (expand_explicit) {
579                         standard_sub_basic( username, domain, tmp_string,
580                                             sizeof(tmp_string) );
581                 }
582                 pdb_set_profile_path(sampass, tmp_string, PDB_SET);
583         } 
584         else {
585                 pdb_set_profile_path(sampass, 
586                         talloc_sub_basic(sampass, username, domain,
587                                          lp_logon_path()),
588                         PDB_DEFAULT);
589         }
590
591         pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
592         pdb_set_workstations(sampass, workstations, PDB_SET);
593         pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
594
595         if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) {
596                 if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) {
597                         ret = False;
598                         goto done;
599                 }
600         }
601
602         if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) {
603                 if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) {
604                         ret = False;
605                         goto done;
606                 }
607         }
608
609         /* Change from V1 is addition of password history field. */
610         pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHistLen);
611         if (pwHistLen) {
612                 uint8 *pw_hist = SMB_MALLOC_ARRAY(uint8, pwHistLen * PW_HISTORY_ENTRY_LEN);
613                 if (!pw_hist) {
614                         ret = False;
615                         goto done;
616                 }
617                 memset(pw_hist, '\0', pwHistLen * PW_HISTORY_ENTRY_LEN);
618                 if (nt_pw_hist_ptr && nt_pw_hist_len) {
619                         int i;
620                         SMB_ASSERT((nt_pw_hist_len % PW_HISTORY_ENTRY_LEN) == 0);
621                         nt_pw_hist_len /= PW_HISTORY_ENTRY_LEN;
622                         for (i = 0; (i < pwHistLen) && (i < nt_pw_hist_len); i++) {
623                                 memcpy(&pw_hist[i*PW_HISTORY_ENTRY_LEN],
624                                         &nt_pw_hist_ptr[i*PW_HISTORY_ENTRY_LEN],
625                                         PW_HISTORY_ENTRY_LEN);
626                         }
627                 }
628                 if (!pdb_set_pw_history(sampass, pw_hist, pwHistLen, PDB_SET)) {
629                         SAFE_FREE(pw_hist);
630                         ret = False;
631                         goto done;
632                 }
633                 SAFE_FREE(pw_hist);
634         } else {
635                 pdb_set_pw_history(sampass, NULL, 0, PDB_SET);
636         }
637
638         pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
639         pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET);
640         pdb_set_hours_len(sampass, hours_len, PDB_SET);
641         pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET);
642         pdb_set_logon_count(sampass, logon_count, PDB_SET);
643         pdb_set_unknown_6(sampass, unknown_6, PDB_SET);
644         pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
645         pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
646         pdb_set_hours(sampass, hours, PDB_SET);
647
648 done:
649
650         SAFE_FREE(username);
651         SAFE_FREE(domain);
652         SAFE_FREE(nt_username);
653         SAFE_FREE(fullname);
654         SAFE_FREE(homedir);
655         SAFE_FREE(dir_drive);
656         SAFE_FREE(logon_script);
657         SAFE_FREE(profile_path);
658         SAFE_FREE(acct_desc);
659         SAFE_FREE(workstations);
660         SAFE_FREE(munged_dial);
661         SAFE_FREE(unknown_str);
662         SAFE_FREE(lm_pw_ptr);
663         SAFE_FREE(nt_pw_ptr);
664         SAFE_FREE(nt_pw_hist_ptr);
665         SAFE_FREE(hours);
666
667         return ret;
668 }
669
670
671 /**********************************************************************
672  Intialize a struct samu struct from a BYTE buffer of size len
673  *********************************************************************/
674
675 static bool init_sam_from_buffer(struct samu *sampass, uint8 *buf, uint32 buflen)
676 {
677         return init_sam_from_buffer_v3(sampass, buf, buflen);
678 }
679
680 /**********************************************************************
681  Intialize a BYTE buffer from a struct samu struct
682  *********************************************************************/
683
684 static uint32 init_buffer_from_sam (uint8 **buf, struct samu *sampass, bool size_only)
685 {
686         return init_buffer_from_sam_v3(buf, sampass, size_only);
687 }
688
689 /**********************************************************************
690  Intialize a BYTE buffer from a struct samu struct
691  *********************************************************************/
692
693 struct tdbsam_convert_state {
694         int32_t from;
695         bool success;
696 };
697
698 static int tdbsam_convert_one(struct db_record *rec, void *priv)
699 {
700         struct tdbsam_convert_state *state =
701                 (struct tdbsam_convert_state *)priv;
702         struct samu *user;
703         TDB_DATA data;
704         NTSTATUS status;
705         bool ret;
706
707         if (rec->key.dsize < USERPREFIX_LEN) {
708                 return 0;
709         }
710         if (strncmp((char *)rec->key.dptr, USERPREFIX, USERPREFIX_LEN) != 0) {
711                 return 0;
712         }
713
714         user = samu_new(talloc_tos());
715         if (user == NULL) {
716                 DEBUG(0,("tdbsam_convert: samu_new() failed!\n"));
717                 state->success = false;
718                 return -1;
719         }
720
721         DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) "
722                   "(version:%d)\n", rec->key.dptr, state->from));
723
724         switch (state->from) {
725         case 0:
726                 ret = init_sam_from_buffer_v0(user, (uint8 *)rec->value.dptr,
727                                               rec->value.dsize);
728                 break;
729         case 1:
730                 ret = init_sam_from_buffer_v1(user, (uint8 *)rec->value.dptr,
731                                               rec->value.dsize);
732                 break;
733         case 2:
734                 ret = init_sam_from_buffer_v2(user, (uint8 *)rec->value.dptr,
735                                               rec->value.dsize);
736                 break;
737         case 3:
738                 ret = init_sam_from_buffer_v3(user, (uint8 *)rec->value.dptr,
739                                               rec->value.dsize);
740                 break;
741         default:
742                 /* unknown tdbsam version */
743                 ret = False;
744         }
745         if (!ret) {
746                 DEBUG(0,("tdbsam_convert: Bad struct samu entry returned "
747                          "from TDB (key:%s) (version:%d)\n", rec->key.dptr,
748                          state->from));
749                 TALLOC_FREE(user);
750                 state->success = false;
751                 return -1;
752         }
753
754         data.dsize = init_buffer_from_sam(&data.dptr, user, false);
755         TALLOC_FREE(user);
756
757         if (data.dsize == -1) {
758                 DEBUG(0,("tdbsam_convert: cannot pack the struct samu into "
759                          "the new format\n"));
760                 state->success = false;
761                 return -1;
762         }
763
764         status = rec->store(rec, data, TDB_MODIFY);
765         if (!NT_STATUS_IS_OK(status)) {
766                 DEBUG(0, ("Could not store the new record: %s\n",
767                           nt_errstr(status)));
768                 state->success = false;
769                 return -1;
770         }
771
772         return 0;
773 }
774
775 static bool tdbsam_convert(struct db_context *db, int32 from)
776 {
777         struct tdbsam_convert_state state;
778         int ret;
779
780         state.from = from;
781         state.success = true;
782
783         if (db->transaction_start(db) != 0) {
784                 DEBUG(0, ("Could not start transaction\n"));
785                 return false;
786         }
787
788         ret = db->traverse(db, tdbsam_convert_one, &state);
789         if (ret < 0) {
790                 DEBUG(0, ("traverse failed\n"));
791                 goto cancel;
792         }
793
794         if (!state.success) {
795                 DEBUG(0, ("Converting records failed\n"));
796                 goto cancel;
797         }
798
799         if (dbwrap_store_int32(db, TDBSAM_VERSION_STRING,
800                                TDBSAM_VERSION) != 0) {
801                 DEBUG(0, ("Could not store tdbsam version\n"));
802                 goto cancel;
803         }
804
805         if (db->transaction_commit(db) != 0) {
806                 DEBUG(0, ("Could not commit transaction\n"));
807                 goto cancel;
808         }
809
810         return true;
811
812  cancel:
813         if (db->transaction_cancel(db) != 0) {
814                 smb_panic("transaction_cancel failed");
815         }
816
817         return false;
818 }
819
820 /*********************************************************************
821  Open the tdbsam file based on the absolute path specified.
822  Uses a reference count to allow multiple open calls.
823 *********************************************************************/
824
825 static bool tdbsam_open( const char *name )
826 {
827         int32   version;
828
829         /* check if we are already open */
830
831         if ( db_sam ) {
832                 return true;
833         }
834
835         /* Try to open tdb passwd.  Create a new one if necessary */
836
837         db_sam = db_open(NULL, name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
838         if (db_sam == NULL) {
839                 DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd "
840                           "[%s]\n", name));
841                 return false;
842         }
843
844         /* Check the version */
845         version = dbwrap_fetch_int32(db_sam, TDBSAM_VERSION_STRING);
846         if (version == -1) {
847                 version = 0;    /* Version not found, assume version 0 */
848         }
849
850         /* Compare the version */
851         if (version > TDBSAM_VERSION) {
852                 /* Version more recent than the latest known */
853                 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
854                 TALLOC_FREE(db_sam);
855                 return false;
856         }
857
858         if ( version < TDBSAM_VERSION ) {
859                 DEBUG(1, ("tdbsam_open: Converting version %d database to "
860                           "version %d.\n", version, TDBSAM_VERSION));
861
862                 if ( !tdbsam_convert(db_sam, version) ) {
863                         DEBUG(0, ("tdbsam_open: Error when trying to convert "
864                                   "tdbsam [%s]\n",name));
865                         TALLOC_FREE(db_sam);
866                         return false;
867                 }
868
869                 DEBUG(3, ("TDBSAM converted successfully.\n"));
870         }
871
872         DEBUG(4,("tdbsam_open: successfully opened %s\n", name ));
873
874         return true;
875 }
876
877 /******************************************************************
878  Lookup a name in the SAM TDB
879 ******************************************************************/
880
881 static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods,
882                                     struct samu *user, const char *sname)
883 {
884         TDB_DATA        data;
885         fstring         keystr;
886         fstring         name;
887
888         if ( !user ) {
889                 DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
890                 return NT_STATUS_NO_MEMORY;
891         }
892
893         /* Data is stored in all lower-case */
894         fstrcpy(name, sname);
895         strlower_m(name);
896
897         /* set search key */
898         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
899
900         /* open the database */
901
902         if ( !tdbsam_open( tdbsam_filename ) ) {
903                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
904                 return NT_STATUS_ACCESS_DENIED;
905         }
906
907         /* get the record */
908
909         data = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr);
910         if (!data.dptr) {
911                 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
912                 DEBUGADD(5, (" Key: %s\n", keystr));
913                 return NT_STATUS_NO_SUCH_USER;
914         }
915
916         /* unpack the buffer */
917
918         if (!init_sam_from_buffer(user, data.dptr, data.dsize)) {
919                 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
920                 SAFE_FREE(data.dptr);
921                 return NT_STATUS_NO_MEMORY;
922         }
923
924         /* success */
925
926         TALLOC_FREE(data.dptr);
927
928         return NT_STATUS_OK;
929 }
930
931 /***************************************************************************
932  Search by rid
933  **************************************************************************/
934
935 static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods,
936                                     struct samu *user, uint32 rid)
937 {
938         NTSTATUS                nt_status = NT_STATUS_UNSUCCESSFUL;
939         TDB_DATA                data;
940         fstring                 keystr;
941         fstring                 name;
942
943         if ( !user ) {
944                 DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
945                 return nt_status;
946         }
947
948         /* set search key */
949
950         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
951
952         /* open the database */
953
954         if ( !tdbsam_open( tdbsam_filename ) ) {
955                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
956                 return NT_STATUS_ACCESS_DENIED;
957         }
958
959         /* get the record */
960
961         data = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr);
962         if (!data.dptr) {
963                 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
964                 return NT_STATUS_UNSUCCESSFUL;
965         }
966
967         fstrcpy(name, (const char *)data.dptr);
968         TALLOC_FREE(data.dptr);
969
970         return tdbsam_getsampwnam (my_methods, user, name);
971 }
972
973 static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods,
974                                    struct samu * user, const DOM_SID *sid)
975 {
976         uint32 rid;
977
978         if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) )
979                 return NT_STATUS_UNSUCCESSFUL;
980
981         return tdbsam_getsampwrid(my_methods, user, rid);
982 }
983
984 static bool tdb_delete_samacct_only( struct samu *sam_pass )
985 {
986         fstring         keystr;
987         fstring         name;
988         NTSTATUS status;
989
990         fstrcpy(name, pdb_get_username(sam_pass));
991         strlower_m(name);
992
993         /* set the search key */
994
995         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
996
997         /* it's outaa here!  8^) */
998
999         status = dbwrap_delete_bystring(db_sam, keystr);
1000         if (!NT_STATUS_IS_OK(status)) {
1001                 DEBUG(5, ("Error deleting entry from tdb passwd "
1002                           "database: %s!\n", nt_errstr(status)));
1003                 return false;
1004         }
1005
1006         return true;
1007 }
1008
1009 /***************************************************************************
1010  Delete a struct samu records for the username and RID key
1011 ****************************************************************************/
1012
1013 static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods,
1014                                           struct samu *sam_pass)
1015 {
1016         NTSTATUS        nt_status = NT_STATUS_UNSUCCESSFUL;
1017         fstring         keystr;
1018         uint32          rid;
1019         fstring         name;
1020
1021         /* open the database */
1022
1023         if ( !tdbsam_open( tdbsam_filename ) ) {
1024                 DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
1025                          tdbsam_filename));
1026                 return NT_STATUS_ACCESS_DENIED;
1027         }
1028
1029         fstrcpy(name, pdb_get_username(sam_pass));
1030         strlower_m(name);
1031
1032         /* set the search key */
1033
1034         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
1035
1036         rid = pdb_get_user_rid(sam_pass);
1037
1038         /* it's outaa here!  8^) */
1039
1040         if (db_sam->transaction_start(db_sam) != 0) {
1041                 DEBUG(0, ("Could not start transaction\n"));
1042                 return NT_STATUS_UNSUCCESSFUL;
1043         }
1044
1045         nt_status = dbwrap_delete_bystring(db_sam, keystr);
1046         if (!NT_STATUS_IS_OK(nt_status)) {
1047                 DEBUG(5, ("Error deleting entry from tdb passwd "
1048                           "database: %s!\n", nt_errstr(nt_status)));
1049                 goto cancel;
1050         }
1051
1052         /* set the search key */
1053
1054         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
1055
1056         /* it's outaa here!  8^) */
1057
1058         nt_status = dbwrap_delete_bystring(db_sam, keystr);
1059         if (!NT_STATUS_IS_OK(nt_status)) {
1060                 DEBUG(5, ("Error deleting entry from tdb rid "
1061                           "database: %s!\n", nt_errstr(nt_status)));
1062                 goto cancel;
1063         }
1064
1065         if (db_sam->transaction_commit(db_sam) != 0) {
1066                 DEBUG(0, ("Could not commit transaction\n"));
1067                 goto cancel;
1068         }
1069
1070         return NT_STATUS_OK;
1071
1072  cancel:
1073         if (db_sam->transaction_cancel(db_sam) != 0) {
1074                 smb_panic("transaction_cancel failed");
1075         }
1076
1077         return nt_status;
1078 }
1079
1080
1081 /***************************************************************************
1082  Update the TDB SAM account record only
1083  Assumes that the tdbsam is already open 
1084 ****************************************************************************/
1085 static bool tdb_update_samacct_only( struct samu* newpwd, int flag )
1086 {
1087         TDB_DATA        data;
1088         uint8           *buf = NULL;
1089         fstring         keystr;
1090         fstring         name;
1091         bool            ret = false;
1092         NTSTATUS status;
1093
1094         /* copy the struct samu struct into a BYTE buffer for storage */
1095
1096         if ( (data.dsize=init_buffer_from_sam (&buf, newpwd, False)) == -1 ) {
1097                 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
1098                 goto done;
1099         }
1100         data.dptr = buf;
1101
1102         fstrcpy(name, pdb_get_username(newpwd));
1103         strlower_m(name);
1104
1105         DEBUG(5, ("Storing %saccount %s with RID %d\n",
1106                   flag == TDB_INSERT ? "(new) " : "", name,
1107                   pdb_get_user_rid(newpwd)));
1108
1109         /* setup the USER index key */
1110         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
1111
1112         /* add the account */
1113
1114         status = dbwrap_store_bystring(db_sam, keystr, data, flag);
1115         if (!NT_STATUS_IS_OK(status)) {
1116                 DEBUG(0, ("Unable to modify passwd TDB: %s!",
1117                           nt_errstr(status)));
1118                 goto done;
1119         }
1120
1121         ret = true;
1122
1123 done:
1124         /* cleanup */
1125         SAFE_FREE(buf);
1126         return ret;
1127 }
1128
1129 /***************************************************************************
1130  Update the TDB SAM RID record only
1131  Assumes that the tdbsam is already open
1132 ****************************************************************************/
1133 static bool tdb_update_ridrec_only( struct samu* newpwd, int flag )
1134 {
1135         TDB_DATA        data;
1136         fstring         keystr;
1137         fstring         name;
1138         NTSTATUS status;
1139
1140         fstrcpy(name, pdb_get_username(newpwd));
1141         strlower_m(name);
1142
1143         /* setup RID data */
1144         data = string_term_tdb_data(name);
1145
1146         /* setup the RID index key */
1147         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX,
1148                  pdb_get_user_rid(newpwd));
1149
1150         /* add the reference */
1151         status = dbwrap_store_bystring(db_sam, keystr, data, flag);
1152         if (!NT_STATUS_IS_OK(status)) {
1153                 DEBUG(0, ("Unable to modify TDB passwd: %s!\n",
1154                           nt_errstr(status)));
1155                 return false;
1156         }
1157
1158         return true;
1159
1160 }
1161
1162 /***************************************************************************
1163  Update the TDB SAM
1164 ****************************************************************************/
1165
1166 static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
1167                            int flag)
1168 {
1169         if (!pdb_get_user_rid(newpwd)) {
1170                 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n",
1171                          pdb_get_username(newpwd)));
1172                 return False;
1173         }
1174
1175         /* open the database */
1176
1177         if ( !tdbsam_open( tdbsam_filename ) ) {
1178                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
1179                 return False;
1180         }
1181
1182         if (db_sam->transaction_start(db_sam) != 0) {
1183                 DEBUG(0, ("Could not start transaction\n"));
1184                 return false;
1185         }
1186
1187         if (!tdb_update_samacct_only(newpwd, flag)
1188             || !tdb_update_ridrec_only(newpwd, flag)) {
1189                 goto cancel;
1190         }
1191
1192         if (db_sam->transaction_commit(db_sam) != 0) {
1193                 DEBUG(0, ("Could not commit transaction\n"));
1194                 goto cancel;
1195         }
1196
1197         return true;
1198
1199  cancel:
1200         if (db_sam->transaction_cancel(db_sam) != 0) {
1201                 smb_panic("transaction_cancel failed");
1202         }
1203         return false;
1204 }
1205
1206 /***************************************************************************
1207  Modifies an existing struct samu
1208 ****************************************************************************/
1209
1210 static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
1211 {
1212         if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
1213                 return NT_STATUS_UNSUCCESSFUL;
1214         
1215         return NT_STATUS_OK;
1216 }
1217
1218 /***************************************************************************
1219  Adds an existing struct samu
1220 ****************************************************************************/
1221
1222 static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
1223 {
1224         if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
1225                 return NT_STATUS_UNSUCCESSFUL;
1226                 
1227         return NT_STATUS_OK;
1228 }
1229
1230 /***************************************************************************
1231  Renames a struct samu
1232  - check for the posix user/rename user script
1233  - Add and lock the new user record
1234  - rename the posix user
1235  - rewrite the rid->username record
1236  - delete the old user
1237  - unlock the new user record
1238 ***************************************************************************/
1239 static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
1240                                           struct samu *old_acct,
1241                                           const char *newname)
1242 {
1243         struct samu      *new_acct = NULL;
1244         char *rename_script = NULL;
1245         int              rename_ret;
1246         fstring          oldname_lower;
1247         fstring          newname_lower;
1248
1249         /* can't do anything without an external script */
1250
1251         if ( !(new_acct = samu_new( talloc_tos() )) ) {
1252                 return NT_STATUS_NO_MEMORY;
1253         }
1254
1255         rename_script = talloc_strdup(new_acct, lp_renameuser_script());
1256         if (!rename_script) {
1257                 TALLOC_FREE(new_acct);
1258                 return NT_STATUS_NO_MEMORY;
1259         }
1260         if (!*rename_script) {
1261                 TALLOC_FREE(new_acct);
1262                 return NT_STATUS_ACCESS_DENIED;
1263         }
1264
1265         if ( !pdb_copy_sam_account(new_acct, old_acct)
1266                 || !pdb_set_username(new_acct, newname, PDB_CHANGED))
1267         {
1268                 TALLOC_FREE(new_acct);
1269                 return NT_STATUS_NO_MEMORY;
1270         }
1271
1272         /* open the database */
1273         if ( !tdbsam_open( tdbsam_filename ) ) {
1274                 DEBUG(0, ("tdbsam_getsampwnam: failed to open %s!\n",
1275                           tdbsam_filename));
1276                 TALLOC_FREE(new_acct);
1277                 return NT_STATUS_ACCESS_DENIED;
1278         }
1279
1280         if (db_sam->transaction_start(db_sam) != 0) {
1281                 DEBUG(0, ("Could not start transaction\n"));
1282                 TALLOC_FREE(new_acct);
1283                 return NT_STATUS_ACCESS_DENIED;
1284
1285         }
1286
1287         /* add the new account and lock it */
1288         if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
1289                 goto cancel;
1290         }
1291
1292         /* Rename the posix user.  Follow the semantics of _samr_create_user()
1293            so that we lower case the posix name but preserve the case in passdb */
1294
1295         fstrcpy( oldname_lower, pdb_get_username(old_acct) );
1296         strlower_m( oldname_lower );
1297
1298         fstrcpy( newname_lower, newname );
1299         strlower_m( newname_lower );
1300
1301         rename_script = talloc_string_sub2(new_acct,
1302                                 rename_script,
1303                                 "%unew",
1304                                 newname_lower,
1305                                 true,
1306                                 false,
1307                                 true);
1308         if (!rename_script) {
1309                 goto cancel;
1310         }
1311         rename_script = talloc_string_sub2(new_acct,
1312                                 rename_script,
1313                                 "%uold",
1314                                 oldname_lower,
1315                                 true,
1316                                 false,
1317                                 true);
1318         if (!rename_script) {
1319                 goto cancel;
1320         }
1321         rename_ret = smbrun(rename_script, NULL);
1322
1323         DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n",
1324                                 rename_script, rename_ret));
1325
1326         if (rename_ret != 0) {
1327                 goto cancel;
1328         }
1329
1330         smb_nscd_flush_user_cache();
1331
1332         /* rewrite the rid->username record */
1333
1334         if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
1335                 goto cancel;
1336         }
1337
1338         tdb_delete_samacct_only( old_acct );
1339
1340         if (db_sam->transaction_commit(db_sam) != 0) {
1341                 /*
1342                  * Ok, we're screwed. We've changed the posix account, but
1343                  * could not adapt passdb.tdb. Shall we change the posix
1344                  * account back?
1345                  */
1346                 DEBUG(0, ("transaction_commit failed\n"));
1347                 goto cancel;
1348         }
1349
1350         TALLOC_FREE(new_acct );
1351         return NT_STATUS_OK;
1352
1353  cancel:
1354         if (db_sam->transaction_cancel(db_sam) != 0) {
1355                 smb_panic("transaction_cancel failed");
1356         }
1357
1358         TALLOC_FREE(new_acct);
1359
1360         return NT_STATUS_ACCESS_DENIED; 
1361 }
1362
1363 static bool tdbsam_rid_algorithm(struct pdb_methods *methods)
1364 {
1365         return False;
1366 }
1367
1368 /*
1369  * Historically, winbind was responsible for allocating RIDs, so the next RID
1370  * value was stored in winbindd_idmap.tdb. It has been moved to passdb now,
1371  * but for compatibility reasons we still keep the the next RID counter in
1372  * winbindd_idmap.tdb.
1373  */
1374
1375 /*****************************************************************************
1376  Initialise idmap database. For now (Dec 2005) this is a copy of the code in
1377  sam/idmap_tdb.c. Maybe at a later stage we can remove that capability from
1378  winbind completely and store the RID counter in passdb.tdb.
1379
1380  Dont' fully initialize with the HWM values, if it's new, we're only
1381  interested in the RID counter.
1382 *****************************************************************************/
1383
1384 static bool init_idmap_tdb(TDB_CONTEXT *tdb)
1385 {
1386         int32 version;
1387
1388         if (tdb_lock_bystring(tdb, "IDMAP_VERSION") != 0) {
1389                 DEBUG(0, ("Could not lock IDMAP_VERSION\n"));
1390                 return False;
1391         }
1392
1393         version = tdb_fetch_int32(tdb, "IDMAP_VERSION");
1394
1395         if (version == -1) {
1396                 /* No key found, must be a new db */
1397                 if (tdb_store_int32(tdb, "IDMAP_VERSION",
1398                                     IDMAP_VERSION) != 0) {
1399                         DEBUG(0, ("Could not store IDMAP_VERSION\n"));
1400                         tdb_unlock_bystring(tdb, "IDMAP_VERSION");
1401                         return False;
1402                 }
1403                 version = IDMAP_VERSION;
1404         }
1405
1406         if (version != IDMAP_VERSION) {
1407                 DEBUG(0, ("Expected IDMAP_VERSION=%d, found %d. Please "
1408                           "start winbind once\n", IDMAP_VERSION, version));
1409                 tdb_unlock_bystring(tdb, "IDMAP_VERSION");
1410                 return False;
1411         }
1412
1413         tdb_unlock_bystring(tdb, "IDMAP_VERSION");
1414         return True;
1415 }
1416
1417 static bool tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid)
1418 {
1419         TDB_CONTEXT *tdb;
1420         uint32 rid;
1421         bool ret = False;
1422
1423         tdb = tdb_open_log(state_path("winbindd_idmap.tdb"), 0,
1424                            TDB_DEFAULT, O_RDWR | O_CREAT, 0644);
1425
1426         if (tdb == NULL) {
1427                 DEBUG(1, ("Could not open idmap: %s\n", strerror(errno)));
1428                 goto done;
1429         }
1430
1431         if (!init_idmap_tdb(tdb)) {
1432                 DEBUG(1, ("Could not init idmap\n"));
1433                 goto done;
1434         }
1435
1436         rid = BASE_RID;         /* Default if not set */
1437
1438         if (!tdb_change_uint32_atomic(tdb, "RID_COUNTER", &rid, 1)) {
1439                 DEBUG(3, ("tdbsam_new_rid: Failed to increase RID_COUNTER\n"));
1440                 goto done;
1441         }
1442
1443         *prid = rid;
1444         ret = True;
1445
1446  done:
1447         if ((tdb != NULL) && (tdb_close(tdb) != 0)) {
1448                 smb_panic("tdb_close(idmap_tdb) failed");
1449         }
1450
1451         return ret;
1452 }
1453
1454 struct tdbsam_search_state {
1455         struct pdb_methods *methods;
1456         uint32_t acct_flags;
1457
1458         uint32_t *rids;
1459         uint32_t num_rids;
1460         ssize_t array_size;
1461         uint32_t current;
1462 };
1463
1464 static int tdbsam_collect_rids(struct db_record *rec, void *private_data)
1465 {
1466         struct tdbsam_search_state *state = talloc_get_type_abort(
1467                 private_data, struct tdbsam_search_state);
1468         size_t prefixlen = strlen(RIDPREFIX);
1469         uint32 rid;
1470
1471         if ((rec->key.dsize < prefixlen)
1472             || (strncmp((char *)rec->key.dptr, RIDPREFIX, prefixlen))) {
1473                 return 0;
1474         }
1475
1476         rid = strtoul((char *)rec->key.dptr+prefixlen, NULL, 16);
1477
1478         ADD_TO_LARGE_ARRAY(state, uint32, rid, &state->rids, &state->num_rids,
1479                            &state->array_size);
1480
1481         return 0;
1482 }
1483
1484 static void tdbsam_search_end(struct pdb_search *search)
1485 {
1486         struct tdbsam_search_state *state = talloc_get_type_abort(
1487                 search->private_data, struct tdbsam_search_state);
1488         TALLOC_FREE(state);
1489 }
1490
1491 static bool tdbsam_search_next_entry(struct pdb_search *search,
1492                                      struct samr_displayentry *entry)
1493 {
1494         struct tdbsam_search_state *state = talloc_get_type_abort(
1495                 search->private_data, struct tdbsam_search_state);
1496         struct samu *user = NULL;
1497         NTSTATUS status;
1498         uint32_t rid;
1499
1500  again:
1501         TALLOC_FREE(user);
1502         user = samu_new(talloc_tos());
1503         if (user == NULL) {
1504                 DEBUG(0, ("samu_new failed\n"));
1505                 return false;
1506         }
1507
1508         if (state->current == state->num_rids) {
1509                 return false;
1510         }
1511
1512         rid = state->rids[state->current++];
1513
1514         status = tdbsam_getsampwrid(state->methods, user, rid);
1515
1516         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
1517                 /*
1518                  * Someone has deleted that user since we listed the RIDs
1519                  */
1520                 goto again;
1521         }
1522
1523         if (!NT_STATUS_IS_OK(status)) {
1524                 DEBUG(10, ("tdbsam_getsampwrid failed: %s\n",
1525                            nt_errstr(status)));
1526                 TALLOC_FREE(user);
1527                 return false;
1528         }
1529
1530         if ((state->acct_flags != 0) &&
1531             ((state->acct_flags & pdb_get_acct_ctrl(user)) == 0)) {
1532                 goto again;
1533         }
1534
1535         entry->acct_flags = pdb_get_acct_ctrl(user);
1536         entry->rid = rid;
1537         entry->account_name = talloc_strdup(
1538                 search->mem_ctx, pdb_get_username(user));
1539         entry->fullname = talloc_strdup(
1540                 search->mem_ctx, pdb_get_fullname(user));
1541         entry->description = talloc_strdup(
1542                 search->mem_ctx, pdb_get_acct_desc(user));
1543
1544         TALLOC_FREE(user);
1545
1546         if ((entry->account_name == NULL) || (entry->fullname == NULL)
1547             || (entry->description == NULL)) {
1548                 DEBUG(0, ("talloc_strdup failed\n"));
1549                 return false;
1550         }
1551
1552         return true;
1553 }
1554
1555 static bool tdbsam_search_users(struct pdb_methods *methods,
1556                                 struct pdb_search *search,
1557                                 uint32 acct_flags)
1558 {
1559         struct tdbsam_search_state *state;
1560
1561         if (!tdbsam_open(tdbsam_filename)) {
1562                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n",
1563                          tdbsam_filename));
1564                 return false;
1565         }
1566
1567         state = TALLOC_ZERO_P(search->mem_ctx, struct tdbsam_search_state);
1568         if (state == NULL) {
1569                 DEBUG(0, ("talloc failed\n"));
1570                 return false;
1571         }
1572         state->acct_flags = acct_flags;
1573         state->methods = methods;
1574
1575         db_sam->traverse_read(db_sam, tdbsam_collect_rids, state);
1576
1577         search->private_data = state;
1578         search->next_entry = tdbsam_search_next_entry;
1579         search->search_end = tdbsam_search_end;
1580
1581         return true;
1582 }
1583
1584 /*********************************************************************
1585  Initialize the tdb sam backend.  Setup the dispath table of methods,
1586  open the tdb, etc...
1587 *********************************************************************/
1588
1589 static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
1590 {
1591         NTSTATUS nt_status;
1592         char *tdbfile = NULL;
1593         const char *pfile = location;
1594
1595         if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
1596                 return nt_status;
1597         }
1598
1599         (*pdb_method)->name = "tdbsam";
1600
1601         (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
1602         (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
1603         (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
1604         (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
1605         (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
1606         (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
1607         (*pdb_method)->search_users = tdbsam_search_users;
1608
1609         (*pdb_method)->rid_algorithm = tdbsam_rid_algorithm;
1610         (*pdb_method)->new_rid = tdbsam_new_rid;
1611
1612         /* save the path for later */
1613
1614         if (!location) {
1615                 if (asprintf(&tdbfile, "%s/%s", lp_private_dir(),
1616                              PASSDB_FILE_NAME) < 0) {
1617                         return NT_STATUS_NO_MEMORY;
1618                 }
1619                 pfile = tdbfile;
1620         }
1621         tdbsam_filename = SMB_STRDUP(pfile);
1622         if (!tdbsam_filename) {
1623                 return NT_STATUS_NO_MEMORY;
1624         }
1625         SAFE_FREE(tdbfile);
1626
1627         /* no private data */
1628
1629         (*pdb_method)->private_data      = NULL;
1630         (*pdb_method)->free_private_data = NULL;
1631
1632         return NT_STATUS_OK;
1633 }
1634
1635 NTSTATUS pdb_tdbsam_init(void)
1636 {
1637         return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);
1638 }