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