2 Unix SMB/Netbios implementation.
4 Password and authentication handling
5 Copyright (C) Jeremy Allison 1996-1998
6 Copyright (C) Luke Kenneth Casson Leighton 1996-1998
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 extern int DEBUGLEVEL;
27 extern DOM_SID global_sam_sid;
30 * NOTE. All these functions are abstracted into a structure
31 * that points to the correct function for the selected database. JRA.
33 * NOTE. for the get/mod/add functions, there are two sets of functions.
34 * one supports struct sam_passwd, the other supports struct smb_passwd.
35 * for speed optimisation it is best to support both these sets.
37 * it is, however, optional to support one set but not the other: there
38 * is conversion-capability built in to passdb.c, and run-time error
39 * detection for when neither are supported.
41 * password database writers are recommended to implement the sam_passwd
42 * functions in a first pass, as struct sam_passwd contains more
43 * information, needed by the NT Domain support.
45 * an API writer is expected to create either one set (struct smb_passwd) or
46 * the other (struct sam_passwd) OR both, and optionally also to write display
47 * info routines * (struct sam_disp_info). functions which the API writer
48 * chooses NOT to write must be wrapped in conversion functions (pwdb_x_to_y)
49 * such that API users can call any function and still get valid results.
51 * the password API does NOT fill in the gaps if you set an API function
52 * to NULL: it will deliberately attempt to call the NULL function.
56 static struct sam_passdb_ops *pwdb_ops;
58 /***************************************************************
59 Initialise the password db operations.
60 ***************************************************************/
62 BOOL initialise_sam_password_db(void)
70 pwdb_ops = nisplus_initialise_sam_password_db();
71 #elif defined(WITH_LDAP)
72 pwdb_ops = ldap_initialise_sam_password_db();
73 #elif defined(HAVE_MYSQL_H) && defined(WITH_MYSQLSAM)
74 pwdb_ops = mysql_initialise_sam_password_db();
75 #elif defined(USE_SMBPASS_DB)
76 pwdb_ops = file_initialise_sam_password_db();
79 return (pwdb_ops != NULL);
83 * Functions that return/manipulate a struct sam_passwd.
86 /***************************************************************
87 Start to enumerate the smb or sam passwd list. Returns a void pointer
88 to ensure no modification outside this module.
90 Note that currently it is being assumed that a pointer returned
91 from this function may be used to enumerate struct sam_passwd
92 entries as well as struct smb_passwd entries. This may need
95 ****************************************************************/
97 void *startsam21pwent(BOOL update)
99 return pwdb_ops->startsam21pwent(update);
102 /***************************************************************
103 End enumeration of the sam passwd list.
105 Note that currently it is being assumed that a pointer returned
106 from this function may be used to enumerate struct sam_passwd
107 entries as well as struct smb_passwd entries. This may need
110 ****************************************************************/
112 void endsam21pwent(void *vp)
114 pwdb_ops->endsam21pwent(vp);
117 /*************************************************************************
118 Routine to return the next entry in the smb passwd list.
119 *************************************************************************/
121 struct sam_passwd *getsam21pwent(void *vp)
123 return pwdb_sam_map_names(pwdb_ops->getsam21pwent(vp));
126 /************************************************************************
127 Routine to search the smb passwd file for an entry matching the username.
128 and then modify its password entry. We can't use the startsampwent()/
129 getsampwent()/endsampwent() interfaces here as we depend on looking
130 in the actual file to decide how much room we have to write data.
131 override = False, normal
132 override = True, override XXXXXXXX'd out password or NO PASS
133 ************************************************************************/
135 BOOL mod_sam21pwd_entry(struct sam_passwd* pwd, BOOL override)
137 DEBUG(10,("mod_sam21pwd_entry: unix user %s rid %d\n",
138 pwd->unix_name, pwd->user_rid));
140 return pwdb_ops->mod_sam21pwd_entry(pwdb_sam_map_names(pwd), override);
143 /************************************************************************
144 Utility function to search sam passwd by name. use this if your database
145 does not have search facilities.
146 *************************************************************************/
148 struct sam_passwd *iterate_getsam21pwntnam(const char *ntname)
151 struct sam_passwd *pwd = NULL;
154 DEBUG(10, ("search by name: %s\n", ntname));
156 fstrcpy(nt_name, ntname);
158 /* Open the smb password database - not for update. */
159 fp = startsmbpwent(False);
163 DEBUG(0, ("unable to open sam password database.\n"));
167 while ((pwd = getsam21pwent(fp)) != NULL && !strequal(pwd->nt_name, nt_name))
169 DEBUG(10, ("iterate: %s 0x%x\n", pwd->nt_name, pwd->user_rid));
174 DEBUG(10, ("found by name: %s\n", nt_name));
181 /************************************************************************
182 Utility function to search sam passwd by rid. use this if your database
183 does not have search facilities.
185 search capability by both rid and uid are needed as the rid <-> uid
186 mapping may be non-monotonic.
188 *************************************************************************/
190 struct sam_passwd *iterate_getsam21pwrid(uint32 rid)
192 struct sam_passwd *pwd = NULL;
195 DEBUG(10, ("search by rid: %x\n", rid));
197 /* Open the smb password file - not for update. */
198 fp = startsmbpwent(False);
202 DEBUG(0, ("unable to open sam password database.\n"));
206 while ((pwd = getsam21pwent(fp)) != NULL && pwd->user_rid != rid)
208 DEBUG(10, ("iterate: %s 0x%x\n", pwd->nt_name, pwd->user_rid));
213 DEBUG(10, ("found by user_rid: %x\n", rid));
220 /************************************************************************
221 Utility function to search sam passwd by uid. use this if your database
222 does not have search facilities.
224 search capability by both rid and uid are needed as the rid <-> uid
225 mapping may be non-monotonic.
227 *************************************************************************/
229 struct sam_passwd *iterate_getsam21pwuid(uid_t uid)
231 struct sam_passwd *pwd = NULL;
234 DEBUG(10, ("search by uid: %x\n", (int)uid));
236 /* Open the smb password file - not for update. */
237 fp = startsmbpwent(False);
241 DEBUG(0, ("unable to open sam password database.\n"));
245 while ((pwd = getsam21pwent(fp)) != NULL && pwd->unix_uid != uid)
251 DEBUG(10, ("found by unix_uid: %x\n", (int)uid));
258 /*************************************************************************
259 Routine to return a display info structure, by rid
260 *************************************************************************/
261 struct sam_disp_info *getsamdisprid(uint32 rid)
263 return pwdb_ops->getsamdisprid(rid);
266 /************************************************************************
267 Routine to search sam passwd by name.
268 *************************************************************************/
270 struct sam_passwd *getsam21pwntnam(const char *name)
272 return pwdb_sam_map_names(pwdb_ops->getsam21pwntnam(name));
275 /************************************************************************
276 Routine to search sam passwd by rid.
277 *************************************************************************/
279 struct sam_passwd *getsam21pwrid(uint32 rid)
281 return pwdb_sam_map_names(pwdb_ops->getsam21pwrid(rid));
285 /**********************************************************
286 **********************************************************
288 utility routines which are likely to be useful to all password
291 **********************************************************
292 **********************************************************/
294 /*************************************************************
295 initialises a struct sam_disp_info.
296 **************************************************************/
298 static void pwdb_init_dispinfo(struct sam_disp_info *user)
300 if (user == NULL) return;
301 bzero(user, sizeof(*user));
302 user->user_rid = 0xffffffff;
305 /*************************************************************
306 initialises a struct sam_passwd.
307 **************************************************************/
308 void pwdb_init_sam(struct sam_passwd *user)
310 if (user == NULL) return;
311 bzero(user, sizeof(*user));
313 init_nt_time(&user->logon_time);
314 init_nt_time(&user->logoff_time);
315 init_nt_time(&user->kickoff_time);
316 init_nt_time(&user->pass_last_set_time);
317 init_nt_time(&user->pass_can_change_time);
318 init_nt_time(&user->pass_must_change_time);
320 user->unix_uid = (uid_t)-1;
321 user->unix_gid = (gid_t)-1;
322 user->user_rid = 0xffffffff;
323 user->group_rid = 0xffffffff;
326 /*************************************************************************
327 Routine to return the next entry in the sam passwd list.
328 *************************************************************************/
330 struct sam_disp_info *pwdb_sam_to_dispinfo(struct sam_passwd *user)
332 static struct sam_disp_info disp_info;
334 if (user == NULL) return NULL;
336 pwdb_init_dispinfo(&disp_info);
338 disp_info.nt_name = user->nt_name;
339 disp_info.full_name = user->full_name;
340 disp_info.user_rid = user->user_rid;
345 static void select_name(fstring string, char **name, const UNISTR2 *from)
347 if (from->buffer != 0)
349 unistr2_to_ascii(string, from, sizeof(string));
354 /*************************************************************
356 **************************************************************/
357 void copy_id23_to_sam_passwd(struct sam_passwd *to, const SAM_USER_INFO_23 *from)
359 static fstring nt_name;
360 static fstring full_name;
361 static fstring home_dir;
362 static fstring dir_drive;
363 static fstring logon_script;
364 static fstring profile_path;
365 static fstring acct_desc;
366 static fstring workstations;
367 static fstring unknown_str;
368 static fstring munged_dial;
370 if (from == NULL || to == NULL) return;
372 memcpy(to, from, sizeof(*from));
374 select_name(nt_name , &to->nt_name , &from->uni_user_name );
375 select_name(full_name , &to->full_name , &from->uni_full_name );
376 select_name(home_dir , &to->home_dir , &from->uni_home_dir );
377 select_name(dir_drive , &to->dir_drive , &from->uni_dir_drive );
378 select_name(logon_script, &to->logon_script, &from->uni_logon_script);
379 select_name(profile_path, &to->profile_path, &from->uni_profile_path);
380 select_name(acct_desc , &to->acct_desc , &from->uni_acct_desc );
381 select_name(workstations, &to->workstations, &from->uni_workstations);
382 select_name(unknown_str , &to->unknown_str , &from->uni_unknown_str );
383 select_name(munged_dial , &to->munged_dial , &from->uni_munged_dial );
387 /*************************************************************
389 **************************************************************/
390 void copy_sam_passwd(struct sam_passwd *to, const struct sam_passwd *from)
392 static fstring nt_name;
393 static fstring unix_name;
394 static fstring full_name;
395 static fstring home_dir;
396 static fstring dir_drive;
397 static fstring logon_script;
398 static fstring profile_path;
399 static fstring acct_desc;
400 static fstring workstations;
401 static fstring unknown_str;
402 static fstring munged_dial;
404 if (from == NULL || to == NULL) return;
406 memcpy(to, from, sizeof(*from));
408 if (from->nt_name != NULL)
410 fstrcpy(nt_name , from->nt_name);
411 to->nt_name = nt_name;
413 else if (to->nt_name != NULL)
415 fstrcpy(nt_name , to->nt_name);
416 to->nt_name = nt_name;
419 if (from->unix_name != NULL)
421 fstrcpy(unix_name, from->unix_name);
422 to->unix_name = unix_name;
424 else if (to->unix_name != NULL)
426 fstrcpy(unix_name, to->unix_name);
427 to->unix_name = unix_name;
430 if (from->full_name != NULL)
432 fstrcpy(full_name, from->full_name);
433 to->full_name = full_name;
435 else if (to->full_name != NULL)
437 fstrcpy(full_name, to->full_name);
438 to->full_name = full_name;
441 if (from->home_dir != NULL)
443 fstrcpy(home_dir , from->home_dir);
444 to->home_dir = home_dir;
446 else if (to->home_dir != NULL)
448 fstrcpy(home_dir , to->home_dir);
449 to->home_dir = home_dir;
452 if (from->dir_drive != NULL)
454 fstrcpy(dir_drive , from->dir_drive);
455 to->dir_drive = dir_drive;
457 else if (to->dir_drive != NULL)
459 fstrcpy(dir_drive , to->dir_drive);
460 to->dir_drive = dir_drive;
463 if (from->logon_script != NULL)
465 fstrcpy(logon_script , from->logon_script);
466 to->logon_script = logon_script;
468 else if (to->logon_script != NULL)
470 fstrcpy(logon_script , to->logon_script);
471 to->logon_script = logon_script;
474 if (from->profile_path != NULL)
476 fstrcpy(profile_path , from->profile_path);
477 to->profile_path = profile_path;
479 else if (to->profile_path != NULL)
481 fstrcpy(profile_path , to->profile_path);
482 to->profile_path = profile_path;
485 if (from->acct_desc != NULL)
487 fstrcpy(acct_desc , from->acct_desc);
488 to->acct_desc = acct_desc;
490 else if (to->acct_desc != NULL)
492 fstrcpy(acct_desc , to->acct_desc);
493 to->acct_desc = acct_desc;
496 if (from->workstations != NULL)
498 fstrcpy(workstations , from->workstations);
499 to->workstations = workstations;
501 else if (to->workstations != NULL)
503 fstrcpy(workstations , to->workstations);
504 to->workstations = workstations;
507 if (from->unknown_str != NULL)
509 fstrcpy(unknown_str , from->unknown_str);
510 to->unknown_str = unknown_str;
512 else if (to->unknown_str != NULL)
514 fstrcpy(unknown_str , to->unknown_str);
515 to->unknown_str = unknown_str;
518 if (from->munged_dial != NULL)
520 fstrcpy(munged_dial , from->munged_dial);
521 to->munged_dial = munged_dial;
523 else if (to->munged_dial != NULL)
525 fstrcpy(munged_dial , to->munged_dial);
526 to->munged_dial = munged_dial;
531 /*************************************************************
532 converts a sam_passwd structure to a smb_passwd structure.
533 **************************************************************/
535 struct smb_passwd *pwdb_sam_to_smb(struct sam_passwd *user)
537 static struct smb_passwd pw_buf;
538 static fstring nt_name;
539 static fstring unix_name;
541 if (user == NULL) return NULL;
543 pwdb_init_smb(&pw_buf);
545 if (user->nt_name != NULL)
547 fstrcpy(nt_name , user->nt_name);
548 pw_buf.nt_name = nt_name;
550 if (user->unix_name != NULL)
552 fstrcpy(unix_name, user->unix_name);
553 pw_buf.unix_name = unix_name;
555 pw_buf.unix_uid = user->unix_uid;
556 pw_buf.user_rid = user->user_rid;
557 pw_buf.smb_passwd = user->smb_passwd;
558 pw_buf.smb_nt_passwd = user->smb_nt_passwd;
559 pw_buf.acct_ctrl = user->acct_ctrl;
560 pw_buf.pass_last_set_time = nt_time_to_unix(&user->pass_last_set_time);
566 /*************************************************************
567 converts a smb_passwd structure to a sam_passwd structure.
568 **************************************************************/
570 struct sam_passwd *pwdb_smb_to_sam(struct smb_passwd *user)
572 static struct sam_passwd pw_buf;
573 static fstring nt_name;
574 static fstring unix_name;
576 if (user == NULL) return NULL;
578 pwdb_init_sam(&pw_buf);
580 if (user->nt_name != NULL)
582 fstrcpy(nt_name , user->nt_name);
583 pw_buf.nt_name = nt_name;
585 if (user->unix_name != NULL)
587 fstrcpy(unix_name, user->unix_name);
588 pw_buf.unix_name = unix_name;
590 pw_buf.unix_uid = user->unix_uid;
591 pw_buf.user_rid = user->user_rid;
592 pw_buf.smb_passwd = user->smb_passwd;
593 pw_buf.smb_nt_passwd = user->smb_nt_passwd;
594 pw_buf.acct_ctrl = user->acct_ctrl;
596 if ( user->pass_last_set_time != (time_t)-1 )
598 unix_to_nt_time(&pw_buf.pass_last_set_time, user->pass_last_set_time);
599 unix_to_nt_time(&pw_buf.pass_can_change_time, user->pass_last_set_time);
605 static BOOL trust_account_warning_done = False;
607 /*************************************************************
608 fills in missing details. one set of details _must_ exist.
609 **************************************************************/
610 struct sam_passwd *pwdb_sam_map_names(struct sam_passwd *sam)
615 static fstring unix_name;
616 static fstring nt_name;
618 DEBUG(10,("pwdb_sam_map_names\n"));
629 if (!found && sam->unix_name != NULL)
631 found = lookupsmbpwnam(sam->unix_name, &gmep);
633 if (!found && sam->unix_uid != (uid_t)-1)
635 found = lookupsmbpwuid(sam->unix_uid , &gmep);
637 if (!found && sam->user_rid != 0xffffffff)
639 sid_copy(&sid, &global_sam_sid);
640 sid_append_rid(&sid, sam->user_rid);
641 found = lookupsmbpwsid (&sid , &gmep);
643 if (!found && sam->nt_name != NULL)
645 found = lookupsmbpwntnam(sam->nt_name, &gmep);
653 if (!sid_front_equal(&global_sam_sid, &gmep.sid))
658 fstrcpy(unix_name, gmep.unix_name);
659 fstrcpy(nt_name , gmep.nt_name );
660 if (sam->unix_name == NULL ) sam->unix_name = unix_name;
661 if (sam->nt_name == NULL ) sam->nt_name = nt_name ;
662 if (sam->unix_uid == (uid_t)-1 ) sam->unix_uid = (uid_t)gmep.unix_id;
663 if (sam->user_rid == 0xffffffff) sid_split_rid(&gmep.sid, &sam->user_rid);
665 DEBUG(10,("pwdb_sam_map_name: found unix user %s nt %s uid %d rid 0x%x\n",
666 sam->unix_name, sam->nt_name, sam->unix_uid, sam->user_rid));
674 if (sam->unix_gid != (gid_t)-1 && sam->group_rid != 0xffffffff)
679 if (sam->unix_gid == (gid_t)-1 && sam->group_rid == 0xffffffff)
681 struct passwd *pass = hashed_getpwnam(unix_name);
684 sam->unix_gid = pass->pw_gid;
688 DEBUG(0,("pwdb_sam_map_names: no unix password entry for %s\n",
693 if (!found && sam->unix_gid != (gid_t)-1)
695 found = lookupsmbgrpgid(sam->unix_gid , &gmep);
697 if (!found && sam->group_rid != 0xffffffff)
699 sid_copy(&sid, &global_sam_sid);
700 sid_append_rid(&sid, sam->group_rid);
701 found = lookupsmbgrpsid(&sid , &gmep);
706 if (IS_BITS_SET_SOME(sam->acct_ctrl, ACB_WSTRUST|ACB_DOMTRUST|ACB_SVRTRUST))
708 if (!trust_account_warning_done)
710 trust_account_warning_done = True;
712 pwdb_sam_map_names: your unix password database appears to have difficulties\n\
713 resolving trust account %s, probably because it ends in a '$'.\n\
714 you will get this warning only once (for all trust accounts)\n", unix_name));
719 if (sam->unix_gid != (gid_t)-1)
721 sam->unix_gid = (gid_t)-1;
723 sam->group_rid = DOMAIN_GROUP_RID_USERS;
729 DEBUG(0, ("pwdb_sam_map_names: could not find Primary Group for %s\n",
735 if (!sid_front_equal(&global_sam_sid, &gmep.sid))
738 sid_to_string(sid_str, &gmep.sid);
739 DEBUG(0,("UNIX User %s Primary Group is in the wrong domain! %s\n",
740 sam->unix_name, sid_str));
744 if (sam->unix_gid == (gid_t)-1 ) sam->unix_gid = (gid_t)gmep.unix_id;
745 if (sam->group_rid == 0xffffffff) sid_split_rid(&gmep.sid, &sam->group_rid);
747 DEBUG(10,("pwdb_sam_map_name: found gid %d and group rid 0x%x for unix user %s\n",
748 sam->unix_gid, sam->group_rid, sam->unix_name));