From 276ff4df82313abcf09db2d373a4229a5b8db506 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 27 Feb 2002 23:51:25 +0000 Subject: this allows us to support foreign SIDs in winbindd and smbd this means "xcopy /o" has a chance of working with ACLs that contain ACEs that use SIDs that the Samba server has no knowledge of. It's a bit hackish, Tim, can you look at my uid.c changes? (This used to be commit fe2db3148587937aa7b674c1c99036d42a3776b3) --- source3/nsswitch/winbindd_group.c | 5 +- source3/nsswitch/winbindd_idmap.c | 202 ++++++++++++++++++++++++++++---------- source3/nsswitch/winbindd_proto.h | 15 +-- source3/nsswitch/winbindd_sid.c | 66 +++---------- source3/nsswitch/winbindd_util.c | 2 +- source3/smbd/uid.c | 15 ++- 6 files changed, 186 insertions(+), 119 deletions(-) (limited to 'source3') diff --git a/source3/nsswitch/winbindd_group.c b/source3/nsswitch/winbindd_group.c index 1818d992b7..c62ce54b59 100644 --- a/source3/nsswitch/winbindd_group.c +++ b/source3/nsswitch/winbindd_group.c @@ -228,10 +228,9 @@ enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state) } /* Fill in group structure */ + sid_peek_rid(&group_sid, &group_rid); - sid_split_rid(&group_sid, &group_rid); - - if (!winbindd_idmap_get_gid_from_rid(domain->name, group_rid, &gid)) { + if (!winbindd_idmap_get_gid_from_sid(&group_sid, &gid)) { DEBUG(1, ("error converting unix gid to sid\n")); return WINBINDD_ERROR; } diff --git a/source3/nsswitch/winbindd_idmap.c b/source3/nsswitch/winbindd_idmap.c index 3a8269f853..977148ad6a 100644 --- a/source3/nsswitch/winbindd_idmap.c +++ b/source3/nsswitch/winbindd_idmap.c @@ -27,6 +27,9 @@ #define HWM_GROUP "GROUP HWM" #define HWM_USER "USER HWM" +/* idmap version determines auto-conversion */ +#define IDMAP_VERSION 2 + /* Globals */ static TDB_CONTEXT *idmap_tdb; @@ -66,17 +69,14 @@ static BOOL allocate_id(uid_t *id, BOOL isgroup) } /* Get an id from a rid */ - -static BOOL get_id_from_rid(char *domain_name, uint32 rid, uid_t *id, - BOOL isgroup) +static BOOL get_id_from_sid(DOM_SID *sid, uid_t *id, BOOL isgroup) { TDB_DATA data, key; fstring keystr; BOOL result = False; - /* Check if rid is present in database */ - - slprintf(keystr, sizeof(keystr), "%s/%d", domain_name, rid); + /* Check if sid is present in database */ + sid_to_string(keystr, sid); key.dptr = keystr; key.dsize = strlen(keystr) + 1; @@ -88,34 +88,29 @@ static BOOL get_id_from_rid(char *domain_name, uint32 rid, uid_t *id, int the_id; /* Parse and return existing uid */ - fstrcpy(scanstr, isgroup ? "GID" : "UID"); fstrcat(scanstr, " %d"); if (sscanf(data.dptr, scanstr, &the_id) == 1) { - /* Store uid */ - if (id) { - *id = the_id; + *id = the_id; } result = True; } SAFE_FREE(data.dptr); - } else { - /* Allocate a new id for this rid */ + /* Allocate a new id for this sid */ if (id && allocate_id(id, isgroup)) { fstring keystr2; /* Store new id */ - slprintf(keystr2, sizeof(keystr2), "%s %d", isgroup ? "GID" : - "UID", *id); + slprintf(keystr2, sizeof(keystr2), "%s %d", isgroup ? "GID" : "UID", *id); data.dptr = keystr2; data.dsize = strlen(keystr2) + 1; @@ -130,24 +125,52 @@ static BOOL get_id_from_rid(char *domain_name, uint32 rid, uid_t *id, return result; } -/* Get a uid from a user rid */ +/* Get a uid from a user sid */ +BOOL winbindd_idmap_get_uid_from_sid(DOM_SID *sid, uid_t *uid) +{ + return get_id_from_sid(sid, uid, False); +} -BOOL winbindd_idmap_get_uid_from_rid(char *domain_name, uint32 user_rid, - uid_t *uid) +/* Get a gid from a group sid */ +BOOL winbindd_idmap_get_gid_from_sid(DOM_SID *sid, gid_t *gid) { - return get_id_from_rid(domain_name, user_rid, uid, False); + return get_id_from_sid(sid, gid, True); } -/* Get a gid from a group rid */ +/* Get a uid from a user rid */ +BOOL winbindd_idmap_get_uid_from_rid(const char *dom_name, uint32 rid, uid_t *uid) +{ + struct winbindd_domain *domain; + DOM_SID sid; + + if (!(domain = find_domain_from_name(dom_name))) { + return False; + } -BOOL winbindd_idmap_get_gid_from_rid(char *domain_name, uint32 group_rid, - gid_t *gid) + sid_copy(&sid, &domain->sid); + sid_append_rid(&sid, rid); + + return get_id_from_sid(&sid, uid, False); +} + +/* Get a gid from a group rid */ +BOOL winbindd_idmap_get_gid_from_rid(const char *dom_name, uint32 rid, gid_t *gid) { - return get_id_from_rid(domain_name, group_rid, gid, True); + struct winbindd_domain *domain; + DOM_SID sid; + + if (!(domain = find_domain_from_name(dom_name))) { + return False; + } + + sid_copy(&sid, &domain->sid); + sid_append_rid(&sid, rid); + + return get_id_from_sid(&sid, gid, True); } -BOOL get_rid_from_id(int id, uint32 *rid, struct winbindd_domain **domain, - BOOL isgroup) + +BOOL get_sid_from_id(int id, DOM_SID *sid, BOOL isgroup) { TDB_DATA key, data; fstring keystr; @@ -161,43 +184,41 @@ BOOL get_rid_from_id(int id, uint32 *rid, struct winbindd_domain **domain, data = tdb_fetch(idmap_tdb, key); if (data.dptr) { - char *p = data.dptr; - fstring domain_name; - uint32 the_rid; - - if (next_token(&p, domain_name, "/", sizeof(fstring))) { - - the_rid = atoi(p); - - if (rid) { - *rid = the_rid; - } - - if (domain) { - *domain = find_domain_from_name(domain_name); - if (*domain == NULL) { - DEBUG(1, ("unknown domain %s for rid %d\n", - domain_name, the_rid)); - result = False; - goto done; - } - } - - result = True; - } - done: - SAFE_FREE(data.dptr); + result = string_to_sid(sid, data.dptr); + SAFE_FREE(data.dptr); } return result; } -/* Get a user rid from a uid */ +/* Get a sid from a uid */ +BOOL winbindd_idmap_get_sid_from_uid(uid_t uid, DOM_SID *sid) +{ + return get_sid_from_id((int)uid, sid, False); +} +/* Get a sid from a gid */ +BOOL winbindd_idmap_get_sid_from_gid(gid_t gid, DOM_SID *sid) +{ + return get_sid_from_id((int)gid, sid, True); +} + +/* Get a user rid from a uid */ BOOL winbindd_idmap_get_rid_from_uid(uid_t uid, uint32 *user_rid, struct winbindd_domain **domain) { - return get_rid_from_id((int)uid, user_rid, domain, False); + DOM_SID sid; + + if (!get_sid_from_id((int)uid, &sid, False)) { + return False; + } + + *domain = find_domain_from_sid(&sid); + if (! *domain) return False; + + sid_split_rid(&sid, user_rid); + + return True; } /* Get a group rid from a gid */ @@ -205,9 +226,79 @@ BOOL winbindd_idmap_get_rid_from_uid(uid_t uid, uint32 *user_rid, BOOL winbindd_idmap_get_rid_from_gid(gid_t gid, uint32 *group_rid, struct winbindd_domain **domain) { - return get_rid_from_id((int)gid, group_rid, domain, True); + DOM_SID sid; + + if (!get_sid_from_id((int)gid, &sid, True)) { + return False; + } + + *domain = find_domain_from_sid(&sid); + if (! *domain) return False; + + sid_split_rid(&sid, group_rid); + + return True; } +/* convert one record to the new format */ +static int convert_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA data, void *ignored) +{ + struct winbindd_domain *domain; + char *p, *dom_name; + DOM_SID sid; + uint32 rid; + fstring keystr; + TDB_DATA key2; + + p = strchr(key.dptr, '/'); + if (!p) return 0; + + *p++ = 0; + dom_name = key.dptr; + + domain = find_domain_from_name(dom_name); + if (!domain) { + /* what do we do about this?? */ + return 0; + } + + rid = atoi(p); + + sid_copy(&sid, &domain->sid); + sid_append_rid(&sid, rid); + + sid_to_string(keystr, &sid); + key2.dptr = keystr; + key2.dsize = strlen(keystr) + 1; + + if (tdb_store(idmap_tdb, key2, data, TDB_INSERT) != 0) { + /* not good! */ + return 0; + } + + tdb_delete(idmap_tdb, key); + + return 0; +} + +/* convert the idmap database from an older version */ +static BOOL idmap_convert(void) +{ + if (tdb_fetch_int(idmap_tdb, "IDMAP_VERSION") == IDMAP_VERSION) { + return True; + } + + /* the old format stored as DOMAIN/rid - now we store the SID direct */ + tdb_traverse(idmap_tdb, convert_fn, NULL); + + if (tdb_store_int(idmap_tdb, "IDMAP_VERSION", IDMAP_VERSION) == -1) { + return False; + } + + return True; +} + + /* Initialise idmap database */ BOOL winbindd_idmap_init(void) @@ -220,6 +311,11 @@ BOOL winbindd_idmap_init(void) return False; } + /* possibly convert from an earlier version */ + if (!idmap_convert()) { + return False; + } + /* Create high water marks for group and user id */ if (tdb_fetch_int(idmap_tdb, HWM_USER) == -1) { diff --git a/source3/nsswitch/winbindd_proto.h b/source3/nsswitch/winbindd_proto.h index 5d1081c719..14edbfdd44 100644 --- a/source3/nsswitch/winbindd_proto.h +++ b/source3/nsswitch/winbindd_proto.h @@ -49,12 +49,13 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state); /* The following definitions come from nsswitch/winbindd_idmap.c */ -BOOL winbindd_idmap_get_uid_from_rid(char *domain_name, uint32 user_rid, - uid_t *uid); -BOOL winbindd_idmap_get_gid_from_rid(char *domain_name, uint32 group_rid, - gid_t *gid); -BOOL get_rid_from_id(int id, uint32 *rid, struct winbindd_domain **domain, - BOOL isgroup); +BOOL winbindd_idmap_get_uid_from_sid(DOM_SID *sid, uid_t *uid); +BOOL winbindd_idmap_get_gid_from_sid(DOM_SID *sid, gid_t *gid); +BOOL winbindd_idmap_get_uid_from_rid(const char *dom_name, uint32 rid, uid_t *uid); +BOOL winbindd_idmap_get_gid_from_rid(const char *dom_name, uint32 rid, gid_t *gid); +BOOL get_sid_from_id(int id, DOM_SID *sid, BOOL isgroup); +BOOL winbindd_idmap_get_sid_from_uid(uid_t uid, DOM_SID *sid); +BOOL winbindd_idmap_get_sid_from_gid(gid_t gid, DOM_SID *sid); BOOL winbindd_idmap_get_rid_from_uid(uid_t uid, uint32 *user_rid, struct winbindd_domain **domain); BOOL winbindd_idmap_get_rid_from_gid(gid_t gid, uint32 *group_rid, @@ -107,7 +108,7 @@ enum winbindd_result winbindd_list_users(struct winbindd_cli_state *state); struct winbindd_domain *domain_list(void); void free_domain_list(void); BOOL init_domain_list(void); -struct winbindd_domain *find_domain_from_name(char *domain_name); +struct winbindd_domain *find_domain_from_name(const char *domain_name); struct winbindd_domain *find_domain_from_sid(DOM_SID *sid); BOOL winbindd_lookup_sid_by_name(struct winbindd_domain *domain, const char *name, DOM_SID *sid, diff --git a/source3/nsswitch/winbindd_sid.c b/source3/nsswitch/winbindd_sid.c index 8153b3a3a5..227ce439d5 100644 --- a/source3/nsswitch/winbindd_sid.c +++ b/source3/nsswitch/winbindd_sid.c @@ -103,31 +103,19 @@ enum winbindd_result winbindd_lookupname(struct winbindd_cli_state *state) enum winbindd_result winbindd_sid_to_uid(struct winbindd_cli_state *state) { DOM_SID sid; - uint32 user_rid; - struct winbindd_domain *domain; DEBUG(3, ("[%5d]: sid to uid %s\n", state->pid, state->request.data.sid)); /* Split sid into domain sid and user rid */ - - string_to_sid(&sid, state->request.data.sid); - sid_split_rid(&sid, &user_rid); - - /* Find domain this sid belongs to */ - - if ((domain = find_domain_from_sid(&sid)) == NULL) { - fstring sid_str; - - sid_to_string(sid_str, &sid); - DEBUG(1, ("Could not find domain for sid %s\n", sid_str)); + if (!string_to_sid(&sid, state->request.data.sid)) { + DEBUG(1, ("Could not get convert sid %s from string\n", + state->request.data.sid)); return WINBINDD_ERROR; } /* Find uid for this sid and return it */ - - if (!winbindd_idmap_get_uid_from_rid(domain->name, user_rid, - &state->response.data.uid)) { + if (!winbindd_idmap_get_uid_from_sid(&sid, &state->response.data.uid)) { DEBUG(1, ("Could not get uid for sid %s\n", state->request.data.sid)); return WINBINDD_ERROR; @@ -142,31 +130,18 @@ enum winbindd_result winbindd_sid_to_uid(struct winbindd_cli_state *state) enum winbindd_result winbindd_sid_to_gid(struct winbindd_cli_state *state) { DOM_SID sid; - uint32 group_rid; - struct winbindd_domain *domain; DEBUG(3, ("[%5d]: sid to gid %s\n", state->pid, state->request.data.sid)); - /* Split sid into domain sid and user rid */ - - string_to_sid(&sid, state->request.data.sid); - sid_split_rid(&sid, &group_rid); - - /* Find domain this sid belongs to */ - - if ((domain = find_domain_from_sid(&sid)) == NULL) { - fstring sid_str; - - sid_to_string(sid_str, &sid); - DEBUG(1, ("Could not find domain for sid %s\n", sid_str)); + if (!string_to_sid(&sid, state->request.data.sid)) { + DEBUG(1, ("Could not cvt string to sid %s\n", + state->request.data.sid)); return WINBINDD_ERROR; } - /* Find uid for this sid and return it */ - - if (!winbindd_idmap_get_gid_from_rid(domain->name, group_rid, - &state->response.data.gid)) { + /* Find gid for this sid and return it */ + if (!winbindd_idmap_get_gid_from_sid(&sid, &state->response.data.gid)) { DEBUG(1, ("Could not get gid for sid %s\n", state->request.data.sid)); return WINBINDD_ERROR; @@ -179,8 +154,6 @@ enum winbindd_result winbindd_sid_to_gid(struct winbindd_cli_state *state) enum winbindd_result winbindd_uid_to_sid(struct winbindd_cli_state *state) { - struct winbindd_domain *domain; - uint32 user_rid; DOM_SID sid; /* Bug out if the uid isn't in the winbind range */ @@ -194,18 +167,12 @@ enum winbindd_result winbindd_uid_to_sid(struct winbindd_cli_state *state) state->request.data.uid)); /* Lookup rid for this uid */ - - if (!winbindd_idmap_get_rid_from_uid(state->request.data.uid, - &user_rid, &domain)) { + if (!winbindd_idmap_get_sid_from_uid(state->request.data.uid, &sid)) { DEBUG(1, ("Could not convert uid %d to rid\n", state->request.data.uid)); return WINBINDD_ERROR; } - /* Construct sid and return it */ - - sid_copy(&sid, &domain->sid); - sid_append_rid(&sid, user_rid); sid_to_string(state->response.data.sid.sid, &sid); state->response.data.sid.type = SID_NAME_USER; @@ -216,8 +183,6 @@ enum winbindd_result winbindd_uid_to_sid(struct winbindd_cli_state *state) enum winbindd_result winbindd_gid_to_sid(struct winbindd_cli_state *state) { - struct winbindd_domain *domain; - uint32 group_rid; DOM_SID sid; /* Bug out if the gid isn't in the winbind range */ @@ -230,19 +195,14 @@ enum winbindd_result winbindd_gid_to_sid(struct winbindd_cli_state *state) DEBUG(3, ("[%5d]: gid to sid %d\n", state->pid, state->request.data.gid)); - /* Lookup rid for this uid */ - - if (!winbindd_idmap_get_rid_from_gid(state->request.data.gid, - &group_rid, &domain)) { - DEBUG(1, ("Could not convert gid %d to rid\n", + /* Lookup sid for this uid */ + if (!winbindd_idmap_get_sid_from_gid(state->request.data.gid, &sid)) { + DEBUG(1, ("Could not convert gid %d to sid\n", state->request.data.gid)); return WINBINDD_ERROR; } /* Construct sid and return it */ - - sid_copy(&sid, &domain->sid); - sid_append_rid(&sid, group_rid); sid_to_string(state->response.data.sid.sid, &sid); state->response.data.sid.type = SID_NAME_DOM_GRP; diff --git a/source3/nsswitch/winbindd_util.c b/source3/nsswitch/winbindd_util.c index 48c756712d..e274c78220 100644 --- a/source3/nsswitch/winbindd_util.c +++ b/source3/nsswitch/winbindd_util.c @@ -178,7 +178,7 @@ BOOL init_domain_list(void) /* Given a domain name, return the struct winbindd domain info for it if it is actually working. */ -struct winbindd_domain *find_domain_from_name(char *domain_name) +struct winbindd_domain *find_domain_from_name(const char *domain_name) { struct winbindd_domain *domain; diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c index 3a939e4fce..f2b3bdbe6c 100644 --- a/source3/smbd/uid.c +++ b/source3/smbd/uid.c @@ -596,6 +596,11 @@ BOOL sid_to_uid(DOM_SID *psid, uid_t *puid, enum SID_NAME_USE *sidtype) *sidtype = SID_NAME_UNKNOWN; + +/* (tridge) I commented out the slab of code below in order to support foreign SIDs + Do we really need to validate the type of SID we have in this case? +*/ +#if 0 /* * First we must look up the name and decide if this is a user sid. */ @@ -616,7 +621,7 @@ BOOL sid_to_uid(DOM_SID *psid, uid_t *puid, enum SID_NAME_USE *sidtype) (unsigned int)name_type )); return False; } - +#endif *sidtype = SID_NAME_USER; /* @@ -658,7 +663,13 @@ BOOL sid_to_gid(DOM_SID *psid, gid_t *pgid, enum SID_NAME_USE *sidtype) DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed - trying local.\n", sid_to_string(sid_str, psid) )); - return local_sid_to_gid(pgid, psid, sidtype); + if (!local_sid_to_gid(pgid, psid, sidtype)) { + /* this was probably a foreign sid - assume its a group rid + and continue */ + name_type = SID_NAME_DOM_GRP; + } else { + return True; + } } /* -- cgit