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 struct sam_passwd *mapped;
139 DEBUG(10,("mod_sam21pwd_entry: unix user %s rid %d\n",
140 pwd->unix_name, pwd->user_rid));
142 mapped = pwdb_sam_map_names(pwd);
145 return pwdb_ops->mod_sam21pwd_entry(mapped, override);
150 /************************************************************************
151 Utility function to search sam passwd by name. use this if your database
152 does not have search facilities.
153 *************************************************************************/
155 struct sam_passwd *iterate_getsam21pwntnam(const char *ntname)
158 struct sam_passwd *pwd = NULL;
161 DEBUG(10, ("search by name: %s\n", ntname));
163 fstrcpy(nt_name, ntname);
165 /* Open the smb password database - not for update. */
166 fp = startsmbpwent(False);
170 DEBUG(0, ("unable to open sam password database.\n"));
174 while ((pwd = getsam21pwent(fp)) != NULL && !strequal(pwd->nt_name, nt_name))
176 DEBUG(10, ("iterate: %s 0x%x\n", pwd->nt_name, pwd->user_rid));
181 DEBUG(10, ("found by name: %s\n", nt_name));
188 /************************************************************************
189 Utility function to search sam passwd by rid. use this if your database
190 does not have search facilities.
192 search capability by both rid and uid are needed as the rid <-> uid
193 mapping may be non-monotonic.
195 *************************************************************************/
197 struct sam_passwd *iterate_getsam21pwrid(uint32 rid)
199 struct sam_passwd *pwd = NULL;
202 DEBUG(10, ("search by rid: %x\n", rid));
204 /* Open the smb password file - not for update. */
205 fp = startsmbpwent(False);
209 DEBUG(0, ("unable to open sam password database.\n"));
213 while ((pwd = getsam21pwent(fp)) != NULL && pwd->user_rid != rid)
215 DEBUG(10, ("iterate: %s 0x%x\n", pwd->nt_name, pwd->user_rid));
220 DEBUG(10, ("found by user_rid: %x\n", rid));
227 /************************************************************************
228 Utility function to search sam passwd by uid. use this if your database
229 does not have search facilities.
231 search capability by both rid and uid are needed as the rid <-> uid
232 mapping may be non-monotonic.
234 *************************************************************************/
236 struct sam_passwd *iterate_getsam21pwuid(uid_t uid)
238 struct sam_passwd *pwd = NULL;
241 DEBUG(10, ("search by uid: %x\n", (int)uid));
243 /* Open the smb password file - not for update. */
244 fp = startsmbpwent(False);
248 DEBUG(0, ("unable to open sam password database.\n"));
252 while ((pwd = getsam21pwent(fp)) != NULL && pwd->unix_uid != uid)
258 DEBUG(10, ("found by unix_uid: %x\n", (int)uid));
265 /*************************************************************************
266 Routine to return a display info structure, by rid
267 *************************************************************************/
268 struct sam_disp_info *getsamdisprid(uint32 rid)
270 return pwdb_ops->getsamdisprid(rid);
273 /************************************************************************
274 Routine to search sam passwd by name.
275 *************************************************************************/
277 struct sam_passwd *getsam21pwntnam(const char *name)
279 return pwdb_sam_map_names(pwdb_ops->getsam21pwntnam(name));
282 /************************************************************************
283 Routine to search sam passwd by rid.
284 *************************************************************************/
286 struct sam_passwd *getsam21pwrid(uint32 rid)
288 return pwdb_sam_map_names(pwdb_ops->getsam21pwrid(rid));
292 /**********************************************************
293 **********************************************************
295 utility routines which are likely to be useful to all password
298 **********************************************************
299 **********************************************************/
301 /*************************************************************
302 initialises a struct sam_disp_info.
303 **************************************************************/
305 static void pwdb_init_dispinfo(struct sam_disp_info *user)
307 if (user == NULL) return;
308 bzero(user, sizeof(*user));
309 user->user_rid = 0xffffffff;
312 /*************************************************************
313 initialises a struct sam_passwd.
314 **************************************************************/
315 void pwdb_init_sam(struct sam_passwd *user)
317 if (user == NULL) return;
318 bzero(user, sizeof(*user));
320 init_nt_time(&user->logon_time);
321 init_nt_time(&user->logoff_time);
322 init_nt_time(&user->kickoff_time);
323 init_nt_time(&user->pass_last_set_time);
324 init_nt_time(&user->pass_can_change_time);
325 init_nt_time(&user->pass_must_change_time);
327 user->unix_uid = (uid_t)-1;
328 user->unix_gid = (gid_t)-1;
329 user->user_rid = 0xffffffff;
330 user->group_rid = 0xffffffff;
333 /*************************************************************************
334 Routine to return the next entry in the sam passwd list.
335 *************************************************************************/
337 struct sam_disp_info *pwdb_sam_to_dispinfo(struct sam_passwd *user)
339 static struct sam_disp_info disp_info;
341 if (user == NULL) return NULL;
343 pwdb_init_dispinfo(&disp_info);
345 disp_info.nt_name = user->nt_name;
346 disp_info.full_name = user->full_name;
347 disp_info.user_rid = user->user_rid;
352 static void select_name(fstring *string, char **name, const UNISTR2 *from)
354 if (from->buffer != 0)
356 unistr2_to_ascii(*string, from, sizeof(*string));
361 /*************************************************************
363 **************************************************************/
364 void copy_id23_to_sam_passwd(struct sam_passwd *to, const SAM_USER_INFO_23 *from)
366 static fstring nt_name;
367 static fstring full_name;
368 static fstring home_dir;
369 static fstring dir_drive;
370 static fstring logon_script;
371 static fstring profile_path;
372 static fstring acct_desc;
373 static fstring workstations;
374 static fstring unknown_str;
375 static fstring munged_dial;
377 if (from == NULL || to == NULL) return;
379 to->logon_time = from->logon_time;
380 to->logoff_time = from->logoff_time;
381 to->kickoff_time = from->kickoff_time;
382 to->pass_last_set_time = from->pass_last_set_time;
383 to->pass_can_change_time = from->pass_can_change_time;
384 to->pass_must_change_time = from->pass_must_change_time;
386 select_name(&nt_name , &to->nt_name , &from->uni_user_name );
387 select_name(&full_name , &to->full_name , &from->uni_full_name );
388 select_name(&home_dir , &to->home_dir , &from->uni_home_dir );
389 select_name(&dir_drive , &to->dir_drive , &from->uni_dir_drive );
390 select_name(&logon_script, &to->logon_script, &from->uni_logon_script);
391 select_name(&profile_path, &to->profile_path, &from->uni_profile_path);
392 select_name(&acct_desc , &to->acct_desc , &from->uni_acct_desc );
393 select_name(&workstations, &to->workstations, &from->uni_workstations);
394 select_name(&unknown_str , &to->unknown_str , &from->uni_unknown_str );
395 select_name(&munged_dial , &to->munged_dial , &from->uni_munged_dial );
397 to->unix_uid = (uid_t)-1;
398 to->unix_gid = (gid_t)-1;
399 to->user_rid = from->user_rid;
400 to->group_rid = from->group_rid;
402 to->smb_passwd = NULL;
403 to->smb_nt_passwd = NULL;
405 to->acct_ctrl = from->acb_info;
406 to->unknown_3 = from->unknown_3;
408 to->logon_divs = from->logon_divs;
409 to->hours_len = from->logon_hrs.len;
410 memcpy(to->hours, from->logon_hrs.hours, MAX_HOURS_LEN);
412 to->unknown_5 = from->unknown_5;
413 to->unknown_6 = from->unknown_6;
417 /*************************************************************
419 **************************************************************/
420 void copy_sam_passwd(struct sam_passwd *to, const struct sam_passwd *from)
422 static fstring nt_name;
423 static fstring unix_name;
424 static fstring full_name;
425 static fstring home_dir;
426 static fstring dir_drive;
427 static fstring logon_script;
428 static fstring profile_path;
429 static fstring acct_desc;
430 static fstring workstations;
431 static fstring unknown_str;
432 static fstring munged_dial;
434 if (from == NULL || to == NULL) return;
436 memcpy(to, from, sizeof(*from));
438 if (from->nt_name != NULL)
440 fstrcpy(nt_name , from->nt_name);
441 to->nt_name = nt_name;
443 else if (to->nt_name != NULL)
445 fstrcpy(nt_name , to->nt_name);
446 to->nt_name = nt_name;
449 if (from->unix_name != NULL)
451 fstrcpy(unix_name, from->unix_name);
452 to->unix_name = unix_name;
454 else if (to->unix_name != NULL)
456 fstrcpy(unix_name, to->unix_name);
457 to->unix_name = unix_name;
460 if (from->full_name != NULL)
462 fstrcpy(full_name, from->full_name);
463 to->full_name = full_name;
465 else if (to->full_name != NULL)
467 fstrcpy(full_name, to->full_name);
468 to->full_name = full_name;
471 if (from->home_dir != NULL)
473 fstrcpy(home_dir , from->home_dir);
474 to->home_dir = home_dir;
476 else if (to->home_dir != NULL)
478 fstrcpy(home_dir , to->home_dir);
479 to->home_dir = home_dir;
482 if (from->dir_drive != NULL)
484 fstrcpy(dir_drive , from->dir_drive);
485 to->dir_drive = dir_drive;
487 else if (to->dir_drive != NULL)
489 fstrcpy(dir_drive , to->dir_drive);
490 to->dir_drive = dir_drive;
493 if (from->logon_script != NULL)
495 fstrcpy(logon_script , from->logon_script);
496 to->logon_script = logon_script;
498 else if (to->logon_script != NULL)
500 fstrcpy(logon_script , to->logon_script);
501 to->logon_script = logon_script;
504 if (from->profile_path != NULL)
506 fstrcpy(profile_path , from->profile_path);
507 to->profile_path = profile_path;
509 else if (to->profile_path != NULL)
511 fstrcpy(profile_path , to->profile_path);
512 to->profile_path = profile_path;
515 if (from->acct_desc != NULL)
517 fstrcpy(acct_desc , from->acct_desc);
518 to->acct_desc = acct_desc;
520 else if (to->acct_desc != NULL)
522 fstrcpy(acct_desc , to->acct_desc);
523 to->acct_desc = acct_desc;
526 if (from->workstations != NULL)
528 fstrcpy(workstations , from->workstations);
529 to->workstations = workstations;
531 else if (to->workstations != NULL)
533 fstrcpy(workstations , to->workstations);
534 to->workstations = workstations;
537 if (from->unknown_str != NULL)
539 fstrcpy(unknown_str , from->unknown_str);
540 to->unknown_str = unknown_str;
542 else if (to->unknown_str != NULL)
544 fstrcpy(unknown_str , to->unknown_str);
545 to->unknown_str = unknown_str;
548 if (from->munged_dial != NULL)
550 fstrcpy(munged_dial , from->munged_dial);
551 to->munged_dial = munged_dial;
553 else if (to->munged_dial != NULL)
555 fstrcpy(munged_dial , to->munged_dial);
556 to->munged_dial = munged_dial;
561 /*************************************************************
562 converts a sam_passwd structure to a smb_passwd structure.
563 **************************************************************/
564 struct smb_passwd *pwdb_sam_to_smb(struct sam_passwd *user)
566 static struct smb_passwd pw_buf;
567 static fstring nt_name;
568 static fstring unix_name;
570 if (user == NULL) return NULL;
572 pwdb_init_smb(&pw_buf);
574 if (user->nt_name != NULL)
576 fstrcpy(nt_name , user->nt_name);
577 pw_buf.nt_name = nt_name;
579 if (user->unix_name != NULL)
581 fstrcpy(unix_name, user->unix_name);
582 pw_buf.unix_name = unix_name;
584 pw_buf.unix_uid = user->unix_uid;
585 pw_buf.user_rid = user->user_rid;
586 pw_buf.smb_passwd = user->smb_passwd;
587 pw_buf.smb_nt_passwd = user->smb_nt_passwd;
588 pw_buf.acct_ctrl = user->acct_ctrl;
589 pw_buf.pass_last_set_time = nt_time_to_unix(&user->pass_last_set_time);
595 /*************************************************************
596 converts a smb_passwd structure to a sam_passwd structure.
597 **************************************************************/
599 struct sam_passwd *pwdb_smb_to_sam(struct smb_passwd *user)
601 static struct sam_passwd pw_buf;
602 struct passwd *pass=NULL;
603 static fstring nt_name;
604 static fstring unix_name;
605 static pstring unix_gecos;
607 if (user == NULL) return NULL;
609 pwdb_init_sam(&pw_buf);
611 if (user->nt_name != NULL)
613 fstrcpy(nt_name , user->nt_name);
614 pw_buf.nt_name = nt_name;
616 if (user->unix_name != NULL)
618 fstrcpy(unix_name, user->unix_name);
619 pw_buf.unix_name = unix_name;
621 pw_buf.unix_uid = user->unix_uid;
622 pw_buf.user_rid = user->user_rid;
623 pw_buf.smb_passwd = user->smb_passwd;
624 pw_buf.smb_nt_passwd = user->smb_nt_passwd;
625 pw_buf.acct_ctrl = user->acct_ctrl;
627 pass = hashed_getpwnam(unix_name);
630 pstrcpy(unix_gecos, pass->pw_gecos);
631 pw_buf.full_name=unix_gecos;
634 if ( user->pass_last_set_time != (time_t)-1 )
636 unix_to_nt_time(&pw_buf.pass_last_set_time, user->pass_last_set_time);
637 unix_to_nt_time(&pw_buf.pass_can_change_time, user->pass_last_set_time);
643 static BOOL trust_account_warning_done = False;
645 /*************************************************************
646 fills in missing details. one set of details _must_ exist.
647 **************************************************************/
648 struct sam_passwd *pwdb_sam_map_names(struct sam_passwd *sam)
653 static fstring unix_name;
654 static fstring nt_name;
662 DEBUG(10,("pwdb_sam_map_names: NULL\n"));
666 DEBUG(10,("pwdb_sam_map_names: unix %s nt %s unix %d nt%d\n",
667 sam->unix_name != NULL ? sam->unix_name : "NULL",
668 sam->nt_name != NULL ? sam->nt_name : "NULL",
669 sam->unix_uid, sam->user_rid));
671 if (!found && sam->unix_name != NULL)
673 found = lookupsmbpwnam(sam->unix_name, &gmep);
675 if (!found && sam->unix_uid != (uid_t)-1)
677 found = lookupsmbpwuid(sam->unix_uid , &gmep);
679 if (!found && sam->user_rid != 0xffffffff)
681 sid_copy(&sid, &global_sam_sid);
682 sid_append_rid(&sid, sam->user_rid);
683 found = lookupsmbpwsid (&sid , &gmep);
685 if (!found && sam->nt_name != NULL)
687 found = lookupsmbpwntnam(sam->nt_name, &gmep);
695 if (!sid_front_equal(&global_sam_sid, &gmep.sid))
700 fstrcpy(unix_name, gmep.unix_name);
701 fstrcpy(nt_name , gmep.nt_name );
702 if (sam->unix_name == NULL ) sam->unix_name = unix_name;
703 if (sam->nt_name == NULL ) sam->nt_name = nt_name ;
704 if (sam->unix_uid == (uid_t)-1 ) sam->unix_uid = (uid_t)gmep.unix_id;
705 if (sam->user_rid == 0xffffffff) sid_split_rid(&gmep.sid, &sam->user_rid);
707 DEBUG(10,("pwdb_sam_map_name: found unix user %s nt %s uid %d rid 0x%x\n",
708 sam->unix_name, sam->nt_name, sam->unix_uid, sam->user_rid));
716 if (sam->unix_gid != (gid_t)-1 && sam->group_rid != 0xffffffff)
721 if (sam->unix_gid == (gid_t)-1 && sam->group_rid == 0xffffffff)
723 struct passwd *pass = hashed_getpwnam(unix_name);
726 sam->unix_gid = pass->pw_gid;
730 DEBUG(0,("pwdb_sam_map_names: no unix password entry for %s\n",
735 if (!found && sam->unix_gid != (gid_t)-1)
737 found = lookupsmbgrpgid(sam->unix_gid , &gmep);
739 if (!found && sam->group_rid != 0xffffffff)
741 sid_copy(&sid, &global_sam_sid);
742 sid_append_rid(&sid, sam->group_rid);
743 found = lookupsmbgrpsid(&sid , &gmep);
748 if (IS_BITS_SET_SOME(sam->acct_ctrl, ACB_WSTRUST|ACB_DOMTRUST|ACB_SVRTRUST))
750 if (!trust_account_warning_done)
752 trust_account_warning_done = True;
754 pwdb_sam_map_names: your unix password database appears to have difficulties\n\
755 resolving trust account %s, probably because it ends in a '$'.\n\
756 you will get this warning only once (for all trust accounts)\n", unix_name));
761 if (sam->unix_gid != (gid_t)-1)
763 sam->unix_gid = (gid_t)-1;
765 sam->group_rid = DOMAIN_GROUP_RID_USERS;
771 DEBUG(0, ("pwdb_sam_map_names: could not find Primary Group for %s\n",
777 if (!sid_front_equal(&global_sam_sid, &gmep.sid))
780 sid_to_string(sid_str, &gmep.sid);
781 DEBUG(0,("UNIX User %s Primary Group is in the wrong domain! %s\n",
782 sam->unix_name, sid_str));
786 if (sam->unix_gid == (gid_t)-1 ) sam->unix_gid = (gid_t)gmep.unix_id;
787 if (sam->group_rid == 0xffffffff) sid_split_rid(&gmep.sid, &sam->group_rid);
789 DEBUG(10,("pwdb_sam_map_name: found gid %d and group rid 0x%x for unix user %s\n",
790 sam->unix_gid, sam->group_rid, sam->unix_name));