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