Another large patch for the passdb rewrite.
[Samba/gbeck.git] / source / passdb / pdb_tdb.c
blobe997d6c31884b392f767d295ba4e331f7d04cf49
1 /*
2 * Unix SMB/Netbios implementation. Version 1.9. SMB parameters and setup
3 * Copyright (C) Andrew Tridgell 1992-1998
4 * Copyright (C) Simo Sorce 2000
5 *
6 * This program is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
16 * You should have received a copy of the GNU General Public License along with
17 * this program; if not, write to the Free Software Foundation, Inc., 675
18 * Mass Ave, Cambridge, MA 02139, USA.
21 #include "includes.h"
23 #ifdef WITH_TDBPWD
25 #define TDB_FORMAT_STRING "ddddddfffPPfPPPPffddBBwdwdBdd"
26 #define USERPREFIX "USER_"
28 extern int DEBUGLEVEL;
29 extern pstring samlogon_user;
30 extern BOOL sam_logon_in_ssb;
33 struct tdb_enum_info
35 TDB_CONTEXT *passwd_tdb;
36 TDB_DATA key;
39 static struct tdb_enum_info global_tdb_ent;
40 static SAM_ACCOUNT global_sam_pass;
42 /**********************************************************************
43 Intialize a SAM_ACCOUNT struct from a BYTE buffer of size len
44 *********************************************************************/
45 static BOOL init_sam_from_buffer (SAM_ACCOUNT *sampass, BYTE *buf,
46 uint32 buflen)
48 static fstring username,
49 domain,
50 nt_username,
51 dir_drive,
52 unknown_str,
53 munged_dial;
54 static pstring full_name,
55 home_dir,
56 logon_script,
57 profile_path,
58 acct_desc,
59 workstations;
60 static BYTE *lm_pw_ptr,
61 *nt_pw_ptr,
62 lm_pw[16],
63 nt_pw[16];
64 uint32 len = 0;
65 uint32 lmpwlen, ntpwlen, hourslen;
67 /* unpack the buffer into variables */
68 len = tdb_unpack (buf, buflen, TDB_FORMAT_STRING,
69 &sampass->logon_time,
70 &sampass->logoff_time,
71 &sampass->kickoff_time,
72 &sampass->pass_last_set_time,
73 &sampass->pass_can_change_time,
74 &sampass->pass_must_change_time,
75 username,
76 domain,
77 nt_username,
78 full_name,
79 home_dir,
80 dir_drive,
81 logon_script,
82 profile_path,
83 acct_desc,
84 workstations,
85 unknown_str,
86 munged_dial,
87 &sampass->user_rid,
88 &sampass->group_rid,
89 &lmpwlen, &lm_pw_ptr,
90 &ntpwlen, &nt_pw_ptr,
91 &sampass->acct_ctrl,
92 &sampass->unknown_3,
93 &sampass->logon_divs,
94 &sampass->hours_len,
95 &hourslen, &sampass->hours,
96 &sampass->unknown_5,
97 &sampass->unknown_6);
99 if (len == -1)
100 return False;
103 * We have to copy the password hashes into static memory
104 * and free the memory allocated by tdb_unpack. This is because
105 * the sampass->own_memory flag is for all pointer members.
106 * The remaining members are using static memory and so
107 * the password hashes must as well. --jerry
109 if (lm_pw_ptr)
111 memcpy(lm_pw, lm_pw_ptr, 16);
112 free (lm_pw_ptr);
114 if (nt_pw_ptr)
116 memcpy(nt_pw, nt_pw_ptr, 16);
117 free (nt_pw_ptr);
120 /* using static memory for strings */
121 pdb_set_mem_ownership(sampass, False);
123 pdb_set_username (sampass, username);
124 pdb_set_domain (sampass, domain);
125 pdb_set_nt_username (sampass, nt_username);
126 pdb_set_fullname (sampass, full_name);
127 pdb_set_homedir (sampass, home_dir);
128 pdb_set_dir_drive (sampass, dir_drive);
129 pdb_set_logon_script (sampass, logon_script);
130 pdb_set_profile_path (sampass, profile_path);
131 pdb_set_acct_desc (sampass, acct_desc);
132 pdb_set_workstations (sampass, workstations);
133 pdb_set_munged_dial (sampass, munged_dial);
134 pdb_set_lanman_passwd(sampass, lm_pw);
135 pdb_set_nt_passwd (sampass, nt_pw);
137 return True;
140 /**********************************************************************
141 Intialize a BYTE buffer from a SAM_ACCOUNT struct
142 *********************************************************************/
143 static uint32 init_buffer_from_sam (BYTE **buf, SAM_ACCOUNT *sampass)
145 size_t len, buflen;
147 fstring username,
148 domain,
149 nt_username,
150 dir_drive,
151 unknown_str,
152 munged_dial;
153 pstring full_name,
154 home_dir,
155 logon_script,
156 profile_path,
157 acct_desc,
158 workstations;
159 BYTE lm_pw[16],
160 nt_pw[16];
161 char null_pw[] = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
163 /* do we have a valid SAM_ACCOUNT pointer? */
164 if (sampass == NULL)
165 return -1;
167 *buf = NULL;
168 buflen = 0;
170 fstrcpy(username, sampass->username);
171 fstrcpy(domain, sampass->domain);
172 fstrcpy(nt_username, sampass->nt_username);
173 fstrcpy(dir_drive, sampass->dir_drive);
174 fstrcpy(unknown_str, sampass->unknown_str);
175 fstrcpy(munged_dial, sampass->munged_dial);
177 pstrcpy(full_name, sampass->full_name);
178 pstrcpy(home_dir, sampass->home_dir);
179 pstrcpy(logon_script, sampass->logon_script);
180 pstrcpy(profile_path, sampass->profile_path);
181 pstrcpy(acct_desc, sampass->acct_desc);
182 pstrcpy(workstations, sampass->workstations);
184 if (sampass->lm_pw)
185 memcpy(lm_pw, sampass->lm_pw, 16);
186 else
187 pdb_gethexpwd (null_pw, lm_pw);
189 if (sampass->nt_pw)
190 memcpy(nt_pw, sampass->nt_pw, 16);
191 else
192 pdb_gethexpwd (null_pw, nt_pw);
195 /* one time to get the size needed */
196 len = tdb_pack(NULL, 0, TDB_FORMAT_STRING,
197 sampass->logon_time,
198 sampass->logoff_time,
199 sampass->kickoff_time,
200 sampass->pass_last_set_time,
201 sampass->pass_can_change_time,
202 sampass->pass_must_change_time,
203 username,
204 domain,
205 nt_username,
206 full_name,
207 home_dir,
208 dir_drive,
209 logon_script,
210 profile_path,
211 acct_desc,
212 workstations,
213 unknown_str,
214 munged_dial,
215 sampass->user_rid,
216 sampass->group_rid,
217 16, lm_pw,
218 16, nt_pw,
219 sampass->acct_ctrl,
220 sampass->unknown_3,
221 sampass->logon_divs,
222 sampass->hours_len,
223 MAX_HOURS_LEN, sampass->hours,
224 sampass->unknown_5,
225 sampass->unknown_6);
228 /* malloc the space needed */
229 if ( (*buf=(BYTE*)malloc(len)) == NULL)
231 DEBUG(0,("init_buffer_from_sam: Unable to malloc() memory for buffer!\n"));
232 return (-1);
235 /* now for the real call to tdb_pack() */
236 /* one time to get the size needed */
237 buflen = tdb_pack(*buf, len, TDB_FORMAT_STRING,
238 sampass->logon_time,
239 sampass->logoff_time,
240 sampass->kickoff_time,
241 sampass->pass_last_set_time,
242 sampass->pass_can_change_time,
243 sampass->pass_must_change_time,
244 username,
245 domain,
246 nt_username,
247 full_name,
248 home_dir,
249 dir_drive,
250 logon_script,
251 profile_path,
252 acct_desc,
253 workstations,
254 unknown_str,
255 munged_dial,
256 sampass->user_rid,
257 sampass->group_rid,
258 16, lm_pw,
259 16, nt_pw,
260 sampass->acct_ctrl,
261 sampass->unknown_3,
262 sampass->logon_divs,
263 sampass->hours_len,
264 MAX_HOURS_LEN, sampass->hours,
265 sampass->unknown_5,
266 sampass->unknown_6);
269 /* check to make sure we got it correct */
270 if (buflen != len)
272 /* error */
273 free (*buf);
274 return (-1);
277 return (buflen);
280 /***************************************************************
281 Open the TDB account SAM fo renumeration.
282 ****************************************************************/
283 BOOL pdb_setsampwent(BOOL update)
285 pstring tdbfile;
287 pstrcpy (tdbfile, lp_private_dir());
288 pstrcat (tdbfile, "/passdb.tdb");
290 /* Open tdb passwd */
291 if (!(global_tdb_ent.passwd_tdb = tdb_open(tdbfile, 0, 0, update ? O_RDWR : O_RDONLY, 0600)))
293 DEBUG(0, ("Unable to open TDB passwd, trying create new!\n"));
294 if (!(global_tdb_ent.passwd_tdb = tdb_open(tdbfile, 0, 0, O_RDWR | O_CREAT | O_EXCL, 0600)))
296 DEBUG(0, ("Unable to create TDB passwd (smbpasswd.tdb) !!!"));
297 return False;
301 global_tdb_ent.key = tdb_firstkey(global_tdb_ent.passwd_tdb);
303 return True;
306 /***************************************************************
307 End enumeration of the TDB passwd list.
308 ****************************************************************/
309 void pdb_endsampwent(void)
311 if (global_tdb_ent.passwd_tdb)
313 tdb_close(global_tdb_ent.passwd_tdb);
314 global_tdb_ent.passwd_tdb = NULL;
317 DEBUG(7, ("endtdbpwent: closed password file.\n"));
321 /*****************************************************************
322 Get one SAM_ACCOUNT from the TDB (next in line)
323 *****************************************************************/
324 SAM_ACCOUNT* pdb_getsampwent(void)
326 TDB_DATA data;
327 struct passwd *pw;
329 /* do we have an valid interation pointer? */
330 if(global_tdb_ent.passwd_tdb == NULL)
332 DEBUG(0,("pdb_get_sampwent: Bad TDB Context pointer.\n"));
333 return NULL;
336 data = tdb_fetch (global_tdb_ent.passwd_tdb, global_tdb_ent.key);
337 if (!data.dptr)
339 DEBUG(5,("pdb_getsampwent: database entry not found.\n"));
340 return NULL;
343 /* unpack the buffer */
344 pdb_clear_sam (&global_sam_pass);
345 if (!init_sam_from_buffer (&global_sam_pass, data.dptr, data.dsize))
347 DEBUG(0,("pdb_getsampwent: Bad SAM_ACCOUNT entry returned from TDB!\n"));
348 return NULL;
351 /* validate the account and fill in UNIX uid and gid. sys_getpwnam()
352 is used instaed of Get_Pwnam() as we do not need to try case
353 permutations */
354 if ((pw=sys_getpwnam(pdb_get_username(&global_sam_pass))) == NULL)
356 DEBUG(0,("pdb_getsampwent: getpwnam(%s) return NULL. User does not exist!\n",
357 pdb_get_username(&global_sam_pass)));
358 return NULL;
361 pdb_set_uid (&global_sam_pass, pw->pw_uid);
362 pdb_set_gid (&global_sam_pass, pw->pw_gid);
364 /* increment to next in line */
365 global_tdb_ent.key = tdb_nextkey (global_tdb_ent.passwd_tdb, global_tdb_ent.key);
367 return (&global_sam_pass);
370 /******************************************************************
371 Lookup a name in the SAM TDB
372 ******************************************************************/
373 SAM_ACCOUNT* pdb_getsampwnam (char *name)
375 TDB_CONTEXT *pwd_tdb;
376 TDB_DATA data, key;
377 fstring keystr;
378 struct passwd *pw;
379 pstring tdbfile;
381 pstrcpy (tdbfile, lp_private_dir());
382 pstrcat (tdbfile, "/passdb.tdb");
384 /* set search key */
385 slprintf(keystr, sizeof(keystr), "%s%s", USERPREFIX, name);
386 key.dptr = keystr;
387 key.dsize = strlen (keystr) + 1;
389 /* open the accounts TDB */
390 if (!(pwd_tdb = tdb_open(tdbfile, 0, 0, O_RDONLY, 0600)))
392 DEBUG(0, ("pdb_getsampwnam: Unable to open TDB passwd!\n"));
393 return False;
396 /* get the record */
397 data = tdb_fetch (pwd_tdb, key);
398 if (!data.dptr)
400 DEBUG(5,("pdb_getsampwnam (TDB): error fetching database.\n"));
401 DEBUGADD(5, (" Error: %s\n", tdb_error(pwd_tdb)));
402 tdb_close (pwd_tdb);
403 return NULL;
406 /* unpack the buffer */
407 pdb_clear_sam (&global_sam_pass);
408 if (!init_sam_from_buffer (&global_sam_pass, data.dptr, data.dsize))
410 DEBUG(0,("pdb_getsampwent: Bad SAM_ACCOUNT entry returned from TDB!\n"));
411 return NULL;
414 /* validate the account and fill in UNIX uid and gid. sys_getpwnam()
415 is used instaed of Get_Pwnam() as we do not need to try case
416 permutations */
417 if ((pw=sys_getpwnam(pdb_get_username(&global_sam_pass))) == NULL)
419 DEBUG(0,("pdb_getsampwent: getpwnam(%s) return NULL. User does not exist!\n",
420 pdb_get_username(&global_sam_pass)));
421 return NULL;
424 pdb_set_uid (&global_sam_pass, pw->pw_uid);
425 pdb_set_gid (&global_sam_pass, pw->pw_gid);
427 /* cleanup */
428 tdb_close (pwd_tdb);
430 return (&global_sam_pass);
433 /***************************************************************************
434 Search by uid
436 I now know what the 'T' stands for in TDB :-( This is an unacceptable
437 solution. We need multiple indexes and transactional support. I'm
438 including this implementation only as an example.
439 **************************************************************************/
440 SAM_ACCOUNT* pdb_getsampwuid (uid_t uid)
442 SAM_ACCOUNT *pw = NULL;
444 if (!pdb_setsampwent(False))
445 return NULL;
447 while ( ((pw=pdb_getsampwent()) != NULL) && (pdb_get_uid(pw) != uid) )
448 /* do nothing */ ;
450 pdb_endsampwent();
452 return pw;
455 /***************************************************************************
456 Search by rid
457 **************************************************************************/
458 SAM_ACCOUNT* pdb_getsampwrid (uint32 rid)
460 SAM_ACCOUNT *pw = NULL;
462 if (!pdb_setsampwent(False))
463 return NULL;
465 while ( ((pw=pdb_getsampwent()) != NULL) && (pdb_get_user_rid(pw) != rid) )
466 /* do nothing */ ;
468 pdb_endsampwent();
470 return pw;
474 /***************************************************************************
475 Delete a SAM_ACCOUNT
476 ****************************************************************************/
477 BOOL pdb_delete_sam_account(char *name)
479 TDB_CONTEXT *pwd_tdb;
480 TDB_DATA key;
481 fstring keystr;
482 pstring tdbfile;
484 pstrcpy (tdbfile, lp_private_dir());
485 pstrcat (tdbfile, "/passdb.tdb");
488 /* open the TDB */
489 if (!(pwd_tdb = tdb_open(tdbfile, 0, 0, O_RDWR, 0600)))
491 DEBUG(0, ("Unable to open TDB passwd!"));
492 return False;
495 /* set the search key */
496 slprintf(keystr, sizeof(keystr), "%s%s", USERPREFIX, name);
497 key.dptr = keystr;
498 key.dsize = strlen (keystr) + 1;
500 /* it's outaa here! 8^) */
501 if (tdb_delete(pwd_tdb, key) != TDB_SUCCESS)
503 DEBUG(5, ("Error deleting entry from tdb database!\n"));
504 DEBUGADD(5, (" Error: %s\n", tdb_error(pwd_tdb)));
505 tdb_close(pwd_tdb);
506 return False;
509 tdb_close(pwd_tdb);
510 return True;
513 /***************************************************************************
514 Update the TDB SAM
515 ****************************************************************************/
516 static BOOL tdb_update_sam(SAM_ACCOUNT* newpwd, BOOL override, int flag)
518 TDB_CONTEXT *pwd_tdb;
519 TDB_DATA key, data;
520 BYTE *buf = NULL;
521 fstring keystr;
522 pstring tdbfile;
524 pstrcpy (tdbfile, lp_private_dir());
525 pstrcat (tdbfile, "/passdb.tdb");
527 if ( (!newpwd->uid) || (!newpwd->gid) )
529 DEBUG (0,("tdb_update_sam: Attempting to store a SAM_ACCOUNT for [%s] with no uid/gid!\n", newpwd->username));
530 return False;
533 /* if we don't have a RID, then generate one */
534 if (!newpwd->user_rid)
535 pdb_set_user_rid (pdb_uid_to_user_rid (newpwd->uid));
536 if (!newpwd->group_rid)
537 pdb_set_user_rid (pdb_uid_to_group_rid (newpwd->gid));
539 /* copy the SAM_ACCOUNT struct into a BYTE buffer for storage */
540 if ((data.dsize=init_buffer_from_sam (&buf, newpwd)) == -1)
542 DEBUG(0,("tdb_update_sam: ERROR - Unable to copy SAM_ACCOUNT info BYTE buffer!\n"));
543 return False;
545 data.dptr = buf;
547 /* setup the index key */
548 slprintf(keystr, sizeof(keystr), "%s%s", USERPREFIX, pdb_get_username(newpwd));
549 key.dptr = keystr;
550 key.dsize = strlen (keystr) + 1;
552 /* invalidate the existing TDB iterator if it is open */
553 if (global_tdb_ent.passwd_tdb)
555 tdb_close(global_tdb_ent.passwd_tdb);
556 global_tdb_ent.passwd_tdb = NULL;
559 /* open the account TDB */
560 if (!(pwd_tdb = tdb_open(tdbfile, 0, 0, O_RDWR, 0600)))
562 DEBUG(0, ("tdb_update_sam: Unable to open TDB passwd!\n"));
563 if (flag == TDB_INSERT)
565 DEBUG(0, ("Unable to open TDB passwd, trying create new!\n"));
566 if (!(pwd_tdb = tdb_open(tdbfile, 0, 0, O_RDWR | O_CREAT | O_EXCL, 0600)))
568 DEBUG(0, ("Unable to create TDB passwd (smbpasswd.tdb) !!!\n"));
569 return False;
574 /* add the account */
575 if (tdb_store(pwd_tdb, key, data, flag) != TDB_SUCCESS)
577 DEBUG(0, ("Unable to modify TDB passwd!"));
578 DEBUGADD(0, (" Error: %s\n", tdb_error (pwd_tdb)));
579 tdb_close (pwd_tdb);
580 return False;
583 /* cleanup */
584 tdb_close (pwd_tdb);
586 return (True);
589 /***************************************************************************
590 Modifies an existing SAM_ACCOUNT
591 ****************************************************************************/
592 BOOL pdb_update_sam_account (SAM_ACCOUNT *newpwd, BOOL override)
594 return (tdb_update_sam(newpwd, override, TDB_MODIFY));
597 /***************************************************************************
598 Adds an existing SAM_ACCOUNT
599 ****************************************************************************/
600 BOOL pdb_add_sam_account (SAM_ACCOUNT *newpwd)
602 return (tdb_update_sam(newpwd, True, TDB_INSERT));
606 #else
607 /* Do *NOT* make this function static. It breaks the compile on gcc. JRA */
608 void samtdb_dummy_function(void) { } /* stop some compilers complaining */
609 #endif /* WITH_TDBPWD */