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;
29 * NOTE. All these functions are abstracted into a structure
30 * that points to the correct function for the selected database. JRA.
32 * NOTE. for the get/mod/add functions, there are two sets of functions.
33 * one supports struct sam_passwd, the other supports struct smb_passwd.
34 * for speed optimisation it is best to support both these sets.
36 * it is, however, optional to support one set but not the other: there
37 * is conversion-capability built in to passdb.c, and run-time error
38 * detection for when neither are supported.
40 * password database writers are recommended to implement the sam_passwd
41 * functions in a first pass, as struct sam_passwd contains more
42 * information, needed by the NT Domain support.
44 * an API writer is expected to create either one set (struct smb_passwd) or
45 * the other (struct sam_passwd) OR both, and optionally also to write display
46 * info routines * (struct sam_disp_info). functions which the API writer
47 * chooses NOT to write must be wrapped in conversion functions (pwdb_x_to_y)
48 * such that API users can call any function and still get valid results.
50 * the password API does NOT fill in the gaps if you set an API function
51 * to NULL: it will deliberately attempt to call the NULL function.
55 static struct passdb_ops *pwdb_ops;
57 /***************************************************************
58 Initialise the password db operations.
59 ***************************************************************/
61 BOOL initialise_password_db(void)
69 pwdb_ops = nisplus_initialise_password_db();
70 #elif defined(WITH_LDAP)
71 pwdb_ops = ldap_initialise_password_db();
72 #elif defined(USE_SMBPASS_DB)
73 pwdb_ops = file_initialise_password_db();
76 return (pwdb_ops != NULL);
80 * Functions that return/manipulate a struct smb_passwd.
83 /************************************************************************
84 Utility function to search smb passwd by rid.
85 *************************************************************************/
87 struct smb_passwd *iterate_getsmbpwrid(uint32 user_rid)
89 return iterate_getsmbpwuid(pwdb_user_rid_to_uid(user_rid));
92 /************************************************************************
93 Utility function to search smb passwd by uid. use this if your database
94 does not have search facilities.
95 *************************************************************************/
97 struct smb_passwd *iterate_getsmbpwuid(uid_t smb_userid)
99 struct smb_passwd *pwd = NULL;
102 DEBUG(10, ("search by smb_userid: %x\n", (int)smb_userid));
104 /* Open the smb password database - not for update. */
105 fp = startsmbpwent(False);
109 DEBUG(0, ("unable to open smb password database.\n"));
113 while ((pwd = getsmbpwent(fp)) != NULL && pwd->smb_userid != smb_userid)
119 DEBUG(10, ("found by smb_userid: %x\n", (int)smb_userid));
126 /************************************************************************
127 Utility function to search smb passwd by name. use this if your database
128 does not have search facilities.
129 *************************************************************************/
131 struct smb_passwd *iterate_getsmbpwnam(char *name)
133 struct smb_passwd *pwd = NULL;
136 DEBUG(10, ("search by name: %s\n", name));
138 /* Open the sam password file - not for update. */
139 fp = startsmbpwent(False);
143 DEBUG(0, ("unable to open smb password database.\n"));
147 while ((pwd = getsmbpwent(fp)) != NULL && !strequal(pwd->smb_name, name))
153 DEBUG(10, ("found by name: %s\n", name));
160 /***************************************************************
161 Start to enumerate the smb or sam passwd list. Returns a void pointer
162 to ensure no modification outside this module.
164 Note that currently it is being assumed that a pointer returned
165 from this function may be used to enumerate struct sam_passwd
166 entries as well as struct smb_passwd entries. This may need
169 ****************************************************************/
171 void *startsmbpwent(BOOL update)
173 return pwdb_ops->startsmbpwent(update);
176 /***************************************************************
177 End enumeration of the smb or sam passwd list.
179 Note that currently it is being assumed that a pointer returned
180 from this function may be used to enumerate struct sam_passwd
181 entries as well as struct smb_passwd entries. This may need
184 ****************************************************************/
186 void endsmbpwent(void *vp)
188 pwdb_ops->endsmbpwent(vp);
191 /*************************************************************************
192 Routine to return the next entry in the smb passwd list.
193 *************************************************************************/
195 struct smb_passwd *getsmbpwent(void *vp)
197 return pwdb_ops->getsmbpwent(vp);
200 /************************************************************************
201 Routine to add an entry to the smb passwd file.
202 *************************************************************************/
204 BOOL add_smbpwd_entry(struct smb_passwd *newpwd)
206 return pwdb_ops->add_smbpwd_entry(newpwd);
209 /************************************************************************
210 Routine to search the smb passwd file for an entry matching the username.
211 and then modify its password entry. We can't use the startsampwent()/
212 getsampwent()/endsampwent() interfaces here as we depend on looking
213 in the actual file to decide how much room we have to write data.
214 override = False, normal
215 override = True, override XXXXXXXX'd out password or NO PASS
216 ************************************************************************/
218 BOOL mod_smbpwd_entry(struct smb_passwd* pwd, BOOL override)
220 return pwdb_ops->mod_smbpwd_entry(pwd, override);
223 /************************************************************************
224 Routine to search smb passwd by name.
225 *************************************************************************/
227 struct smb_passwd *getsmbpwnam(char *name)
229 return pwdb_ops->getsmbpwnam(name);
232 /************************************************************************
233 Routine to search smb passwd by user rid.
234 *************************************************************************/
236 struct smb_passwd *getsmbpwrid(uint32 user_rid)
238 return pwdb_ops->getsmbpwrid(user_rid);
241 /************************************************************************
242 Routine to search smb passwd by uid.
243 *************************************************************************/
245 struct smb_passwd *getsmbpwuid(uid_t smb_userid)
247 return pwdb_ops->getsmbpwuid(smb_userid);
251 * Functions that manupulate a struct sam_passwd.
254 /************************************************************************
255 Utility function to search sam passwd by name. use this if your database
256 does not have search facilities.
257 *************************************************************************/
259 struct sam_passwd *iterate_getsam21pwnam(char *name)
261 struct sam_passwd *pwd = NULL;
264 DEBUG(10, ("search by name: %s\n", name));
266 /* Open the smb password database - not for update. */
267 fp = startsmbpwent(False);
271 DEBUG(0, ("unable to open sam password database.\n"));
275 while ((pwd = getsam21pwent(fp)) != NULL && !strequal(pwd->smb_name, name))
277 DEBUG(10, ("iterate: %s 0x%x\n", pwd->smb_name, pwd->user_rid));
282 DEBUG(10, ("found by name: %s\n", name));
289 /************************************************************************
290 Utility function to search sam passwd by rid. use this if your database
291 does not have search facilities.
293 search capability by both rid and uid are needed as the rid <-> uid
294 mapping may be non-monotonic.
296 *************************************************************************/
298 struct sam_passwd *iterate_getsam21pwrid(uint32 rid)
300 struct sam_passwd *pwd = NULL;
303 DEBUG(10, ("search by rid: %x\n", rid));
305 /* Open the smb password file - not for update. */
306 fp = startsmbpwent(False);
310 DEBUG(0, ("unable to open sam password database.\n"));
314 while ((pwd = getsam21pwent(fp)) != NULL && pwd->user_rid != rid)
316 DEBUG(10, ("iterate: %s 0x%x\n", pwd->smb_name, pwd->user_rid));
321 DEBUG(10, ("found by user_rid: %x\n", rid));
328 /************************************************************************
329 Utility function to search sam passwd by uid. use this if your database
330 does not have search facilities.
332 search capability by both rid and uid are needed as the rid <-> uid
333 mapping may be non-monotonic.
335 *************************************************************************/
337 struct sam_passwd *iterate_getsam21pwuid(uid_t uid)
339 struct sam_passwd *pwd = NULL;
342 DEBUG(10, ("search by uid: %x\n", (int)uid));
344 /* Open the smb password file - not for update. */
345 fp = startsmbpwent(False);
349 DEBUG(0, ("unable to open sam password database.\n"));
353 while ((pwd = getsam21pwent(fp)) != NULL && pwd->smb_userid != uid)
359 DEBUG(10, ("found by smb_userid: %x\n", (int)uid));
366 /*************************************************************************
367 Routine to return a display info structure, by rid
368 *************************************************************************/
369 struct sam_disp_info *getsamdisprid(uint32 rid)
371 return pwdb_ops->getsamdisprid(rid);
374 /*************************************************************************
375 Routine to return the next entry in the sam passwd list.
376 *************************************************************************/
378 struct sam_passwd *getsam21pwent(void *vp)
380 return pwdb_ops->getsam21pwent(vp);
384 /************************************************************************
385 Routine to search sam passwd by name.
386 *************************************************************************/
388 struct sam_passwd *getsam21pwnam(char *name)
390 return pwdb_ops->getsam21pwnam(name);
393 /************************************************************************
394 Routine to search sam passwd by rid.
395 *************************************************************************/
397 struct sam_passwd *getsam21pwrid(uint32 rid)
399 return pwdb_ops->getsam21pwrid(rid);
403 /**********************************************************
404 **********************************************************
406 utility routines which are likely to be useful to all password
409 **********************************************************
410 **********************************************************/
412 /*************************************************************
413 initialises a struct sam_disp_info.
414 **************************************************************/
416 static void pwdb_init_dispinfo(struct sam_disp_info *user)
418 if (user == NULL) return;
419 bzero(user, sizeof(*user));
422 /*************************************************************
423 initialises a struct smb_passwd.
424 **************************************************************/
426 void pwdb_init_smb(struct smb_passwd *user)
428 if (user == NULL) return;
429 bzero(user, sizeof(*user));
430 user->pass_last_set_time = (time_t)-1;
433 /*************************************************************
434 initialises a struct sam_passwd.
435 **************************************************************/
436 void pwdb_init_sam(struct sam_passwd *user)
438 if (user == NULL) return;
439 bzero(user, sizeof(*user));
440 user->logon_time = (time_t)-1;
441 user->logoff_time = (time_t)-1;
442 user->kickoff_time = (time_t)-1;
443 user->pass_last_set_time = (time_t)-1;
444 user->pass_can_change_time = (time_t)-1;
445 user->pass_must_change_time = (time_t)-1;
448 /*************************************************************************
449 Routine to return the next entry in the sam passwd list.
450 *************************************************************************/
452 struct sam_disp_info *pwdb_sam_to_dispinfo(struct sam_passwd *user)
454 static struct sam_disp_info disp_info;
456 if (user == NULL) return NULL;
458 pwdb_init_dispinfo(&disp_info);
460 disp_info.smb_name = user->smb_name;
461 disp_info.full_name = user->full_name;
462 disp_info.user_rid = user->user_rid;
467 /*************************************************************
468 converts a sam_passwd structure to a smb_passwd structure.
469 **************************************************************/
471 struct smb_passwd *pwdb_sam_to_smb(struct sam_passwd *user)
473 static struct smb_passwd pw_buf;
475 if (user == NULL) return NULL;
477 pwdb_init_smb(&pw_buf);
479 pw_buf.smb_userid = user->smb_userid;
480 pw_buf.smb_name = user->smb_name;
481 pw_buf.smb_passwd = user->smb_passwd;
482 pw_buf.smb_nt_passwd = user->smb_nt_passwd;
483 pw_buf.acct_ctrl = user->acct_ctrl;
484 pw_buf.pass_last_set_time = user->pass_last_set_time;
490 /*************************************************************
491 converts a smb_passwd structure to a sam_passwd structure.
492 **************************************************************/
494 struct sam_passwd *pwdb_smb_to_sam(struct smb_passwd *user)
496 static struct sam_passwd pw_buf;
498 if (user == NULL) return NULL;
500 pwdb_init_sam(&pw_buf);
502 pw_buf.smb_userid = user->smb_userid;
503 pw_buf.smb_name = user->smb_name;
504 pw_buf.smb_passwd = user->smb_passwd;
505 pw_buf.smb_nt_passwd = user->smb_nt_passwd;
506 pw_buf.acct_ctrl = user->acct_ctrl;
507 pw_buf.pass_last_set_time = user->pass_last_set_time;
512 /**********************************************************
513 Encode the account control bits into a string.
514 length = length of string to encode into (including terminating
515 null). length *MUST BE MORE THAN 2* !
516 **********************************************************/
518 char *pwdb_encode_acct_ctrl(uint16 acct_ctrl, size_t length)
520 static fstring acct_str;
525 if (acct_ctrl & ACB_PWNOTREQ ) acct_str[i++] = 'N';
526 if (acct_ctrl & ACB_DISABLED ) acct_str[i++] = 'D';
527 if (acct_ctrl & ACB_HOMDIRREQ) acct_str[i++] = 'H';
528 if (acct_ctrl & ACB_TEMPDUP ) acct_str[i++] = 'T';
529 if (acct_ctrl & ACB_NORMAL ) acct_str[i++] = 'U';
530 if (acct_ctrl & ACB_MNS ) acct_str[i++] = 'M';
531 if (acct_ctrl & ACB_WSTRUST ) acct_str[i++] = 'W';
532 if (acct_ctrl & ACB_SVRTRUST ) acct_str[i++] = 'S';
533 if (acct_ctrl & ACB_AUTOLOCK ) acct_str[i++] = 'L';
534 if (acct_ctrl & ACB_PWNOEXP ) acct_str[i++] = 'X';
535 if (acct_ctrl & ACB_DOMTRUST ) acct_str[i++] = 'I';
537 for ( ; i < length - 2 ; i++ )
544 acct_str[i++] = '\0';
549 /**********************************************************
550 Decode the account control bits from a string.
552 this function breaks coding standards minimum line width of 80 chars.
553 reason: vertical line-up code clarity - all case statements fit into
554 15 lines, which is more important.
555 **********************************************************/
557 uint16 pwdb_decode_acct_ctrl(const char *p)
559 uint16 acct_ctrl = 0;
560 BOOL finished = False;
563 * Check if the account type bits have been encoded after the
564 * NT password (in the form [NDHTUWSLXI]).
567 if (*p != '[') return 0;
569 for (p++; *p && !finished; p++)
573 case 'N': { acct_ctrl |= ACB_PWNOTREQ ; break; /* 'N'o password. */ }
574 case 'D': { acct_ctrl |= ACB_DISABLED ; break; /* 'D'isabled. */ }
575 case 'H': { acct_ctrl |= ACB_HOMDIRREQ; break; /* 'H'omedir required. */ }
576 case 'T': { acct_ctrl |= ACB_TEMPDUP ; break; /* 'T'emp account. */ }
577 case 'U': { acct_ctrl |= ACB_NORMAL ; break; /* 'U'ser account (normal). */ }
578 case 'M': { acct_ctrl |= ACB_MNS ; break; /* 'M'NS logon user account. What is this ? */ }
579 case 'W': { acct_ctrl |= ACB_WSTRUST ; break; /* 'W'orkstation account. */ }
580 case 'S': { acct_ctrl |= ACB_SVRTRUST ; break; /* 'S'erver account. */ }
581 case 'L': { acct_ctrl |= ACB_AUTOLOCK ; break; /* 'L'ocked account. */ }
582 case 'X': { acct_ctrl |= ACB_PWNOEXP ; break; /* No 'X'piry on password */ }
583 case 'I': { acct_ctrl |= ACB_DOMTRUST ; break; /* 'I'nterdomain trust account. */ }
589 default: { finished = True; }
596 /*******************************************************************
597 gets password-database-format time from a string.
598 ********************************************************************/
600 static time_t get_time_from_string(const char *p)
604 for (i = 0; i < 8; i++)
606 if (p[i] == '\0' || !isxdigit((int)(p[i]&0xFF)))
614 * p points at 8 characters of hex digits -
615 * read into a time_t as the seconds since
616 * 1970 that the password was last changed.
618 return (time_t)strtol(p, NULL, 16);
623 /*******************************************************************
624 gets password last set time
625 ********************************************************************/
627 time_t pwdb_get_last_set_time(const char *p)
629 if (*p && StrnCaseCmp(p, "LCT-", 4))
631 return get_time_from_string(p + 4);
637 /*******************************************************************
638 sets password-database-format time in a string.
639 ********************************************************************/
640 static void set_time_in_string(char *p, int max_len, char *type, time_t t)
642 slprintf(p, max_len, ":%s-%08X:", type, (uint32)t);
645 /*******************************************************************
647 ********************************************************************/
648 void pwdb_set_logon_time(char *p, int max_len, time_t t)
650 set_time_in_string(p, max_len, "LNT", t);
653 /*******************************************************************
655 ********************************************************************/
656 void pwdb_set_logoff_time(char *p, int max_len, time_t t)
658 set_time_in_string(p, max_len, "LOT", t);
661 /*******************************************************************
663 ********************************************************************/
664 void pwdb_set_kickoff_time(char *p, int max_len, time_t t)
666 set_time_in_string(p, max_len, "KOT", t);
669 /*******************************************************************
670 sets password can change time
671 ********************************************************************/
672 void pwdb_set_can_change_time(char *p, int max_len, time_t t)
674 set_time_in_string(p, max_len, "CCT", t);
677 /*******************************************************************
678 sets password last set time
679 ********************************************************************/
680 void pwdb_set_must_change_time(char *p, int max_len, time_t t)
682 set_time_in_string(p, max_len, "MCT", t);
685 /*******************************************************************
686 sets password last set time
687 ********************************************************************/
688 void pwdb_set_last_set_time(char *p, int max_len, time_t t)
690 set_time_in_string(p, max_len, "LCT", t);
694 /*************************************************************
695 Routine to set 32 hex password characters from a 16 byte array.
696 **************************************************************/
697 void pwdb_sethexpwd(char *p, char *pwd, uint16 acct_ctrl)
702 for (i = 0; i < 16; i++)
704 slprintf(&p[i*2], 33, "%02X", pwd[i]);
709 if (IS_BITS_SET_ALL(acct_ctrl, ACB_PWNOTREQ))
711 safe_strcpy(p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", 33);
715 safe_strcpy(p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 33);
720 /*************************************************************
721 Routine to get the 32 hex characters and turn them
722 into a 16 byte array.
723 **************************************************************/
724 BOOL pwdb_gethexpwd(char *p, char *pwd)
726 return strhex_to_str(pwd, 32, p) == 16;
729 /*******************************************************************
730 converts UNIX uid to an NT User RID. NOTE: IS SOMETHING SPECIFIC TO SAMBA
731 ********************************************************************/
732 uid_t pwdb_user_rid_to_uid(uint32 user_rid)
734 uid_t uid = (uid_t)(((user_rid & (~RID_TYPE_USER))- 1000)/RID_MULTIPLIER);
738 /*******************************************************************
739 converts UNIX uid to an NT User RID. NOTE: IS SOMETHING SPECIFIC TO SAMBA
740 ********************************************************************/
741 uint32 pwdb_uid_to_user_rid(uid_t uid)
743 uint32 user_rid = (((((uint32)uid)*RID_MULTIPLIER) + 1000) | RID_TYPE_USER);
747 /*******************************************************************
748 converts NT Group RID to a UNIX uid. NOTE: IS SOMETHING SPECIFIC TO SAMBA
749 ********************************************************************/
750 uint32 pwdb_gid_to_group_rid(gid_t gid)
752 uint32 grp_rid = (((((uint32)gid)*RID_MULTIPLIER) + 1000) | RID_TYPE_GROUP);
756 /*******************************************************************
757 converts NT Group RID to a UNIX uid. NOTE: IS SOMETHING SPECIFIC TO SAMBA
758 ********************************************************************/
759 gid_t pwdb_group_rid_to_gid(uint32 group_rid)
761 gid_t gid = (gid_t)(((group_rid & (~RID_TYPE_GROUP))- 1000)/RID_MULTIPLIER);
765 /*******************************************************************
766 converts UNIX gid to an NT Alias RID. NOTE: IS SOMETHING SPECIFIC TO SAMBA
767 ********************************************************************/
768 uint32 pwdb_gid_to_alias_rid(gid_t gid)
770 uint32 alias_rid = (((((uint32)gid)*RID_MULTIPLIER) + 1000) | RID_TYPE_ALIAS);
774 /*******************************************************************
775 converts NT Alias RID to a UNIX uid. NOTE: IS SOMETHING SPECIFIC TO SAMBA
776 ********************************************************************/
777 gid_t pwdb_alias_rid_to_gid(uint32 alias_rid)
779 gid_t gid = (gid_t)(((alias_rid & (~RID_TYPE_ALIAS))- 1000)/RID_MULTIPLIER);
783 /*******************************************************************
784 Decides if a RID is a well known RID.
785 ********************************************************************/
786 static BOOL pwdb_rid_is_well_known(uint32 rid)
791 /*******************************************************************
792 determines a rid's type. NOTE: THIS IS SOMETHING SPECIFIC TO SAMBA
793 ********************************************************************/
794 static uint32 pwdb_rid_type(uint32 rid)
796 /* lkcl i understand that NT attaches an enumeration to a RID
797 * such that it can be identified as either a user, group etc
798 * type: SID_ENUM_TYPE.
800 if (pwdb_rid_is_well_known(rid))
803 * The only well known user RIDs are DOMAIN_USER_RID_ADMIN
804 * and DOMAIN_USER_RID_GUEST.
806 if (rid == DOMAIN_USER_RID_ADMIN || rid == DOMAIN_USER_RID_GUEST)
808 return RID_TYPE_USER;
810 if (DOMAIN_GROUP_RID_ADMINS <= rid && rid <= DOMAIN_GROUP_RID_GUESTS)
812 return RID_TYPE_GROUP;
814 if (BUILTIN_ALIAS_RID_ADMINS <= rid && rid <= BUILTIN_ALIAS_RID_REPLICATOR)
816 return RID_TYPE_ALIAS;
819 return (rid & RID_TYPE_MASK);
822 /*******************************************************************
823 checks whether rid is a user rid. NOTE: THIS IS SOMETHING SPECIFIC TO SAMBA
824 ********************************************************************/
825 BOOL pwdb_rid_is_user(uint32 rid)
827 return pwdb_rid_type(rid) == RID_TYPE_USER;