/* Unix SMB/Netbios implementation. Version 1.9. Password and authentication handling Copyright (C) Jeremy Allison 1996-1998 Copyright (C) Luke Kenneth Casson Leighton 1996-1998 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "includes.h" #include "nterr.h" extern int DEBUGLEVEL; extern DOM_SID global_sam_sid; /* * NOTE. All these functions are abstracted into a structure * that points to the correct function for the selected database. JRA. * * NOTE. for the get/mod/add functions, there are two sets of functions. * one supports struct sam_passwd, the other supports struct smb_passwd. * for speed optimisation it is best to support both these sets. * * it is, however, optional to support one set but not the other: there * is conversion-capability built in to passdb.c, and run-time error * detection for when neither are supported. * * password database writers are recommended to implement the sam_passwd * functions in a first pass, as struct sam_passwd contains more * information, needed by the NT Domain support. * * an API writer is expected to create either one set (struct smb_passwd) or * the other (struct sam_passwd) OR both, and optionally also to write display * info routines * (struct sam_disp_info). functions which the API writer * chooses NOT to write must be wrapped in conversion functions (pwdb_x_to_y) * such that API users can call any function and still get valid results. * * the password API does NOT fill in the gaps if you set an API function * to NULL: it will deliberately attempt to call the NULL function. * */ static struct sam_passdb_ops *pwdb_ops; /*************************************************************** Initialise the password db operations. ***************************************************************/ BOOL initialise_sam_password_db(void) { if (pwdb_ops) { return True; } #ifdef WITH_NISPLUS pwdb_ops = nisplus_initialise_sam_password_db(); #elif defined(WITH_LDAP) pwdb_ops = ldap_initialise_sam_password_db(); #elif defined(USE_SMBPASS_DB) pwdb_ops = file_initialise_sam_password_db(); #endif return (pwdb_ops != NULL); } /* * Functions that return/manipulate a struct sam_passwd. */ /*************************************************************** Start to enumerate the smb or sam passwd list. Returns a void pointer to ensure no modification outside this module. Note that currently it is being assumed that a pointer returned from this function may be used to enumerate struct sam_passwd entries as well as struct smb_passwd entries. This may need to change. JRA. ****************************************************************/ void *startsam21pwent(BOOL update) { return pwdb_ops->startsam21pwent(update); } /*************************************************************** End enumeration of the sam passwd list. Note that currently it is being assumed that a pointer returned from this function may be used to enumerate struct sam_passwd entries as well as struct smb_passwd entries. This may need to change. JRA. ****************************************************************/ void endsam21pwent(void *vp) { pwdb_ops->endsam21pwent(vp); } /************************************************************************* Routine to return the next entry in the smb passwd list. *************************************************************************/ struct sam_passwd *getsam21pwent(void *vp) { return pwdb_sam_map_names(pwdb_ops->getsam21pwent(vp)); } /************************************************************************ Utility function to search sam passwd by name. use this if your database does not have search facilities. *************************************************************************/ struct sam_passwd *iterate_getsam21pwntnam(const char *ntname) { fstring nt_name; struct sam_passwd *pwd = NULL; void *fp = NULL; DEBUG(10, ("search by name: %s\n", ntname)); fstrcpy(nt_name, ntname); /* Open the smb password database - not for update. */ fp = startsmbpwent(False); if (fp == NULL) { DEBUG(0, ("unable to open sam password database.\n")); return NULL; } while ((pwd = getsam21pwent(fp)) != NULL && !strequal(pwd->nt_name, nt_name)) { DEBUG(10, ("iterate: %s 0x%x\n", pwd->nt_name, pwd->user_rid)); } if (pwd != NULL) { DEBUG(10, ("found by name: %s\n", nt_name)); } endsmbpwent(fp); return pwd; } /************************************************************************ Utility function to search sam passwd by rid. use this if your database does not have search facilities. search capability by both rid and uid are needed as the rid <-> uid mapping may be non-monotonic. *************************************************************************/ struct sam_passwd *iterate_getsam21pwrid(uint32 rid) { struct sam_passwd *pwd = NULL; void *fp = NULL; DEBUG(10, ("search by rid: %x\n", rid)); /* Open the smb password file - not for update. */ fp = startsmbpwent(False); if (fp == NULL) { DEBUG(0, ("unable to open sam password database.\n")); return NULL; } while ((pwd = getsam21pwent(fp)) != NULL && pwd->user_rid != rid) { DEBUG(10, ("iterate: %s 0x%x\n", pwd->nt_name, pwd->user_rid)); } if (pwd != NULL) { DEBUG(10, ("found by user_rid: %x\n", rid)); } endsmbpwent(fp); return pwd; } /************************************************************************ Utility function to search sam passwd by uid. use this if your database does not have search facilities. search capability by both rid and uid are needed as the rid <-> uid mapping may be non-monotonic. *************************************************************************/ struct sam_passwd *iterate_getsam21pwuid(uid_t uid) { struct sam_passwd *pwd = NULL; void *fp = NULL; DEBUG(10, ("search by uid: %x\n", (int)uid)); /* Open the smb password file - not for update. */ fp = startsmbpwent(False); if (fp == NULL) { DEBUG(0, ("unable to open sam password database.\n")); return NULL; } while ((pwd = getsam21pwent(fp)) != NULL && pwd->unix_uid != uid) { } if (pwd != NULL) { DEBUG(10, ("found by unix_uid: %x\n", (int)uid)); } endsmbpwent(fp); return pwd; } /************************************************************************* Routine to return a display info structure, by rid *************************************************************************/ struct sam_disp_info *getsamdisprid(uint32 rid) { return pwdb_ops->getsamdisprid(rid); } /************************************************************************ Routine to search sam passwd by name. *************************************************************************/ struct sam_passwd *getsam21pwntnam(const char *name) { return pwdb_sam_map_names(pwdb_ops->getsam21pwntnam(name)); } /************************************************************************ Routine to search sam passwd by rid. *************************************************************************/ struct sam_passwd *getsam21pwrid(uint32 rid) { return pwdb_sam_map_names(pwdb_ops->getsam21pwrid(rid)); } /********************************************************** ********************************************************** utility routines which are likely to be useful to all password databases ********************************************************** **********************************************************/ /************************************************************* initialises a struct sam_disp_info. **************************************************************/ static void pwdb_init_dispinfo(struct sam_disp_info *user) { if (user == NULL) return; bzero(user, sizeof(*user)); user->user_rid = 0xffffffff; } /************************************************************* initialises a struct sam_passwd. **************************************************************/ void pwdb_init_sam(struct sam_passwd *user) { if (user == NULL) return; bzero(user, sizeof(*user)); init_nt_time(&user->logon_time); init_nt_time(&user->logoff_time); init_nt_time(&user->kickoff_time); init_nt_time(&user->pass_last_set_time); init_nt_time(&user->pass_can_change_time); init_nt_time(&user->pass_must_change_time); user->unix_uid = (uid_t)-1; user->unix_gid = (gid_t)-1; user->user_rid = 0xffffffff; user->group_rid = 0xffffffff; } /************************************************************************* Routine to return the next entry in the sam passwd list. *************************************************************************/ struct sam_disp_info *pwdb_sam_to_dispinfo(struct sam_passwd *user) { static struct sam_disp_info disp_info; if (user == NULL) return NULL; pwdb_init_dispinfo(&disp_info); disp_info.nt_name = user->nt_name; disp_info.full_name = user->full_name; disp_info.user_rid = user->user_rid; return &disp_info; } /************************************************************* converts a sam_passwd structure to a smb_passwd structure. **************************************************************/ struct smb_passwd *pwdb_sam_to_smb(struct sam_passwd *user) { static struct smb_passwd pw_buf; static fstring nt_name; static fstring unix_name; if (user == NULL) return NULL; pwdb_init_smb(&pw_buf); fstrcpy(nt_name , user->nt_name); fstrcpy(unix_name, user->unix_name); pw_buf.nt_name = nt_name; pw_buf.unix_name = unix_name; pw_buf.unix_uid = user->unix_uid; pw_buf.user_rid = user->user_rid; pw_buf.smb_passwd = user->smb_passwd; pw_buf.smb_nt_passwd = user->smb_nt_passwd; pw_buf.acct_ctrl = user->acct_ctrl; pw_buf.pass_last_set_time = nt_time_to_unix(&user->pass_last_set_time); return &pw_buf; } /************************************************************* converts a smb_passwd structure to a sam_passwd structure. **************************************************************/ struct sam_passwd *pwdb_smb_to_sam(struct smb_passwd *user) { static struct sam_passwd pw_buf; static fstring nt_name; static fstring unix_name; if (user == NULL) return NULL; pwdb_init_sam(&pw_buf); fstrcpy(nt_name , user->nt_name); fstrcpy(unix_name, user->unix_name); pw_buf.nt_name = nt_name; pw_buf.unix_name = unix_name; pw_buf.unix_uid = user->unix_uid; pw_buf.user_rid = user->user_rid; pw_buf.smb_passwd = user->smb_passwd; pw_buf.smb_nt_passwd = user->smb_nt_passwd; pw_buf.acct_ctrl = user->acct_ctrl; if ( user->pass_last_set_time != (time_t)-1 ) { unix_to_nt_time(&pw_buf.pass_last_set_time, user->pass_last_set_time); unix_to_nt_time(&pw_buf.pass_can_change_time, user->pass_last_set_time); } return &pw_buf; } static BOOL trust_account_warning_done = False; /************************************************************* fills in missing details. one set of details _must_ exist. **************************************************************/ struct sam_passwd *pwdb_sam_map_names(struct sam_passwd *sam) { DOM_NAME_MAP gmep; BOOL found = False; DOM_SID sid; static fstring unix_name; static fstring nt_name; DEBUG(10,("pwdb_sam_map_names\n")); /* * name details */ if (sam == NULL) { return NULL; } if (!found && sam->unix_name != NULL) { found = lookupsmbpwnam(sam->unix_name, &gmep); } if (!found && sam->unix_uid != (uid_t)-1) { found = lookupsmbpwuid(sam->unix_uid , &gmep); } if (!found && sam->user_rid != 0xffffffff) { sid_copy(&sid, &global_sam_sid); sid_append_rid(&sid, sam->user_rid); found = lookupsmbpwsid (&sid , &gmep); } if (!found && sam->nt_name != NULL) { found = lookupsmbpwntnam(sam->nt_name, &gmep); } if (!found) { return NULL; } if (!sid_front_equal(&global_sam_sid, &gmep.sid)) { return NULL; } fstrcpy(unix_name, gmep.unix_name); fstrcpy(nt_name , gmep.nt_name ); if (sam->unix_name == NULL ) sam->unix_name = unix_name; if (sam->nt_name == NULL ) sam->nt_name = nt_name ; if (sam->unix_uid == (uid_t)-1 ) sam->unix_uid = (uid_t)gmep.unix_id; if (sam->user_rid == 0xffffffff) sid_split_rid(&gmep.sid, &sam->user_rid); DEBUG(10,("pwdb_sam_map_name: found unix user %s nt %s uid %d rid 0x%x\n", sam->unix_name, sam->nt_name, sam->unix_uid, sam->user_rid)); /* * group details */ found = False; if (sam->unix_gid != (gid_t)-1 && sam->group_rid != 0xffffffff) { return sam; } if (sam->unix_gid == (gid_t)-1 && sam->group_rid == 0xffffffff) { struct passwd *pass = getpwnam(unix_name); if (pass != NULL) { sam->unix_gid = pass->pw_gid; } else { DEBUG(0,("pwdb_sam_map_names: no unix password entry for %s\n", unix_name)); } } if (!found && sam->unix_gid != (gid_t)-1) { found = lookupsmbgrpgid(sam->unix_gid , &gmep); } if (!found && sam->group_rid != 0xffffffff) { sid_copy(&sid, &global_sam_sid); sid_append_rid(&sid, sam->group_rid); found = lookupsmbgrpsid(&sid , &gmep); } if (!found) { if (IS_BITS_SET_SOME(sam->acct_ctrl, ACB_WSTRUST|ACB_DOMTRUST|ACB_SVRTRUST)) { if (!trust_account_warning_done) { trust_account_warning_done = True; DEBUG(0, ("\ pwdb_sam_map_names: your unix password database appears to have difficulties\n\ resolving trust account %s, probably because it ends in a '$'.\n\ you will get this warning only once (for all trust accounts)\n", unix_name)); } /* * oh, dear. */ if (sam->unix_gid != (gid_t)-1) { sam->unix_gid = (gid_t)-1; } sam->group_rid = DOMAIN_GROUP_RID_USERS; return sam; } else { DEBUG(0, ("pwdb_sam_map_names: could not find Primary Group for %s\n", unix_name)); return NULL; } } if (!sid_front_equal(&global_sam_sid, &gmep.sid)) { fstring sid_str; sid_to_string(sid_str, &gmep.sid); DEBUG(0,("UNIX User %s Primary Group is in the wrong domain! %s\n", sam->unix_name, sid_str)); return NULL; } if (sam->unix_gid == (gid_t)-1 ) sam->unix_gid = (gid_t)gmep.unix_id; if (sam->group_rid == 0xffffffff) sid_split_rid(&gmep.sid, &sam->group_rid); DEBUG(10,("pwdb_sam_map_name: found gid %d and group rid 0x%x for unix user %s\n", sam->unix_gid, sam->group_rid, sam->unix_name)); return sam; }