Convert pdb_tdb to use dbwrap
[jra/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
779         state.from = from;
780         state.success = true;
781
782         if (db->transaction_start(db) != 0) {
783                 DEBUG(0, ("Could not start transaction\n"));
784                 return false;
785         }
786
787         if (db->traverse(db, tdbsam_convert_one, &state) != 0) {
788                 DEBUG(0, ("traverse failed\n"));
789                 goto cancel;
790         }
791
792         if (!state.success) {
793                 DEBUG(0, ("Converting records failed\n"));
794                 goto cancel;
795         }
796
797         if (dbwrap_store_int32(db, TDBSAM_VERSION_STRING,
798                                TDBSAM_VERSION) != 0) {
799                 DEBUG(0, ("Could not store tdbsam version\n"));
800                 goto cancel;
801         }
802
803         if (db->transaction_commit(db) != 0) {
804                 DEBUG(0, ("Could not commit transaction\n"));
805                 goto cancel;
806         }
807
808         return true;
809
810  cancel:
811         if (db->transaction_cancel(db) != 0) {
812                 smb_panic("transaction_cancel failed");
813         }
814
815         return false;
816 }
817
818 /*********************************************************************
819  Open the tdbsam file based on the absolute path specified.
820  Uses a reference count to allow multiple open calls.
821 *********************************************************************/
822
823 static bool tdbsam_open( const char *name )
824 {
825         int32   version;
826
827         /* check if we are already open */
828
829         if ( db_sam ) {
830                 return true;
831         }
832
833         /* Try to open tdb passwd.  Create a new one if necessary */
834
835         db_sam = db_open(NULL, name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600);
836         if (db_sam == NULL) {
837                 DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd "
838                           "[%s]\n", name));
839                 return false;
840         }
841
842         /* Check the version */
843         version = dbwrap_fetch_int32(db_sam, TDBSAM_VERSION_STRING);
844         if (version == -1) {
845                 version = 0;    /* Version not found, assume version 0 */
846         }
847
848         /* Compare the version */
849         if (version > TDBSAM_VERSION) {
850                 /* Version more recent than the latest known */
851                 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
852                 TALLOC_FREE(db_sam);
853                 return false;
854         }
855
856         if ( version < TDBSAM_VERSION ) {
857                 DEBUG(1, ("tdbsam_open: Converting version %d database to "
858                           "version %d.\n", version, TDBSAM_VERSION));
859
860                 if ( !tdbsam_convert(db_sam, version) ) {
861                         DEBUG(0, ("tdbsam_open: Error when trying to convert "
862                                   "tdbsam [%s]\n",name));
863                         TALLOC_FREE(db_sam);
864                         return false;
865                 }
866
867                 DEBUG(3, ("TDBSAM converted successfully.\n"));
868         }
869
870         DEBUG(4,("tdbsam_open: successfully opened %s\n", name ));
871
872         return true;
873 }
874
875 /******************************************************************
876  Lookup a name in the SAM TDB
877 ******************************************************************/
878
879 static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods,
880                                     struct samu *user, const char *sname)
881 {
882         TDB_DATA        data;
883         fstring         keystr;
884         fstring         name;
885
886         if ( !user ) {
887                 DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
888                 return NT_STATUS_NO_MEMORY;
889         }
890
891         /* Data is stored in all lower-case */
892         fstrcpy(name, sname);
893         strlower_m(name);
894
895         /* set search key */
896         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
897
898         /* open the database */
899
900         if ( !tdbsam_open( tdbsam_filename ) ) {
901                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
902                 return NT_STATUS_ACCESS_DENIED;
903         }
904
905         /* get the record */
906
907         data = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr);
908         if (!data.dptr) {
909                 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
910                 DEBUGADD(5, (" Key: %s\n", keystr));
911                 return NT_STATUS_NO_SUCH_USER;
912         }
913
914         /* unpack the buffer */
915
916         if (!init_sam_from_buffer(user, data.dptr, data.dsize)) {
917                 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
918                 SAFE_FREE(data.dptr);
919                 return NT_STATUS_NO_MEMORY;
920         }
921
922         /* success */
923
924         TALLOC_FREE(data.dptr);
925
926         return NT_STATUS_OK;
927 }
928
929 /***************************************************************************
930  Search by rid
931  **************************************************************************/
932
933 static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods,
934                                     struct samu *user, uint32 rid)
935 {
936         NTSTATUS                nt_status = NT_STATUS_UNSUCCESSFUL;
937         TDB_DATA                data;
938         fstring                 keystr;
939         fstring                 name;
940
941         if ( !user ) {
942                 DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
943                 return nt_status;
944         }
945
946         /* set search key */
947
948         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
949
950         /* open the database */
951
952         if ( !tdbsam_open( tdbsam_filename ) ) {
953                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
954                 return NT_STATUS_ACCESS_DENIED;
955         }
956
957         /* get the record */
958
959         data = dbwrap_fetch_bystring(db_sam, talloc_tos(), keystr);
960         if (!data.dptr) {
961                 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
962                 return NT_STATUS_UNSUCCESSFUL;
963         }
964
965         fstrcpy(name, (const char *)data.dptr);
966         TALLOC_FREE(data.dptr);
967
968         return tdbsam_getsampwnam (my_methods, user, name);
969 }
970
971 static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods,
972                                    struct samu * user, const DOM_SID *sid)
973 {
974         uint32 rid;
975
976         if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) )
977                 return NT_STATUS_UNSUCCESSFUL;
978
979         return tdbsam_getsampwrid(my_methods, user, rid);
980 }
981
982 static bool tdb_delete_samacct_only( struct samu *sam_pass )
983 {
984         fstring         keystr;
985         fstring         name;
986         NTSTATUS status;
987
988         fstrcpy(name, pdb_get_username(sam_pass));
989         strlower_m(name);
990
991         /* set the search key */
992
993         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
994
995         /* it's outaa here!  8^) */
996
997         status = dbwrap_delete_bystring(db_sam, keystr);
998         if (!NT_STATUS_IS_OK(status)) {
999                 DEBUG(5, ("Error deleting entry from tdb passwd "
1000                           "database: %s!\n", nt_errstr(status)));
1001                 return false;
1002         }
1003
1004         return true;
1005 }
1006
1007 /***************************************************************************
1008  Delete a struct samu records for the username and RID key
1009 ****************************************************************************/
1010
1011 static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods,
1012                                           struct samu *sam_pass)
1013 {
1014         NTSTATUS        nt_status = NT_STATUS_UNSUCCESSFUL;
1015         fstring         keystr;
1016         uint32          rid;
1017         fstring         name;
1018
1019         /* open the database */
1020
1021         if ( !tdbsam_open( tdbsam_filename ) ) {
1022                 DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
1023                          tdbsam_filename));
1024                 return NT_STATUS_ACCESS_DENIED;
1025         }
1026
1027         fstrcpy(name, pdb_get_username(sam_pass));
1028         strlower_m(name);
1029
1030         /* set the search key */
1031
1032         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
1033
1034         rid = pdb_get_user_rid(sam_pass);
1035
1036         /* it's outaa here!  8^) */
1037
1038         if (db_sam->transaction_start(db_sam) != 0) {
1039                 DEBUG(0, ("Could not start transaction\n"));
1040                 return NT_STATUS_UNSUCCESSFUL;
1041         }
1042
1043         nt_status = dbwrap_delete_bystring(db_sam, keystr);
1044         if (!NT_STATUS_IS_OK(nt_status)) {
1045                 DEBUG(5, ("Error deleting entry from tdb passwd "
1046                           "database: %s!\n", nt_errstr(nt_status)));
1047                 goto cancel;
1048         }
1049
1050         /* set the search key */
1051
1052         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
1053
1054         /* it's outaa here!  8^) */
1055
1056         nt_status = dbwrap_delete_bystring(db_sam, keystr);
1057         if (!NT_STATUS_IS_OK(nt_status)) {
1058                 DEBUG(5, ("Error deleting entry from tdb rid "
1059                           "database: %s!\n", nt_errstr(nt_status)));
1060                 goto cancel;
1061         }
1062
1063         if (db_sam->transaction_commit(db_sam) != 0) {
1064                 DEBUG(0, ("Could not commit transaction\n"));
1065                 goto cancel;
1066         }
1067
1068         return NT_STATUS_OK;
1069
1070  cancel:
1071         if (db_sam->transaction_cancel(db_sam) != 0) {
1072                 smb_panic("transaction_cancel failed");
1073         }
1074
1075         return nt_status;
1076 }
1077
1078
1079 /***************************************************************************
1080  Update the TDB SAM account record only
1081  Assumes that the tdbsam is already open 
1082 ****************************************************************************/
1083 static bool tdb_update_samacct_only( struct samu* newpwd, int flag )
1084 {
1085         TDB_DATA        data;
1086         uint8           *buf = NULL;
1087         fstring         keystr;
1088         fstring         name;
1089         bool            ret = false;
1090         NTSTATUS status;
1091
1092         /* copy the struct samu struct into a BYTE buffer for storage */
1093
1094         if ( (data.dsize=init_buffer_from_sam (&buf, newpwd, False)) == -1 ) {
1095                 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
1096                 goto done;
1097         }
1098         data.dptr = buf;
1099
1100         fstrcpy(name, pdb_get_username(newpwd));
1101         strlower_m(name);
1102
1103         DEBUG(5, ("Storing %saccount %s with RID %d\n",
1104                   flag == TDB_INSERT ? "(new) " : "", name,
1105                   pdb_get_user_rid(newpwd)));
1106
1107         /* setup the USER index key */
1108         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
1109
1110         /* add the account */
1111
1112         status = dbwrap_store_bystring(db_sam, keystr, data, flag);
1113         if (!NT_STATUS_IS_OK(status)) {
1114                 DEBUG(0, ("Unable to modify passwd TDB: %s!",
1115                           nt_errstr(status)));
1116                 goto done;
1117         }
1118
1119         ret = true;
1120
1121 done:
1122         /* cleanup */
1123         SAFE_FREE(buf);
1124         return ret;
1125 }
1126
1127 /***************************************************************************
1128  Update the TDB SAM RID record only
1129  Assumes that the tdbsam is already open
1130 ****************************************************************************/
1131 static bool tdb_update_ridrec_only( struct samu* newpwd, int flag )
1132 {
1133         TDB_DATA        data;
1134         fstring         keystr;
1135         fstring         name;
1136         NTSTATUS status;
1137
1138         fstrcpy(name, pdb_get_username(newpwd));
1139         strlower_m(name);
1140
1141         /* setup RID data */
1142         data = string_term_tdb_data(name);
1143
1144         /* setup the RID index key */
1145         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX,
1146                  pdb_get_user_rid(newpwd));
1147
1148         /* add the reference */
1149         status = dbwrap_store_bystring(db_sam, keystr, data, flag);
1150         if (!NT_STATUS_IS_OK(status)) {
1151                 DEBUG(0, ("Unable to modify TDB passwd: %s!\n",
1152                           nt_errstr(status)));
1153                 return false;
1154         }
1155
1156         return true;
1157
1158 }
1159
1160 /***************************************************************************
1161  Update the TDB SAM
1162 ****************************************************************************/
1163
1164 static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
1165                            int flag)
1166 {
1167         if (!pdb_get_user_rid(newpwd)) {
1168                 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n",
1169                          pdb_get_username(newpwd)));
1170                 return False;
1171         }
1172
1173         /* open the database */
1174
1175         if ( !tdbsam_open( tdbsam_filename ) ) {
1176                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
1177                 return False;
1178         }
1179
1180         if (db_sam->transaction_start(db_sam) != 0) {
1181                 DEBUG(0, ("Could not start transaction\n"));
1182                 return false;
1183         }
1184
1185         if (!tdb_update_samacct_only(newpwd, flag)
1186             || !tdb_update_ridrec_only(newpwd, flag)) {
1187                 goto cancel;
1188         }
1189
1190         if (db_sam->transaction_commit(db_sam) != 0) {
1191                 DEBUG(0, ("Could not commit transaction\n"));
1192                 goto cancel;
1193         }
1194
1195         return true;
1196
1197  cancel:
1198         if (db_sam->transaction_cancel(db_sam) != 0) {
1199                 smb_panic("transaction_cancel failed");
1200         }
1201         return false;
1202 }
1203
1204 /***************************************************************************
1205  Modifies an existing struct samu
1206 ****************************************************************************/
1207
1208 static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
1209 {
1210         if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
1211                 return NT_STATUS_UNSUCCESSFUL;
1212         
1213         return NT_STATUS_OK;
1214 }
1215
1216 /***************************************************************************
1217  Adds an existing struct samu
1218 ****************************************************************************/
1219
1220 static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
1221 {
1222         if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
1223                 return NT_STATUS_UNSUCCESSFUL;
1224                 
1225         return NT_STATUS_OK;
1226 }
1227
1228 /***************************************************************************
1229  Renames a struct samu
1230  - check for the posix user/rename user script
1231  - Add and lock the new user record
1232  - rename the posix user
1233  - rewrite the rid->username record
1234  - delete the old user
1235  - unlock the new user record
1236 ***************************************************************************/
1237 static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
1238                                           struct samu *old_acct,
1239                                           const char *newname)
1240 {
1241         struct samu      *new_acct = NULL;
1242         char *rename_script = NULL;
1243         int              rename_ret;
1244         fstring          oldname_lower;
1245         fstring          newname_lower;
1246
1247         /* can't do anything without an external script */
1248
1249         if ( !(new_acct = samu_new( talloc_tos() )) ) {
1250                 return NT_STATUS_NO_MEMORY;
1251         }
1252
1253         rename_script = talloc_strdup(new_acct, lp_renameuser_script());
1254         if (!rename_script) {
1255                 TALLOC_FREE(new_acct);
1256                 return NT_STATUS_NO_MEMORY;
1257         }
1258         if (!*rename_script) {
1259                 TALLOC_FREE(new_acct);
1260                 return NT_STATUS_ACCESS_DENIED;
1261         }
1262
1263         if ( !pdb_copy_sam_account(new_acct, old_acct)
1264                 || !pdb_set_username(new_acct, newname, PDB_CHANGED))
1265         {
1266                 TALLOC_FREE(new_acct);
1267                 return NT_STATUS_NO_MEMORY;
1268         }
1269
1270         /* open the database */
1271         if ( !tdbsam_open( tdbsam_filename ) ) {
1272                 DEBUG(0, ("tdbsam_getsampwnam: failed to open %s!\n",
1273                           tdbsam_filename));
1274                 TALLOC_FREE(new_acct);
1275                 return NT_STATUS_ACCESS_DENIED;
1276         }
1277
1278         if (db_sam->transaction_start(db_sam) == -1) {
1279                 DEBUG(0, ("Could not start transaction\n"));
1280                 TALLOC_FREE(new_acct);
1281                 return NT_STATUS_ACCESS_DENIED;
1282
1283         }
1284
1285         /* add the new account and lock it */
1286         if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
1287                 goto cancel;
1288         }
1289
1290         /* Rename the posix user.  Follow the semantics of _samr_create_user()
1291            so that we lower case the posix name but preserve the case in passdb */
1292
1293         fstrcpy( oldname_lower, pdb_get_username(old_acct) );
1294         strlower_m( oldname_lower );
1295
1296         fstrcpy( newname_lower, newname );
1297         strlower_m( newname_lower );
1298
1299         rename_script = talloc_string_sub2(new_acct,
1300                                 rename_script,
1301                                 "%unew",
1302                                 newname_lower,
1303                                 true,
1304                                 false,
1305                                 true);
1306         if (!rename_script) {
1307                 goto cancel;
1308         }
1309         rename_script = talloc_string_sub2(new_acct,
1310                                 rename_script,
1311                                 "%uold",
1312                                 oldname_lower,
1313                                 true,
1314                                 false,
1315                                 true);
1316         if (!rename_script) {
1317                 goto cancel;
1318         }
1319         rename_ret = smbrun(rename_script, NULL);
1320
1321         DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n",
1322                                 rename_script, rename_ret));
1323
1324         if (rename_ret != 0) {
1325                 goto cancel;
1326         }
1327
1328         smb_nscd_flush_user_cache();
1329
1330         /* rewrite the rid->username record */
1331
1332         if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
1333                 goto cancel;
1334         }
1335
1336         tdb_delete_samacct_only( old_acct );
1337
1338         if (db_sam->transaction_commit(db_sam) == -1) {
1339                 /*
1340                  * Ok, we're screwed. We've changed the posix account, but
1341                  * could not adapt passdb.tdb. Shall we change the posix
1342                  * account back?
1343                  */
1344                 DEBUG(0, ("transaction_commit failed\n"));
1345                 goto cancel;
1346         }
1347
1348         TALLOC_FREE(new_acct );
1349         return NT_STATUS_OK;
1350
1351  cancel:
1352         if (db_sam->transaction_cancel(db_sam) != 0) {
1353                 smb_panic("transaction_cancel failed");
1354         }
1355
1356         TALLOC_FREE(new_acct);
1357
1358         return NT_STATUS_ACCESS_DENIED; 
1359 }
1360
1361 static bool tdbsam_rid_algorithm(struct pdb_methods *methods)
1362 {
1363         return False;
1364 }
1365
1366 /*
1367  * Historically, winbind was responsible for allocating RIDs, so the next RID
1368  * value was stored in winbindd_idmap.tdb. It has been moved to passdb now,
1369  * but for compatibility reasons we still keep the the next RID counter in
1370  * winbindd_idmap.tdb.
1371  */
1372
1373 /*****************************************************************************
1374  Initialise idmap database. For now (Dec 2005) this is a copy of the code in
1375  sam/idmap_tdb.c. Maybe at a later stage we can remove that capability from
1376  winbind completely and store the RID counter in passdb.tdb.
1377
1378  Dont' fully initialize with the HWM values, if it's new, we're only
1379  interested in the RID counter.
1380 *****************************************************************************/
1381
1382 static bool init_idmap_tdb(TDB_CONTEXT *tdb)
1383 {
1384         int32 version;
1385
1386         if (tdb_lock_bystring(tdb, "IDMAP_VERSION") != 0) {
1387                 DEBUG(0, ("Could not lock IDMAP_VERSION\n"));
1388                 return False;
1389         }
1390
1391         version = tdb_fetch_int32(tdb, "IDMAP_VERSION");
1392
1393         if (version == -1) {
1394                 /* No key found, must be a new db */
1395                 if (tdb_store_int32(tdb, "IDMAP_VERSION",
1396                                     IDMAP_VERSION) != 0) {
1397                         DEBUG(0, ("Could not store IDMAP_VERSION\n"));
1398                         tdb_unlock_bystring(tdb, "IDMAP_VERSION");
1399                         return False;
1400                 }
1401                 version = IDMAP_VERSION;
1402         }
1403
1404         if (version != IDMAP_VERSION) {
1405                 DEBUG(0, ("Expected IDMAP_VERSION=%d, found %d. Please "
1406                           "start winbind once\n", IDMAP_VERSION, version));
1407                 tdb_unlock_bystring(tdb, "IDMAP_VERSION");
1408                 return False;
1409         }
1410
1411         tdb_unlock_bystring(tdb, "IDMAP_VERSION");
1412         return True;
1413 }
1414
1415 static bool tdbsam_new_rid(struct pdb_methods *methods, uint32 *prid)
1416 {
1417         TDB_CONTEXT *tdb;
1418         uint32 rid;
1419         bool ret = False;
1420
1421         tdb = tdb_open_log(state_path("winbindd_idmap.tdb"), 0,
1422                            TDB_DEFAULT, O_RDWR | O_CREAT, 0644);
1423
1424         if (tdb == NULL) {
1425                 DEBUG(1, ("Could not open idmap: %s\n", strerror(errno)));
1426                 goto done;
1427         }
1428
1429         if (!init_idmap_tdb(tdb)) {
1430                 DEBUG(1, ("Could not init idmap\n"));
1431                 goto done;
1432         }
1433
1434         rid = BASE_RID;         /* Default if not set */
1435
1436         if (!tdb_change_uint32_atomic(tdb, "RID_COUNTER", &rid, 1)) {
1437                 DEBUG(3, ("tdbsam_new_rid: Failed to increase RID_COUNTER\n"));
1438                 goto done;
1439         }
1440
1441         *prid = rid;
1442         ret = True;
1443
1444  done:
1445         if ((tdb != NULL) && (tdb_close(tdb) != 0)) {
1446                 smb_panic("tdb_close(idmap_tdb) failed");
1447         }
1448
1449         return ret;
1450 }
1451
1452 struct tdbsam_search_state {
1453         struct pdb_methods *methods;
1454         uint32_t acct_flags;
1455
1456         uint32_t *rids;
1457         uint32_t num_rids;
1458         ssize_t array_size;
1459         uint32_t current;
1460 };
1461
1462 static int tdbsam_collect_rids(struct db_record *rec, void *private_data)
1463 {
1464         struct tdbsam_search_state *state = talloc_get_type_abort(
1465                 private_data, struct tdbsam_search_state);
1466         size_t prefixlen = strlen(RIDPREFIX);
1467         uint32 rid;
1468
1469         if ((rec->key.dsize < prefixlen)
1470             || (strncmp((char *)rec->key.dptr, RIDPREFIX, prefixlen))) {
1471                 return 0;
1472         }
1473
1474         rid = strtoul((char *)rec->key.dptr+prefixlen, NULL, 16);
1475
1476         ADD_TO_LARGE_ARRAY(state, uint32, rid, &state->rids, &state->num_rids,
1477                            &state->array_size);
1478
1479         return 0;
1480 }
1481
1482 static void tdbsam_search_end(struct pdb_search *search)
1483 {
1484         struct tdbsam_search_state *state = talloc_get_type_abort(
1485                 search->private_data, struct tdbsam_search_state);
1486         TALLOC_FREE(state);
1487 }
1488
1489 static bool tdbsam_search_next_entry(struct pdb_search *search,
1490                                      struct samr_displayentry *entry)
1491 {
1492         struct tdbsam_search_state *state = talloc_get_type_abort(
1493                 search->private_data, struct tdbsam_search_state);
1494         struct samu *user = NULL;
1495         NTSTATUS status;
1496         uint32_t rid;
1497
1498  again:
1499         TALLOC_FREE(user);
1500         user = samu_new(talloc_tos());
1501         if (user == NULL) {
1502                 DEBUG(0, ("samu_new failed\n"));
1503                 return false;
1504         }
1505
1506         if (state->current == state->num_rids) {
1507                 return false;
1508         }
1509
1510         rid = state->rids[state->current++];
1511
1512         status = tdbsam_getsampwrid(state->methods, user, rid);
1513
1514         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
1515                 /*
1516                  * Someone has deleted that user since we listed the RIDs
1517                  */
1518                 goto again;
1519         }
1520
1521         if (!NT_STATUS_IS_OK(status)) {
1522                 DEBUG(10, ("tdbsam_getsampwrid failed: %s\n",
1523                            nt_errstr(status)));
1524                 TALLOC_FREE(user);
1525                 return false;
1526         }
1527
1528         if ((state->acct_flags != 0) &&
1529             ((state->acct_flags & pdb_get_acct_ctrl(user)) == 0)) {
1530                 goto again;
1531         }
1532
1533         entry->acct_flags = pdb_get_acct_ctrl(user);
1534         entry->rid = rid;
1535         entry->account_name = talloc_strdup(
1536                 search->mem_ctx, pdb_get_username(user));
1537         entry->fullname = talloc_strdup(
1538                 search->mem_ctx, pdb_get_fullname(user));
1539         entry->description = talloc_strdup(
1540                 search->mem_ctx, pdb_get_acct_desc(user));
1541
1542         TALLOC_FREE(user);
1543
1544         if ((entry->account_name == NULL) || (entry->fullname == NULL)
1545             || (entry->description == NULL)) {
1546                 DEBUG(0, ("talloc_strdup failed\n"));
1547                 return false;
1548         }
1549
1550         return true;
1551 }
1552
1553 static bool tdbsam_search_users(struct pdb_methods *methods,
1554                                 struct pdb_search *search,
1555                                 uint32 acct_flags)
1556 {
1557         struct tdbsam_search_state *state;
1558
1559         if (!tdbsam_open(tdbsam_filename)) {
1560                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n",
1561                          tdbsam_filename));
1562                 return false;
1563         }
1564
1565         state = TALLOC_ZERO_P(search->mem_ctx, struct tdbsam_search_state);
1566         if (state == NULL) {
1567                 DEBUG(0, ("talloc failed\n"));
1568                 return false;
1569         }
1570         state->acct_flags = acct_flags;
1571         state->methods = methods;
1572
1573         db_sam->traverse_read(db_sam, tdbsam_collect_rids, state);
1574
1575         search->private_data = state;
1576         search->next_entry = tdbsam_search_next_entry;
1577         search->search_end = tdbsam_search_end;
1578
1579         return true;
1580 }
1581
1582 /*********************************************************************
1583  Initialize the tdb sam backend.  Setup the dispath table of methods,
1584  open the tdb, etc...
1585 *********************************************************************/
1586
1587 static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
1588 {
1589         NTSTATUS nt_status;
1590         char *tdbfile = NULL;
1591         const char *pfile = location;
1592
1593         if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
1594                 return nt_status;
1595         }
1596
1597         (*pdb_method)->name = "tdbsam";
1598
1599         (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
1600         (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
1601         (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
1602         (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
1603         (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
1604         (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
1605         (*pdb_method)->search_users = tdbsam_search_users;
1606
1607         (*pdb_method)->rid_algorithm = tdbsam_rid_algorithm;
1608         (*pdb_method)->new_rid = tdbsam_new_rid;
1609
1610         /* save the path for later */
1611
1612         if (!location) {
1613                 if (asprintf(&tdbfile, "%s/%s", lp_private_dir(),
1614                              PASSDB_FILE_NAME) < 0) {
1615                         return NT_STATUS_NO_MEMORY;
1616                 }
1617                 pfile = tdbfile;
1618         }
1619         tdbsam_filename = SMB_STRDUP(pfile);
1620         if (!tdbsam_filename) {
1621                 return NT_STATUS_NO_MEMORY;
1622         }
1623         SAFE_FREE(tdbfile);
1624
1625         /* no private data */
1626
1627         (*pdb_method)->private_data      = NULL;
1628         (*pdb_method)->free_private_data = NULL;
1629
1630         return NT_STATUS_OK;
1631 }
1632
1633 NTSTATUS pdb_tdbsam_init(void)
1634 {
1635         return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);
1636 }