Set the "stable" vendor string in VERSION.
[ira/wip.git] / source3 / passdb / pdb_tdb.c
1 /*
2  * Unix SMB/CIFS implementation. 
3  * SMB parameters and setup
4  * Copyright (C) Andrew Tridgell   1992-1998
5  * Copyright (C) Simo Sorce        2000-2003
6  * Copyright (C) Gerald Carter     2000-2006
7  * Copyright (C) Jeremy Allison    2001
8  * Copyright (C) Andrew Bartlett   2002
9  * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2005
10  * 
11  * This program is free software; you can redistribute it and/or modify it under
12  * the terms of the GNU General Public License as published by the Free
13  * Software Foundation; either version 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 RIDPREFIX               "RID_"
45 #define PRIVPREFIX              "PRIV_"
46
47 /* GLOBAL TDB SAM CONTEXT */
48
49 static TDB_CONTEXT *tdbsam;
50 static int ref_count = 0;
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 static bool tdbsam_convert(int32 from) 
694 {
695         const char      *vstring = TDBSAM_VERSION_STRING;
696         const char      *prefix = USERPREFIX;
697         TDB_DATA        data, key, old_key;
698         uint8           *buf = NULL;
699         bool            ret;
700
701         /* handle a Samba upgrade */
702         tdb_lock_bystring(tdbsam, vstring);
703         
704         /* Enumerate all records and convert them */
705         key = tdb_firstkey(tdbsam);
706
707         while (key.dptr) {
708         
709                 /* skip all non-USER entries (eg. RIDs) */
710                 while ((key.dsize != 0) && (strncmp((const char *)key.dptr, prefix, strlen (prefix)))) {
711                         old_key = key;
712                         /* increment to next in line */
713                         key = tdb_nextkey(tdbsam, key);
714                         SAFE_FREE(old_key.dptr);
715                 }
716         
717                 if (key.dptr) {
718                         struct samu *user = NULL;
719
720                         /* read from tdbsam */
721                         data = tdb_fetch(tdbsam, key);
722                         if (!data.dptr) {
723                                 DEBUG(0,("tdbsam_convert: database entry not found: %s.\n",key.dptr));
724                                 return False;
725                         }
726         
727                         /* unpack the buffer from the former format */
728                         if ( !(user = samu_new( NULL )) ) {
729                                 DEBUG(0,("tdbsam_convert: samu_new() failed!\n"));
730                                 SAFE_FREE( data.dptr );
731                                 return False;
732                         }
733                         DEBUG(10,("tdbsam_convert: Try unpacking a record with (key:%s) (version:%d)\n", key.dptr, from));
734                         switch (from) {
735                                 case 0:
736                                         ret = init_sam_from_buffer_v0(user, (uint8 *)data.dptr, data.dsize);
737                                         break;
738                                 case 1:
739                                         ret = init_sam_from_buffer_v1(user, (uint8 *)data.dptr, data.dsize);
740                                         break;
741                                 case 2:
742                                         ret = init_sam_from_buffer_v2(user, (uint8 *)data.dptr, data.dsize);
743                                         break;
744                                 case 3:
745                                         ret = init_sam_from_buffer_v3(user, (uint8 *)data.dptr, data.dsize);
746                                         break;
747                                 default:
748                                         /* unknown tdbsam version */
749                                         ret = False;
750                         }
751                         if (!ret) {
752                                 DEBUG(0,("tdbsam_convert: Bad struct samu entry returned from TDB (key:%s) (version:%d)\n", key.dptr, from));
753                                 SAFE_FREE(data.dptr);
754                                 TALLOC_FREE(user );
755                                 return False;
756                         }
757         
758                         /* We're finished with the old data. */
759                         SAFE_FREE(data.dptr);
760
761                         /* pack from the buffer into the new format */
762                         
763                         DEBUG(10,("tdbsam_convert: Try packing a record (key:%s) (version:%d)\n",
764                                   (const char *)key.dptr, from));
765                         data.dsize = init_buffer_from_sam (&buf, user, False);
766                         TALLOC_FREE(user );
767                         
768                         if ( data.dsize == -1 ) {
769                                 DEBUG(0,("tdbsam_convert: cannot pack the struct samu into the new format\n"));
770                                 return False;
771                         }
772                         data.dptr = buf;
773                         
774                         /* Store the buffer inside the TDBSAM */
775                         if (tdb_store(tdbsam, key, data, TDB_MODIFY) != TDB_SUCCESS) {
776                                 DEBUG(0,("tdbsam_convert: cannot store the struct samu (key:%s) in new format\n",key.dptr));
777                                 SAFE_FREE(data.dptr);
778                                 return False;
779                         }
780                         
781                         SAFE_FREE(data.dptr);
782                         
783                         /* increment to next in line */
784                         old_key = key;
785                         key = tdb_nextkey(tdbsam, key);
786                         SAFE_FREE(old_key.dptr);
787                 }
788                 
789         }
790
791         
792         /* upgrade finished */
793         tdb_store_int32(tdbsam, vstring, TDBSAM_VERSION);
794         tdb_unlock_bystring(tdbsam, vstring);
795
796         return(True);   
797 }
798
799 /*********************************************************************
800  Open the tdbsam file based on the absolute path specified.
801  Uses a reference count to allow multiple open calls.
802 *********************************************************************/
803
804 static bool tdbsam_open( const char *name )
805 {
806         int32   version;
807         
808         /* check if we are already open */
809         
810         if ( tdbsam ) {
811                 ref_count++;
812                 DEBUG(8,("tdbsam_open: Incrementing open reference count.  Ref count is now %d\n", 
813                         ref_count));
814                 return True;
815         }
816         
817         SMB_ASSERT( ref_count == 0 );
818         
819         /* Try to open tdb passwd.  Create a new one if necessary */
820         
821         if (!(tdbsam = tdb_open_log(name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600))) {
822                 DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd [%s]\n", name));
823                 return False;
824         }
825
826         /* set the initial reference count - must be done before tdbsam_convert
827            as that calls tdbsam_open()/tdbsam_close(). */
828
829         ref_count = 1;
830
831         /* Check the version */
832         version = tdb_fetch_int32( tdbsam, TDBSAM_VERSION_STRING );
833         
834         if (version == -1) {
835                 version = 0;    /* Version not found, assume version 0 */
836         }
837         
838         /* Compare the version */
839         if (version > TDBSAM_VERSION) {
840                 /* Version more recent than the latest known */ 
841                 DEBUG(0, ("tdbsam_open: unknown version => %d\n", version));
842                 tdb_close( tdbsam );
843                 ref_count = 0;
844                 return False;
845         } 
846         
847         
848         if ( version < TDBSAM_VERSION ) {       
849                 DEBUG(1, ("tdbsam_open: Converting version %d database to version %d.\n", 
850                         version, TDBSAM_VERSION));
851                 
852                 if ( !tdbsam_convert(version) ) {
853                         DEBUG(0, ("tdbsam_open: Error when trying to convert tdbsam [%s]\n",name));
854                         tdb_close(tdbsam);
855                         ref_count = 0;
856                         return False;
857                 }
858                         
859                 DEBUG(3, ("TDBSAM converted successfully.\n"));
860         }
861         
862         DEBUG(4,("tdbsam_open: successfully opened %s\n", name ));      
863         
864         return True;
865 }
866
867 /****************************************************************************
868  wrapper atound tdb_close() to handle the reference count
869 ****************************************************************************/
870
871 void tdbsam_close( void )
872 {
873         ref_count--;
874         
875         DEBUG(8,("tdbsam_close: Reference count is now %d.\n", ref_count));
876
877         SMB_ASSERT(ref_count >= 0 );
878         
879         if ( ref_count == 0 ) {
880                 tdb_close( tdbsam );
881                 tdbsam = NULL;
882         }
883         
884         return;
885 }
886
887 /******************************************************************
888  Lookup a name in the SAM TDB
889 ******************************************************************/
890
891 static NTSTATUS tdbsam_getsampwnam (struct pdb_methods *my_methods, struct samu *user, const char *sname)
892 {
893         TDB_DATA        data;
894         fstring         keystr;
895         fstring         name;
896
897         if ( !user ) {
898                 DEBUG(0,("pdb_getsampwnam: struct samu is NULL.\n"));
899                 return NT_STATUS_NO_MEMORY;
900         }
901
902         /* Data is stored in all lower-case */
903         fstrcpy(name, sname);
904         strlower_m(name);
905
906         /* set search key */
907         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
908
909         /* open the database */
910                 
911         if ( !tdbsam_open( tdbsam_filename ) ) {
912                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
913                 return NT_STATUS_ACCESS_DENIED;
914         }
915         
916         /* get the record */
917         
918         data = tdb_fetch_bystring(tdbsam, keystr);
919         if (!data.dptr) {
920                 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
921                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
922                 DEBUGADD(5, (" Key: %s\n", keystr));
923                 tdbsam_close();
924                 return NT_STATUS_NO_SUCH_USER;
925         }
926   
927         /* unpack the buffer */
928         
929         if (!init_sam_from_buffer(user, data.dptr, data.dsize)) {
930                 DEBUG(0,("pdb_getsampwent: Bad struct samu entry returned from TDB!\n"));
931                 SAFE_FREE(data.dptr);
932                 tdbsam_close();
933                 return NT_STATUS_NO_MEMORY;
934         }
935         
936         /* success */
937         
938         SAFE_FREE(data.dptr);
939         tdbsam_close();
940         
941         return NT_STATUS_OK;
942 }
943
944 /***************************************************************************
945  Search by rid
946  **************************************************************************/
947
948 static NTSTATUS tdbsam_getsampwrid (struct pdb_methods *my_methods, struct samu *user, uint32 rid)
949 {
950         NTSTATUS                nt_status = NT_STATUS_UNSUCCESSFUL;
951         TDB_DATA                data;
952         fstring                 keystr;
953         fstring                 name;
954
955         if ( !user ) {
956                 DEBUG(0,("pdb_getsampwrid: struct samu is NULL.\n"));
957                 return nt_status;
958         }
959         
960         /* set search key */
961         
962         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
963
964         /* open the database */
965                 
966         if ( !tdbsam_open( tdbsam_filename ) ) {
967                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
968                 return NT_STATUS_ACCESS_DENIED;
969         }
970
971         /* get the record */
972         
973         data = tdb_fetch_bystring (tdbsam, keystr);
974         if (!data.dptr) {
975                 DEBUG(5,("pdb_getsampwrid (TDB): error looking up RID %d by key %s.\n", rid, keystr));
976                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
977                 nt_status = NT_STATUS_UNSUCCESSFUL;
978                 goto done;
979         }
980
981         fstrcpy(name, (const char *)data.dptr);
982         SAFE_FREE(data.dptr);
983         
984         nt_status = tdbsam_getsampwnam (my_methods, user, name);
985
986  done:
987         /* cleanup */
988         
989         tdbsam_close();
990                 
991         return nt_status;
992 }
993
994 static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods, struct samu * user, const DOM_SID *sid)
995 {
996         uint32 rid;
997         
998         if ( !sid_peek_check_rid(get_global_sam_sid(), sid, &rid) )
999                 return NT_STATUS_UNSUCCESSFUL;
1000
1001         return tdbsam_getsampwrid(my_methods, user, rid);
1002 }
1003
1004 static bool tdb_delete_samacct_only( struct samu *sam_pass )
1005 {
1006         fstring         keystr;
1007         fstring         name;
1008
1009         fstrcpy(name, pdb_get_username(sam_pass));
1010         strlower_m(name);
1011         
1012         /* set the search key */
1013         
1014         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
1015         
1016         /* it's outaa here!  8^) */
1017         
1018         if (tdb_delete_bystring(tdbsam, keystr) != TDB_SUCCESS) {
1019                 DEBUG(5, ("Error deleting entry from tdb passwd database!\n"));
1020                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
1021                 return False;
1022         }
1023         
1024         return True;
1025 }
1026
1027 /***************************************************************************
1028  Delete a struct samu records for the username and RID key
1029 ****************************************************************************/
1030
1031 static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods, struct samu *sam_pass)
1032 {
1033         NTSTATUS        nt_status = NT_STATUS_UNSUCCESSFUL;
1034         fstring         keystr;
1035         uint32          rid;
1036         fstring         name;
1037         
1038         /* open the database */
1039                 
1040         if ( !tdbsam_open( tdbsam_filename ) ) {
1041                 DEBUG(0,("tdbsam_delete_sam_account: failed to open %s!\n",
1042                          tdbsam_filename));
1043                 return NT_STATUS_ACCESS_DENIED;
1044         }
1045
1046         fstrcpy(name, pdb_get_username(sam_pass));
1047         strlower_m(name);
1048         
1049         /* set the search key */
1050
1051         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
1052         
1053         rid = pdb_get_user_rid(sam_pass);
1054
1055         /* it's outaa here!  8^) */
1056
1057         if ( tdb_delete_bystring(tdbsam, keystr) != TDB_SUCCESS ) {
1058                 DEBUG(5, ("Error deleting entry from tdb passwd database!\n"));
1059                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
1060                 nt_status = NT_STATUS_UNSUCCESSFUL;
1061                 goto done;
1062         }
1063
1064         /* set the search key */
1065         
1066         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, rid);
1067
1068         /* it's outaa here!  8^) */
1069         
1070         if ( tdb_delete_bystring(tdbsam, keystr) != TDB_SUCCESS ) {
1071                 DEBUG(5, ("Error deleting entry from tdb rid database!\n"));
1072                 DEBUGADD(5, (" Error: %s\n", tdb_errorstr(tdbsam)));
1073                 nt_status = NT_STATUS_UNSUCCESSFUL;
1074                 goto done;
1075         }
1076
1077         nt_status = NT_STATUS_OK;
1078         
1079  done:
1080         tdbsam_close();
1081         
1082         return nt_status;
1083 }
1084
1085
1086 /***************************************************************************
1087  Update the TDB SAM account record only
1088  Assumes that the tdbsam is already open 
1089 ****************************************************************************/
1090 static bool tdb_update_samacct_only( struct samu* newpwd, int flag )
1091 {
1092         TDB_DATA        data;
1093         uint8           *buf = NULL;
1094         fstring         keystr;
1095         fstring         name;
1096         bool            ret = True;
1097
1098         /* copy the struct samu struct into a BYTE buffer for storage */
1099         
1100         if ( (data.dsize=init_buffer_from_sam (&buf, newpwd, False)) == -1 ) {
1101                 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy struct samu info BYTE buffer!\n"));
1102                 ret = False;
1103                 goto done;
1104         }
1105         data.dptr = buf;
1106
1107         fstrcpy(name, pdb_get_username(newpwd));
1108         strlower_m(name);
1109         
1110         DEBUG(5, ("Storing %saccount %s with RID %d\n", 
1111                   flag == TDB_INSERT ? "(new) " : "", name, 
1112                   pdb_get_user_rid(newpwd)));
1113
1114         /* setup the USER index key */
1115         slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name);
1116
1117         /* add the account */
1118         
1119         if ( tdb_store_bystring(tdbsam, keystr, data, flag) != TDB_SUCCESS ) {
1120                 DEBUG(0, ("Unable to modify passwd TDB!"));
1121                 DEBUGADD(0, (" Error: %s", tdb_errorstr(tdbsam)));
1122                 DEBUGADD(0, (" occured while storing the main record (%s)\n",
1123                              keystr));
1124                 ret = False;
1125                 goto done;
1126         }
1127
1128 done:   
1129         /* cleanup */
1130         SAFE_FREE(buf);
1131         
1132         return ret;
1133 }
1134
1135 /***************************************************************************
1136  Update the TDB SAM RID record only
1137  Assumes that the tdbsam is already open 
1138 ****************************************************************************/
1139 static bool tdb_update_ridrec_only( struct samu* newpwd, int flag )
1140 {
1141         TDB_DATA        data;
1142         fstring         keystr;
1143         fstring         name;
1144
1145         fstrcpy(name, pdb_get_username(newpwd));
1146         strlower_m(name);
1147
1148         /* setup RID data */
1149         data = string_term_tdb_data(name);
1150
1151         /* setup the RID index key */
1152         slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX,  pdb_get_user_rid(newpwd));
1153         
1154         /* add the reference */
1155         if (tdb_store_bystring(tdbsam, keystr, data, flag) != TDB_SUCCESS) {
1156                 DEBUG(0, ("Unable to modify TDB passwd !"));
1157                 DEBUGADD(0, (" Error: %s\n", tdb_errorstr(tdbsam)));
1158                 DEBUGADD(0, (" occured while storing the RID index (%s)\n", keystr));
1159                 return False;
1160         }
1161
1162         return True;
1163
1164 }
1165
1166 /***************************************************************************
1167  Update the TDB SAM
1168 ****************************************************************************/
1169
1170 static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd, int flag)
1171 {
1172         bool            result = True;
1173
1174 #if 0 
1175         if ( !pdb_get_group_rid(newpwd) ) {
1176                 DEBUG (0,("tdb_update_sam: Failing to store a struct samu for [%s] "
1177                         "without a primary group RID\n", pdb_get_username(newpwd)));
1178                 return False;
1179         }
1180 #endif
1181
1182         if (!pdb_get_user_rid(newpwd)) {
1183                 DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n", pdb_get_username(newpwd)));
1184                 return False;
1185         }
1186
1187         /* open the database */
1188                 
1189         if ( !tdbsam_open( tdbsam_filename ) ) {
1190                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
1191                 return False;
1192         }
1193         
1194         if ( !tdb_update_samacct_only(newpwd, flag) || !tdb_update_ridrec_only(newpwd, flag)) {
1195                 result = False;
1196         }
1197
1198         /* cleanup */
1199
1200         tdbsam_close();
1201         
1202         return result;  
1203 }
1204
1205 /***************************************************************************
1206  Modifies an existing struct samu
1207 ****************************************************************************/
1208
1209 static NTSTATUS tdbsam_update_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
1210 {
1211         if ( !tdb_update_sam(my_methods, newpwd, TDB_MODIFY) )
1212                 return NT_STATUS_UNSUCCESSFUL;
1213         
1214         return NT_STATUS_OK;
1215 }
1216
1217 /***************************************************************************
1218  Adds an existing struct samu
1219 ****************************************************************************/
1220
1221 static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, struct samu *newpwd)
1222 {
1223         if ( !tdb_update_sam(my_methods, newpwd, TDB_INSERT) )
1224                 return NT_STATUS_UNSUCCESSFUL;
1225                 
1226         return NT_STATUS_OK;
1227 }
1228
1229 /***************************************************************************
1230  Renames a struct samu
1231  - check for the posix user/rename user script
1232  - Add and lock the new user record
1233  - rename the posix user
1234  - rewrite the rid->username record
1235  - delete the old user
1236  - unlock the new user record
1237 ***************************************************************************/
1238 static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods,
1239                                           struct samu *old_acct,
1240                                           const char *newname)
1241 {
1242         TALLOC_CTX *ctx = talloc_tos();
1243         struct samu      *new_acct = NULL;
1244         char *rename_script = NULL;
1245         bool             interim_account = False;
1246         int              rename_ret;
1247         fstring          oldname_lower;
1248         fstring          newname_lower;
1249
1250         /* can't do anything without an external script */
1251
1252         rename_script = talloc_strdup(ctx, lp_renameuser_script());
1253         if (!rename_script) {
1254                 return NT_STATUS_NO_MEMORY;
1255         }
1256         if (!*rename_script) {
1257                 return NT_STATUS_ACCESS_DENIED;
1258         }
1259
1260         if ( !(new_acct = samu_new( NULL )) ) {
1261                 return NT_STATUS_NO_MEMORY;
1262         }
1263
1264         if ( !pdb_copy_sam_account(new_acct, old_acct)
1265                 || !pdb_set_username(new_acct, newname, PDB_CHANGED))
1266         {
1267                 TALLOC_FREE(new_acct );
1268                 return NT_STATUS_NO_MEMORY;
1269         }
1270
1271         /* open the database */
1272         if ( !tdbsam_open( tdbsam_filename ) ) {
1273                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n", tdbsam_filename));
1274                 TALLOC_FREE(new_acct );
1275                 return NT_STATUS_ACCESS_DENIED;
1276         }
1277
1278         /* add the new account and lock it */
1279         if ( !tdb_update_samacct_only(new_acct, TDB_INSERT) ) {
1280                 goto done;
1281         }
1282
1283         interim_account = True;
1284
1285         if ( tdb_lock_bystring_with_timeout(tdbsam, newname, 30) == -1 ) {
1286                 goto done;
1287         }
1288
1289         /* Rename the posix user.  Follow the semantics of _samr_create_user()
1290            so that we lower case the posix name but preserve the case in passdb */
1291
1292         fstrcpy( oldname_lower, pdb_get_username(old_acct) );
1293         strlower_m( oldname_lower );
1294
1295         fstrcpy( newname_lower, newname );
1296         strlower_m( newname_lower );
1297
1298         rename_script = talloc_string_sub2(ctx,
1299                                 rename_script,
1300                                 "%unew",
1301                                 newname_lower,
1302                                 true,
1303                                 false,
1304                                 true);
1305         if (!rename_script) {
1306                 goto done;
1307         }
1308         rename_script = talloc_string_sub2(ctx,
1309                                 rename_script,
1310                                 "%uold",
1311                                 oldname_lower,
1312                                 true,
1313                                 false,
1314                                 true);
1315         if (!rename_script) {
1316                 goto done;
1317         }
1318         rename_ret = smbrun(rename_script, NULL);
1319
1320         DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n",
1321                                 rename_script, rename_ret));
1322
1323         if (rename_ret == 0) {
1324                 smb_nscd_flush_user_cache();
1325         }
1326
1327         if (rename_ret) {
1328                 goto done;
1329         }
1330
1331         /* rewrite the rid->username record */
1332
1333         if ( !tdb_update_ridrec_only( new_acct, TDB_MODIFY) ) {
1334                 goto done;
1335         }
1336         interim_account = False;
1337         tdb_unlock_bystring( tdbsam, newname );
1338
1339         tdb_delete_samacct_only( old_acct );
1340
1341         tdbsam_close();
1342
1343         TALLOC_FREE(new_acct );
1344         return NT_STATUS_OK;
1345
1346 done:
1347         /* cleanup */
1348         if (interim_account) {
1349                 tdb_unlock_bystring(tdbsam, newname);
1350                 tdb_delete_samacct_only(new_acct);
1351         }
1352
1353         tdbsam_close();
1354
1355         if (new_acct)
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(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data,
1463                                void *private_data)
1464 {
1465         struct tdbsam_search_state *state = talloc_get_type_abort(
1466                 private_data, struct tdbsam_search_state);
1467         size_t prefixlen = strlen(RIDPREFIX);
1468         uint32 rid;
1469
1470         if ((key.dsize < prefixlen)
1471             || (strncmp((char *)key.dptr, RIDPREFIX, prefixlen))) {
1472                 return 0;
1473         }
1474
1475         rid = strtoul((char *)key.dptr+prefixlen, NULL, 16);
1476
1477         ADD_TO_LARGE_ARRAY(state, uint32, rid, &state->rids, &state->num_rids,
1478                            &state->array_size);
1479
1480         return 0;
1481 }
1482
1483 static void tdbsam_search_end(struct pdb_search *search)
1484 {
1485         struct tdbsam_search_state *state = talloc_get_type_abort(
1486                 search->private_data, struct tdbsam_search_state);
1487         TALLOC_FREE(state);
1488 }
1489
1490 static bool tdbsam_search_next_entry(struct pdb_search *search,
1491                                      struct samr_displayentry *entry)
1492 {
1493         struct tdbsam_search_state *state = talloc_get_type_abort(
1494                 search->private_data, struct tdbsam_search_state);
1495         struct samu *user = NULL;
1496         NTSTATUS status;
1497         uint32_t rid;
1498
1499  again:
1500         TALLOC_FREE(user);
1501         user = samu_new(talloc_tos());
1502         if (user == NULL) {
1503                 DEBUG(0, ("samu_new failed\n"));
1504                 return false;
1505         }
1506
1507         if (state->current == state->num_rids) {
1508                 return false;
1509         }
1510
1511         rid = state->rids[state->current++];
1512
1513         status = tdbsam_getsampwrid(state->methods, user, rid);
1514
1515         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
1516                 /*
1517                  * Someone has deleted that user since we listed the RIDs
1518                  */
1519                 goto again;
1520         }
1521
1522         if (!NT_STATUS_IS_OK(status)) {
1523                 DEBUG(10, ("tdbsam_getsampwrid failed: %s\n",
1524                            nt_errstr(status)));
1525                 TALLOC_FREE(user);
1526                 return false;
1527         }
1528
1529         if ((state->acct_flags != 0) &&
1530             ((state->acct_flags & pdb_get_acct_ctrl(user)) == 0)) {
1531                 goto again;
1532         }
1533
1534         entry->acct_flags = pdb_get_acct_ctrl(user);
1535         entry->rid = rid;
1536         entry->account_name = talloc_strdup(
1537                 search->mem_ctx, pdb_get_username(user));
1538         entry->fullname = talloc_strdup(
1539                 search->mem_ctx, pdb_get_fullname(user));
1540         entry->description = talloc_strdup(
1541                 search->mem_ctx, pdb_get_acct_desc(user));
1542
1543         TALLOC_FREE(user);
1544
1545         if ((entry->account_name == NULL) || (entry->fullname == NULL)
1546             || (entry->description == NULL)) {
1547                 DEBUG(0, ("talloc_strdup failed\n"));
1548                 return false;
1549         }
1550
1551         return true;
1552 }
1553
1554 static bool tdbsam_search_users(struct pdb_methods *methods,
1555                                 struct pdb_search *search,
1556                                 uint32 acct_flags)
1557 {
1558         struct tdbsam_search_state *state;
1559
1560         if (!tdbsam_open(tdbsam_filename)) {
1561                 DEBUG(0,("tdbsam_getsampwnam: failed to open %s!\n",
1562                          tdbsam_filename));
1563                 return false;
1564         }
1565
1566         state = TALLOC_ZERO_P(search->mem_ctx, struct tdbsam_search_state);
1567         if (state == NULL) {
1568                 DEBUG(0, ("talloc failed\n"));
1569                 return false;
1570         }
1571         state->acct_flags = acct_flags;
1572         state->methods = methods;
1573
1574         tdb_traverse(tdbsam, tdbsam_collect_rids, state);
1575
1576         tdbsam_close();
1577
1578         search->private_data = state;
1579         search->next_entry = tdbsam_search_next_entry;
1580         search->search_end = tdbsam_search_end;
1581
1582         return true;
1583 }
1584
1585 /*********************************************************************
1586  Initialize the tdb sam backend.  Setup the dispath table of methods,
1587  open the tdb, etc...
1588 *********************************************************************/
1589
1590 static NTSTATUS pdb_init_tdbsam(struct pdb_methods **pdb_method, const char *location)
1591 {
1592         NTSTATUS nt_status;
1593         char *tdbfile = NULL;
1594         const char *pfile = location;
1595
1596         if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
1597                 return nt_status;
1598         }
1599
1600         (*pdb_method)->name = "tdbsam";
1601
1602         (*pdb_method)->getsampwnam = tdbsam_getsampwnam;
1603         (*pdb_method)->getsampwsid = tdbsam_getsampwsid;
1604         (*pdb_method)->add_sam_account = tdbsam_add_sam_account;
1605         (*pdb_method)->update_sam_account = tdbsam_update_sam_account;
1606         (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account;
1607         (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account;
1608         (*pdb_method)->search_users = tdbsam_search_users;
1609
1610         (*pdb_method)->rid_algorithm = tdbsam_rid_algorithm;
1611         (*pdb_method)->new_rid = tdbsam_new_rid;
1612
1613         /* save the path for later */
1614
1615         if (!location) {
1616                 if (asprintf(&tdbfile, "%s/%s", lp_private_dir(),
1617                              PASSDB_FILE_NAME) < 0) {
1618                         return NT_STATUS_NO_MEMORY;
1619                 }
1620                 pfile = tdbfile;
1621         }
1622         tdbsam_filename = SMB_STRDUP(pfile);
1623         if (!tdbsam_filename) {
1624                 return NT_STATUS_NO_MEMORY;
1625         }
1626         SAFE_FREE(tdbfile);
1627
1628         /* no private data */
1629
1630         (*pdb_method)->private_data      = NULL;
1631         (*pdb_method)->free_private_data = NULL;
1632
1633         return NT_STATUS_OK;
1634 }
1635
1636 NTSTATUS pdb_tdbsam_init(void)
1637 {
1638         return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);
1639 }