From 1a9394195d0c53c23b9377ce122f399fa914f58c Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 23 Apr 2003 11:54:56 +0000 Subject: Merge HEAD's winbind into 3.0. This includes the 'SIDs Rule' patch, mimir's trusted domains cacheing code, the winbind_idmap abstraction (not idmap proper, but the stuff that held up the winbind LDAP backend in HEAD). Andrew Bartlett (This used to be commit d4d5e6c2ee6383c6cceb5d449aa2ba6c83eb0666) --- source3/nsswitch/winbindd_idmap.c | 577 ++++++++------------------------------ 1 file changed, 121 insertions(+), 456 deletions(-) (limited to 'source3/nsswitch/winbindd_idmap.c') diff --git a/source3/nsswitch/winbindd_idmap.c b/source3/nsswitch/winbindd_idmap.c index 6d184fec5f..3b23089200 100644 --- a/source3/nsswitch/winbindd_idmap.c +++ b/source3/nsswitch/winbindd_idmap.c @@ -1,20 +1,19 @@ /* Unix SMB/CIFS implementation. - - Winbind daemon - user related function - + Winbind ID Mapping Copyright (C) Tim Potter 2000 - + Copyright (C) Anthony Liguori 2003 + 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. @@ -22,508 +21,174 @@ #include "winbindd.h" -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_WINBIND - -/* High water mark keys */ +static struct { + const char *name; + /* Function to create a member of the idmap_methods list */ + BOOL (*reg_meth)(struct winbindd_idmap_methods **methods); + struct winbindd_idmap_methods *methods; +} builtin_winbindd_idmap_functions[] = { + { "tdb", winbind_idmap_reg_tdb, NULL }, + { NULL, NULL, NULL } +}; -#define HWM_GROUP "GROUP HWM" -#define HWM_USER "USER HWM" +/* singleton pattern: uberlazy evaluation */ +static struct winbindd_idmap_methods *impl; -/* idmap version determines auto-conversion */ -#define IDMAP_VERSION 2 - -/* Globals */ - -static TDB_CONTEXT *idmap_tdb; - -/* Allocate either a user or group id from the pool */ - -static BOOL allocate_id(uid_t *id, BOOL isgroup) +static struct winbindd_idmap_methods *get_impl(const char *name) { - int hwm; + int i = 0; + struct winbindd_idmap_methods *ret = NULL; - /* Get current high water mark */ + while (builtin_winbindd_idmap_functions[i].name && + strcmp(builtin_winbindd_idmap_functions[i].name, name)) { + i++; + } - if ((hwm = tdb_fetch_int32(idmap_tdb, - isgroup ? HWM_GROUP : HWM_USER)) == -1) { - return False; + if (builtin_winbindd_idmap_functions[i].name) { + if (!builtin_winbindd_idmap_functions[i].methods) { + builtin_winbindd_idmap_functions[i].reg_meth(&builtin_winbindd_idmap_functions[i].methods); } - /* Return next available uid in list */ - - if ((isgroup && (hwm > server_state.gid_high)) || - (!isgroup && (hwm > server_state.uid_high))) { - DEBUG(0, ("winbind %sid range full!\n", isgroup ? "g" : "u")); - return False; - } + ret = builtin_winbindd_idmap_functions[i].methods; + } - if (id) { - *id = hwm; - } - - hwm++; - - /* Store new high water mark */ - - tdb_store_int32(idmap_tdb, isgroup ? HWM_GROUP : HWM_USER, hwm); - - return True; + return ret; } -/* Get an id from a rid */ -static BOOL get_id_from_sid(DOM_SID *sid, uid_t *id, BOOL isgroup) +/* Initialize backend */ +BOOL winbindd_idmap_init(void) { - TDB_DATA data, key; - fstring keystr; - BOOL result = False; - - /* Check if sid is present in database */ - sid_to_string(keystr, sid); - - key.dptr = keystr; - key.dsize = strlen(keystr) + 1; - - data = tdb_fetch(idmap_tdb, key); - - if (data.dptr) { - fstring scanstr; - 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; - } + BOOL ret = False; - result = True; - } + DEBUG(3, ("winbindd_idmap_init: using '%s' as backend\n", + lp_winbind_backend())); - SAFE_FREE(data.dptr); - } else { - - /* 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); - - data.dptr = keystr2; - data.dsize = strlen(keystr2) + 1; - - tdb_store(idmap_tdb, key, data, TDB_REPLACE); - tdb_store(idmap_tdb, data, key, TDB_REPLACE); - - result = True; - } + if (!impl) { + impl = get_impl(lp_winbind_backend()); + if (!impl) { + DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n", + lp_winbind_backend())); } + } - return result; -} + if (impl) { + ret = impl->init(); + } -/* 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); -} + DEBUG(3, ("winbind_idmap_init: returning %s\n", ret ? "true" : "false")); -/* Get a gid from a group sid */ -BOOL winbindd_idmap_get_gid_from_sid(DOM_SID *sid, gid_t *gid) -{ - return get_id_from_sid(sid, gid, True); + return ret; } -/* Get a uid from a user rid */ -BOOL winbindd_idmap_get_uid_from_rid(const char *dom_name, uint32 rid, uid_t *uid) +/* Get UID from SID */ +BOOL winbindd_idmap_get_uid_from_sid(DOM_SID *sid, uid_t *uid) { - struct winbindd_domain *domain; - DOM_SID sid; + BOOL ret = False; - if (!(domain = find_domain_from_name(dom_name))) { - return False; - } + if (!impl) { + impl = get_impl(lp_winbind_backend()); + if (!impl) { + DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n", + lp_winbind_backend())); + } + } - sid_copy(&sid, &domain->sid); - sid_append_rid(&sid, rid); + if (impl) { + ret = impl->get_uid_from_sid(sid, uid); + } - return get_id_from_sid(&sid, uid, False); + return ret; } -/* Get a gid from a group rid */ -BOOL winbindd_idmap_get_gid_from_rid(const char *dom_name, uint32 rid, gid_t *gid) +/* Get GID from SID */ +BOOL winbindd_idmap_get_gid_from_sid(DOM_SID *sid, gid_t *gid) { - struct winbindd_domain *domain; - DOM_SID sid; + BOOL ret = False; - if (!(domain = find_domain_from_name(dom_name))) { - return False; - } + if (!impl) { + impl = get_impl(lp_winbind_backend()); + if (!impl) { + DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n", + lp_winbind_backend())); + } + } - sid_copy(&sid, &domain->sid); - sid_append_rid(&sid, rid); + if (impl) { + ret = impl->get_gid_from_sid(sid, gid); + } - return get_id_from_sid(&sid, gid, True); + return ret; } - -BOOL get_sid_from_id(int id, DOM_SID *sid, BOOL isgroup) +/* Get SID from UID */ +BOOL winbindd_idmap_get_sid_from_uid(uid_t uid, DOM_SID *sid) { - TDB_DATA key, data; - fstring keystr; - BOOL result = False; - - slprintf(keystr, sizeof(keystr), "%s %d", isgroup ? "GID" : "UID", id); - - key.dptr = keystr; - key.dsize = strlen(keystr) + 1; + BOOL ret = False; - data = tdb_fetch(idmap_tdb, key); - - if (data.dptr) { - result = string_to_sid(sid, data.dptr); - SAFE_FREE(data.dptr); + if (!impl) { + impl = get_impl(lp_winbind_backend()); + if (!impl) { + DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n", + lp_winbind_backend())); } + } - return result; -} + if (impl) { + ret = impl->get_sid_from_uid(uid, sid); + } -/* 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); + return ret; } -/* Get a sid from a gid */ +/* Get SID from 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) -{ - DOM_SID sid; - - if (!get_sid_from_id((int)uid, &sid, False)) { - return False; - } + BOOL ret = False; - *domain = find_domain_from_sid(&sid); - if (! *domain) return False; + if (!impl) { + impl = get_impl(lp_winbind_backend()); + } - sid_split_rid(&sid, user_rid); + if (impl) { + ret = impl->get_sid_from_gid(gid, sid); + } else { + DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n", + lp_winbind_backend())); + } - return True; -} - -/* Get a group rid from a gid */ - -BOOL winbindd_idmap_get_rid_from_gid(gid_t gid, uint32 *group_rid, - struct winbindd_domain **domain) -{ - 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_SID sid; - uint32 rid; - fstring keystr; - fstring dom_name; - TDB_DATA key2; - - p = strchr(key.dptr, '/'); - if (!p) - return 0; - - *p = 0; - fstrcpy(dom_name, key.dptr); - *p++ = '/'; - - domain = find_domain_from_name(dom_name); - if (!domain) { - /* We must delete the old record. */ - DEBUG(0,("winbindd: convert_fn : Unable to find domain %s\n", dom_name )); - DEBUG(0,("winbindd: convert_fn : deleting record %s\n", key.dptr )); - tdb_delete(idmap_tdb, key); - 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! */ - DEBUG(0,("winbindd: convert_fn : Unable to update record %s\n", key2.dptr )); - DEBUG(0,("winbindd: convert_fn : conversion failed - idmap corrupt ?\n")); - return -1; - } - - if (tdb_store(idmap_tdb, data, key2, TDB_REPLACE) != 0) { - /* not good! */ - DEBUG(0,("winbindd: convert_fn : Unable to update record %s\n", data.dptr )); - DEBUG(0,("winbindd: convert_fn : conversion failed - idmap corrupt ?\n")); - return -1; - } - - tdb_delete(idmap_tdb, key); - - return 0; -} - -#if 0 -/***************************************************************************** - Make a backup copy of the old idmap just to be safe.... JRA. -*****************************************************************************/ - -static BOOL backup_old_idmap(const char *idmap_name) -{ - pstring new_name; - int outfd = -1; - SMB_OFF_T size; - struct stat st; - - pstrcpy(new_name, idmap_name); - pstrcat(new_name, ".bak"); - - DEBUG(10,("backup_old_idmap: backing up %s to %s before upgrade.\n", - idmap_name, new_name )); - - if (tdb_lockall(idmap_tdb) == -1) { - DEBUG(10,("backup_old_idmap: failed to lock %s. Error %s\n", - idmap_name, tdb_errorstr(idmap_tdb) )); - return False; - } - if ((outfd = open(new_name, O_CREAT|O_EXCL|O_RDWR, 0600)) == -1) { - DEBUG(10,("backup_old_idmap: failed to open %s. Error %s\n", - new_name, strerror(errno) )); - goto fail; - } - - if (fstat(idmap_tdb->fd, &st) == -1) { - DEBUG(10,("backup_old_idmap: failed to fstat %s. Error %s\n", - idmap_name, strerror(errno) )); - goto fail; - } - - size = (SMB_OFF_T)st.st_size; - - if (transfer_file(idmap_tdb->fd, outfd, size) != size ) { - DEBUG(10,("backup_old_idmap: failed to copy %s. Error %s\n", - idmap_name, strerror(errno) )); - goto fail; - } - - if (close(outfd) == -1) { - DEBUG(10,("backup_old_idmap: failed to close %s. Error %s\n", - idmap_name, strerror(errno) )); - outfd = -1; - goto fail; - } - tdb_unlockall(idmap_tdb); - return True; - -fail: - - if (outfd != -1) - close(outfd); - tdb_unlockall(idmap_tdb); - return False; -} -#endif - -/***************************************************************************** - Convert the idmap database from an older version. -*****************************************************************************/ - -static BOOL idmap_convert(const char *idmap_name) -{ - int32 vers = tdb_fetch_int32(idmap_tdb, "IDMAP_VERSION"); - BOOL bigendianheader = (idmap_tdb->flags & TDB_BIGENDIAN) ? True : False; - - if (vers == IDMAP_VERSION) - return True; - -#if 0 - /* Make a backup copy before doing anything else.... */ - if (!backup_old_idmap(idmap_name)) - return False; -#endif - - if (((vers == -1) && bigendianheader) || (IREV(vers) == IDMAP_VERSION)) { - /* Arrggghh ! Bytereversed or old big-endian - make order independent ! */ - /* - * high and low records were created on a - * big endian machine and will need byte-reversing. - */ - - int32 wm; - - wm = tdb_fetch_int32(idmap_tdb, HWM_USER); - - if (wm != -1) { - wm = IREV(wm); - } else - wm = server_state.uid_low; - - if (tdb_store_int32(idmap_tdb, HWM_USER, wm) == -1) { - DEBUG(0, ("idmap_convert: Unable to byteswap user hwm in idmap database\n")); - return False; - } - - wm = tdb_fetch_int32(idmap_tdb, HWM_GROUP); - if (wm != -1) { - wm = IREV(wm); - } else - wm = server_state.gid_low; - - if (tdb_store_int32(idmap_tdb, HWM_GROUP, wm) == -1) { - DEBUG(0, ("idmap_convert: Unable to byteswap group hwm in idmap database\n")); - return False; - } - } - - /* the old format stored as DOMAIN/rid - now we store the SID direct */ - tdb_traverse(idmap_tdb, convert_fn, NULL); - - if (tdb_store_int32(idmap_tdb, "IDMAP_VERSION", IDMAP_VERSION) == -1) { - DEBUG(0, ("idmap_convert: Unable to byteswap group hwm in idmap database\n")); - return False; - } - - return True; -} - -/***************************************************************************** - Initialise idmap database. -*****************************************************************************/ - -BOOL winbindd_idmap_init(void) -{ - /* Open tdb cache */ - - if (!(idmap_tdb = tdb_open_log(lock_path("winbindd_idmap.tdb"), 0, - TDB_DEFAULT, O_RDWR | O_CREAT, 0600))) { - DEBUG(0, ("winbindd_idmap_init: Unable to open idmap database\n")); - return False; - } - - /* possibly convert from an earlier version */ - if (!idmap_convert(lock_path("winbindd_idmap.tdb"))) { - DEBUG(0, ("winbindd_idmap_init: Unable to open idmap database\n")); - return False; - } - - /* Create high water marks for group and user id */ - - if (tdb_fetch_int32(idmap_tdb, HWM_USER) == -1) { - if (tdb_store_int32(idmap_tdb, HWM_USER, server_state.uid_low) == -1) { - DEBUG(0, ("winbindd_idmap_init: Unable to initialise user hwm in idmap database\n")); - return False; - } - } - - if (tdb_fetch_int32(idmap_tdb, HWM_GROUP) == -1) { - if (tdb_store_int32(idmap_tdb, HWM_GROUP, server_state.gid_low) == -1) { - DEBUG(0, ("winbindd_idmap_init: Unable to initialise group hwm in idmap database\n")); - return False; - } - } - - return True; + return ret; } +/* Close backend */ BOOL winbindd_idmap_close(void) { - if (idmap_tdb) - return (tdb_close(idmap_tdb) == 0); - return True; -} + BOOL ret = False; -/* Dump status information to log file. Display different stuff based on - the debug level: + if (!impl) { + impl = get_impl(lp_winbind_backend()); + } - Debug Level Information Displayed - ================================================================= - 0 Percentage of [ug]id range allocated - 0 High water marks (next allocated ids) -*/ + if (impl) { + ret = impl->close(); + } else { + DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n", + lp_winbind_backend())); + } -#define DUMP_INFO 0 + return ret; +} +/* Dump backend status */ void winbindd_idmap_status(void) { - int user_hwm, group_hwm; - - DEBUG(0, ("winbindd idmap status:\n")); - - /* Get current high water marks */ - - if ((user_hwm = tdb_fetch_int32(idmap_tdb, HWM_USER)) == -1) { - DEBUG(DUMP_INFO, ("\tCould not get userid high water mark!\n")); - } - - if ((group_hwm = tdb_fetch_int32(idmap_tdb, HWM_GROUP)) == -1) { - DEBUG(DUMP_INFO, ("\tCould not get groupid high water mark!\n")); - } - - /* Display next ids to allocate */ - - if (user_hwm != -1) { - DEBUG(DUMP_INFO, ("\tNext userid to allocate is %d\n", user_hwm)); - } - - if (group_hwm != -1) { - DEBUG(DUMP_INFO, ("\tNext groupid to allocate is %d\n", group_hwm)); - } - - /* Display percentage of id range already allocated. */ - - if (user_hwm != -1) { - int num_users = user_hwm - server_state.uid_low; - int total_users = server_state.uid_high - server_state.uid_low; - - DEBUG(DUMP_INFO, ("\tUser id range is %d%% full (%d of %d)\n", - num_users * 100 / total_users, num_users, - total_users)); - } - - if (group_hwm != -1) { - int num_groups = group_hwm - server_state.gid_low; - int total_groups = server_state.gid_high - server_state.gid_low; - - DEBUG(DUMP_INFO, ("\tGroup id range is %d%% full (%d of %d)\n", - num_groups * 100 / total_groups, num_groups, - total_groups)); - } + if (!impl) { + impl = get_impl(lp_winbind_backend()); + } - /* Display complete mapping of users and groups to rids */ + if (impl) { + impl->status(); + } else { + DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n", + lp_winbind_backend())); + } } -- cgit