From 3db52feb1f3b2c07ce0b06ad4a7099fa6efe3fc7 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 13 Dec 1999 13:27:58 +0000 Subject: first pass at updating head branch to be to be the same as the SAMBA_2_0 branch (This used to be commit 453a822a76780063dff23526c35408866d0c0154) --- source3/passdb/passdb.c | 1079 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 969 insertions(+), 110 deletions(-) (limited to 'source3/passdb/passdb.c') diff --git a/source3/passdb/passdb.c b/source3/passdb/passdb.c index 6579d14351..c0a20f3420 100644 --- a/source3/passdb/passdb.c +++ b/source3/passdb/passdb.c @@ -24,7 +24,16 @@ #include "nterr.h" extern int DEBUGLEVEL; + +/* + * This is set on startup - it defines the SID for this + * machine, and therefore the SAM database for which it is + * responsible. + */ + extern DOM_SID global_sam_sid; +extern pstring global_myname; +extern fstring global_myworkgroup; /* * NOTE. All these functions are abstracted into a structure @@ -42,58 +51,62 @@ extern DOM_SID global_sam_sid; * 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. + * a full example set of derivative functions are listed below. an API + * writer is expected to cut/paste these into their module, replace + * 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). lkcl * */ -static struct smb_passdb_ops *pwdb_ops; +static struct passdb_ops *pdb_ops; /*************************************************************** - Initialise the password db operations. + Initialize the password db operations. ***************************************************************/ -BOOL initialise_password_db(void) +BOOL initialize_password_db(void) { - if (pwdb_ops) + if (pdb_ops) { return True; } #ifdef WITH_NISPLUS - pwdb_ops = nisplus_initialise_password_db(); + pdb_ops = nisplus_initialize_password_db(); #elif defined(WITH_LDAP) - pwdb_ops = ldap_initialise_password_db(); -#elif defined(HAVE_MYSQL_H) && defined(WITH_MYSQLSAM) - pwdb_ops = mysql_initialise_password_db(); -#elif defined(USE_SMBPASS_DB) - pwdb_ops = file_initialise_password_db(); + pdb_ops = ldap_initialize_password_db(); +#else + pdb_ops = file_initialize_password_db(); #endif - return (pwdb_ops != NULL); + return (pdb_ops != NULL); } /* * Functions that return/manipulate a struct smb_passwd. */ +/************************************************************************ + Utility function to search smb passwd by rid. +*************************************************************************/ + +struct smb_passwd *iterate_getsmbpwrid(uint32 user_rid) +{ + return iterate_getsmbpwuid(pdb_user_rid_to_uid(user_rid)); +} + /************************************************************************ Utility function to search smb passwd by uid. use this if your database does not have search facilities. *************************************************************************/ -struct smb_passwd *iterate_getsmbpwuid(uid_t unix_uid) +struct smb_passwd *iterate_getsmbpwuid(uid_t smb_userid) { struct smb_passwd *pwd = NULL; void *fp = NULL; - DEBUG(10, ("search by unix_uid: %x\n", (int)unix_uid)); + DEBUG(10, ("search by smb_userid: %x\n", (int)smb_userid)); /* Open the smb password database - not for update. */ fp = startsmbpwent(False); @@ -104,13 +117,12 @@ struct smb_passwd *iterate_getsmbpwuid(uid_t unix_uid) return NULL; } - while ((pwd = getsmbpwent(fp)) != NULL && pwd->unix_uid != unix_uid) - { - } + while ((pwd = getsmbpwent(fp)) != NULL && pwd->smb_userid != smb_userid) + ; if (pwd != NULL) { - DEBUG(10, ("found by unix_uid: %x\n", (int)unix_uid)); + DEBUG(10, ("found by smb_userid: %x\n", (int)smb_userid)); } endsmbpwent(fp); @@ -122,7 +134,7 @@ struct smb_passwd *iterate_getsmbpwuid(uid_t unix_uid) does not have search facilities. *************************************************************************/ -struct smb_passwd *iterate_getsmbpwnam(const char *name) +struct smb_passwd *iterate_getsmbpwnam(char *name) { struct smb_passwd *pwd = NULL; void *fp = NULL; @@ -138,10 +150,8 @@ struct smb_passwd *iterate_getsmbpwnam(const char *name) return NULL; } - while ((pwd = getsmbpwent(fp)) != NULL && !strequal(pwd->unix_name, name)) - { - DEBUG(10, ("iterate: %s 0x%x\n", pwd->unix_name, pwd->unix_uid)); - } + while ((pwd = getsmbpwent(fp)) != NULL && !strequal(pwd->smb_name, name)) + ; if (pwd != NULL) { @@ -165,7 +175,7 @@ struct smb_passwd *iterate_getsmbpwnam(const char *name) void *startsmbpwent(BOOL update) { - return pwdb_ops->startsmbpwent(update); + return pdb_ops->startsmbpwent(update); } /*************************************************************** @@ -180,17 +190,7 @@ void *startsmbpwent(BOOL update) void endsmbpwent(void *vp) { - pwdb_ops->endsmbpwent(vp); -} - -SMB_BIG_UINT getsmbpwpos(void *vp) -{ - return pwdb_ops->getsmbpwpos(vp); -} - -BOOL setsmbpwpos(void *vp, SMB_BIG_UINT tok) -{ - return pwdb_ops->setsmbpwpos(vp, tok); + pdb_ops->endsmbpwent(vp); } /************************************************************************* @@ -199,7 +199,7 @@ BOOL setsmbpwpos(void *vp, SMB_BIG_UINT tok) struct smb_passwd *getsmbpwent(void *vp) { - return pwdb_smb_map_names(pwdb_ops->getsmbpwent(vp)); + return pdb_ops->getsmbpwent(vp); } /************************************************************************ @@ -208,12 +208,7 @@ struct smb_passwd *getsmbpwent(void *vp) BOOL add_smbpwd_entry(struct smb_passwd *newpwd) { - struct smb_passwd *mapped = pwdb_smb_map_names(newpwd); - if (mapped) - { - return pwdb_ops->add_smbpwd_entry(mapped); - } - return False; + return pdb_ops->add_smbpwd_entry(newpwd); } /************************************************************************ @@ -227,121 +222,985 @@ BOOL add_smbpwd_entry(struct smb_passwd *newpwd) BOOL mod_smbpwd_entry(struct smb_passwd* pwd, BOOL override) { - struct smb_passwd *mapped = pwdb_smb_map_names(pwd); - if (mapped) - { - return pwdb_ops->mod_smbpwd_entry(mapped, override); - } - return False; + return pdb_ops->mod_smbpwd_entry(pwd, override); } /************************************************************************ Routine to search smb passwd by name. *************************************************************************/ -struct smb_passwd *getsmbpwnam(const char *name) +struct smb_passwd *getsmbpwnam(char *name) { - return pwdb_smb_map_names(pwdb_ops->getsmbpwnam(name)); + return pdb_ops->getsmbpwnam(name); +} + +/************************************************************************ + Routine to search smb passwd by user rid. +*************************************************************************/ + +struct smb_passwd *getsmbpwrid(uint32 user_rid) +{ + return pdb_ops->getsmbpwrid(user_rid); } /************************************************************************ Routine to search smb passwd by uid. *************************************************************************/ -struct smb_passwd *getsmbpwuid(uid_t unix_uid) +struct smb_passwd *getsmbpwuid(uid_t smb_userid) { - return pwdb_smb_map_names(pwdb_ops->getsmbpwuid(unix_uid)); + return pdb_ops->getsmbpwuid(smb_userid); +} + +/* + * Functions that manupulate a struct sam_passwd. + */ + +/************************************************************************ + Utility function to search sam passwd by name. use this if your database + does not have search facilities. +*************************************************************************/ + +struct sam_passwd *iterate_getsam21pwnam(char *name) +{ + struct sam_passwd *pwd = NULL; + void *fp = NULL; + + DEBUG(10, ("search by name: %s\n", name)); + + /* 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->smb_name, name)) + { + DEBUG(10, ("iterate: %s 0x%x\n", pwd->smb_name, pwd->user_rid)); + } + + if (pwd != NULL) + { + DEBUG(10, ("found by name: %s\n", 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->smb_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->smb_userid != uid) + ; + + if (pwd != NULL) + { + DEBUG(10, ("found by smb_userid: %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 pdb_ops->getsamdisprid(rid); +} + +/************************************************************************* + Routine to return the next entry in the sam passwd list. + *************************************************************************/ + +struct sam_passwd *getsam21pwent(void *vp) +{ + return pdb_ops->getsam21pwent(vp); +} + + +/************************************************************************ + Routine to search sam passwd by name. +*************************************************************************/ + +struct sam_passwd *getsam21pwnam(char *name) +{ + return pdb_ops->getsam21pwnam(name); +} + +/************************************************************************ + Routine to search sam passwd by rid. +*************************************************************************/ + +struct sam_passwd *getsam21pwrid(uint32 rid) +{ + return pdb_ops->getsam21pwrid(rid); +} + + +/********************************************************** + ********************************************************** + + utility routines which are likely to be useful to all password + databases + + ********************************************************** + **********************************************************/ + +/************************************************************* + initialises a struct sam_disp_info. + **************************************************************/ + +static void pdb_init_dispinfo(struct sam_disp_info *user) +{ + if (user == NULL) return; + memset((char *)user, '\0', sizeof(*user)); } /************************************************************* initialises a struct smb_passwd. **************************************************************/ -void pwdb_init_smb(struct smb_passwd *user) + +void pdb_init_smb(struct smb_passwd *user) { if (user == NULL) return; - bzero(user, sizeof(*user)); + memset((char *)user, '\0', sizeof(*user)); user->pass_last_set_time = (time_t)-1; - user->unix_uid = (uid_t)-1; - user->user_rid = 0xffffffff; } /************************************************************* - fills in missing details. one set of details _must_ exist. + initialises a struct sam_passwd. + **************************************************************/ +void pdb_init_sam(struct sam_passwd *user) +{ + if (user == NULL) return; + memset((char *)user, '\0', sizeof(*user)); + user->logon_time = (time_t)-1; + user->logoff_time = (time_t)-1; + user->kickoff_time = (time_t)-1; + user->pass_last_set_time = (time_t)-1; + user->pass_can_change_time = (time_t)-1; + user->pass_must_change_time = (time_t)-1; +} + +/************************************************************************* + Routine to return the next entry in the sam passwd list. + *************************************************************************/ + +struct sam_disp_info *pdb_sam_to_dispinfo(struct sam_passwd *user) +{ + static struct sam_disp_info disp_info; + + if (user == NULL) return NULL; + + pdb_init_dispinfo(&disp_info); + + disp_info.smb_name = user->smb_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 *pdb_sam_to_smb(struct sam_passwd *user) +{ + static struct smb_passwd pw_buf; + + if (user == NULL) return NULL; + + pdb_init_smb(&pw_buf); + + pw_buf.smb_userid = user->smb_userid; + pw_buf.smb_name = user->smb_name; + 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 = user->pass_last_set_time; + + return &pw_buf; +} + + +/************************************************************* + converts a smb_passwd structure to a sam_passwd structure. **************************************************************/ -struct smb_passwd *pwdb_smb_map_names(struct smb_passwd *smb) + +struct sam_passwd *pdb_smb_to_sam(struct smb_passwd *user) { - DOM_NAME_MAP gmep; - BOOL found = False; - DOM_SID sid; - static fstring unix_name; - static fstring nt_name; + static struct sam_passwd pw_buf; + + if (user == NULL) return NULL; + + pdb_init_sam(&pw_buf); + + pw_buf.smb_userid = user->smb_userid; + pw_buf.smb_name = user->smb_name; + 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 = user->pass_last_set_time; + + return &pw_buf; +} + +/********************************************************** + Encode the account control bits into a string. + length = length of string to encode into (including terminating + null). length *MUST BE MORE THAN 2* ! + **********************************************************/ + +char *pdb_encode_acct_ctrl(uint16 acct_ctrl, size_t length) +{ + static fstring acct_str; + size_t i = 0; + + acct_str[i++] = '['; + + if (acct_ctrl & ACB_PWNOTREQ ) acct_str[i++] = 'N'; + if (acct_ctrl & ACB_DISABLED ) acct_str[i++] = 'D'; + if (acct_ctrl & ACB_HOMDIRREQ) acct_str[i++] = 'H'; + if (acct_ctrl & ACB_TEMPDUP ) acct_str[i++] = 'T'; + if (acct_ctrl & ACB_NORMAL ) acct_str[i++] = 'U'; + if (acct_ctrl & ACB_MNS ) acct_str[i++] = 'M'; + if (acct_ctrl & ACB_WSTRUST ) acct_str[i++] = 'W'; + if (acct_ctrl & ACB_SVRTRUST ) acct_str[i++] = 'S'; + if (acct_ctrl & ACB_AUTOLOCK ) acct_str[i++] = 'L'; + if (acct_ctrl & ACB_PWNOEXP ) acct_str[i++] = 'X'; + if (acct_ctrl & ACB_DOMTRUST ) acct_str[i++] = 'I'; + + for ( ; i < length - 2 ; i++ ) { acct_str[i] = ' '; } - if (smb == NULL) + i = length - 2; + acct_str[i++] = ']'; + acct_str[i++] = '\0'; + + return acct_str; +} + +/********************************************************** + Decode the account control bits from a string. + + this function breaks coding standards minimum line width of 80 chars. + reason: vertical line-up code clarity - all case statements fit into + 15 lines, which is more important. + **********************************************************/ + +uint16 pdb_decode_acct_ctrl(const char *p) +{ + uint16 acct_ctrl = 0; + BOOL finished = False; + + /* + * Check if the account type bits have been encoded after the + * NT password (in the form [NDHTUWSLXI]). + */ + + if (*p != '[') return 0; + + for (p++; *p && !finished; p++) { - DEBUG(10,("pwdb_smb_map_names: NULL\n")); - return NULL; + switch (*p) + { + case 'N': { acct_ctrl |= ACB_PWNOTREQ ; break; /* 'N'o password. */ } + case 'D': { acct_ctrl |= ACB_DISABLED ; break; /* 'D'isabled. */ } + case 'H': { acct_ctrl |= ACB_HOMDIRREQ; break; /* 'H'omedir required. */ } + case 'T': { acct_ctrl |= ACB_TEMPDUP ; break; /* 'T'emp account. */ } + case 'U': { acct_ctrl |= ACB_NORMAL ; break; /* 'U'ser account (normal). */ } + case 'M': { acct_ctrl |= ACB_MNS ; break; /* 'M'NS logon user account. What is this ? */ } + case 'W': { acct_ctrl |= ACB_WSTRUST ; break; /* 'W'orkstation account. */ } + case 'S': { acct_ctrl |= ACB_SVRTRUST ; break; /* 'S'erver account. */ } + case 'L': { acct_ctrl |= ACB_AUTOLOCK ; break; /* 'L'ocked account. */ } + case 'X': { acct_ctrl |= ACB_PWNOEXP ; break; /* No 'X'piry on password */ } + case 'I': { acct_ctrl |= ACB_DOMTRUST ; break; /* 'I'nterdomain trust account. */ } + case ' ': { break; } + case ':': + case '\n': + case '\0': + case ']': + default: { finished = True; } + } } - DEBUG(10,("pwdb_smb_map_names: unix %s nt %s unix %d nt%d\n", - smb->unix_name != NULL ? smb->unix_name : "NULL", - smb->nt_name != NULL ? smb->nt_name : "NULL", - smb->unix_uid, smb->user_rid)); + return acct_ctrl; +} + +/******************************************************************* + gets password-database-format time from a string. + ********************************************************************/ - if (smb->unix_name == NULL && smb->nt_name == NULL && - smb->unix_uid == (uid_t)-1 && smb->user_rid == 0xffffffff) +static time_t get_time_from_string(const char *p) +{ + int i; + + for (i = 0; i < 8; i++) { - return NULL; + if (p[i] == '\0' || !isxdigit((int)(p[i]&0xFF))) + break; + } + if (i == 8) + { + /* + * p points at 8 characters of hex digits - + * read into a time_t as the seconds since + * 1970 that the password was last changed. + */ + return (time_t)strtol(p, NULL, 16); } - if (smb->unix_name != NULL && smb->nt_name != NULL && - smb->unix_uid != (uid_t)-1 && smb->user_rid != 0xffffffff) + return (time_t)-1; +} + +/******************************************************************* + gets password last set time + ********************************************************************/ + +time_t pdb_get_last_set_time(const char *p) +{ + if (*p && StrnCaseCmp(p, "LCT-", 4)) { - return smb; + return get_time_from_string(p + 4); } + return (time_t)-1; +} - if (!found && smb->unix_name != NULL) + +/******************************************************************* + sets password-database-format time in a string. + ********************************************************************/ +static void set_time_in_string(char *p, int max_len, char *type, time_t t) +{ + slprintf(p, max_len, ":%s-%08X:", type, (uint32)t); +} + +/******************************************************************* + sets logon time + ********************************************************************/ +void pdb_set_logon_time(char *p, int max_len, time_t t) +{ + set_time_in_string(p, max_len, "LNT", t); +} + +/******************************************************************* + sets logoff time + ********************************************************************/ +void pdb_set_logoff_time(char *p, int max_len, time_t t) +{ + set_time_in_string(p, max_len, "LOT", t); +} + +/******************************************************************* + sets kickoff time + ********************************************************************/ +void pdb_set_kickoff_time(char *p, int max_len, time_t t) +{ + set_time_in_string(p, max_len, "KOT", t); +} + +/******************************************************************* + sets password can change time + ********************************************************************/ +void pdb_set_can_change_time(char *p, int max_len, time_t t) +{ + set_time_in_string(p, max_len, "CCT", t); +} + +/******************************************************************* + sets password last set time + ********************************************************************/ +void pdb_set_must_change_time(char *p, int max_len, time_t t) +{ + set_time_in_string(p, max_len, "MCT", t); +} + +/******************************************************************* + sets password last set time + ********************************************************************/ +void pdb_set_last_set_time(char *p, int max_len, time_t t) +{ + set_time_in_string(p, max_len, "LCT", t); +} + + +/************************************************************* + Routine to set 32 hex password characters from a 16 byte array. +**************************************************************/ +void pdb_sethexpwd(char *p, unsigned char *pwd, uint16 acct_ctrl) +{ + if (pwd != NULL) { - found = lookupsmbpwnam(smb->unix_name, &gmep); + int i; + for (i = 0; i < 16; i++) + { + slprintf(&p[i*2], 3, "%02X", pwd[i]); + } } - if (!found && smb->unix_uid != (uid_t)-1) + else { - found = lookupsmbpwuid(smb->unix_uid , &gmep); + if (IS_BITS_SET_ALL(acct_ctrl, ACB_PWNOTREQ)) + { + safe_strcpy(p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", 33); + } + else + { + safe_strcpy(p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 33); + } } +} +/************************************************************* + Routine to get the 32 hex characters and turn them + into a 16 byte array. +**************************************************************/ +BOOL pdb_gethexpwd(char *p, unsigned char *pwd) +{ + int i; + unsigned char lonybble, hinybble; + char *hexchars = "0123456789ABCDEF"; + char *p1, *p2; - if (!found) + for (i = 0; i < 32; i += 2) { - sid_copy(&sid, &global_sam_sid); - sid_append_rid(&sid, smb->user_rid); + hinybble = toupper(p[i]); + lonybble = toupper(p[i + 1]); + + p1 = strchr(hexchars, hinybble); + p2 = strchr(hexchars, lonybble); + + if (!p1 || !p2) + { + return (False); + } + + hinybble = PTR_DIFF(p1, hexchars); + lonybble = PTR_DIFF(p2, hexchars); + + pwd[i / 2] = (hinybble << 4) | lonybble; } + return (True); +} + +/******************************************************************* + Group and User RID username mapping function + ********************************************************************/ - if (!found && smb->user_rid != 0xffffffff) +BOOL pdb_name_to_rid(char *user_name, uint32 *u_rid, uint32 *g_rid) +{ + struct passwd *pw = Get_Pwnam(user_name, False); + + if (u_rid == NULL || g_rid == NULL || user_name == NULL) { - found = lookupsmbpwsid (&sid , &gmep); + return False; } - if (!found && smb->nt_name != NULL) + + if (!pw) { - found = lookupsmbpwntnam(smb->nt_name, &gmep); + DEBUG(1,("Username %s is invalid on this system\n", user_name)); + return False; } - if (!found) + if (user_in_list(user_name, lp_domain_guest_users())) { - return NULL; + *u_rid = DOMAIN_USER_RID_GUEST; } - - if (!sid_front_equal(&global_sam_sid, &gmep.sid)) + else if (user_in_list(user_name, lp_domain_admin_users())) { - fstring sid_str; - sid_to_string(sid_str, &gmep.sid); - DEBUG(0,("UNIX User %s Primary Group is in the wrong domain! %s\n", - smb->unix_name, sid_str)); - return NULL; + *u_rid = DOMAIN_USER_RID_ADMIN; + } + else + { + /* turn the unix UID into a Domain RID. this is what the posix + sub-system does (adds 1000 to the uid) */ + *u_rid = pdb_uid_to_user_rid(pw->pw_uid); + } + + /* absolutely no idea what to do about the unix GID to Domain RID mapping */ + *g_rid = pdb_gid_to_group_rid(pw->pw_gid); + + return True; +} + +/**************************************************************************** + Read the machine SID from a file. +****************************************************************************/ + +static BOOL read_sid_from_file(int fd, char *sid_file) +{ + fstring fline; + + memset(fline, '\0', sizeof(fline)); + + if(read(fd, fline, sizeof(fline) -1 ) < 0) { + DEBUG(0,("unable to read file %s. Error was %s\n", + sid_file, strerror(errno) )); + return False; + } + + /* + * Convert to the machine SID. + */ + + fline[sizeof(fline)-1] = '\0'; + if(!string_to_sid( &global_sam_sid, fline)) { + DEBUG(0,("unable to generate machine SID.\n")); + return False; + } + + return True; +} + +/**************************************************************************** + Generate the global machine sid. Look for the MACHINE.SID file first, if + not found then look in smb.conf and use it to create the MACHINE.SID file. +****************************************************************************/ +BOOL pdb_generate_sam_sid(void) +{ + int fd; + char *p; + pstring sid_file; + fstring sid_string; + SMB_STRUCT_STAT st; + BOOL overwrite_bad_sid = False; + + generate_wellknown_sids(); + + pstrcpy(sid_file, lp_smb_passwd_file()); + p = strrchr(sid_file, '/'); + if(p != NULL) { + *++p = '\0'; + } + + if (!directory_exist(sid_file, NULL)) { + if (mkdir(sid_file, 0700) != 0) { + DEBUG(0,("can't create private directory %s : %s\n", + sid_file, strerror(errno))); + return False; + } + } + + pstrcat(sid_file, "MACHINE.SID"); + + if((fd = sys_open(sid_file, O_RDWR | O_CREAT, 0644)) == -1) { + DEBUG(0,("unable to open or create file %s. Error was %s\n", + sid_file, strerror(errno) )); + return False; + } + + /* + * Check if the file contains data. + */ + + if(sys_fstat( fd, &st) < 0) { + DEBUG(0,("unable to stat file %s. Error was %s\n", + sid_file, strerror(errno) )); + close(fd); + return False; + } + + if(st.st_size > 0) { + /* + * We have a valid SID - read it. + */ + if(!read_sid_from_file( fd, sid_file)) { + DEBUG(0,("unable to read file %s. Error was %s\n", + sid_file, strerror(errno) )); + close(fd); + return False; + } + + /* + * JRA. Reversed the sense of this test now that I have + * actually done this test *personally*. One more reason + * to never trust third party information you have not + * independently verified.... sigh. JRA. + */ + + if(global_sam_sid.num_auths > 0 && global_sam_sid.sub_auths[0] == 0x21) { + /* + * Fix and re-write... + */ + overwrite_bad_sid = True; + global_sam_sid.sub_auths[0] = 21; + DEBUG(5,("pdb_generate_sam_sid: Old (incorrect) sid id_auth of hex 21 \ +detected - re-writing to be decimal 21 instead.\n" )); + sid_to_string(sid_string, &global_sam_sid); + if(sys_lseek(fd, (SMB_OFF_T)0, SEEK_SET) != 0) { + DEBUG(0,("unable to seek file file %s. Error was %s\n", + sid_file, strerror(errno) )); + close(fd); + return False; + } + } else { + close(fd); + return True; + } + } else { + /* + * The file contains no data - we need to generate our + * own sid. + * Generate the new sid data & turn it into a string. + */ + int i; + uchar raw_sid_data[12]; + DOM_SID mysid; + + memset((char *)&mysid, '\0', sizeof(DOM_SID)); + mysid.sid_rev_num = 1; + mysid.id_auth[5] = 5; + mysid.num_auths = 0; + mysid.sub_auths[mysid.num_auths++] = 21; + + generate_random_buffer( raw_sid_data, 12, True); + for( i = 0; i < 3; i++) + mysid.sub_auths[mysid.num_auths++] = IVAL(raw_sid_data, i*4); + + sid_to_string(sid_string, &mysid); + } + + fstrcat(sid_string, "\n"); + + /* + * Ensure our new SID is valid. + */ + + if(!string_to_sid( &global_sam_sid, sid_string)) { + DEBUG(0,("unable to generate machine SID.\n")); + return False; + } + + /* + * Do an exclusive blocking lock on the file. + */ + + if(!do_file_lock( fd, 60, F_WRLCK)) { + DEBUG(0,("unable to lock file %s. Error was %s\n", + sid_file, strerror(errno) )); + close(fd); + return False; + } + + if(!overwrite_bad_sid) { + /* + * At this point we have a blocking lock on the SID + * file - check if in the meantime someone else wrote + * SID data into the file. If so - they were here first, + * use their data. + */ + + if(sys_fstat( fd, &st) < 0) { + DEBUG(0,("unable to stat file %s. Error was %s\n", + sid_file, strerror(errno) )); + close(fd); + return False; + } + + if(st.st_size > 0) { + /* + * Unlock as soon as possible to reduce + * contention on the exclusive lock. + */ + do_file_lock( fd, 60, F_UNLCK); + + /* + * We have a valid SID - read it. + */ + + if(!read_sid_from_file( fd, sid_file)) { + DEBUG(0,("unable to read file %s. Error was %s\n", + sid_file, strerror(errno) )); + close(fd); + return False; + } + close(fd); + return True; + } + } + + /* + * The file is still empty and we have an exlusive lock on it, + * or we're fixing an earlier mistake. + * Write out out SID data into the file. + */ + + /* + * Use chmod here as some (strange) UNIX's don't + * have fchmod. JRA. + */ + + if(chmod(sid_file, 0644) < 0) { + DEBUG(0,("unable to set correct permissions on file %s. \ +Error was %s\n", sid_file, strerror(errno) )); + do_file_lock( fd, 60, F_UNLCK); + close(fd); + return False; + } + + if(write( fd, sid_string, strlen(sid_string)) != strlen(sid_string)) { + DEBUG(0,("unable to write file %s. Error was %s\n", + sid_file, strerror(errno) )); + do_file_lock( fd, 60, F_UNLCK); + close(fd); + return False; + } + + /* + * Unlock & exit. + */ + + do_file_lock( fd, 60, F_UNLCK); + close(fd); + return True; +} + +/******************************************************************* + Converts NT user RID to a UNIX uid. + ********************************************************************/ + +uid_t pdb_user_rid_to_uid(uint32 user_rid) +{ + return (uid_t)(((user_rid & (~USER_RID_TYPE))- 1000)/RID_MULTIPLIER); +} + +/******************************************************************* + Converts NT user RID to a UNIX gid. + ********************************************************************/ + +gid_t pdb_user_rid_to_gid(uint32 user_rid) +{ + return (uid_t)(((user_rid & (~GROUP_RID_TYPE))- 1000)/RID_MULTIPLIER); +} + +/******************************************************************* + converts UNIX uid to an NT User RID. + ********************************************************************/ + +uint32 pdb_uid_to_user_rid(uid_t uid) +{ + return (((((uint32)uid)*RID_MULTIPLIER) + 1000) | USER_RID_TYPE); +} + +/******************************************************************* + converts NT Group RID to a UNIX uid. + ********************************************************************/ + +uint32 pdb_gid_to_group_rid(gid_t gid) +{ + return (((((uint32)gid)*RID_MULTIPLIER) + 1000) | GROUP_RID_TYPE); +} + +/******************************************************************* + Decides if a RID is a well known RID. + ********************************************************************/ + +static BOOL pdb_rid_is_well_known(uint32 rid) +{ + return (rid < 1000); +} + +/******************************************************************* + Decides if a RID is a user or group RID. + ********************************************************************/ + +BOOL pdb_rid_is_user(uint32 rid) +{ + /* lkcl i understand that NT attaches an enumeration to a RID + * such that it can be identified as either a user, group etc + * type. there are 5 such categories, and they are documented. + */ + if(pdb_rid_is_well_known(rid)) { + /* + * The only well known user RIDs are DOMAIN_USER_RID_ADMIN + * and DOMAIN_USER_RID_GUEST. + */ + if(rid == DOMAIN_USER_RID_ADMIN || rid == DOMAIN_USER_RID_GUEST) + return True; + } else if((rid & RID_TYPE_MASK) == USER_RID_TYPE) { + return True; + } + return False; +} + +/******************************************************************* + Convert a rid into a name. Used in the lookup SID rpc. + ********************************************************************/ + +BOOL lookup_local_rid(uint32 rid, char *name, uint8 *psid_name_use) +{ + + BOOL is_user = pdb_rid_is_user(rid); + + DEBUG(5,("lookup_local_rid: looking up %s RID %u.\n", is_user ? "user" : + "group", (unsigned int)rid)); + + if(is_user) { + if(rid == DOMAIN_USER_RID_ADMIN) { + pstring admin_users; + char *p = admin_users; + pstrcpy( admin_users, lp_domain_admin_users()); + if(!next_token(&p, name, NULL, sizeof(fstring))) + fstrcpy(name, "Administrator"); + } else if (rid == DOMAIN_USER_RID_GUEST) { + pstring guest_users; + char *p = guest_users; + pstrcpy( guest_users, lp_domain_guest_users()); + if(!next_token(&p, name, NULL, sizeof(fstring))) + fstrcpy(name, "Guest"); + } else { + uid_t uid = pdb_user_rid_to_uid(rid); + struct passwd *pass = sys_getpwuid(uid); + + *psid_name_use = SID_NAME_USER; + + DEBUG(5,("lookup_local_rid: looking up uid %u %s\n", (unsigned int)uid, + pass ? "succeeded" : "failed" )); + + if(!pass) { + slprintf(name, sizeof(fstring)-1, "unix_user.%u", (unsigned int)uid); + return True; + } + + fstrcpy(name, pass->pw_name); + + DEBUG(5,("lookup_local_rid: found user %s for rid %u\n", name, + (unsigned int)rid )); + } + + } else { + gid_t gid = pdb_user_rid_to_gid(rid); + struct group *gr = getgrgid(gid); + + *psid_name_use = SID_NAME_ALIAS; + + DEBUG(5,("lookup_local_rid: looking up gid %u %s\n", (unsigned int)gid, + gr ? "succeeded" : "failed" )); + + if(!gr) { + slprintf(name, sizeof(fstring)-1, "unix_group.%u", (unsigned int)gid); + return True; + } + + fstrcpy( name, gr->gr_name); + + DEBUG(5,("lookup_local_rid: found group %s for rid %u\n", name, + (unsigned int)rid )); + } + + return True; +} + +/******************************************************************* + Convert a name into a SID. Used in the lookup name rpc. + ********************************************************************/ + +BOOL lookup_local_name(char *domain, char *user, DOM_SID *psid, uint8 *psid_name_use) +{ + extern DOM_SID global_sid_World_Domain; + struct passwd *pass = NULL; + DOM_SID local_sid; + + sid_copy(&local_sid, &global_sam_sid); + + if(!strequal(global_myname, domain) && !strequal(global_myworkgroup, domain)) + return False; + + /* + * Special case for MACHINE\Everyone. Map to the world_sid. + */ + + if(strequal(user, "Everyone")) { + sid_copy( psid, &global_sid_World_Domain); + sid_append_rid(psid, 0); + *psid_name_use = SID_NAME_ALIAS; + return True; + } + + (void)map_username(user); + + if(!(pass = Get_Pwnam(user, False))) { + /* + * Maybe it was a group ? + */ + struct group *grp = getgrnam(user); + + if(!grp) + return False; + + sid_append_rid( &local_sid, pdb_gid_to_group_rid(grp->gr_gid)); + *psid_name_use = SID_NAME_ALIAS; + } else { + + sid_append_rid( &local_sid, pdb_uid_to_user_rid(pass->pw_uid)); + *psid_name_use = SID_NAME_USER; } - fstrcpy(unix_name, gmep.unix_name); - fstrcpy(nt_name , gmep.nt_name ); - if (smb->unix_name == NULL ) smb->unix_name = unix_name; - if (smb->nt_name == NULL ) smb->nt_name = nt_name ; - if (smb->unix_uid == (uid_t)-1 ) smb->unix_uid = (uid_t)gmep.unix_id; - if (smb->user_rid == 0xffffffff) sid_split_rid(&gmep.sid, &smb->user_rid); + sid_copy( psid, &local_sid); - return smb; + return True; } -- cgit