summaryrefslogtreecommitdiff
path: root/source3/lib
diff options
context:
space:
mode:
Diffstat (limited to 'source3/lib')
-rw-r--r--source3/lib/domain_namemap.c1186
-rw-r--r--source3/lib/sids.c554
-rw-r--r--source3/lib/util_pwdb.c444
3 files changed, 2184 insertions, 0 deletions
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;
+}