From 53373894acfff45885caf1e19a54141546ba5eea Mon Sep 17 00:00:00 2001 From: Luke Leighton Date: Sun, 29 Nov 1998 20:06:52 +0000 Subject: "retired" two modules to preserve their cvs history. added their replacements, added sam password database API modules (This used to be commit b1d1c1337c69c6f6bf25ab932a1a6a757e3ea2ae) --- source3/lib/domain_namemap.c | 1186 ++++++++++++++++++++++++++++++++++++++++++ source3/lib/sids.c | 554 ++++++++++++++++++++ source3/lib/util_pwdb.c | 444 ++++++++++++++++ source3/passdb/sampass.c | 198 +++++++ source3/passdb/sampassdb.c | 515 ++++++++++++++++++ source3/rpc_server/srv_sid.c | 521 +------------------ source3/smbd/groupname.c | 639 +---------------------- 7 files changed, 2899 insertions(+), 1158 deletions(-) create mode 100644 source3/lib/domain_namemap.c create mode 100644 source3/lib/sids.c create mode 100644 source3/lib/util_pwdb.c create mode 100644 source3/passdb/sampass.c create mode 100644 source3/passdb/sampassdb.c (limited to 'source3') diff --git a/source3/lib/domain_namemap.c b/source3/lib/domain_namemap.c new file mode 100644 index 0000000000..3de5b60785 --- /dev/null +++ b/source3/lib/domain_namemap.c @@ -0,0 +1,1186 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Groupname handling + Copyright (C) Jeremy Allison 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. +*/ + +/* + * UNIX gid and Local or Domain SID resolution. This module resolves + * only those entries in the map files, it is *NOT* responsible for + * resolving UNIX groups not listed: that is an entirely different + * matter, altogether... + */ + +/* + * + * + + format of the file is: + + unixname NT Group name + unixname Domain Admins (well-known Domain Group) + unixname DOMAIN_NAME\NT Group name + unixname OTHER_DOMAIN_NAME\NT Group name + unixname DOMAIN_NAME\Domain Admins (well-known Domain Group) + .... + + if the DOMAIN_NAME\ component is left off, then your own domain is assumed. + + * + * + */ + + +#include "includes.h" +extern int DEBUGLEVEL; + +extern fstring global_sam_name; +extern DOM_SID global_sam_sid; +extern DOM_SID global_sid_S_1_5_20; + +/******************************************************************* + converts UNIX uid to an NT User RID. NOTE: IS SOMETHING SPECIFIC TO SAMBA + ********************************************************************/ +static uid_t pwdb_user_rid_to_uid(uint32 user_rid) +{ + return ((user_rid & (~RID_TYPE_USER))- 1000)/RID_MULTIPLIER; +} + +/******************************************************************* + converts NT Group RID to a UNIX uid. NOTE: IS SOMETHING SPECIFIC TO SAMBA + ********************************************************************/ +static uint32 pwdb_group_rid_to_gid(uint32 group_rid) +{ + return ((group_rid & (~RID_TYPE_GROUP))- 1000)/RID_MULTIPLIER; +} + +/******************************************************************* + converts NT Alias RID to a UNIX uid. NOTE: IS SOMETHING SPECIFIC TO SAMBA + ********************************************************************/ +static uint32 pwdb_alias_rid_to_gid(uint32 alias_rid) +{ + return ((alias_rid & (~RID_TYPE_ALIAS))- 1000)/RID_MULTIPLIER; +} + +/******************************************************************* + converts NT Group RID to a UNIX uid. NOTE: IS SOMETHING SPECIFIC TO SAMBA + ********************************************************************/ +static uint32 pwdb_gid_to_group_rid(uint32 gid) +{ + uint32 grp_rid = ((((gid)*RID_MULTIPLIER) + 1000) | RID_TYPE_GROUP); + return grp_rid; +} + +/****************************************************************** + converts UNIX gid to an NT Alias RID. NOTE: IS SOMETHING SPECIFIC TO SAMBA + ********************************************************************/ +static uint32 pwdb_gid_to_alias_rid(uint32 gid) +{ + uint32 alias_rid = ((((gid)*RID_MULTIPLIER) + 1000) | RID_TYPE_ALIAS); + return alias_rid; +} + +/******************************************************************* + converts UNIX uid to an NT User RID. NOTE: IS SOMETHING SPECIFIC TO SAMBA + ********************************************************************/ +static uint32 pwdb_uid_to_user_rid(uint32 uid) +{ + uint32 user_rid = ((((uid)*RID_MULTIPLIER) + 1000) | RID_TYPE_USER); + return user_rid; +} + +/****************************************************************** + converts SID + SID_NAME_USE type to a UNIX id. the Domain SID is, + and can only be, our own SID. + ********************************************************************/ +static BOOL pwdb_sam_sid_to_unixid(DOM_SID *sid, uint8 type, uint32 *id) +{ + DOM_SID tmp_sid; + uint32 rid; + + sid_copy(&tmp_sid, sid); + sid_split_rid(&tmp_sid, &rid); + if (!sid_equal(&global_sam_sid, &tmp_sid)) + { + return False; + } + + switch (type) + { + case SID_NAME_USER: + { + *id = pwdb_user_rid_to_uid(rid); + return True; + } + case SID_NAME_ALIAS: + { + *id = pwdb_alias_rid_to_gid(rid); + return True; + } + case SID_NAME_DOM_GRP: + case SID_NAME_WKN_GRP: + { + *id = pwdb_group_rid_to_gid(rid); + return True; + } + } + return False; +} + +/****************************************************************** + converts UNIX gid + SID_NAME_USE type to a SID. the Domain SID is, + and can only be, our own SID. + ********************************************************************/ +static BOOL pwdb_unixid_to_sam_sid(uint32 id, uint8 type, DOM_SID *sid) +{ + sid_copy(sid, &global_sam_sid); + switch (type) + { + case SID_NAME_USER: + { + sid_append_rid(sid, pwdb_uid_to_user_rid(id)); + return True; + } + case SID_NAME_ALIAS: + { + sid_append_rid(sid, pwdb_gid_to_alias_rid(id)); + return True; + } + case SID_NAME_DOM_GRP: + case SID_NAME_WKN_GRP: + { + sid_append_rid(sid, pwdb_gid_to_group_rid(id)); + return True; + } + } + return False; +} + +/******************************************************************* + Decides if a RID is a well known RID. + ********************************************************************/ +static BOOL pwdb_rid_is_well_known(uint32 rid) +{ + return (rid < 1000); +} + +/******************************************************************* + determines a rid's type. NOTE: THIS IS SOMETHING SPECIFIC TO SAMBA + ********************************************************************/ +static uint32 pwdb_rid_type(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: SID_ENUM_TYPE. + */ + if (pwdb_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 RID_TYPE_USER; + } + if (DOMAIN_GROUP_RID_ADMINS <= rid && rid <= DOMAIN_GROUP_RID_GUESTS) + { + return RID_TYPE_GROUP; + } + if (BUILTIN_ALIAS_RID_ADMINS <= rid && rid <= BUILTIN_ALIAS_RID_REPLICATOR) + { + return RID_TYPE_ALIAS; + } + } + return (rid & RID_TYPE_MASK); +} + +/******************************************************************* + checks whether rid is a user rid. NOTE: THIS IS SOMETHING SPECIFIC TO SAMBA + ********************************************************************/ +BOOL pwdb_rid_is_user(uint32 rid) +{ + return pwdb_rid_type(rid) == RID_TYPE_USER; +} + +/************************************************************************** + Groupname map functionality. The code loads a groupname map file and + (currently) loads it into a linked list. This is slow and memory + hungry, but can be changed into a more efficient storage format + if the demands on it become excessive. +***************************************************************************/ + +typedef struct name_map +{ + ubi_slNode next; + DOM_NAME_MAP grp; + +} name_map_entry; + +static ubi_slList groupname_map_list; +static ubi_slList aliasname_map_list; +static ubi_slList ntusrname_map_list; + +static void delete_name_entry(name_map_entry *gmep) +{ + if (gmep->grp.nt_name) + { + free(gmep->grp.nt_name); + } + if (gmep->grp.nt_domain) + { + free(gmep->grp.nt_domain); + } + if (gmep->grp.unix_name) + { + free(gmep->grp.unix_name); + } + free((char*)gmep); +} + +/************************************************************************** + Delete all the entries in the name map list. +***************************************************************************/ + +static void delete_map_list(ubi_slList *map_list) +{ + name_map_entry *gmep; + + while ((gmep = (name_map_entry *)ubi_slRemHead(map_list )) != NULL) + { + delete_name_entry(gmep); + } +} + + +/************************************************************************** + makes a group sid out of a domain sid and a _unix_ gid. +***************************************************************************/ +static BOOL make_mydomain_sid(DOM_NAME_MAP *grp, DOM_MAP_TYPE type) +{ + DEBUG(10,("make_mydomain_sid\n")); + + if (!map_domain_name_to_sid(&grp->sid, &(grp->nt_domain))) + { + DEBUG(0,("make_mydomain_sid: unknown domain %s\n", + grp->nt_domain)); + return False; + } + + if (sid_equal(&grp->sid, &global_sid_S_1_5_20)) + { + /* + * only builtin aliases are recognised in S-1-5-20 + */ + + if (!lookup_builtin_alias_name(grp->nt_name, "BUILTIN", &grp->sid, &grp->type)) + { + DEBUG(0,("unix group %s mapped to an unrecognised BUILTIN domain name %s\n", + grp->unix_name, grp->nt_name)); + return False; + } + return True; + } + else if (lookup_wk_user_name(grp->nt_name, grp->nt_domain, &grp->sid, &grp->type) == 0x0) + { + if (type != DOM_MAP_USER) + { + DEBUG(0,("well-known NT user %s\%s listed in wrong map file\n", + grp->nt_domain, grp->nt_name)); + return False; + } + return True; + } + else if (lookup_wk_group_name(grp->nt_name, grp->nt_domain, &grp->sid, &grp->type) == 0x0) + { + if (type != DOM_MAP_DOMAIN) + { + DEBUG(0,("well-known NT group %s\%s listed in wrong map file\n", + grp->nt_domain, grp->nt_name)); + return False; + } + return True; + } + else + { + BOOL ret; + fstring sid_str; + switch (type) + { + case DOM_MAP_USER: + { + grp->type = SID_NAME_USER; + break; + } + case DOM_MAP_DOMAIN: + { + grp->type = SID_NAME_DOM_GRP; + break; + } + case DOM_MAP_LOCAL: + { + grp->type = SID_NAME_ALIAS; + break; + } + } + + ret = pwdb_unixid_to_sam_sid(grp->unix_id, grp->type, &grp->sid); + sid_to_string(sid_str, &grp->sid); + DEBUG(10,("nt name %s gid %d mapped to %s\n", + grp->nt_name, grp->unix_id, sid_str)); + return ret; + } + + return False; +} + +/************************************************************************** + makes a group sid out of an nt domain, nt group name or a unix group name. +***************************************************************************/ +static BOOL unix_name_to_group_info(DOM_NAME_MAP *grp, DOM_MAP_TYPE type) +{ + struct group *gptr = NULL; + + /* + * Attempt to get the unix gid_t for this name. + */ + + DEBUG(5,("unix_name_to_group_info: unix_name:%s\n", grp->unix_name)); + + gptr = (struct group *)getgrnam(grp->unix_name); + if (gptr == NULL) + { + DEBUG(0,("unix_name_to_group_info: getgrnam for group %s\ +failed. Error was %s.\n", grp->unix_name, strerror(errno) )); + return False; + } + + grp->unix_id = (uint32)gptr->gr_gid; + + DEBUG(5,("unix_name_to_group_info: unix gid:%d\n", grp->unix_id)); + + /* + * Now map the name to an NT SID+RID. + */ + + if (grp->nt_domain != NULL && !strequal(grp->nt_domain, global_sam_name)) + { + /* Must add client-call lookup code here, to + * resolve remote domain's sid and the group's rid, + * in that domain. + * + * NOTE: it is _incorrect_ to put code here that assumes + * we are responsible for lookups for foriegn domains' RIDs. + * + * for foriegn domains for which we are *NOT* the PDC, all + * we can be responsible for is the unix gid_t to which + * the foriegn SID+rid maps to, on this _local_ machine. + * we *CANNOT* make any short-cuts or assumptions about + * RIDs in a foriegn domain. + */ + + if (!map_domain_name_to_sid(&grp->sid, &(grp->nt_domain))) + { + DEBUG(0,("unix_name_to_group_info: no known sid for %s\n", + grp->nt_domain)); + return False; + } + } + + return make_mydomain_sid(grp, type); +} + +static BOOL make_name_entry(name_map_entry **new_ep, + char *nt_domain, char *nt_group, char *unix_group, + DOM_MAP_TYPE type) +{ + /* + * Create the list entry and add it onto the list. + */ + + DEBUG(5,("make_name_entry:%s,%s,%s\n", nt_domain, nt_group, unix_group)); + + (*new_ep) = (name_map_entry *)malloc(sizeof(name_map_entry)); + if ((*new_ep) == NULL) + { + DEBUG(0,("make_name_entry: malloc fail for name_map_entry.\n")); + return False; + } + + ZERO_STRUCTP(*new_ep); + + (*new_ep)->grp.nt_name = strdup(nt_group ); + (*new_ep)->grp.nt_domain = strdup(nt_domain ); + (*new_ep)->grp.unix_name = strdup(unix_group); + + if ((*new_ep)->grp.nt_name == NULL || + (*new_ep)->grp.unix_name == NULL) + { + DEBUG(0,("make_name_entry: malloc fail for names in name_map_entry.\n")); + delete_name_entry((*new_ep)); + return False; + } + + /* + * look up the group names, make the Group-SID and unix gid + */ + + if (!unix_name_to_group_info(&(*new_ep)->grp, type)) + { + delete_name_entry((*new_ep)); + return False; + } + + return True; +} + +/************************************************************************** + Load a name map file. Sets last accessed timestamp. +***************************************************************************/ +static ubi_slList *load_name_map(DOM_MAP_TYPE type) +{ + static time_t groupmap_file_last_modified = (time_t)0; + static time_t aliasmap_file_last_modified = (time_t)0; + static time_t ntusrmap_file_last_modified = (time_t)0; + static BOOL initialised_group = False; + static BOOL initialised_alias = False; + static BOOL initialised_ntusr = False; + char *groupname_map_file = lp_groupname_map(); + char *aliasname_map_file = lp_aliasname_map(); + char *ntusrname_map_file = lp_ntusrname_map(); + + SMB_STRUCT_STAT st; + FILE *fp; + char *s; + pstring buf; + name_map_entry *new_ep; + + time_t *file_last_modified = NULL; + int *initialised = NULL; + char *map_file = NULL; + ubi_slList *map_list = NULL; + + switch (type) + { + case DOM_MAP_DOMAIN: + { + file_last_modified = &groupmap_file_last_modified; + initialised = &initialised_group; + map_file = groupname_map_file; + map_list = &groupname_map_list; + + break; + } + case DOM_MAP_LOCAL: + { + file_last_modified = &aliasmap_file_last_modified; + initialised = &initialised_alias; + map_file = aliasname_map_file; + map_list = &aliasname_map_list; + + break; + } + case DOM_MAP_USER: + { + file_last_modified = &ntusrmap_file_last_modified; + initialised = &initialised_ntusr; + map_file = ntusrname_map_file; + map_list = &ntusrname_map_list; + + break; + } + } + + if (!(*initialised)) + { + DEBUG(10,("initialising map %s\n", map_file)); + ubi_slInitList(map_list); + (*initialised) = True; + } + + if (!*map_file) + { + return map_list; + } + + if (sys_stat(map_file, &st) != 0) + { + DEBUG(0, ("load_name_map: Unable to stat file %s. Error was %s\n", + map_file, strerror(errno) )); + return map_list; + } + + /* + * Check if file has changed. + */ + if (st.st_mtime <= (*file_last_modified)) + { + return map_list; + } + + (*file_last_modified) = st.st_mtime; + + /* + * Load the file. + */ + + fp = fopen(map_file,"r"); + if (!fp) + { + DEBUG(0,("load_name_map: can't open name map %s. Error was %s\n", + map_file, strerror(errno))); + return map_list; + } + + /* + * Throw away any previous list. + */ + delete_map_list(map_list); + + DEBUG(4,("load_name_map: Scanning name map %s\n",map_file)); + + while ((s = fgets_slash(buf, sizeof(buf), fp)) != NULL) + { + pstring unixname; + pstring nt_name; + fstring nt_domain; + fstring nt_group; + char *p; + + DEBUG(10,("Read line |%s|\n", s)); + + memset(nt_name, 0, sizeof(nt_name)); + + if (!*s || strchr("#;",*s)) + continue; + + if (!next_token(&s,unixname, "\t\n\r=", sizeof(unixname))) + continue; + + if (!next_token(&s,nt_name, "\t\n\r=", sizeof(nt_name))) + continue; + + trim_string(unixname, " ", " "); + trim_string(nt_name, " ", " "); + + if (!*nt_name) + continue; + + if (!*unixname) + continue; + + DEBUG(5,("unixname = %s, ntname = %s.\n", + unixname, nt_name)); + + p = strchr(nt_name, '\\'); + + if (p == NULL) + { + memset(nt_domain, 0, sizeof(nt_domain)); + fstrcpy(nt_group, nt_name); + } + else + { + *p = 0; + p++; + fstrcpy(nt_domain, nt_name); + fstrcpy(nt_group , p); + } + + if (make_name_entry(&new_ep, nt_domain, nt_name, unixname, type)) + { + ubi_slAddTail(map_list, (ubi_slNode *)new_ep); + } + } + + DEBUG(10,("load_name_map: Added %ld entries to name map.\n", + ubi_slCount(map_list))); + + fclose(fp); + + return map_list; +} + +static void copy_grp_map_entry(DOM_NAME_MAP *grp, const DOM_NAME_MAP *from) +{ + sid_copy(&grp->sid, &from->sid); + grp->unix_id = from->unix_id; + grp->nt_name = from->nt_name; + grp->nt_domain = from->nt_domain; + grp->unix_name = from->unix_name; + grp->type = from->type; +} + +#if 0 +/*********************************************************** + Lookup unix name. +************************************************************/ +static BOOL map_unixname(DOM_MAP_TYPE type, + char *unixname, DOM_NAME_MAP *grp_info) +{ + name_map_entry *gmep; + ubi_slList *map_list; + + /* + * Initialise and load if not already loaded. + */ + map_list = load_name_map(type); + + for (gmep = (name_map_entry *)ubi_slFirst(map_list); + gmep != NULL; + gmep = (name_map_entry *)ubi_slNext(gmep )) + { + if (strequal(gmep->grp.unix_name, unixname)) + { + copy_grp_map_entry(grp_info, &gmep->grp); + DEBUG(7,("map_unixname: Mapping unix group %s to nt group %s.\n", + gmep->grp.unix_name, gmep->grp.nt_name )); + return True; + } + } + + return False; +} + +#endif + +/*********************************************************** + Lookup nt name. +************************************************************/ +static BOOL map_ntname(DOM_MAP_TYPE type, char *ntname, char *ntdomain, + DOM_NAME_MAP *grp_info) +{ + name_map_entry *gmep; + ubi_slList *map_list; + + /* + * Initialise and load if not already loaded. + */ + map_list = load_name_map(type); + + for (gmep = (name_map_entry *)ubi_slFirst(map_list); + gmep != NULL; + gmep = (name_map_entry *)ubi_slNext(gmep )) + { + if (strequal(gmep->grp.nt_name , ntname) && + strequal(gmep->grp.nt_domain, ntdomain)) + { + copy_grp_map_entry(grp_info, &gmep->grp); + DEBUG(7,("map_ntname: Mapping unix group %s to nt group %s.\n", + gmep->grp.unix_name, gmep->grp.nt_name )); + return True; + } + } + + return False; +} + + +/*********************************************************** + Lookup by SID +************************************************************/ +static BOOL map_sid(DOM_MAP_TYPE type, + DOM_SID *psid, DOM_NAME_MAP *grp_info) +{ + name_map_entry *gmep; + ubi_slList *map_list; + + /* + * Initialise and load if not already loaded. + */ + map_list = load_name_map(type); + + for (gmep = (name_map_entry *)ubi_slFirst(map_list); + gmep != NULL; + gmep = (name_map_entry *)ubi_slNext(gmep )) + { + if (sid_equal(&gmep->grp.sid, psid)) + { + copy_grp_map_entry(grp_info, &gmep->grp); + DEBUG(7,("map_sid: Mapping unix group %s to nt group %s.\n", + gmep->grp.unix_name, gmep->grp.nt_name )); + return True; + } + } + + return False; +} + +/*********************************************************** + Lookup by gid_t. +************************************************************/ +static BOOL map_unixid(DOM_MAP_TYPE type, uint32 unix_id, DOM_NAME_MAP *grp_info) +{ + name_map_entry *gmep; + ubi_slList *map_list; + + /* + * Initialise and load if not already loaded. + */ + map_list = load_name_map(type); + + for (gmep = (name_map_entry *)ubi_slFirst(map_list); + gmep != NULL; + gmep = (name_map_entry *)ubi_slNext(gmep )) + { + fstring sid_str; + sid_to_string(sid_str, &gmep->grp.sid); + DEBUG(10,("map_unixid: enum entry unix group %s %d nt %s %s\n", + gmep->grp.unix_name, gmep->grp.unix_id, gmep->grp.nt_name, sid_str)); + if (gmep->grp.unix_id == unix_id) + { + copy_grp_map_entry(grp_info, &gmep->grp); + DEBUG(7,("map_unixid: Mapping unix group %s to nt group %s type %d\n", + gmep->grp.unix_name, gmep->grp.nt_name, gmep->grp.type)); + return True; + } + } + + return False; +} + +/*********************************************************** + * + * Call four functions to resolve unix group ids and either + * local group SIDs or domain group SIDs listed in the local group + * or domain group map files. + * + * Note that it is *NOT* the responsibility of these functions to + * resolve entries that are not in the map files. + * + * Any SID can be in the map files (i.e from any Domain). + * + ***********************************************************/ + +#if 0 + +/*********************************************************** + Lookup a UNIX Group entry by name. +************************************************************/ +BOOL map_unix_group_name(char *group_name, DOM_NAME_MAP *grp_info) +{ + return map_unixname(DOM_MAP_DOMAIN, group_name, grp_info); +} + +/*********************************************************** + Lookup a UNIX Alias entry by name. +************************************************************/ +BOOL map_unix_alias_name(char *alias_name, DOM_NAME_MAP *grp_info) +{ + return map_unixname(DOM_MAP_LOCAL, alias_name, grp_info); +} + +/*********************************************************** + Lookup an Alias name entry +************************************************************/ +BOOL map_nt_alias_name(char *ntalias_name, char *nt_domain, DOM_NAME_MAP *grp_info) +{ + return map_ntname(DOM_MAP_LOCAL, ntalias_name, nt_domain, grp_info); +} + +/*********************************************************** + Lookup a Group entry +************************************************************/ +BOOL map_nt_group_name(char *ntgroup_name, char *nt_domain, DOM_NAME_MAP *grp_info) +{ + return map_ntname(DOM_MAP_DOMAIN, ntgroup_name, nt_domain, grp_info); +} + +#endif + +/*********************************************************** + Lookup a Username entry by name. +************************************************************/ +static BOOL map_nt_username(char *nt_name, char *nt_domain, DOM_NAME_MAP *grp_info) +{ + return map_ntname(DOM_MAP_USER, nt_name, nt_domain, grp_info); +} + +/*********************************************************** + Lookup a Username entry by SID. +************************************************************/ +static BOOL map_username_sid(DOM_SID *sid, DOM_NAME_MAP *grp_info) +{ + return map_sid(DOM_MAP_USER, sid, grp_info); +} + +/*********************************************************** + Lookup a Username SID entry by uid. +************************************************************/ +static BOOL map_username_uid(uid_t gid, DOM_NAME_MAP *grp_info) +{ + return map_unixid(DOM_MAP_USER, (uint32)gid, grp_info); +} + +/*********************************************************** + Lookup an Alias SID entry by name. +************************************************************/ +BOOL map_alias_sid(DOM_SID *psid, DOM_NAME_MAP *grp_info) +{ + return map_sid(DOM_MAP_LOCAL, psid, grp_info); +} + +/*********************************************************** + Lookup a Group entry by sid. +************************************************************/ +BOOL map_group_sid(DOM_SID *psid, DOM_NAME_MAP *grp_info) +{ + return map_sid(DOM_MAP_DOMAIN, psid, grp_info); +} + +/*********************************************************** + Lookup an Alias SID entry by gid_t. +************************************************************/ +static BOOL map_alias_gid(gid_t gid, DOM_NAME_MAP *grp_info) +{ + return map_unixid(DOM_MAP_LOCAL, (uint32)gid, grp_info); +} + +/*********************************************************** + Lookup a Group SID entry by gid_t. +************************************************************/ +static BOOL map_group_gid( gid_t gid, DOM_NAME_MAP *grp_info) +{ + return map_unixid(DOM_MAP_DOMAIN, (uint32)gid, grp_info); +} + + +/************************************************************************ + Routine to look up User details by UNIX name +*************************************************************************/ +BOOL lookupsmbpwnam(const char *unix_usr_name, DOM_NAME_MAP *grp) +{ + uid_t uid; + DEBUG(10,("lookupsmbpwnam: unix user name %s\n", unix_usr_name)); + if (nametouid(unix_usr_name, &uid)) + { + return lookupsmbpwuid(uid, grp); + } + else + { + return False; + } +} + +/* + * used by lookup functions below + */ + +static fstring nt_name; +static fstring unix_name; +static fstring nt_domain; + +/************************************************************************* + looks up a uid, returns User Information. +*************************************************************************/ +BOOL lookupsmbpwuid(uid_t uid, DOM_NAME_MAP *gmep) +{ + DEBUG(10,("lookupsmbpwuid: unix uid %d\n", uid)); + if (map_username_uid(uid, gmep)) + { + return True; + } + if (lp_server_role() != ROLE_DOMAIN_NONE) + { + gmep->nt_name = nt_name; + gmep->unix_name = unix_name; + + gmep->unix_id = (uint32)uid; + + /* + * here we should do a LsaLookupNames() call + * to check the status of the name with the PDC. + * if the PDC know nothing of the name, it's ours. + */ + + if (lp_server_role() == ROLE_DOMAIN_MEMBER) + { +#if 0 + do_lsa_lookup_names(global_myworkgroup, gmep->nt_name, &gmep->sid...); +#endif + } + + gmep->type = SID_NAME_USER; + fstrcpy(gmep->nt_name, uidtoname(uid)); + fstrcpy(gmep->unix_name, gmep->nt_name); + gmep->nt_domain = global_sam_name; + pwdb_unixid_to_sam_sid(gmep->unix_id, gmep->type, &gmep->sid); + + return True; + } + + /* oops. */ + + return False; +} + +/************************************************************************* + looks up by NT name, returns User Information. +*************************************************************************/ +BOOL lookupsmbpwntnam(char *fullntname, DOM_NAME_MAP *gmep) +{ + DEBUG(10,("lookupsmbpwntnam: nt user name %s\n", fullntname)); + + if (!split_domain_name(fullntname, nt_name, nt_domain)) + { + return False; + } + + if (map_nt_username(nt_name, nt_domain, gmep)) + { + return True; + } + if (lp_server_role() != ROLE_DOMAIN_NONE) + { + uid_t uid; + gmep->nt_name = nt_name; + gmep->unix_name = unix_name; + gmep->nt_domain = nt_domain; + + /* + * here we should do a LsaLookupNames() call + * to check the status of the name with the PDC. + * if the PDC know nothing of the name, it's ours. + */ + + if (lp_server_role() == ROLE_DOMAIN_MEMBER) + { +#if 0 + do_lsa_lookup_names(global_myworkgroup, gmep->nt_name, gmep->nt_domain, &gmep->sid...); +#endif + } + + gmep->type = SID_NAME_USER; + fstrcpy(gmep->unix_name, gmep->nt_name); + if (!nametouid(gmep->unix_name, &uid)) + { + return False; + } + gmep->unix_id = (uint32)uid; + if (!pwdb_unixid_to_sam_sid(gmep->unix_id, gmep->type, &gmep->sid)) + { + return False; + } + + return True; + } + + /* oops. */ + + return False; +} + +/************************************************************************* + looks up by RID, returns User Information. +*************************************************************************/ +BOOL lookupsmbpwsid(DOM_SID *sid, DOM_NAME_MAP *gmep) +{ + fstring sid_str; + sid_to_string(sid_str, sid); + DEBUG(10,("lookupsmbpwsid: nt sid %s\n", sid_str)); + + if (map_username_sid(sid, gmep)) + { + return True; + } + if (lp_server_role() != ROLE_DOMAIN_NONE) + { + gmep->nt_name = nt_name; + gmep->unix_name = unix_name; + gmep->nt_domain = nt_domain; + + /* + * here we should do a LsaLookupNames() call + * to check the status of the name with the PDC. + * if the PDC know nothing of the name, it's ours. + */ + + if (lp_server_role() == ROLE_DOMAIN_MEMBER) + { +#if 0 + do_lsa_lookup_sids(global_myworkgroup, gmep->sid, gmep->nt_name, gmep->nt_domain...); +#endif + } + + gmep->type = SID_NAME_USER; + sid_copy(&gmep->sid, sid); + if (!pwdb_sam_sid_to_unixid(&gmep->sid, gmep->type, &gmep->unix_id)) + { + return False; + } + fstrcpy(gmep->nt_name, uidtoname((uid_t)gmep->unix_id)); + fstrcpy(gmep->unix_name, gmep->nt_name); + gmep->nt_domain = global_sam_name; + + return True; + } + + /* oops. */ + + return False; +} + +/************************************************************************ + Routine to look up group / alias / well-known group RID by UNIX name +*************************************************************************/ +BOOL lookupsmbgrpnam(const char *unix_grp_name, DOM_NAME_MAP *grp) +{ + gid_t gid; + DEBUG(10,("lookupsmbgrpnam: unix user group %s\n", unix_grp_name)); + if (nametogid(unix_grp_name, &gid)) + { + return lookupsmbgrpgid(gid, grp); + } + else + { + return False; + } +} + +/************************************************************************* + looks up a SID, returns name map entry +*************************************************************************/ +BOOL lookupsmbgrpsid(DOM_SID *sid, DOM_NAME_MAP *gmep) +{ + fstring sid_str; + sid_to_string(sid_str, sid); + DEBUG(10,("lookupsmbgrpsid: nt sid %s\n", sid_str)); + + if (map_alias_sid(sid, gmep)) + { + return True; + } + if (map_group_sid(sid, gmep)) + { + return True; + } + if (lp_server_role() != ROLE_DOMAIN_NONE) + { + gmep->nt_name = nt_name; + gmep->unix_name = unix_name; + gmep->nt_domain = nt_domain; + + /* + * here we should do a LsaLookupNames() call + * to check the status of the name with the PDC. + * if the PDC know nothing of the name, it's ours. + */ + + if (lp_server_role() == ROLE_DOMAIN_MEMBER) + { +#if 0 + do_lsa_lookup_sids(global_myworkgroup, gmep->sid, gmep->nt_name, gmep->nt_domain...); +#endif + } + + /* name is not explicitly mapped + * with map files or the PDC + * so we are responsible for it... + */ + + if (lp_server_role() == ROLE_DOMAIN_MEMBER) + { + /* ... as a LOCAL group. */ + gmep->type = SID_NAME_ALIAS; + } + else + { + /* ... as a DOMAIN group. */ + gmep->type = SID_NAME_DOM_GRP; + } + + sid_copy(&gmep->sid, sid); + if (!pwdb_sam_sid_to_unixid(&gmep->sid, gmep->type, &gmep->unix_id)) + { + return False; + } + fstrcpy(gmep->nt_name, gidtoname((gid_t)gmep->unix_id)); + fstrcpy(gmep->unix_name, gmep->nt_name); + gmep->nt_domain = global_sam_name; + + return True; + } + + /* oops */ + return False; +} + +/************************************************************************* + looks up a gid, returns RID and type local, domain or well-known domain group +*************************************************************************/ +BOOL lookupsmbgrpgid(gid_t gid, DOM_NAME_MAP *gmep) +{ + DEBUG(10,("lookupsmbgrpgid: unix gid %d\n", (int)gid)); + if (map_alias_gid(gid, gmep)) + { + return True; + } + if (map_group_gid(gid, gmep)) + { + return True; + } + if (lp_server_role() != ROLE_DOMAIN_NONE) + { + gmep->nt_name = nt_name; + gmep->unix_name = unix_name; + + gmep->unix_id = (uint32)gid; + + /* + * here we should do a LsaLookupNames() call + * to check the status of the name with the PDC. + * if the PDC know nothing of the name, it's ours. + */ + + if (lp_server_role() == ROLE_DOMAIN_MEMBER) + { +#if 0 + do_lsa_lookup_names(global_myworkgroup, gmep->nt_name, &gmep->sid...); + { + return True; + } +#endif + } + + /* name is not explicitly mapped + * with map files or the PDC + * so we are responsible for it... + */ + + if (lp_server_role() == ROLE_DOMAIN_MEMBER) + { + /* ... as a LOCAL group. */ + gmep->type = SID_NAME_ALIAS; + } + else + { + /* ... as a DOMAIN group. */ + gmep->type = SID_NAME_DOM_GRP; + } + fstrcpy(gmep->nt_name, gidtoname(gid)); + fstrcpy(gmep->unix_name, gmep->nt_name); + gmep->nt_domain = global_sam_name; + pwdb_unixid_to_sam_sid(gmep->unix_id, gmep->type, &gmep->sid); + + return True; + } + + /* oops */ + return False; +} + diff --git a/source3/lib/sids.c b/source3/lib/sids.c new file mode 100644 index 0000000000..432c3349e3 --- /dev/null +++ b/source3/lib/sids.c @@ -0,0 +1,554 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Samba utility functions + Copyright (C) Andrew Tridgell 1992-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" + + +extern int DEBUGLEVEL; +extern pstring scope; +extern pstring global_myname; + +/* + * This is set on startup - it defines the SID for this + * machine, and therefore the SAM database for which it is + * responsible. + */ + +DOM_SID global_sam_sid; + +/* + * This is the name associated with the SAM database for + * which this machine is responsible. In the case of a PDC + * or PDC, this name is the same as the workgroup. In the + * case of "security = domain" mode, this is the same as + * the name of the server (global_myname). + */ + +fstring global_sam_name; + +/* + * This is obtained on startup - it defines the SID for which + * this machine is a member. It is therefore only set, and + * used, in "security = domain" mode. + */ + +DOM_SID global_member_sid; + +/* + * note the lack of a "global_member_name" - this is because + * this is the same as "global_myworkgroup". + */ + +extern fstring global_myworkgroup; +/* fstring global_member_dom_name; */ + +/* + * some useful sids + */ + +DOM_SID global_sid_S_1_5_20; /* local well-known domain */ +DOM_SID global_sid_S_1_1; /* everyone */ +DOM_SID global_sid_S_1_3; /* Creator Owner */ +DOM_SID global_sid_S_1_5; /* NT Authority */ + +static struct sid_name_map_info +{ + DOM_SID *sid; + char *name; + +} +sid_name_map[] = +{ + { &global_sid_S_1_5_20, "BUILTIN" }, + { &global_sid_S_1_1 , "Everyone" }, + { &global_sid_S_1_3 , "Creator Owner" }, + { &global_sid_S_1_5 , "NT Authority" }, + { &global_sam_sid , global_sam_name }, + { &global_member_sid , global_myworkgroup }, + { NULL , NULL } +}; + +/**************************************************************************** + Read the machine SID from a file. +****************************************************************************/ + +static BOOL read_sid_from_file(int fd, char *sid_file) +{ + fstring fline; + fstring sid_str; + + 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; + } + + sid_to_string(sid_str, &global_sam_sid); + DEBUG(5,("read_sid_from_file: sid %s\n", sid_str)); + + return True; +} + +/**************************************************************************** + sets up the name associated with the SAM database for which we are responsible +****************************************************************************/ +void get_sam_domain_name(void) +{ + switch (lp_server_role()) + { + case ROLE_DOMAIN_PDC: + case ROLE_DOMAIN_BDC: + { + /* we are PDC (or BDC) for a Domain */ + fstrcpy(global_sam_name, lp_workgroup()); + break; + } + case ROLE_DOMAIN_MEMBER: + { + /* we are a "PDC", but FOR LOCAL SAM DATABASE ONLY */ + fstrcpy(global_sam_name, global_myname); + break; + } + default: + { + /* no domain role, probably due to "security = share" */ + memset(global_sam_name, 0, sizeof(global_sam_name)); + break; + } + } +} + +/**************************************************************************** + obtain the sid from the PDC. do some verification along the way... +****************************************************************************/ +BOOL get_member_domain_sid(void) +{ + POLICY_HND pol; + fstring srv_name; + struct cli_state cli; + BOOL res = True; + DOM_SID sid3; + DOM_SID sid5; + fstring dom3; + fstring dom5; + + switch (lp_server_role()) + { + case ROLE_DOMAIN_NONE: + { + ZERO_STRUCT(global_member_sid); + return True; + } + case ROLE_DOMAIN_PDC: + { + sid_copy(&global_member_sid, &global_sam_sid); + return True; + } + default: + { + /* member or BDC, we're going for connection to PDC */ + break; + } + } + + if (!cli_connect_serverlist(&cli, lp_passwordserver())) + { + DEBUG(0,("get_member_domain_sid: unable to initialise client connection.\n")); + return False; + } + + /* + * Ok - we have an anonymous connection to the IPC$ share. + * Now start the NT Domain stuff :-). + */ + + fstrcpy(dom3, ""); + fstrcpy(dom5, ""); + ZERO_STRUCT(sid3); + ZERO_STRUCT(sid5); + + fstrcpy(srv_name, "\\\\"); + fstrcat(srv_name, global_myname); + strupper(srv_name); + + /* open LSARPC session. */ + res = res ? cli_nt_session_open(&cli, PIPE_LSARPC) : False; + + /* lookup domain controller; receive a policy handle */ + res = res ? do_lsa_open_policy(&cli, srv_name, &pol, False) : False; + + /* send client info query, level 3. receive domain name and sid */ + res = res ? do_lsa_query_info_pol(&cli, &pol, 3, dom3, &sid3) : False; + + /* send client info query, level 5. receive domain name and sid */ + res = res ? do_lsa_query_info_pol(&cli, &pol, 5, dom5, &sid5) : False; + + /* close policy handle */ + res = res ? do_lsa_close(&cli, &pol) : False; + + /* close the session */ + cli_nt_session_close(&cli); + cli_ulogoff(&cli); + cli_shutdown(&cli); + + if (res) + { + pstring sid; + DEBUG(2,("LSA Query Info Policy\n")); + sid_to_string(sid, &sid3); + DEBUG(2,("Domain Member - Domain: %s SID: %s\n", dom3, sid)); + sid_to_string(sid, &sid5); + DEBUG(2,("Domain Controller - Domain: %s SID: %s\n", dom5, sid)); + + if (!strequal(dom3, global_myworkgroup) || + !strequal(dom5, global_myworkgroup)) + { + DEBUG(0,("get_member_domain_sid: %s is a DC for %s not %s\n", + cli.desthost, dom5, global_myworkgroup)); + res = False; + } + } + else + { + DEBUG(1,("lsa query info failed\n")); + } + + if (!res) + { + DEBUG(0,("get_member_domain_sid: unable to obtain Domain member SID\n")); + } + else + { + /* this is a _lot_ of trouble to go to for just this info: */ + global_member_sid = sid5; + } + + return res; +} + +/**************************************************************************** + creates some useful well known sids +****************************************************************************/ +void generate_wellknown_sids(void) +{ + string_to_sid(&global_sid_S_1_5_20, "S-1-5-32"); + string_to_sid(&global_sid_S_1_1 , "S-1-1" ); + string_to_sid(&global_sid_S_1_3 , "S-1-3" ); + string_to_sid(&global_sid_S_1_5 , "S-1-5" ); +} + +/**************************************************************************** + 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 generate_sam_sid(void) +{ + int fd; + int i; + char *p; + pstring sid_file; + fstring sid_string; + SMB_STRUCT_STAT st; + uchar raw_sid_data[12]; + + pstrcpy(sid_file, lp_smb_passwd_file()); + p = strrchr(sid_file, '/'); + if (p != NULL) { + *++p = '\0'; + } + + if (!directory_exist(sid_file, NULL)) { + if (dos_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; + } + close(fd); + return True; + } + + /* + * Generate the new sid data & turn it into a string. + */ + generate_random_buffer( raw_sid_data, 12, True); + + fstrcpy( sid_string, "S-1-5-21"); + for( i = 0; i < 3; i++) { + fstring tmp_string; + slprintf( tmp_string, sizeof(tmp_string) - 1, "-%u", IVAL(raw_sid_data, i*4)); + fstrcat( sid_string, tmp_string); + } + + 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; + } + + /* + * 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. + * Write out out SID data into the file. + */ + + if (fchmod(fd, 0644) < 0) { + DEBUG(0,("unable to set correct permissions on file %s. \ +Error was %s\n", sid_file, strerror(errno) )); + 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) )); + close(fd); + return False; + } + + /* + * Unlock & exit. + */ + + do_file_lock( fd, 60, F_UNLCK); + close(fd); + return True; +} + +/************************************************************************** + turns a domain name into a SID. + + *** side-effect: if the domain name is NULL, it is set to our domain *** + +***************************************************************************/ +BOOL map_domain_name_to_sid(DOM_SID *sid, char **nt_domain) +{ + int i = 0; + + if (nt_domain == NULL) + { + sid_copy(sid, &global_sam_sid); + return True; + } + + if ((*nt_domain) == NULL) + { + DEBUG(5,("map_domain_name_to_sid: overriding NULL name to %s\n", + global_sam_name)); + (*nt_domain) = strdup(global_sam_name); + sid_copy(sid, &global_sam_sid); + return True; + } + + if ((*nt_domain)[0] == 0) + { + DEBUG(5,("map_domain_name_to_sid: overriding blank name to %s\n", + global_sam_name)); + free(*nt_domain); + (*nt_domain) = strdup(global_sam_name); + sid_copy(sid, &global_sam_sid); + return True; + } + + DEBUG(5,("map_domain_name_to_sid: %s\n", (*nt_domain))); + + while (sid_name_map[i].name != NULL) + { + DEBUG(5,("compare: %s\n", sid_name_map[i].name)); + if (strequal(sid_name_map[i].name, (*nt_domain))) + { + fstring sid_str; + sid_copy(sid, sid_name_map[i].sid); + sid_to_string(sid_str, sid_name_map[i].sid); + DEBUG(5,("found %s\n", sid_str)); + return True; + } + i++; + } + + DEBUG(0,("map_domain_name_to_sid: mapping to %s NOT IMPLEMENTED\n", + (*nt_domain))); + return False; +} + +/************************************************************************** + turns a domain SID into a name. + +***************************************************************************/ +BOOL map_domain_sid_to_name(DOM_SID *sid, char *nt_domain) +{ + fstring sid_str; + int i = 0; + sid_to_string(sid_str, sid); + + DEBUG(5,("map_domain_sid_to_name: %s\n", sid_str)); + + if (nt_domain == NULL) + { + return False; + } + + while (sid_name_map[i].sid != NULL) + { + sid_to_string(sid_str, sid_name_map[i].sid); + DEBUG(5,("compare: %s\n", sid_str)); + if (sid_equal(sid_name_map[i].sid, sid)) + { + fstrcpy(nt_domain, sid_name_map[i].name); + DEBUG(5,("found %s\n", nt_domain)); + return True; + } + i++; + } + + DEBUG(0,("map_domain_sid_to_name: mapping NOT IMPLEMENTED\n")); + + return False; +} + +/************************************************************************** + splits a name of format \DOMAIN\name into its two components. + sets the DOMAIN name to global_sam_name if it has not been specified. +***************************************************************************/ +BOOL split_domain_name(char *fullname, char *domain, char *name) +{ + fstring full_name; + char *p; + + if (fullname == NULL || domain == NULL || name == NULL) + { + return False; + } + + if (fullname[0] == '\\') + { + fullname++; + } + fstrcpy(full_name, fullname); + p = strchr(full_name+1, '\\'); + + if (p != NULL) + { + *p = 0; + fstrcpy(domain, full_name); + fstrcpy(name, p+1); + } + else + { + fstrcpy(domain, global_sam_name); + fstrcpy(name, full_name); + } + + DEBUG(5,("name '%s' split into '%s\\%s'\n", fullname, domain, name)); + return True; +} diff --git a/source3/lib/util_pwdb.c b/source3/lib/util_pwdb.c new file mode 100644 index 0000000000..50cc0510d8 --- /dev/null +++ b/source3/lib/util_pwdb.c @@ -0,0 +1,444 @@ +/* + 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; +extern fstring global_sam_name; +extern DOM_SID global_sid_S_1_5_20; +extern fstring global_myworkgroup; + +/* + * A list of the rids of well known BUILTIN and Domain users + * and groups. + */ + +rid_name builtin_alias_rids[] = +{ + { BUILTIN_ALIAS_RID_ADMINS , "Administrators" }, + { BUILTIN_ALIAS_RID_USERS , "Users" }, + { BUILTIN_ALIAS_RID_GUESTS , "Guests" }, + { BUILTIN_ALIAS_RID_POWER_USERS , "Power Users" }, + + { BUILTIN_ALIAS_RID_ACCOUNT_OPS , "Account Operators" }, + { BUILTIN_ALIAS_RID_SYSTEM_OPS , "System Operators" }, + { BUILTIN_ALIAS_RID_PRINT_OPS , "Print Operators" }, + { BUILTIN_ALIAS_RID_BACKUP_OPS , "Backup Operators" }, + { BUILTIN_ALIAS_RID_REPLICATOR , "Replicator" }, + { 0 , NULL } +}; + +/* array lookup of well-known Domain RID users. */ +rid_name domain_user_rids[] = +{ + { DOMAIN_USER_RID_ADMIN , "Administrator" }, + { DOMAIN_USER_RID_GUEST , "Guest" }, + { 0 , NULL } +}; + +/* array lookup of well-known Domain RID groups. */ +rid_name domain_group_rids[] = +{ + { DOMAIN_GROUP_RID_ADMINS , "Domain Admins" }, + { DOMAIN_GROUP_RID_USERS , "Domain Users" }, + { DOMAIN_GROUP_RID_GUESTS , "Domain Guests" }, + { 0 , NULL } +}; + + +/******************************************************************* + lookup_wk_group_name + ********************************************************************/ +uint32 lookup_wk_group_name(const char *group_name, const char *domain, + DOM_SID *sid, uint8 *type) +{ + char *grp_name; + int i = -1; /* start do loop at -1 */ + uint32 rid; + (*type) = SID_NAME_WKN_GRP; + + if (strequal(domain, global_sam_name)) + { + sid_copy(sid, &global_sam_sid); + } + else if (strequal(domain, "BUILTIN")) + { + sid_copy(sid, &global_sid_S_1_5_20); + } + else + { + return 0xC0000000 | NT_STATUS_NONE_MAPPED; + } + + do /* find, if it exists, a group rid for the group name */ + { + i++; + rid = domain_group_rids[i].rid; + grp_name = domain_group_rids[i].name; + + if (strequal(grp_name, group_name)) + { + sid_append_rid(sid, rid); + + return 0x0; + } + + } while (grp_name != NULL); + + return 0xC0000000 | NT_STATUS_NONE_MAPPED; +} + +/******************************************************************* + lookup_wk_user_name + ********************************************************************/ +uint32 lookup_wk_user_name(const char *user_name, const char *domain, + DOM_SID *sid, uint8 *type) +{ + char *usr_name; + int i = -1; /* start do loop at -1 */ + (*type) = SID_NAME_USER; + + if (strequal(domain, global_sam_name)) + { + sid_copy(sid, &global_sam_sid); + } + else if (strequal(domain, "BUILTIN")) + { + sid_copy(sid, &global_sid_S_1_5_20); + } + else + { + return 0xC0000000 | NT_STATUS_NONE_MAPPED; + } + + do /* find, if it exists, a alias rid for the alias name */ + { + i++; + usr_name = domain_user_rids[i].name; + + } while (usr_name != NULL && !strequal(usr_name, user_name)); + + if (usr_name != NULL) + { + sid_copy(sid, &global_sid_S_1_5_20); + sid_append_rid(sid, domain_user_rids[i].rid); + return 0; + } + + return 0xC0000000 | NT_STATUS_NONE_MAPPED; +} + +/******************************************************************* + lookup_builtin_alias_name + ********************************************************************/ +uint32 lookup_builtin_alias_name(const char *alias_name, const char *domain, + DOM_SID *sid, uint8 *type) +{ + char *als_name; + int i = 0; + uint32 rid; + + if (strequal(domain, "BUILTIN")) + { + if (sid != NULL) + { + sid_copy(sid, &global_sid_S_1_5_20); + } + } + else + { + return 0xC0000000 | NT_STATUS_NONE_MAPPED; + } + + do /* find, if it exists, a alias rid for the alias name*/ + { + rid = builtin_alias_rids[i].rid; + als_name = builtin_alias_rids[i].name; + + i++; + + if (strequal(als_name, alias_name)) + { + if (sid != NULL) + { + sid_append_rid(sid, rid); + } + + if (type != NULL) + { + (*type) = SID_NAME_ALIAS; + } + + return 0x0; + } + + } while (als_name != NULL); + + return 0xC0000000 | NT_STATUS_NONE_MAPPED; +} +/********************************************************** + 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 *pwdb_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] = ' '; + } + + 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 pwdb_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++) + { + 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; } + } + } + + return acct_ctrl; +} + +/******************************************************************* + gets password-database-format time from a string. + ********************************************************************/ + +static time_t get_time_from_string(const char *p) +{ + int i; + + for (i = 0; i < 8; i++) + { + 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); + } + return (time_t)-1; +} + +/******************************************************************* + gets password last set time + ********************************************************************/ + +time_t pwdb_get_last_set_time(const char *p) +{ + if (*p && StrnCaseCmp(p, "LCT-", 4)) + { + return get_time_from_string(p + 4); + } + return (time_t)-1; +} + + +/******************************************************************* + 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 pwdb_set_logon_time(char *p, int max_len, time_t t) +{ + set_time_in_string(p, max_len, "LNT", t); +} + +/******************************************************************* + sets logoff time + ********************************************************************/ +void pwdb_set_logoff_time(char *p, int max_len, time_t t) +{ + set_time_in_string(p, max_len, "LOT", t); +} + +/******************************************************************* + sets kickoff time + ********************************************************************/ +void pwdb_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 pwdb_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 pwdb_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 pwdb_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 pwdb_sethexpwd(char *p, const char *pwd, uint16 acct_ctrl) +{ + if (pwd != NULL) + { + int i; + for (i = 0; i < 16; i++) + { + slprintf(&p[i*2], 33, "%02X", pwd[i]); + } + } + else + { + 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 pwdb_gethexpwd(const char *p, char *pwd) +{ + return strhex_to_str(pwd, 32, p) == 16; +} + +/************************************************************* + initialise password databases, domain names, domain sid. +**************************************************************/ +BOOL pwdb_initialise(void) +{ + fstrcpy(global_myworkgroup, lp_workgroup()); + + if (strequal(global_myworkgroup,"*")) + { + DEBUG(0,("ERROR: a workgroup name of * is no longer supported\n")); + return False; + } + + get_sam_domain_name(); + + generate_wellknown_sids(); + + if (!generate_sam_sid()) + { + DEBUG(0,("ERROR: Samba cannot create a SAM SID.\n")); + return False; + } + + if(!initialise_password_db()) + return False; + + return True; +} diff --git a/source3/passdb/sampass.c b/source3/passdb/sampass.c new file mode 100644 index 0000000000..967e0502e3 --- /dev/null +++ b/source3/passdb/sampass.c @@ -0,0 +1,198 @@ +/* + * Unix SMB/Netbios implementation. Version 1.9. SMB parameters and setup + * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995. + * + * 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" + +#ifdef USE_SMBPASS_DB + +extern int DEBUGLEVEL; +extern pstring samlogon_user; +extern BOOL sam_logon_in_ssb; + +extern DOM_SID global_sam_sid; + +/*************************************************************** + Start to enumerate the smbpasswd list. Returns a void pointer + to ensure no modification outside this module. +****************************************************************/ + +void *startsamfilepwent(BOOL update) +{ + return startsmbpwent(update); +} + +/*************************************************************** + End enumeration of the smbpasswd list. +****************************************************************/ + +void endsamfilepwent(void *vp) +{ + endsmbpwent(vp); +} + +/************************************************************************* + Return the current position in the smbpasswd list as an SMB_BIG_UINT. + This must be treated as an opaque token. +*************************************************************************/ + +SMB_BIG_UINT getsamfilepwpos(void *vp) +{ + return getsmbpwpos(vp); +} + +/************************************************************************* + Set the current position in the smbpasswd list from an SMB_BIG_UINT. + This must be treated as an opaque token. +*************************************************************************/ + +BOOL setsamfilepwpos(void *vp, SMB_BIG_UINT tok) +{ + return setsmbpwpos(vp, tok); +} + +/************************************************************************* + Routine to return the next entry in the smbpasswd list. + this function is a nice, messy combination of reading: + - the smbpasswd file + - the unix password database + - smb.conf options (not done at present). + *************************************************************************/ + +static struct sam_passwd *getsamfile21pwent(void *vp) +{ + struct sam_passwd *user; + + static pstring full_name; + static pstring home_dir; + static pstring home_drive; + static pstring logon_script; + static pstring profile_path; + static pstring acct_desc; + static pstring workstations; + + DEBUG(5,("getsamfile21pwent\n")); + + user = pwdb_smb_to_sam(getsmbpwent(vp)); + if (user == NULL) + { + return NULL; + } + + /* + * get all the other gubbins we need + */ + + pstrcpy(samlogon_user, user->nt_name); + + if (samlogon_user[strlen(samlogon_user)-1] == '$' && + user->group_rid != DOMAIN_GROUP_RID_USERS) + { + DEBUG(0,("trust account %s should be in DOMAIN_GROUP_RID_USERS\n", + samlogon_user)); + } + + /* XXXX hack to get standard_sub_basic() to use sam logon username */ + /* possibly a better way would be to do a become_user() call */ + sam_logon_in_ssb = True; + + pstrcpy(full_name , ""); + pstrcpy(logon_script , lp_logon_script ()); + pstrcpy(profile_path , lp_logon_path ()); + pstrcpy(home_drive , lp_logon_drive ()); + pstrcpy(home_dir , lp_logon_home ()); + pstrcpy(acct_desc , ""); + pstrcpy(workstations , ""); + + sam_logon_in_ssb = False; + + user->full_name = full_name; + user->home_dir = home_dir; + user->dir_drive = home_drive; + user->logon_script = logon_script; + user->profile_path = profile_path; + user->acct_desc = acct_desc; + user->workstations = workstations; + + user->unknown_str = NULL; /* don't know, yet! */ + user->munged_dial = NULL; /* "munged" dial-back telephone number */ + + user->unknown_3 = 0xffffff; /* don't know */ + user->logon_divs = 168; /* hours per week */ + user->hours_len = 21; /* 21 times 8 bits = 168 */ + memset(user->hours, 0xff, user->hours_len); /* available at all hours */ + user->unknown_5 = 0x00020000; /* don't know */ + user->unknown_6 = 0x000004ec; /* don't know */ + + return user; +} + +/* + * Stub functions - implemented in terms of others. + */ + +static BOOL mod_samfile21pwd_entry(struct sam_passwd* pwd, BOOL override) +{ + return mod_smbpwd_entry(pwdb_sam_to_smb(pwd), override); +} + +static BOOL add_samfile21pwd_entry(struct sam_passwd *newpwd) +{ + return add_smbpwd_entry(pwdb_sam_to_smb(newpwd)); +} + +static struct sam_disp_info *getsamfiledispntnam(const char *name) +{ + return pwdb_sam_to_dispinfo(getsam21pwntnam(name)); +} + +static struct sam_disp_info *getsamfiledisprid(uint32 rid) +{ + return pwdb_sam_to_dispinfo(getsam21pwrid(rid)); +} + +static struct sam_disp_info *getsamfiledispent(void *vp) +{ + return pwdb_sam_to_dispinfo(getsam21pwent(vp)); +} + +static struct sam_passdb_ops file_ops = { + startsamfilepwent, + endsamfilepwent, + getsamfilepwpos, + setsamfilepwpos, + iterate_getsam21pwntnam, + iterate_getsam21pwuid, + iterate_getsam21pwrid, + getsamfile21pwent, + add_samfile21pwd_entry, + mod_samfile21pwd_entry, + getsamfiledispntnam, + getsamfiledisprid, + getsamfiledispent +}; + +struct sam_passdb_ops *file_initialise_sam_password_db(void) +{ + return &file_ops; +} + +#else + /* Do *NOT* make this function static. It breaks the compile on gcc. JRA */ + void sampass_dummy_function(void) { } /* stop some compilers complaining */ +#endif /* USE_SMBPASS_DB */ diff --git a/source3/passdb/sampassdb.c b/source3/passdb/sampassdb.c new file mode 100644 index 0000000000..95055ed298 --- /dev/null +++ b/source3/passdb/sampassdb.c @@ -0,0 +1,515 @@ +/* + 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 *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->nt_name, name)) + { + DEBUG(10, ("iterate: %s 0x%x\n", pwd->nt_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->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); + + /* + * 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)) + { + 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); + + return sam; +} diff --git a/source3/rpc_server/srv_sid.c b/source3/rpc_server/srv_sid.c index a428a7f068..6552e0963b 100644 --- a/source3/rpc_server/srv_sid.c +++ b/source3/rpc_server/srv_sid.c @@ -19,523 +19,4 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "includes.h" - - -extern int DEBUGLEVEL; -extern pstring scope; -extern pstring global_myname; - -/* - * This is set on startup - it defines the SID for this - * machine, and therefore the SAM database for which it is - * responsible. - */ - -DOM_SID global_sam_sid; - -/* - * This is the name associated with the SAM database for - * which this machine is responsible. In the case of a PDC - * or PDC, this name is the same as the workgroup. In the - * case of "security = domain" mode, this is the same as - * the name of the server (global_myname). - */ - -fstring global_sam_name; - -/* - * This is obtained on startup - it defines the SID for which - * this machine is a member. It is therefore only set, and - * used, in "security = domain" mode. - */ - -DOM_SID global_member_sid; - -/* - * note the lack of a "global_member_name" - this is because - * this is the same as "global_myworkgroup". - */ - -/* - * some useful sids - */ - -DOM_SID global_sid_S_1_5_20; /* local well-known domain */ -DOM_SID global_sid_S_1_1; /* everyone */ -DOM_SID global_sid_S_1_3; /* */ -DOM_SID global_sid_S_1_5; /* NT Authority */ - -extern fstring global_myworkgroup; -/* extern fstring global_member_dom_name; */ - -static struct sid_name_map_info -{ - DOM_SID *sid; - char *name; - -} -sid_name_map[] = -{ - { &global_sid_S_1_5_20, "BUILTIN" }, - { &global_sid_S_1_1 , "Everyone" }, - { &global_sid_S_1_3 , "don't know" }, - { &global_sid_S_1_5 , "NT Authority" }, - { &global_sam_sid , global_sam_name }, - { &global_member_sid , global_myworkgroup }, - { NULL , NULL } -}; - -/**************************************************************************** - Read the machine SID from a file. -****************************************************************************/ - -static BOOL read_sid_from_file(int fd, char *sid_file) -{ - fstring fline; - fstring sid_str; - - 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; - } - - sid_to_string(sid_str, &global_sam_sid); - DEBUG(5,("read_sid_from_file: sid %s\n", sid_str)); - - return True; -} - -/**************************************************************************** - sets up the name associated with the SAM database for which we are responsible -****************************************************************************/ -void get_sam_domain_name(void) -{ - switch (lp_server_role()) - { - case ROLE_DOMAIN_PDC: - case ROLE_DOMAIN_BDC: - { - /* we are PDC (or BDC) for a Domain */ - fstrcpy(global_sam_name, lp_workgroup()); - break; - } - case ROLE_DOMAIN_MEMBER: - { - /* we are a "PDC", but FOR LOCAL SAM DATABASE ONLY */ - fstrcpy(global_sam_name, global_myname); - break; - } - default: - { - /* no domain role, probably due to "security = share" */ - memset(global_sam_name, 0, sizeof(global_sam_name)); - break; - } - } -} - -/**************************************************************************** - obtain the sid from the PDC. do some verification along the way... -****************************************************************************/ -BOOL get_member_domain_sid(void) -{ - POLICY_HND pol; - fstring srv_name; - struct cli_state cli; - BOOL res = True; - DOM_SID sid3; - DOM_SID sid5; - fstring dom3; - fstring dom5; - - switch (lp_server_role()) - { - case ROLE_DOMAIN_NONE: - { - ZERO_STRUCT(global_member_sid); - return True; - } - case ROLE_DOMAIN_PDC: - { - sid_copy(&global_member_sid, &global_sam_sid); - return True; - } - default: - { - /* member or BDC, we're going for connection to PDC */ - break; - } - } - - if (!cli_connect_serverlist(&cli, lp_passwordserver())) - { - DEBUG(0,("get_member_domain_sid: unable to initialise client connection.\n")); - return False; - } - - /* - * Ok - we have an anonymous connection to the IPC$ share. - * Now start the NT Domain stuff :-). - */ - - fstrcpy(dom3, ""); - fstrcpy(dom5, ""); - ZERO_STRUCT(sid3); - ZERO_STRUCT(sid5); - - fstrcpy(srv_name, "\\\\"); - fstrcat(srv_name, global_myname); - strupper(srv_name); - - /* open LSARPC session. */ - res = res ? cli_nt_session_open(&cli, PIPE_LSARPC) : False; - - /* lookup domain controller; receive a policy handle */ - res = res ? do_lsa_open_policy(&cli, srv_name, &pol, False) : False; - - /* send client info query, level 3. receive domain name and sid */ - res = res ? do_lsa_query_info_pol(&cli, &pol, 3, dom3, &sid3) : False; - - /* send client info query, level 5. receive domain name and sid */ - res = res ? do_lsa_query_info_pol(&cli, &pol, 5, dom5, &sid5) : False; - - /* close policy handle */ - res = res ? do_lsa_close(&cli, &pol) : False; - - /* close the session */ - cli_nt_session_close(&cli); - cli_ulogoff(&cli); - cli_shutdown(&cli); - - if (res) - { - pstring sid; - DEBUG(2,("LSA Query Info Policy\n")); - sid_to_string(sid, &sid3); - DEBUG(2,("Domain Member - Domain: %s SID: %s\n", dom3, sid)); - sid_to_string(sid, &sid5); - DEBUG(2,("Domain Controller - Domain: %s SID: %s\n", dom5, sid)); - - if (!strequal(dom3, global_myworkgroup) || - !strequal(dom5, global_myworkgroup)) - { - DEBUG(0,("get_member_domain_sid: %s is a DC for %s not %s\n", - cli.desthost, dom5, global_myworkgroup)); - res = False; - } - } - else - { - DEBUG(1,("lsa query info failed\n")); - } - if (!res) - { - DEBUG(0,("get_member_domain_sid: unable to obtain Domain member SID\n")); - } - else - { - /* this is a _lot_ of trouble to go to for just this info: */ - global_member_sid = sid5; - } - - return res; -} - -/**************************************************************************** - creates some useful well known sids -****************************************************************************/ -void generate_wellknown_sids(void) -{ - string_to_sid(&global_sid_S_1_5_20, "S-1-5-32"); - string_to_sid(&global_sid_S_1_1 , "S-1-1" ); - string_to_sid(&global_sid_S_1_3 , "S-1-3" ); - string_to_sid(&global_sid_S_1_5 , "S-1-5" ); -} - -/**************************************************************************** - 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 generate_sam_sid(void) -{ - int fd; - int i; - char *p; - pstring sid_file; - fstring sid_string; - SMB_STRUCT_STAT st; - uchar raw_sid_data[12]; - - pstrcpy(sid_file, lp_smb_passwd_file()); - p = strrchr(sid_file, '/'); - if (p != NULL) { - *++p = '\0'; - } - - if (!directory_exist(sid_file, NULL)) { - if (dos_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; - } - close(fd); - return True; - } - - /* - * Generate the new sid data & turn it into a string. - */ - generate_random_buffer( raw_sid_data, 12, True); - - fstrcpy( sid_string, "S-1-5-21"); - for( i = 0; i < 3; i++) { - fstring tmp_string; - slprintf( tmp_string, sizeof(tmp_string) - 1, "-%u", IVAL(raw_sid_data, i*4)); - fstrcat( sid_string, tmp_string); - } - - 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; - } - - /* - * 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. - * Write out out SID data into the file. - */ - - if (fchmod(fd, 0644) < 0) { - DEBUG(0,("unable to set correct permissions on file %s. \ -Error was %s\n", sid_file, strerror(errno) )); - 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) )); - close(fd); - return False; - } - - /* - * Unlock & exit. - */ - - do_file_lock( fd, 60, F_UNLCK); - close(fd); - return True; -} - -/************************************************************************** - turns a domain name into a SID. - - *** side-effect: if the domain name is NULL, it is set to our domain *** - -***************************************************************************/ -BOOL map_domain_name_to_sid(DOM_SID *sid, char **nt_domain) -{ - if (nt_domain == NULL) - { - *sid = global_sam_sid; - return True; - } - - if ((*nt_domain) == NULL) - { - DEBUG(5,("map_domain_name_to_sid: overriding NULL name to %s\n", - global_sam_name)); - (*nt_domain) = strdup(global_sam_name); - sid_copy(sid, &global_sam_sid); - return True; - } - - if ((*nt_domain)[0] == 0) - { - DEBUG(5,("map_domain_name_to_sid: overriding blank name to %s\n", - global_sam_name)); - free(*nt_domain); - (*nt_domain) = strdup(global_sam_name); - sid_copy(sid, &global_sam_sid); - return True; - } - - if (strequal((*nt_domain), global_sam_name)) - { - sid_copy(sid, &global_sam_sid); - return True; - } - - DEBUG(0,("map_domain_name_to_sid: mapping to %s NOT IMPLEMENTED\n", - (*nt_domain))); - return False; -} - -/************************************************************************** - turns a domain SID into a name. - -***************************************************************************/ -BOOL map_domain_sid_to_name(DOM_SID *sid, char *nt_domain) -{ - fstring sid_str; - int i = 0; - sid_to_string(sid_str, sid); - - DEBUG(5,("map_domain_sid_to_name: %s\n", sid_str)); - - if (nt_domain == NULL) - { - return False; - } - - while (sid_name_map[i].sid != NULL) - { - sid_to_string(sid_str, sid_name_map[i].sid); - DEBUG(5,("compare: %s\n", sid_str)); - if (sid_equal(sid_name_map[i].sid, sid)) - { - fstrcpy(nt_domain, sid_name_map[i].name); - DEBUG(5,("found %s\n", nt_domain)); - return True; - } - i++; - } - - DEBUG(0,("map_domain_sid_to_name: mapping NOT IMPLEMENTED\n")); - - return False; -} - -/************************************************************************** - splits a name of format \DOMAIN\name into its two components. - sets the DOMAIN name to global_sam_name if it has not been specified. -***************************************************************************/ -BOOL split_domain_name(char *fullname, char *domain, char *name) -{ - fstring full_name; - char *p; - - if (fullname == NULL || domain == NULL || name == NULL) - { - return False; - } - - if (fullname[0] == '\\') - { - fullname++; - } - fstrcpy(full_name, fullname); - p = strchr(full_name+1, '\\'); - - if (p != NULL) - { - *p = 0; - fstrcpy(domain, full_name); - fstrcpy(name, p+1); - } - else - { - fstrcpy(domain, global_sam_name); - fstrcpy(name, full_name); - } - - DEBUG(5,("name '%s' split into '\\%s\\%s'\n", fullname, domain, name)); - return True; -} +/* this module is retired, is is called lib/sids.c */ diff --git a/source3/smbd/groupname.c b/source3/smbd/groupname.c index a81114169c..0be558848a 100644 --- a/source3/smbd/groupname.c +++ b/source3/smbd/groupname.c @@ -19,641 +19,4 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* - * UNIX gid and Local or Domain SID resolution. This module resolves - * only those entries in the map files, it is *NOT* responsible for - * resolving UNIX groups not listed: that is an entirely different - * matter, altogether... - */ - -/* - * - * - - format of the file is: - - unixname NT Group name - unixname Domain Admins (well-known Domain Group) - unixname DOMAIN_NAME\NT Group name - unixname OTHER_DOMAIN_NAME\NT Group name - unixname DOMAIN_NAME\Domain Admins (well-known Domain Group) - .... - - if the DOMAIN_NAME\ component is left off, then your own domain is assumed. - - * - * - */ - - -#include "includes.h" -extern int DEBUGLEVEL; - -extern fstring global_sam_name; - -/* we can map either local aliases or domain groups */ -typedef enum -{ - GROUP_LOCAL, - GROUP_DOMAIN - -} GROUP_TYPE; - -/************************************************************************** - Groupname map functionality. The code loads a groupname map file and - (currently) loads it into a linked list. This is slow and memory - hungry, but can be changed into a more efficient storage format - if the demands on it become excessive. -***************************************************************************/ - -typedef struct group_name_info -{ - char *nt_name; - char *nt_domain; - char *unix_name; - - DOM_SID sid; - gid_t unix_gid; - -} GROUP_NAME_INFO; - -typedef struct name_map -{ - ubi_slNode next; - GROUP_NAME_INFO grp; - -} name_map_entry; - -static ubi_slList groupname_map_list; -static ubi_slList aliasname_map_list; - -static void delete_name_entry(name_map_entry *gmep) -{ - if (gmep->grp.nt_name) - { - free(gmep->grp.nt_name); - } - if (gmep->grp.nt_domain) - { - free(gmep->grp.nt_domain); - } - if (gmep->grp.unix_name) - { - free(gmep->grp.unix_name); - } - free((char*)gmep); -} - -/************************************************************************** - Delete all the entries in the name map list. -***************************************************************************/ - -static void delete_map_list(ubi_slList *map_list) -{ - name_map_entry *gmep; - - while ((gmep = (name_map_entry *)ubi_slRemHead(map_list )) != NULL) - { - delete_name_entry(gmep); - } -} - - -/************************************************************************** - makes a group sid out of a domain sid and a _unix_ gid. -***************************************************************************/ -static BOOL make_mydomain_sid(GROUP_NAME_INFO *grp, GROUP_TYPE type) -{ - uint32 tmp_rid; - DOM_SID sid; - uint8 tmp_type; - - DEBUG(10,("make_mydomain_sid\n")); - - if (!map_domain_name_to_sid(&grp->sid, &(grp->nt_domain))) - { - DEBUG(0,("make_mydomain_sid: unknown domain %s\n", - grp->nt_domain)); - return False; - } - - if (strequal(grp->nt_domain, global_sam_name) && - lookup_builtin_grp_name(grp->nt_name, &sid, &tmp_type) == 0x0) - { - sid_copy(&grp->sid, &sid); - return True; - } - else - { - BOOL ret; - fstring sid_str; - if (type == GROUP_DOMAIN) - { - tmp_rid = pwdb_gid_to_group_rid(grp->unix_gid); - } - else - { - tmp_rid = pwdb_gid_to_alias_rid(grp->unix_gid); - } - ret = sid_append_rid(&(grp->sid), tmp_rid); - sid_to_string(sid_str, &grp->sid); - DEBUG(10,("nt name %s gid %d mapped to %s\n", - grp->nt_name, grp->unix_gid, sid_str)); - return ret; - } -} - -/************************************************************************** - makes a group sid out of an nt domain, nt group name or a unix group name. -***************************************************************************/ -static BOOL unix_name_to_group_info(GROUP_NAME_INFO *grp, GROUP_TYPE type) -{ - struct group *gptr = NULL; - - /* - * Attempt to get the unix gid_t for this name. - */ - - DEBUG(5,("unix_name_to_group_info: unix_name:%s\n", grp->unix_name)); - - gptr = (struct group *)getgrnam(grp->unix_name); - if (gptr == NULL) - { - DEBUG(0,("unix_name_to_group_info: getgrnam for group %s\ -failed. Error was %s.\n", grp->unix_name, strerror(errno) )); - return False; - } - - grp->unix_gid = (gid_t)gptr->gr_gid; - - DEBUG(5,("unix_name_to_group_info: unix gid:%d\n", grp->unix_gid)); - - /* - * Now map the name to an NT SID+RID. - */ - - if (grp->nt_domain != NULL && !strequal(grp->nt_domain, global_sam_name)) - { - /* Must add client-call lookup code here, to - * resolve remote domain's sid and the group's rid, - * in that domain. - * - * NOTE: it is _incorrect_ to put code here that assumes - * that we can call pwdb_gid_to_group_rid() or _alias_rid(): - * it is a totally different domain for which we are *NOT* - * responsible. - * for foriegn domains for which we are *NOT* the PDC, all - * we can be responsible for is the unix * gid_t to which - * the foriegn SID+rid maps to, on this _local_ machine. - */ - - if (!map_domain_name_to_sid(&grp->sid, &(grp->nt_domain))) - { - DEBUG(0,("unix_name_to_group_info: no known sid for %s\n", - grp->nt_domain)); - return False; - } - } - - return make_mydomain_sid(grp, type); -} - -static BOOL make_name_entry(name_map_entry **new_ep, - char *nt_domain, char *nt_group, char *unix_group, - GROUP_TYPE type) -{ - /* - * Create the list entry and add it onto the list. - */ - - DEBUG(5,("make_name_entry:%s,%s,%s\n", nt_domain, nt_group, unix_group)); - - (*new_ep) = (name_map_entry *)malloc(sizeof(name_map_entry)); - if ((*new_ep) == NULL) - { - DEBUG(0,("make_name_entry: malloc fail for name_map_entry.\n")); - return False; - } - - ZERO_STRUCTP(*new_ep); - - (*new_ep)->grp.nt_name = strdup(nt_group ); - (*new_ep)->grp.nt_domain = strdup(nt_domain ); - (*new_ep)->grp.unix_name = strdup(unix_group); - - if ((*new_ep)->grp.nt_name == NULL || - (*new_ep)->grp.unix_name == NULL) - { - DEBUG(0,("make_name_entry: malloc fail for names in name_map_entry.\n")); - delete_name_entry((*new_ep)); - return False; - } - - /* - * look up the group names, make the Group-SID and unix gid - */ - - if (!unix_name_to_group_info(&(*new_ep)->grp, type)) - { - delete_name_entry((*new_ep)); - return False; - } - - return True; -} - -/************************************************************************** - Load a name map file. Sets last accessed timestamp. -***************************************************************************/ -static ubi_slList *load_name_map(GROUP_TYPE type) -{ - static time_t groupmap_file_last_modified = (time_t)0; - static time_t aliasmap_file_last_modified = (time_t)0; - static BOOL initialised_group = False; - static BOOL initialised_alias = False; - char *groupname_map_file = lp_groupname_map(); - char *aliasname_map_file = lp_aliasname_map(); - - SMB_STRUCT_STAT st; - FILE *fp; - char *s; - pstring buf; - name_map_entry *new_ep; - - time_t *file_last_modified; - int *initialised; - char *map_file; - ubi_slList *map_list; - - if (type == GROUP_DOMAIN) - { - file_last_modified = &groupmap_file_last_modified; - initialised = &initialised_group; - map_file = groupname_map_file; - map_list = &groupname_map_list; - } - else - { - file_last_modified = &aliasmap_file_last_modified; - initialised = &initialised_alias; - map_file = aliasname_map_file; - map_list = &aliasname_map_list; - } - - if (!(*initialised)) - { - DEBUG(10,("initialising group map %s\n", map_file)); - ubi_slInitList(map_list); - (*initialised) = True; - } - - if (!*map_file) - { - return map_list; - } - - if (sys_stat(map_file, &st) != 0) - { - DEBUG(0, ("load_name_map: Unable to stat file %s. Error was %s\n", - map_file, strerror(errno) )); - return map_list; - } - - /* - * Check if file has changed. - */ - if (st.st_mtime <= (*file_last_modified)) - { - return map_list; - } - - (*file_last_modified) = st.st_mtime; - - /* - * Load the file. - */ - - fp = fopen(map_file,"r"); - if (!fp) - { - DEBUG(0,("load_name_map: can't open name map %s. Error was %s\n", - map_file, strerror(errno))); - return map_list; - } - - /* - * Throw away any previous list. - */ - delete_map_list(map_list); - - DEBUG(4,("load_name_map: Scanning name map %s\n",map_file)); - - while ((s = fgets_slash(buf, sizeof(buf), fp)) != NULL) - { - pstring unixname; - pstring nt_name; - fstring nt_domain; - fstring nt_group; - char *p; - - DEBUG(10,("Read line |%s|\n", s)); - - memset(nt_name, 0, sizeof(nt_name)); - - if (!*s || strchr("#;",*s)) - continue; - - if (!next_token(&s,unixname, "\t\n\r=", sizeof(unixname))) - continue; - - if (!next_token(&s,nt_name, "\t\n\r=", sizeof(nt_name))) - continue; - - trim_string(unixname, " ", " "); - trim_string(nt_name, " ", " "); - - if (!*nt_name) - continue; - - if (!*unixname) - continue; - - DEBUG(5,("unixname = %s, ntname = %s.\n", - unixname, nt_name)); - - p = strchr(nt_name, '\\'); - - if (p == NULL) - { - memset(nt_domain, 0, sizeof(nt_domain)); - fstrcpy(nt_group, nt_name); - } - else - { - *p = 0; - p++; - fstrcpy(nt_domain, nt_name); - fstrcpy(nt_group , p); - } - - if (make_name_entry(&new_ep, nt_domain, nt_name, unixname, type)) - { - ubi_slAddTail(map_list, (ubi_slNode *)new_ep); - } - } - - DEBUG(10,("load_name_map: Added %ld entries to name map.\n", - ubi_slCount(map_list))); - - fclose(fp); - - return map_list; -} - -/*********************************************************** - Lookup by SID -************************************************************/ -static BOOL map_sid(GROUP_TYPE type, - DOM_SID *psid, gid_t *gid, char *ntname, char *ntdomain) -{ - name_map_entry *gmep; - ubi_slList *map_list; - - /* - * Initialise and load if not already loaded. - */ - map_list = load_name_map(type); - - for (gmep = (name_map_entry *)ubi_slFirst(map_list); - gmep != NULL; - gmep = (name_map_entry *)ubi_slNext(gmep )) - { - if (sid_equal(&gmep->grp.sid, psid)) - { - if (gid != NULL) - { - *gid = gmep->grp.unix_gid; - } - if (ntname != NULL) - { - fstrcpy(ntname, gmep->grp.nt_name); - } - if (ntdomain != NULL) - { - fstrcpy(ntdomain, gmep->grp.nt_domain); - } - DEBUG(7,("map_sid: Mapping unix group %s to nt group %s.\n", - gmep->grp.unix_name, gmep->grp.nt_name )); - return True; - } - } - - return False; -} - -/*********************************************************** - Lookup nt name. -************************************************************/ -static BOOL map_ntname(GROUP_TYPE type, - char *ntname, char *ntdomain, DOM_SID *psid, - char *unixname, gid_t *gid) -{ - name_map_entry *gmep; - ubi_slList *map_list; - - /* - * Initialise and load if not already loaded. - */ - map_list = load_name_map(type); - - for (gmep = (name_map_entry *)ubi_slFirst(map_list); - gmep != NULL; - gmep = (name_map_entry *)ubi_slNext(gmep )) - { - if (strequal(gmep->grp.nt_name , ntname) && - strequal(gmep->grp.nt_domain, ntdomain)) - { - if (psid != NULL) - { - sid_copy(psid, &gmep->grp.sid); - } - if (gid != NULL) - { - *gid = gmep->grp.unix_gid; - } - if (unixname != NULL) - { - fstrcpy(unixname, gmep->grp.unix_name); - } - DEBUG(7,("map_ntname: Mapping unix group %s to nt group %s.\n", - gmep->grp.unix_name, gmep->grp.nt_name )); - return True; - } - } - - return False; -} - -/*********************************************************** - Lookup unix name. -************************************************************/ -static BOOL map_unixname(GROUP_TYPE type, - char *unixname, DOM_SID *psid, char *ntname, char *ntdomain) -{ - name_map_entry *gmep; - ubi_slList *map_list; - - /* - * Initialise and load if not already loaded. - */ - map_list = load_name_map(type); - - for (gmep = (name_map_entry *)ubi_slFirst(map_list); - gmep != NULL; - gmep = (name_map_entry *)ubi_slNext(gmep )) - { - if (strequal(gmep->grp.unix_name, unixname)) - { - if (psid != NULL) - { - sid_copy(psid, &gmep->grp.sid); - } - if (ntname != NULL) - { - fstrcpy(ntname, gmep->grp.nt_name); - } - if (ntdomain != NULL) - { - fstrcpy(ntdomain, gmep->grp.nt_domain); - } - DEBUG(7,("map_unixname: Mapping unix group %s to nt group %s.\n", - gmep->grp.unix_name, gmep->grp.nt_name )); - return True; - } - } - - return False; -} - -/*********************************************************** - Lookup by gid_t. -************************************************************/ -static BOOL map_gid(GROUP_TYPE type, - gid_t gid, DOM_SID *psid, char *ntname, char *ntdomain) -{ - name_map_entry *gmep; - ubi_slList *map_list; - - /* - * Initialise and load if not already loaded. - */ - map_list = load_name_map(type); - - for (gmep = (name_map_entry *)ubi_slFirst(map_list); - gmep != NULL; - gmep = (name_map_entry *)ubi_slNext(gmep )) - { - fstring sid_str; - sid_to_string(sid_str, &gmep->grp.sid); - DEBUG(10,("map_gid: enum entry unix group %s %d nt %s %s\n", - gmep->grp.unix_name, gmep->grp.unix_gid, gmep->grp.nt_name, sid_str)); - if (gmep->grp.unix_gid == gid) - { - if (psid != NULL) - { - sid_copy(psid, &gmep->grp.sid); - } - if (ntname != NULL) - { - fstrcpy(ntname, gmep->grp.nt_name); - } - if (ntdomain != NULL) - { - fstrcpy(ntdomain, gmep->grp.nt_domain); - } - DEBUG(7,("map_gid: Mapping unix group %s to nt group %s.\n", - gmep->grp.unix_name, gmep->grp.nt_name )); - return True; - } - } - - return False; -} - -/*********************************************************** - * - * Call four functions to resolve unix group ids and either - * local group SIDs or domain group SIDs listed in the local group - * or domain group map files. - * - * Note that it is *NOT* the responsibility of these functions to - * resolve entries that are not in the map files. - * - * Any SID can be in the map files (i.e from any Domain). - * - ***********************************************************/ - -/*********************************************************** - Lookup a Group entry by sid. -************************************************************/ -BOOL map_group_sid(DOM_SID *psid, gid_t *gid, char *group_name, char *nt_domain) -{ - return map_sid(GROUP_DOMAIN, psid, gid, group_name, nt_domain); -} - -/*********************************************************** - Lookup an Alias SID entry by name. -************************************************************/ -BOOL map_alias_sid(DOM_SID *psid, gid_t *gid, char *alias_name, char *nt_domain) -{ - return map_sid(GROUP_LOCAL, psid, gid, alias_name, nt_domain); -} - -/*********************************************************** - Lookup a UNIX Group entry by name. -************************************************************/ -BOOL map_unix_group_name(char *group_name, DOM_SID *psid, char *ntgroup_name, char *nt_domain) -{ - return map_unixname(GROUP_DOMAIN, group_name, psid, ntgroup_name, nt_domain); -} - -/*********************************************************** - Lookup a UNIX Alias entry by name. -************************************************************/ -BOOL map_unix_alias_name(char *alias_name, DOM_SID *psid, char *ntalias_name, char *nt_domain) -{ - return map_unixname(GROUP_LOCAL, alias_name, psid, ntalias_name, nt_domain); -} - -/*********************************************************** - Lookup a Group entry -************************************************************/ -BOOL map_nt_group_name(char *ntgroup_name, char *nt_domain, DOM_SID *psid, char *group_name, gid_t *gid) -{ - return map_ntname(GROUP_DOMAIN, ntgroup_name, nt_domain, psid, group_name, gid); -} - -/*********************************************************** - Lookup an Alias name entry -************************************************************/ -BOOL map_nt_alias_name(char *ntalias_name, char *nt_domain, DOM_SID *psid, char *alias_name, gid_t *gid) -{ - return map_ntname(GROUP_LOCAL, ntalias_name, nt_domain, psid, alias_name, gid); -} - -/*********************************************************** - Lookup an Alias SID entry by gid_t. -************************************************************/ -BOOL map_alias_gid(gid_t gid, DOM_SID *psid, char *nt_als_name, char *nt_domain) -{ - return map_gid(GROUP_LOCAL, gid, psid, nt_als_name, nt_domain); -} - -/*********************************************************** - Lookup a Group SID entry by gid_t. -************************************************************/ -BOOL map_group_gid( gid_t gid, DOM_SID *psid, char *nt_grp_name, char *nt_domain) -{ - return map_gid(GROUP_DOMAIN, gid, psid, nt_grp_name, nt_domain); -} - +/* this module is retired, it is moved to lib/domain_namemap.c */ -- cgit