1
0
mirror of https://github.com/samba-team/samba.git synced 2025-12-12 12:23:50 +03:00
Files
samba-mirror/source/passdb/sampassdb.c

529 lines
15 KiB
C

/*
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));
unix_to_nt_time(&user->logon_time , (time_t)-1);
unix_to_nt_time(&user->logoff_time , (time_t)-1);
unix_to_nt_time(&user->kickoff_time , (time_t)-1);
unix_to_nt_time(&user->pass_last_set_time , (time_t)-1);
unix_to_nt_time(&user->pass_can_change_time , (time_t)-1);
unix_to_nt_time(&user->pass_must_change_time , (time_t)-1);
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;
unix_to_nt_time(&pw_buf.pass_last_set_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;
}