diff options
Diffstat (limited to 'source3/winbindd')
-rw-r--r-- | source3/winbindd/idmap_nss.c | 10 | ||||
-rw-r--r-- | source3/winbindd/idmap_tdb2.c | 1017 | ||||
-rw-r--r-- | source3/winbindd/winbindd.c | 23 | ||||
-rw-r--r-- | source3/winbindd/winbindd.h | 6 | ||||
-rw-r--r-- | source3/winbindd/winbindd_ads.c | 110 | ||||
-rw-r--r-- | source3/winbindd/winbindd_async.c | 20 | ||||
-rw-r--r-- | source3/winbindd/winbindd_cache.c | 209 | ||||
-rw-r--r-- | source3/winbindd/winbindd_cm.c | 205 | ||||
-rw-r--r-- | source3/winbindd/winbindd_creds.c | 2 | ||||
-rw-r--r-- | source3/winbindd/winbindd_dual.c | 92 | ||||
-rw-r--r-- | source3/winbindd/winbindd_group.c | 31 | ||||
-rw-r--r-- | source3/winbindd/winbindd_locator.c | 6 | ||||
-rw-r--r-- | source3/winbindd/winbindd_misc.c | 6 | ||||
-rw-r--r-- | source3/winbindd/winbindd_ndr.c | 153 | ||||
-rw-r--r-- | source3/winbindd/winbindd_pam.c | 52 | ||||
-rw-r--r-- | source3/winbindd/winbindd_rpc.c | 36 | ||||
-rw-r--r-- | source3/winbindd/winbindd_util.c | 104 |
17 files changed, 1767 insertions, 315 deletions
diff --git a/source3/winbindd/idmap_nss.c b/source3/winbindd/idmap_nss.c index fa9f2c9681..46c24d7fcb 100644 --- a/source3/winbindd/idmap_nss.c +++ b/source3/winbindd/idmap_nss.c @@ -145,7 +145,6 @@ static NTSTATUS idmap_nss_sids_to_unixids(struct idmap_domain *dom, struct id_ma } for (i = 0; ids[i]; i++) { - struct passwd *pw; struct group *gr; enum lsa_SidType type; const char *dom_name = NULL; @@ -166,17 +165,20 @@ static NTSTATUS idmap_nss_sids_to_unixids(struct idmap_domain *dom, struct id_ma } switch (type) { - case SID_NAME_USER: + case SID_NAME_USER: { + struct passwd *pw; /* this will find also all lower case name and use username level */ - - pw = Get_Pwnam(name); + + pw = Get_Pwnam_alloc(talloc_tos(), name); if (pw) { ids[i]->xid.id = pw->pw_uid; ids[i]->xid.type = ID_TYPE_UID; ids[i]->status = ID_MAPPED; } + TALLOC_FREE(pw); break; + } case SID_NAME_DOM_GRP: case SID_NAME_ALIAS: diff --git a/source3/winbindd/idmap_tdb2.c b/source3/winbindd/idmap_tdb2.c new file mode 100644 index 0000000000..ab89e615f7 --- /dev/null +++ b/source3/winbindd/idmap_tdb2.c @@ -0,0 +1,1017 @@ +/* + Unix SMB/CIFS implementation. + + idmap TDB2 backend, used for clustered Samba setups. + + This uses 2 tdb files. One is permanent, and is in shared storage + on the cluster (using "tdb:idmap2.tdb =" in smb.conf). The other is a + temporary cache tdb on local storage. + + Copyright (C) Andrew Tridgell 2007 + + This is heavily based upon idmap_tdb.c, which is: + + Copyright (C) Tim Potter 2000 + Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003 + Copyright (C) Jeremy Allison 2006 + Copyright (C) Simo Sorce 2003-2006 + + 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 "winbindd.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_IDMAP + +/* High water mark keys */ +#define HWM_GROUP "GROUP HWM" +#define HWM_USER "USER HWM" + +static struct idmap_tdb2_state { + /* User and group id pool */ + uid_t low_uid, high_uid; /* Range of uids to allocate */ + gid_t low_gid, high_gid; /* Range of gids to allocate */ + const char *idmap_script; +} idmap_tdb2_state; + + + +/* tdb context for the local cache tdb */ +static TDB_CONTEXT *idmap_tdb2_tmp; + +/* handle to the permanent tdb */ +static struct db_context *idmap_tdb2_perm; + +/* + open the cache tdb + */ +static NTSTATUS idmap_tdb2_open_cache_db(void) +{ + const char *db_path; + + if (idmap_tdb2_tmp) { + /* its already open */ + return NT_STATUS_OK; + } + + db_path = lock_path("idmap2_cache.tdb"); + + /* Open idmap repository */ + if (!(idmap_tdb2_tmp = tdb_open_log(db_path, 0, TDB_CLEAR_IF_FIRST, O_RDWR|O_CREAT, 0644))) { + DEBUG(0, ("Unable to open cache idmap database '%s'\n", db_path)); + return NT_STATUS_UNSUCCESSFUL; + } + + return NT_STATUS_OK; +} + + +static NTSTATUS idmap_tdb2_alloc_load(void); + +/* + open the permanent tdb + */ +static NTSTATUS idmap_tdb2_open_perm_db(void) +{ + char *db_path; + + if (idmap_tdb2_perm) { + /* its already open */ + return NT_STATUS_OK; + } + + db_path = lp_parm_talloc_string(-1, "tdb", "idmap2.tdb", NULL); + if (db_path == NULL) { + /* fall back to the private directory, which, despite + its name, is usually on shared storage */ + db_path = talloc_asprintf(NULL, "%s/idmap2.tdb", lp_private_dir()); + } + NT_STATUS_HAVE_NO_MEMORY(db_path); + + /* Open idmap repository */ + idmap_tdb2_perm = db_open(NULL, db_path, 0, TDB_DEFAULT, + O_RDWR|O_CREAT, 0644); + TALLOC_FREE(db_path); + + if (idmap_tdb2_perm == NULL) { + DEBUG(0, ("Unable to open permanent idmap database '%s'\n", + db_path)); + return NT_STATUS_UNSUCCESSFUL; + } + + /* load the ranges and high/low water marks */ + return idmap_tdb2_alloc_load(); +} + + +/* + load the idmap allocation ranges and high/low water marks +*/ +static NTSTATUS idmap_tdb2_alloc_load(void) +{ + const char *range; + uid_t low_uid = 0; + uid_t high_uid = 0; + gid_t low_gid = 0; + gid_t high_gid = 0; + + /* load ranges */ + idmap_tdb2_state.low_uid = 0; + idmap_tdb2_state.high_uid = 0; + idmap_tdb2_state.low_gid = 0; + idmap_tdb2_state.high_gid = 0; + + /* see if a idmap script is configured */ + idmap_tdb2_state.idmap_script = lp_parm_const_string(-1, "idmap", "script", NULL); + + if (idmap_tdb2_state.idmap_script) { + DEBUG(1, ("using idmap script '%s'\n", idmap_tdb2_state.idmap_script)); + } + + range = lp_parm_const_string(-1, "idmap alloc config", "range", NULL); + if (range && range[0]) { + unsigned low_id, high_id; + if (sscanf(range, "%u - %u", &low_id, &high_id) == 2) { + if (low_id < high_id) { + idmap_tdb2_state.low_gid = idmap_tdb2_state.low_uid = low_id; + idmap_tdb2_state.high_gid = idmap_tdb2_state.high_uid = high_id; + } else { + DEBUG(1, ("ERROR: invalid idmap alloc range [%s]", range)); + } + } else { + DEBUG(1, ("ERROR: invalid syntax for idmap alloc config:range [%s]", range)); + } + } + + /* Create high water marks for group and user id */ + if (lp_idmap_uid(&low_uid, &high_uid)) { + idmap_tdb2_state.low_uid = low_uid; + idmap_tdb2_state.high_uid = high_uid; + } + + if (lp_idmap_gid(&low_gid, &high_gid)) { + idmap_tdb2_state.low_gid = low_gid; + idmap_tdb2_state.high_gid = high_gid; + } + + if (idmap_tdb2_state.high_uid <= idmap_tdb2_state.low_uid) { + DEBUG(1, ("idmap uid range missing or invalid\n")); + DEBUGADD(1, ("idmap will be unable to map foreign SIDs\n")); + return NT_STATUS_UNSUCCESSFUL; + } else { + uint32 low_id; + + if (((low_id = dbwrap_fetch_int32(idmap_tdb2_perm, + HWM_USER)) == -1) || + (low_id < idmap_tdb2_state.low_uid)) { + if (dbwrap_store_int32( + idmap_tdb2_perm, HWM_USER, + idmap_tdb2_state.low_uid) == -1) { + DEBUG(0, ("Unable to initialise user hwm in idmap database\n")); + return NT_STATUS_INTERNAL_DB_ERROR; + } + } + } + + if (idmap_tdb2_state.high_gid <= idmap_tdb2_state.low_gid) { + DEBUG(1, ("idmap gid range missing or invalid\n")); + DEBUGADD(1, ("idmap will be unable to map foreign SIDs\n")); + return NT_STATUS_UNSUCCESSFUL; + } else { + uint32 low_id; + + if (((low_id = dbwrap_fetch_int32(idmap_tdb2_perm, + HWM_GROUP)) == -1) || + (low_id < idmap_tdb2_state.low_gid)) { + if (dbwrap_store_int32( + idmap_tdb2_perm, HWM_GROUP, + idmap_tdb2_state.low_gid) == -1) { + DEBUG(0, ("Unable to initialise group hwm in idmap database\n")); + return NT_STATUS_INTERNAL_DB_ERROR; + } + } + } + + return NT_STATUS_OK; +} + + +/* + Initialise idmap alloc database. +*/ +static NTSTATUS idmap_tdb2_alloc_init(const char *params) +{ + /* nothing to do - we want to avoid opening the permanent + database if possible. Instead we load the params when we + first need it. */ + return NT_STATUS_OK; +} + + +/* + Allocate a new id. +*/ +static NTSTATUS idmap_tdb2_allocate_id(struct unixid *xid) +{ + bool ret; + const char *hwmkey; + const char *hwmtype; + uint32_t high_hwm; + uint32_t hwm; + NTSTATUS status; + + status = idmap_tdb2_open_perm_db(); + NT_STATUS_NOT_OK_RETURN(status); + + /* Get current high water mark */ + switch (xid->type) { + + case ID_TYPE_UID: + hwmkey = HWM_USER; + hwmtype = "UID"; + high_hwm = idmap_tdb2_state.high_uid; + break; + + case ID_TYPE_GID: + hwmkey = HWM_GROUP; + hwmtype = "GID"; + high_hwm = idmap_tdb2_state.high_gid; + break; + + default: + DEBUG(2, ("Invalid ID type (0x%x)\n", xid->type)); + return NT_STATUS_INVALID_PARAMETER; + } + + if ((hwm = dbwrap_fetch_int32(idmap_tdb2_perm, hwmkey)) == -1) { + return NT_STATUS_INTERNAL_DB_ERROR; + } + + /* check it is in the range */ + if (hwm > high_hwm) { + DEBUG(1, ("Fatal Error: %s range full!! (max: %lu)\n", + hwmtype, (unsigned long)high_hwm)); + return NT_STATUS_UNSUCCESSFUL; + } + + /* fetch a new id and increment it */ + ret = dbwrap_change_uint32_atomic(idmap_tdb2_perm, hwmkey, &hwm, 1); + if (ret == -1) { + DEBUG(1, ("Fatal error while fetching a new %s value\n!", hwmtype)); + return NT_STATUS_UNSUCCESSFUL; + } + + /* recheck it is in the range */ + if (hwm > high_hwm) { + DEBUG(1, ("Fatal Error: %s range full!! (max: %lu)\n", + hwmtype, (unsigned long)high_hwm)); + return NT_STATUS_UNSUCCESSFUL; + } + + xid->id = hwm; + DEBUG(10,("New %s = %d\n", hwmtype, hwm)); + + return NT_STATUS_OK; +} + +/* + Get current highest id. +*/ +static NTSTATUS idmap_tdb2_get_hwm(struct unixid *xid) +{ + const char *hwmkey; + const char *hwmtype; + uint32_t hwm; + uint32_t high_hwm; + + /* Get current high water mark */ + switch (xid->type) { + + case ID_TYPE_UID: + hwmkey = HWM_USER; + hwmtype = "UID"; + high_hwm = idmap_tdb2_state.high_uid; + break; + + case ID_TYPE_GID: + hwmkey = HWM_GROUP; + hwmtype = "GID"; + high_hwm = idmap_tdb2_state.high_gid; + break; + + default: + return NT_STATUS_INVALID_PARAMETER; + } + + if ((hwm = dbwrap_fetch_int32(idmap_tdb2_perm, hwmkey)) == -1) { + return NT_STATUS_INTERNAL_DB_ERROR; + } + + xid->id = hwm; + + /* Warn if it is out of range */ + if (hwm >= high_hwm) { + DEBUG(0, ("Warning: %s range full!! (max: %lu)\n", + hwmtype, (unsigned long)high_hwm)); + } + + return NT_STATUS_OK; +} + +/* + Set high id. +*/ +static NTSTATUS idmap_tdb2_set_hwm(struct unixid *xid) +{ + /* not supported, or we would invalidate the cache tdb on + other nodes */ + DEBUG(0,("idmap_tdb2_set_hwm not supported\n")); + return NT_STATUS_NOT_SUPPORTED; +} + +/* + Close the alloc tdb +*/ +static NTSTATUS idmap_tdb2_alloc_close(void) +{ + /* don't actually close it */ + return NT_STATUS_OK; +} + +/* + IDMAP MAPPING TDB BACKEND +*/ +struct idmap_tdb2_context { + uint32_t filter_low_id; + uint32_t filter_high_id; +}; + +/* + try fetching from the cache tdb, and if that fails then + fetch from the permanent tdb + */ +static TDB_DATA tdb2_fetch_bystring(TALLOC_CTX *mem_ctx, const char *keystr) +{ + TDB_DATA ret; + NTSTATUS status; + + ret = tdb_fetch_bystring(idmap_tdb2_tmp, keystr); + if (ret.dptr != NULL) { + /* got it from cache */ + unsigned char *tmp; + + tmp = (unsigned char *)talloc_memdup(mem_ctx, ret.dptr, + ret.dsize); + SAFE_FREE(ret.dptr); + ret.dptr = tmp; + + if (ret.dptr == NULL) { + return make_tdb_data(NULL, 0); + } + return ret; + } + + status = idmap_tdb2_open_perm_db(); + if (!NT_STATUS_IS_OK(status)) { + return ret; + } + + /* fetch from the permanent tdb */ + return dbwrap_fetch_bystring(idmap_tdb2_perm, mem_ctx, keystr); +} + +/* + store into both databases + */ +static NTSTATUS tdb2_store_bystring(const char *keystr, TDB_DATA data, int flags) +{ + NTSTATUS ret; + NTSTATUS status = idmap_tdb2_open_perm_db(); + if (!NT_STATUS_IS_OK(status)) { + return NT_STATUS_UNSUCCESSFUL; + } + ret = dbwrap_store_bystring(idmap_tdb2_perm, keystr, data, flags); + if (!NT_STATUS_IS_OK(ret)) { + ret = tdb_store_bystring(idmap_tdb2_tmp, keystr, data, flags) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL; + } + return ret; +} + +/* + delete from both databases + */ +static NTSTATUS tdb2_delete_bystring(const char *keystr) +{ + NTSTATUS ret; + NTSTATUS status = idmap_tdb2_open_perm_db(); + if (!NT_STATUS_IS_OK(status)) { + return NT_STATUS_UNSUCCESSFUL; + } + ret = dbwrap_delete_bystring(idmap_tdb2_perm, keystr); + if (!NT_STATUS_IS_OK(ret)) { + ret = tdb_delete_bystring(idmap_tdb2_tmp, keystr) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL; + } + return ret; +} + +/* + Initialise idmap database. +*/ +static NTSTATUS idmap_tdb2_db_init(struct idmap_domain *dom) +{ + NTSTATUS ret; + struct idmap_tdb2_context *ctx; + char *config_option = NULL; + const char *range; + NTSTATUS status; + + status = idmap_tdb2_open_cache_db(); + NT_STATUS_NOT_OK_RETURN(status); + + ctx = talloc(dom, struct idmap_tdb2_context); + if ( ! ctx) { + DEBUG(0, ("Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + config_option = talloc_asprintf(ctx, "idmap config %s", dom->name); + if ( ! config_option) { + DEBUG(0, ("Out of memory!\n")); + ret = NT_STATUS_NO_MEMORY; + goto failed; + } + + range = lp_parm_const_string(-1, config_option, "range", NULL); + if (( ! range) || + (sscanf(range, "%u - %u", &ctx->filter_low_id, &ctx->filter_high_id) != 2) || + (ctx->filter_low_id > ctx->filter_high_id)) { + ctx->filter_low_id = 0; + ctx->filter_high_id = 0; + } + + dom->private_data = ctx; + dom->initialized = True; + + talloc_free(config_option); + return NT_STATUS_OK; + +failed: + talloc_free(ctx); + return ret; +} + + +/* + run a script to perform a mapping + + The script should the following command lines: + + SIDTOID S-1-xxxx + IDTOSID UID xxxx + IDTOSID GID xxxx + + and should return one of the following as a single line of text + UID:xxxx + GID:xxxx + SID:xxxx + ERR:xxxx + */ +static NTSTATUS idmap_tdb2_script(struct idmap_tdb2_context *ctx, struct id_map *map, + const char *fmt, ...) +{ + va_list ap; + char *cmd; + FILE *p; + char line[64]; + unsigned long v; + + cmd = talloc_asprintf(ctx, "%s ", idmap_tdb2_state.idmap_script); + NT_STATUS_HAVE_NO_MEMORY(cmd); + + va_start(ap, fmt); + cmd = talloc_vasprintf_append(cmd, fmt, ap); + va_end(ap); + NT_STATUS_HAVE_NO_MEMORY(cmd); + + p = popen(cmd, "r"); + talloc_free(cmd); + if (p == NULL) { + return NT_STATUS_NONE_MAPPED; + } + + if (fgets(line, sizeof(line)-1, p) == NULL) { + pclose(p); + return NT_STATUS_NONE_MAPPED; + } + pclose(p); + + DEBUG(10,("idmap script gave: %s\n", line)); + + if (sscanf(line, "UID:%lu", &v) == 1) { + map->xid.id = v; + map->xid.type = ID_TYPE_UID; + } else if (sscanf(line, "GID:%lu", &v) == 1) { + map->xid.id = v; + map->xid.type = ID_TYPE_GID; + } else if (strncmp(line, "SID:S-", 6) == 0) { + if (!string_to_sid(map->sid, &line[4])) { + DEBUG(0,("Bad SID in '%s' from idmap script %s\n", + line, idmap_tdb2_state.idmap_script)); + return NT_STATUS_NONE_MAPPED; + } + } else { + DEBUG(0,("Bad reply '%s' from idmap script %s\n", + line, idmap_tdb2_state.idmap_script)); + return NT_STATUS_NONE_MAPPED; + } + + return NT_STATUS_OK; +} + + + +/* + Single id to sid lookup function. +*/ +static NTSTATUS idmap_tdb2_id_to_sid(struct idmap_tdb2_context *ctx, struct id_map *map) +{ + NTSTATUS ret; + TDB_DATA data; + char *keystr; + + if (!ctx || !map) { + return NT_STATUS_INVALID_PARAMETER; + } + + /* apply filters before checking */ + if ((ctx->filter_low_id && (map->xid.id < ctx->filter_low_id)) || + (ctx->filter_high_id && (map->xid.id > ctx->filter_high_id))) { + DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n", + map->xid.id, ctx->filter_low_id, ctx->filter_high_id)); + return NT_STATUS_NONE_MAPPED; + } + + switch (map->xid.type) { + + case ID_TYPE_UID: + keystr = talloc_asprintf(ctx, "UID %lu", (unsigned long)map->xid.id); + break; + + case ID_TYPE_GID: + keystr = talloc_asprintf(ctx, "GID %lu", (unsigned long)map->xid.id); + break; + + default: + DEBUG(2, ("INVALID unix ID type: 0x02%x\n", map->xid.type)); + return NT_STATUS_INVALID_PARAMETER; + } + + /* final SAFE_FREE safe */ + data.dptr = NULL; + + if (keystr == NULL) { + DEBUG(0, ("Out of memory!\n")); + ret = NT_STATUS_NO_MEMORY; + goto done; + } + + DEBUG(10,("Fetching record %s\n", keystr)); + + /* Check if the mapping exists */ + data = tdb2_fetch_bystring(keystr, keystr); + + if (!data.dptr) { + fstring sidstr; + + DEBUG(10,("Record %s not found\n", keystr)); + if (idmap_tdb2_state.idmap_script == NULL) { + ret = NT_STATUS_NONE_MAPPED; + goto done; + } + + ret = idmap_tdb2_script(ctx, map, "IDTOSID %s", keystr); + + /* store it on shared storage */ + if (!NT_STATUS_IS_OK(ret)) { + goto done; + } + + if (sid_to_fstring(sidstr, map->sid)) { + /* both forward and reverse mappings */ + tdb2_store_bystring(keystr, + string_term_tdb_data(sidstr), + TDB_REPLACE); + tdb2_store_bystring(sidstr, + string_term_tdb_data(keystr), + TDB_REPLACE); + } + goto done; + } + + if (!string_to_sid(map->sid, (const char *)data.dptr)) { + DEBUG(10,("INVALID SID (%s) in record %s\n", + (const char *)data.dptr, keystr)); + ret = NT_STATUS_INTERNAL_DB_ERROR; + goto done; + } + + DEBUG(10,("Found record %s -> %s\n", keystr, (const char *)data.dptr)); + ret = NT_STATUS_OK; + +done: + talloc_free(keystr); + return ret; +} + + +/* + Single sid to id lookup function. +*/ +static NTSTATUS idmap_tdb2_sid_to_id(struct idmap_tdb2_context *ctx, struct id_map *map) +{ + NTSTATUS ret; + TDB_DATA data; + char *keystr; + unsigned long rec_id = 0; + + if ((keystr = sid_string_talloc(ctx, map->sid)) == NULL) { + DEBUG(0, ("Out of memory!\n")); + ret = NT_STATUS_NO_MEMORY; + goto done; + } + + DEBUG(10,("Fetching record %s\n", keystr)); + + /* Check if sid is present in database */ + data = tdb2_fetch_bystring(keystr, keystr); + if (!data.dptr) { + fstring idstr; + + DEBUG(10,(__location__ " Record %s not found\n", keystr)); + + if (idmap_tdb2_state.idmap_script == NULL) { + ret = NT_STATUS_NONE_MAPPED; + goto done; + } + + ret = idmap_tdb2_script(ctx, map, "SIDTOID %s", keystr); + /* store it on shared storage */ + if (!NT_STATUS_IS_OK(ret)) { + goto done; + } + + snprintf(idstr, sizeof(idstr), "%cID %lu", + map->xid.type == ID_TYPE_UID?'U':'G', + (unsigned long)map->xid.id); + /* store both forward and reverse mappings */ + tdb2_store_bystring(keystr, string_term_tdb_data(idstr), + TDB_REPLACE); + tdb2_store_bystring(idstr, string_term_tdb_data(keystr), + TDB_REPLACE); + goto done; + } + + /* What type of record is this ? */ + if (sscanf((const char *)data.dptr, "UID %lu", &rec_id) == 1) { /* Try a UID record. */ + map->xid.id = rec_id; + map->xid.type = ID_TYPE_UID; + DEBUG(10,("Found uid record %s -> %s \n", keystr, (const char *)data.dptr )); + ret = NT_STATUS_OK; + + } else if (sscanf((const char *)data.dptr, "GID %lu", &rec_id) == 1) { /* Try a GID record. */ + map->xid.id = rec_id; + map->xid.type = ID_TYPE_GID; + DEBUG(10,("Found gid record %s -> %s \n", keystr, (const char *)data.dptr )); + ret = NT_STATUS_OK; + + } else { /* Unknown record type ! */ + DEBUG(2, ("Found INVALID record %s -> %s\n", keystr, (const char *)data.dptr)); + ret = NT_STATUS_INTERNAL_DB_ERROR; + } + + /* apply filters before returning result */ + if ((ctx->filter_low_id && (map->xid.id < ctx->filter_low_id)) || + (ctx->filter_high_id && (map->xid.id > ctx->filter_high_id))) { + DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n", + map->xid.id, ctx->filter_low_id, ctx->filter_high_id)); + ret = NT_STATUS_NONE_MAPPED; + } + +done: + talloc_free(keystr); + return ret; +} + +/* + lookup a set of unix ids. +*/ +static NTSTATUS idmap_tdb2_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids) +{ + struct idmap_tdb2_context *ctx; + NTSTATUS ret; + int i; + + /* make sure we initialized */ + if ( ! dom->initialized) { + ret = idmap_tdb2_db_init(dom); + if ( ! NT_STATUS_IS_OK(ret)) { + return ret; + } + } + + ctx = talloc_get_type(dom->private_data, struct idmap_tdb2_context); + + for (i = 0; ids[i]; i++) { + ret = idmap_tdb2_id_to_sid(ctx, ids[i]); + if ( ! NT_STATUS_IS_OK(ret)) { + + /* if it is just a failed mapping continue */ + if (NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED)) { + + /* make sure it is marked as unmapped */ + ids[i]->status = ID_UNMAPPED; + continue; + } + + /* some fatal error occurred, return immediately */ + goto done; + } + + /* all ok, id is mapped */ + ids[i]->status = ID_MAPPED; + } + + ret = NT_STATUS_OK; + +done: + return ret; +} + +/* + lookup a set of sids. +*/ +static NTSTATUS idmap_tdb2_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids) +{ + struct idmap_tdb2_context *ctx; + NTSTATUS ret; + int i; + + /* make sure we initialized */ + if ( ! dom->initialized) { + ret = idmap_tdb2_db_init(dom); + if ( ! NT_STATUS_IS_OK(ret)) { + return ret; + } + } + + ctx = talloc_get_type(dom->private_data, struct idmap_tdb2_context); + + for (i = 0; ids[i]; i++) { + ret = idmap_tdb2_sid_to_id(ctx, ids[i]); + if ( ! NT_STATUS_IS_OK(ret)) { + + /* if it is just a failed mapping continue */ + if (NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED)) { + + /* make sure it is marked as unmapped */ + ids[i]->status = ID_UNMAPPED; + continue; + } + + /* some fatal error occurred, return immediately */ + goto done; + } + + /* all ok, id is mapped */ + ids[i]->status = ID_MAPPED; + } + + ret = NT_STATUS_OK; + +done: + return ret; +} + + +/* + set a mapping. +*/ +static NTSTATUS idmap_tdb2_set_mapping(struct idmap_domain *dom, const struct id_map *map) +{ + struct idmap_tdb2_context *ctx; + NTSTATUS ret; + TDB_DATA data; + char *ksidstr, *kidstr; + struct db_record *update_lock = NULL; + struct db_record *rec = NULL; + + /* make sure we initialized */ + if ( ! dom->initialized) { + ret = idmap_tdb2_db_init(dom); + if ( ! NT_STATUS_IS_OK(ret)) { + return ret; + } + } + + if (!map || !map->sid) { + return NT_STATUS_INVALID_PARAMETER; + } + + ksidstr = kidstr = NULL; + data.dptr = NULL; + + /* TODO: should we filter a set_mapping using low/high filters ? */ + + ctx = talloc_get_type(dom->private_data, struct idmap_tdb2_context); + + switch (map->xid.type) { + + case ID_TYPE_UID: + kidstr = talloc_asprintf(ctx, "UID %lu", (unsigned long)map->xid.id); + break; + + case ID_TYPE_GID: + kidstr = talloc_asprintf(ctx, "GID %lu", (unsigned long)map->xid.id); + break; + + default: + DEBUG(2, ("INVALID unix ID type: 0x02%x\n", map->xid.type)); + return NT_STATUS_INVALID_PARAMETER; + } + + if (kidstr == NULL) { + DEBUG(0, ("ERROR: Out of memory!\n")); + ret = NT_STATUS_NO_MEMORY; + goto done; + } + + if (!(ksidstr = sid_string_talloc(ctx, map->sid))) { + DEBUG(0, ("Out of memory!\n")); + ret = NT_STATUS_NO_MEMORY; + goto done; + } + + DEBUG(10, ("Storing %s <-> %s map\n", ksidstr, kidstr)); + + /* + * Get us the update lock. This is necessary to get the lock orders + * right, we need to deal with two records under a lock. + */ + + if (!(update_lock = idmap_tdb2_perm->fetch_locked( + idmap_tdb2_perm, ctx, + string_term_tdb_data("UPDATELOCK")))) { + DEBUG(10,("Failed to lock record %s\n", ksidstr)); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + /* + * *DELETE* previous mappings if any. * + */ + + /* First delete indexed on SID */ + + if (((rec = idmap_tdb2_perm->fetch_locked( + idmap_tdb2_perm, update_lock, + string_term_tdb_data(ksidstr))) != NULL) + && (rec->value.dsize != 0)) { + struct db_record *rec2; + + if ((rec2 = idmap_tdb2_perm->fetch_locked( + idmap_tdb2_perm, update_lock, rec->value)) + != NULL) { + rec2->delete_rec(rec2); + TALLOC_FREE(rec2); + } + + rec->delete_rec(rec); + + tdb_delete(idmap_tdb2_tmp, rec->key); + tdb_delete(idmap_tdb2_tmp, rec->value); + } + TALLOC_FREE(rec); + + /* Now delete indexed on unix ID */ + + if (((rec = idmap_tdb2_perm->fetch_locked( + idmap_tdb2_perm, update_lock, + string_term_tdb_data(kidstr))) != NULL) + && (rec->value.dsize != 0)) { + struct db_record *rec2; + + if ((rec2 = idmap_tdb2_perm->fetch_locked( + idmap_tdb2_perm, update_lock, rec->value)) + != NULL) { + rec2->delete_rec(rec2); + TALLOC_FREE(rec2); + } + + rec->delete_rec(rec); + + tdb_delete(idmap_tdb2_tmp, rec->key); + tdb_delete(idmap_tdb2_tmp, rec->value); + } + TALLOC_FREE(rec); + + if (!NT_STATUS_IS_OK(tdb2_store_bystring(ksidstr, string_term_tdb_data(kidstr), + TDB_INSERT))) { + DEBUG(0, ("Error storing SID -> ID\n")); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + if (!NT_STATUS_IS_OK(tdb2_store_bystring(kidstr, string_term_tdb_data(ksidstr), + TDB_INSERT))) { + DEBUG(0, ("Error storing ID -> SID\n")); + /* try to remove the previous stored SID -> ID map */ + tdb2_delete_bystring(ksidstr); + ret = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + DEBUG(10,("Stored %s <-> %s\n", ksidstr, kidstr)); + ret = NT_STATUS_OK; + +done: + talloc_free(ksidstr); + talloc_free(kidstr); + SAFE_FREE(data.dptr); + TALLOC_FREE(update_lock); + return ret; +} + +/* + remove a mapping. +*/ +static NTSTATUS idmap_tdb2_remove_mapping(struct idmap_domain *dom, const struct id_map *map) +{ + /* not supported as it would invalidate the cache tdb on other + nodes */ + DEBUG(0,("idmap_tdb2_remove_mapping not supported\n")); + return NT_STATUS_NOT_SUPPORTED; +} + +/* + Close the idmap tdb instance +*/ +static NTSTATUS idmap_tdb2_close(struct idmap_domain *dom) +{ + /* don't do anything */ + return NT_STATUS_OK; +} + + +/* + Dump all mappings out +*/ +static NTSTATUS idmap_tdb2_dump_data(struct idmap_domain *dom, struct id_map **maps, int *num_maps) +{ + DEBUG(0,("idmap_tdb2_dump_data not supported\n")); + return NT_STATUS_NOT_SUPPORTED; +} + +static struct idmap_methods db_methods = { + .init = idmap_tdb2_db_init, + .unixids_to_sids = idmap_tdb2_unixids_to_sids, + .sids_to_unixids = idmap_tdb2_sids_to_unixids, + .set_mapping = idmap_tdb2_set_mapping, + .remove_mapping = idmap_tdb2_remove_mapping, + .dump_data = idmap_tdb2_dump_data, + .close_fn = idmap_tdb2_close +}; + +static struct idmap_alloc_methods db_alloc_methods = { + .init = idmap_tdb2_alloc_init, + .allocate_id = idmap_tdb2_allocate_id, + .get_id_hwm = idmap_tdb2_get_hwm, + .set_id_hwm = idmap_tdb2_set_hwm, + .close_fn = idmap_tdb2_alloc_close +}; + +NTSTATUS idmap_tdb2_init(void) +{ + NTSTATUS ret; + + /* register both backends */ + ret = smb_register_idmap_alloc(SMB_IDMAP_INTERFACE_VERSION, "tdb2", &db_alloc_methods); + if (! NT_STATUS_IS_OK(ret)) { + DEBUG(0, ("Unable to register idmap alloc tdb2 module: %s\n", get_friendly_nt_error_msg(ret))); + return ret; + } + + return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "tdb2", &db_methods); +} diff --git a/source3/winbindd/winbindd.c b/source3/winbindd/winbindd.c index 07cf22618e..615f4a918e 100644 --- a/source3/winbindd/winbindd.c +++ b/source3/winbindd/winbindd.c @@ -121,7 +121,24 @@ static void flush_caches(void) otherwise cached access denied errors due to restrict anonymous hang around until the sequence number changes. */ - wcache_invalidate_cache(); + if (!wcache_invalidate_cache()) { + DEBUG(0, ("invalidating the cache failed; revalidate the cache\n")); + /* Close the cache to be able to valdite the cache */ + close_winbindd_cache(); + /* + * Ensure all cache and idmap caches are consistent + * before we initialize the cache again. + */ + if (winbindd_validate_cache() < 0) { + DEBUG(0, ("winbindd cache tdb corrupt and no backup " + "could be restore.\n")); + } + + /* Initialize cache again. */ + if (!initialize_winbindd_cache()) { + exit(1); + } + } } /* Handle the signal by unlinking socket and exiting */ @@ -1210,6 +1227,10 @@ int main(int argc, char **argv, char **envp) MSG_WINBIND_VALIDATE_CACHE, winbind_msg_validate_cache); + messaging_register(winbind_messaging_context(), NULL, + MSG_WINBIND_DUMP_DOMAIN_LIST, + winbind_msg_dump_domain_list); + netsamlogon_cache_init(); /* Non-critical */ /* clear the cached list of trusted domains */ diff --git a/source3/winbindd/winbindd.h b/source3/winbindd/winbindd.h index 6bf6e6c68f..c4c1278d73 100644 --- a/source3/winbindd/winbindd.h +++ b/source3/winbindd/winbindd.h @@ -164,9 +164,9 @@ struct winbindd_domain { fstring alt_name; /* alt Domain name, if any (FQDN for ADS) */ fstring forest_name; /* Name of the AD forest we're in */ DOM_SID sid; /* SID for this domain */ - uint32 domain_flags; /* Domain flags from rpc_ds.h */ - uint32 domain_type; /* Domain type from rpc_ds.h */ - uint32 domain_trust_attribs; /* Trust attribs from rpc_ds.h */ + uint32 domain_flags; /* Domain flags from netlogon.h */ + uint32 domain_type; /* Domain type from netlogon.h */ + uint32 domain_trust_attribs; /* Trust attribs from netlogon.h */ bool initialized; /* Did we already ask for the domain mode? */ bool native_mode; /* is this a win2k domain in native mode ? */ bool active_directory; /* is this a win2k active directory ? */ diff --git a/source3/winbindd/winbindd_ads.c b/source3/winbindd/winbindd_ads.c index c9b2a52388..db7ceca04d 100644 --- a/source3/winbindd/winbindd_ads.c +++ b/source3/winbindd/winbindd_ads.c @@ -596,8 +596,9 @@ static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain, num_groups = 0; /* always add the primary group to the sid array */ - if (!add_sid_to_array(mem_ctx, primary_group, user_sids, &num_groups)) { - status = NT_STATUS_NO_MEMORY; + status = add_sid_to_array(mem_ctx, primary_group, user_sids, + &num_groups); + if (!NT_STATUS_IS_OK(status)) { goto done; } @@ -615,10 +616,10 @@ static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain, if (sid_check_is_in_builtin(&group_sid)) { continue; } - - if (!add_sid_to_array(mem_ctx, &group_sid, user_sids, - &num_groups)) { - status = NT_STATUS_NO_MEMORY; + + status = add_sid_to_array(mem_ctx, &group_sid, + user_sids, &num_groups); + if (!NT_STATUS_IS_OK(status)) { goto done; } } @@ -684,8 +685,9 @@ static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain, num_groups = 0; /* always add the primary group to the sid array */ - if (!add_sid_to_array(mem_ctx, primary_group, user_sids, &num_groups)) { - status = NT_STATUS_NO_MEMORY; + status = add_sid_to_array(mem_ctx, primary_group, user_sids, + &num_groups); + if (!NT_STATUS_IS_OK(status)) { goto done; } @@ -720,10 +722,10 @@ static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain, if (sid_check_is_in_builtin(&group_sids[i])) { continue; } - - if (!add_sid_to_array(mem_ctx, &group_sids[i], user_sids, - &num_groups)) { - status = NT_STATUS_NO_MEMORY; + + status = add_sid_to_array(mem_ctx, &group_sids[i], user_sids, + &num_groups); + if (!NT_STATUS_IS_OK(status)) { goto done; } @@ -861,8 +863,9 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, *user_sids = NULL; num_groups = 0; - if (!add_sid_to_array(mem_ctx, &primary_group, user_sids, &num_groups)) { - status = NT_STATUS_NO_MEMORY; + status = add_sid_to_array(mem_ctx, &primary_group, user_sids, + &num_groups); + if (!NT_STATUS_IS_OK(status)) { goto done; } @@ -872,10 +875,10 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, if (sid_check_is_in_builtin(&sids[i])) { continue; } - - if (!add_sid_to_array_unique(mem_ctx, &sids[i], - user_sids, &num_groups)) { - status = NT_STATUS_NO_MEMORY; + + status = add_sid_to_array_unique(mem_ctx, &sids[i], + user_sids, &num_groups); + if (!NT_STATUS_IS_OK(status)) { goto done; } } @@ -1154,12 +1157,11 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain, DOM_SID **dom_sids) { NTSTATUS result = NT_STATUS_UNSUCCESSFUL; - struct ds_domain_trust *domains = NULL; - int count = 0; + struct netr_DomainTrustList trusts; int i; uint32 flags; struct rpc_pipe_client *cli; - uint32 fr_flags = (DS_DOMAIN_IN_FOREST | DS_DOMAIN_TREE_ROOT); + uint32 fr_flags = (NETR_TRUST_FLAG_IN_FOREST | NETR_TRUST_FLAG_TREEROOT); int ret_count; DEBUG(3,("ads: trusted_domains\n")); @@ -1176,11 +1178,11 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain, if ( domain->primary || ((domain->domain_flags&fr_flags) == fr_flags) ) { - flags = DS_DOMAIN_DIRECT_OUTBOUND | - DS_DOMAIN_DIRECT_INBOUND | - DS_DOMAIN_IN_FOREST; + flags = NETR_TRUST_FLAG_OUTBOUND | + NETR_TRUST_FLAG_INBOUND | + NETR_TRUST_FLAG_IN_FOREST; } else { - flags = DS_DOMAIN_IN_FOREST; + flags = NETR_TRUST_FLAG_IN_FOREST; } result = cm_connect_netlogon(domain, &cli); @@ -1191,29 +1193,27 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain, domain->name, nt_errstr(result))); return NT_STATUS_UNSUCCESSFUL; } - - if ( NT_STATUS_IS_OK(result) ) { - result = rpccli_ds_enum_domain_trusts(cli, mem_ctx, - cli->cli->desthost, - flags, &domains, - (unsigned int *)&count); - } - - if ( NT_STATUS_IS_OK(result) && count) { + + result = rpccli_netr_DsrEnumerateDomainTrusts(cli, mem_ctx, + cli->cli->desthost, + flags, + &trusts, + NULL); + if ( NT_STATUS_IS_OK(result) && trusts.count) { /* Allocate memory for trusted domain names and sids */ - if ( !(*names = TALLOC_ARRAY(mem_ctx, char *, count)) ) { + if ( !(*names = TALLOC_ARRAY(mem_ctx, char *, trusts.count)) ) { DEBUG(0, ("trusted_domains: out of memory\n")); return NT_STATUS_NO_MEMORY; } - if ( !(*alt_names = TALLOC_ARRAY(mem_ctx, char *, count)) ) { + if ( !(*alt_names = TALLOC_ARRAY(mem_ctx, char *, trusts.count)) ) { DEBUG(0, ("trusted_domains: out of memory\n")); return NT_STATUS_NO_MEMORY; } - if ( !(*dom_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, count)) ) { + if ( !(*dom_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, trusts.count)) ) { DEBUG(0, ("trusted_domains: out of memory\n")); return NT_STATUS_NO_MEMORY; } @@ -1222,7 +1222,7 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain, ret_count = 0; - for (i = 0; i < count; i++) { + for (i = 0; i < trusts.count; i++) { struct winbindd_domain d; /* drop external trusts if this is not our primary @@ -1230,24 +1230,24 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain, domains may be less that the ones actually trusted by the DC. */ - if ( (domains[i].trust_attributes == DS_DOMAIN_TRUST_ATTRIB_QUARANTINED_DOMAIN) && + if ( (trusts.array[i].trust_attributes == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) && !domain->primary ) { DEBUG(10,("trusted_domains: Skipping external trusted domain " "%s because it is outside of our primary domain\n", - domains[i].netbios_domain)); + trusts.array[i].netbios_name)); continue; } - (*names)[ret_count] = domains[i].netbios_domain; - (*alt_names)[ret_count] = domains[i].dns_domain; - sid_copy(&(*dom_sids)[ret_count], &domains[i].sid); + (*names)[ret_count] = CONST_DISCARD(char *, trusts.array[i].netbios_name); + (*alt_names)[ret_count] = CONST_DISCARD(char *, trusts.array[i].dns_name); + sid_copy(&(*dom_sids)[ret_count], trusts.array[i].sid); /* add to the trusted domain cache */ - fstrcpy( d.name, domains[i].netbios_domain ); - fstrcpy( d.alt_name, domains[i].dns_domain ); - sid_copy( &d.sid, &domains[i].sid ); + fstrcpy( d.name, trusts.array[i].netbios_name); + fstrcpy( d.alt_name, trusts.array[i].dns_name); + sid_copy( &d.sid, trusts.array[i].sid); /* This gets a little tricky. If we are following a transitive forest trust, then @@ -1266,16 +1266,28 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain, we have the current trust flags and attributes */ - d.domain_flags = domains[i].flags; - d.domain_type = domains[i].trust_type; - d.domain_trust_attribs = domains[i].trust_attributes; + d.domain_flags = trusts.array[i].trust_flags; + d.domain_type = trusts.array[i].trust_type; + d.domain_trust_attribs = trusts.array[i].trust_attributes; } else { + /* Look up the record in the cache */ + struct winbindd_tdc_domain *parent; + DEBUG(10,("trusted_domains(ads): Inheriting trust " "flags for domain %s\n", d.alt_name)); + + parent = wcache_tdc_fetch_domain(NULL, domain->name); + if (parent) { + d.domain_flags = parent->trust_flags; + d.domain_type = parent->trust_type; + d.domain_trust_attribs = parent->trust_attribs; + } else { d.domain_flags = domain->domain_flags; d.domain_type = domain->domain_type; d.domain_trust_attribs = domain->domain_trust_attribs; } + TALLOC_FREE(parent); + } wcache_tdc_add_domain( &d ); diff --git a/source3/winbindd/winbindd_async.c b/source3/winbindd/winbindd_async.c index 76724582a1..ab32ee0c76 100644 --- a/source3/winbindd/winbindd_async.c +++ b/source3/winbindd/winbindd_async.c @@ -492,7 +492,9 @@ static bool parse_sidlist(TALLOC_CTX *mem_ctx, char *sidstr, DEBUG(0, ("Could not parse sid %s\n", p)); return False; } - if (!add_sid_to_array(mem_ctx, &sid, sids, num_sids)) { + if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &sid, sids, + num_sids))) + { return False; } p = q; @@ -714,7 +716,9 @@ enum winbindd_result winbindd_dual_getsidaliases(struct winbindd_domain *domain, DEBUGADD(10, (" rid %d\n", alias_rids[i])); sid_copy(&sid, &domain->sid); sid_append_rid(&sid, alias_rids[i]); - if (!add_sid_to_array(state->mem_ctx, &sid, &sids, &num_sids)) { + result = add_sid_to_array(state->mem_ctx, &sid, &sids, + &num_sids); + if (!NT_STATUS_IS_OK(result)) { return WINBINDD_ERROR; } } @@ -832,8 +836,9 @@ static void gettoken_recvdomgroups(TALLOC_CTX *mem_ctx, bool success, state->sids = NULL; state->num_sids = 0; - if (!add_sid_to_array(mem_ctx, &state->user_sid, &state->sids, - &state->num_sids)) { + if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &state->user_sid, + &state->sids, &state->num_sids))) + { DEBUG(0, ("Out of memory\n")); state->cont(state->private_data, False, NULL, 0); return; @@ -874,8 +879,11 @@ static void gettoken_recvaliases(void *private_data, bool success, } for (i=0; i<num_aliases; i++) { - if (!add_sid_to_array(state->mem_ctx, &aliases[i], - &state->sids, &state->num_sids)) { + if (!NT_STATUS_IS_OK(add_sid_to_array(state->mem_ctx, + &aliases[i], + &state->sids, + &state->num_sids))) + { DEBUG(0, ("Out of memory\n")); state->cont(state->private_data, False, NULL, 0); return; diff --git a/source3/winbindd/winbindd_cache.c b/source3/winbindd/winbindd_cache.c index f63c7a5b2f..c293861492 100644 --- a/source3/winbindd/winbindd_cache.c +++ b/source3/winbindd/winbindd_cache.c @@ -62,7 +62,7 @@ static bool is_non_centry_key(TDB_DATA kbuf) int i; if (kbuf.dptr == NULL || kbuf.dsize == 0) { - return False; + return false; } for (i = 0; non_centry_keys[i] != NULL; i++) { size_t namelen = strlen(non_centry_keys[i]); @@ -70,10 +70,10 @@ static bool is_non_centry_key(TDB_DATA kbuf) continue; } if (strncmp(non_centry_keys[i], (const char *)kbuf.dptr, namelen) == 0) { - return True; + return true; } } - return False; + return false; } /* Global online/offline state - False when online. winbindd starts up online @@ -210,9 +210,9 @@ static bool centry_check_bytes(struct cache_entry *centry, size_t nbytes) DEBUG(0,("centry corruption? needed %u bytes, have %d\n", (unsigned int)nbytes, centry->len - centry->ofs)); - return False; + return false; } - return True; + return true; } /* @@ -348,9 +348,9 @@ static bool centry_sid(struct cache_entry *centry, TALLOC_CTX *mem_ctx, DOM_SID char *sid_string; sid_string = centry_string(centry, mem_ctx); if ((sid_string == NULL) || (!string_to_sid(sid, sid_string))) { - return False; + return false; } - return True; + return true; } @@ -372,7 +372,7 @@ static bool wcache_server_down(struct winbindd_domain *domain) bool ret; if (!wcache->tdb) - return False; + return false; ret = (domain->sequence_number == DOM_SEQUENCE_NONE); @@ -454,7 +454,7 @@ static NTSTATUS store_cache_seqnum( struct winbindd_domain *domain ) } /* - refresh the domain sequence number. If force is True + refresh the domain sequence number. If force is true then always refresh it, no matter how recently we fetched it */ @@ -538,7 +538,7 @@ static bool centry_expired(struct winbindd_domain *domain, const char *keystr, s if (lp_winbind_offline_logon() && global_winbindd_offline_state) { DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n", keystr, domain->name )); - return False; + return false; } /* when the domain is offline return the cached entry. @@ -547,7 +547,7 @@ static bool centry_expired(struct winbindd_domain *domain, const char *keystr, s if (!domain->online) { DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n", keystr, domain->name )); - return False; + return false; } /* if the server is OK and our cache entry came from when it was down then @@ -556,7 +556,7 @@ static bool centry_expired(struct winbindd_domain *domain, const char *keystr, s (centry->sequence_number == DOM_SEQUENCE_NONE)) { DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n", keystr, domain->name )); - return True; + return true; } /* if the server is down or the cache entry is not older than the @@ -565,14 +565,14 @@ static bool centry_expired(struct winbindd_domain *domain, const char *keystr, s centry->sequence_number == domain->sequence_number) { DEBUG(10,("centry_expired: Key %s for domain %s is good.\n", keystr, domain->name )); - return False; + return false; } DEBUG(10,("centry_expired: Key %s for domain %s expired\n", keystr, domain->name )); /* it's expired */ - return True; + return true; } static struct cache_entry *wcache_fetch_raw(char *kstr) @@ -625,7 +625,7 @@ static struct cache_entry *wcache_fetch(struct winbind_cache *cache, return NULL; } - refresh_sequence_number(domain, False); + refresh_sequence_number(domain, false); va_start(ap, format); smb_xvasprintf(&kstr, format, ap); @@ -1189,7 +1189,7 @@ do_query: (retry++ < 5)); /* and save it */ - refresh_sequence_number(domain, False); + refresh_sequence_number(domain, false); centry = centry_start(domain, status); if (!centry) goto skip_save; @@ -1280,7 +1280,7 @@ do_query: status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info); /* and save it */ - refresh_sequence_number(domain, False); + refresh_sequence_number(domain, false); centry = centry_start(domain, status); if (!centry) goto skip_save; @@ -1364,7 +1364,7 @@ do_query: status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info); /* and save it */ - refresh_sequence_number(domain, False); + refresh_sequence_number(domain, false); centry = centry_start(domain, status); if (!centry) goto skip_save; @@ -1437,7 +1437,7 @@ do_query: domain_name, name, sid, type); /* and save it */ - refresh_sequence_number(domain, False); + refresh_sequence_number(domain, false); if (domain->online && (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) { @@ -1510,7 +1510,7 @@ do_query: status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type); /* and save it */ - refresh_sequence_number(domain, False); + refresh_sequence_number(domain, false); wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type); /* We can't save the name to sid mapping here, as with sid history a @@ -1554,7 +1554,7 @@ static NTSTATUS rids_to_names(struct winbindd_domain *domain, goto error; } - have_mapped = have_unmapped = False; + have_mapped = have_unmapped = false; for (i=0; i<num_rids; i++) { DOM_SID sid; @@ -1577,7 +1577,7 @@ static NTSTATUS rids_to_names(struct winbindd_domain *domain, if (NT_STATUS_IS_OK(centry->status)) { char *dom; - have_mapped = True; + have_mapped = true; (*types)[i] = (enum lsa_SidType)centry_uint32(centry); dom = centry_string(centry, mem_ctx); @@ -1590,7 +1590,7 @@ static NTSTATUS rids_to_names(struct winbindd_domain *domain, (*names)[i] = centry_string(centry, *names); } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) { - have_unmapped = True; + have_unmapped = true; } else { /* something's definitely wrong */ @@ -1647,7 +1647,7 @@ static NTSTATUS rids_to_names(struct winbindd_domain *domain, return result; } - refresh_sequence_number(domain, False); + refresh_sequence_number(domain, false); for (i=0; i<num_rids; i++) { DOM_SID sid; @@ -1739,7 +1739,7 @@ do_query: status = domain->backend->query_user(domain, mem_ctx, user_sid, info); /* and save it */ - refresh_sequence_number(domain, False); + refresh_sequence_number(domain, false); wcache_save_user(domain, status, info); return status; @@ -1819,7 +1819,7 @@ do_query: goto skip_save; /* and save it */ - refresh_sequence_number(domain, False); + refresh_sequence_number(domain, false); centry = centry_start(domain, status); if (!centry) goto skip_save; @@ -1912,7 +1912,7 @@ static NTSTATUS lookup_useraliases(struct winbindd_domain *domain, num_aliases, alias_rids); /* and save it */ - refresh_sequence_number(domain, False); + refresh_sequence_number(domain, false); centry = centry_start(domain, status); if (!centry) goto skip_save; @@ -1993,7 +1993,7 @@ do_query: sid_mem, names, name_types); /* and save it */ - refresh_sequence_number(domain, False); + refresh_sequence_number(domain, false); centry = centry_start(domain, status); if (!centry) goto skip_save; @@ -2013,7 +2013,7 @@ skip_save: /* find the sequence number for a domain */ static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq) { - refresh_sequence_number(domain, False); + refresh_sequence_number(domain, false); *seq = domain->sequence_number; @@ -2104,7 +2104,7 @@ do_query: the main parent and always to make the query. --jerry */ /* and save it */ - refresh_sequence_number(domain, False); + refresh_sequence_number(domain, false); centry = centry_start(domain, status); if (!centry) @@ -2170,7 +2170,7 @@ do_query: status = domain->backend->lockout_policy(domain, mem_ctx, policy); /* and save it */ - refresh_sequence_number(domain, False); + refresh_sequence_number(domain, false); wcache_save_lockout_policy(domain, status, policy); return status; @@ -2221,7 +2221,7 @@ do_query: status = domain->backend->password_policy(domain, mem_ctx, policy); /* and save it */ - refresh_sequence_number(domain, False); + refresh_sequence_number(domain, false); wcache_save_password_policy(domain, status, policy); return status; @@ -2261,7 +2261,7 @@ void wcache_invalidate_samlogon(struct winbindd_domain *domain, netsamlogon_clear_cached_user(cache->tdb, info3); } -void wcache_invalidate_cache(void) +bool wcache_invalidate_cache(void) { struct winbindd_domain *domain; @@ -2270,9 +2270,15 @@ void wcache_invalidate_cache(void) DEBUG(10, ("wcache_invalidate_cache: invalidating cache " "entries for %s\n", domain->name)); - if (cache) - tdb_traverse(cache->tdb, traverse_fn, NULL); + if (cache) { + if (cache->tdb) { + tdb_traverse(cache->tdb, traverse_fn, NULL); + } else { + return false; + } + } } + return true; } bool init_wcache(void) @@ -2283,7 +2289,7 @@ bool init_wcache(void) } if (wcache->tdb != NULL) - return True; + return true; /* when working offline we must not clear the cache on restart */ wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), @@ -2293,10 +2299,10 @@ bool init_wcache(void) if (wcache->tdb == NULL) { DEBUG(0,("Failed to open winbindd_cache.tdb!\n")); - return False; + return false; } - return True; + return true; } /************************************************************************ @@ -2307,18 +2313,18 @@ bool init_wcache(void) bool initialize_winbindd_cache(void) { - bool cache_bad = True; + bool cache_bad = true; uint32 vers; if (!init_wcache()) { DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n")); - return False; + return false; } /* Check version number. */ if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) && vers == WINBINDD_CACHE_VERSION) { - cache_bad = False; + cache_bad = false; } if (cache_bad) { @@ -2333,25 +2339,36 @@ bool initialize_winbindd_cache(void) DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ", lock_path("winbindd_cache.tdb"), strerror(errno) )); - return False; + return false; } if (!init_wcache()) { DEBUG(0,("initialize_winbindd_cache: re-initialization " "init_wcache failed.\n")); - return False; + return false; } /* Write the version. */ if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) { DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n", tdb_errorstr(wcache->tdb) )); - return False; + return false; } } tdb_close(wcache->tdb); wcache->tdb = NULL; - return True; + return true; +} + +void close_winbindd_cache(void) +{ + if (!wcache) { + return; + } + if (wcache->tdb) { + tdb_close(wcache->tdb); + wcache->tdb = NULL; + } } void cache_store_response(pid_t pid, struct winbindd_response *response) @@ -2400,7 +2417,7 @@ bool cache_retrieve_response(pid_t pid, struct winbindd_response * response) fstring key_str; if (!init_wcache()) - return False; + return false; DEBUG(10, ("Retrieving response for pid %d\n", pid)); @@ -2408,17 +2425,17 @@ bool cache_retrieve_response(pid_t pid, struct winbindd_response * response) data = tdb_fetch(wcache->tdb, string_tdb_data(key_str)); if (data.dptr == NULL) - return False; + return false; if (data.dsize != sizeof(*response)) - return False; + return false; memcpy(response, data.dptr, data.dsize); SAFE_FREE(data.dptr); if (response->length == sizeof(*response)) { response->extra_data.data = NULL; - return True; + return true; } /* There's extra data */ @@ -2431,19 +2448,19 @@ bool cache_retrieve_response(pid_t pid, struct winbindd_response * response) if (data.dptr == NULL) { DEBUG(0, ("Did not find extra data\n")); - return False; + return false; } if (data.dsize != (response->length - sizeof(*response))) { DEBUG(0, ("Invalid extra data length: %d\n", (int)data.dsize)); SAFE_FREE(data.dptr); - return False; + return false; } dump_data(11, (uint8 *)data.dptr, data.dsize); response->extra_data.data = data.dptr; - return True; + return true; } void cache_cleanup_response(pid_t pid) @@ -2475,19 +2492,19 @@ bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid, domain = find_lookup_domain_from_sid(sid); if (domain == NULL) { - return False; + return false; } cache = get_cache(domain); if (cache->tdb == NULL) { - return False; + return false; } centry = wcache_fetch(cache, domain, "SN/%s", sid_to_fstring(tmp, sid)); if (centry == NULL) { - return False; + return false; } if (NT_STATUS_IS_OK(centry->status)) { @@ -2516,13 +2533,13 @@ bool lookup_cached_name(TALLOC_CTX *mem_ctx, domain = find_lookup_domain_from_name(domain_name); if (domain == NULL) { - return False; + return false; } cache = get_cache(domain); if (cache->tdb == NULL) { - return False; + return false; } fstrcpy(uname, name); @@ -2532,12 +2549,12 @@ bool lookup_cached_name(TALLOC_CTX *mem_ctx, offline so the cache won't expire the entry */ original_online_state = domain->online; - domain->online = False; + domain->online = false; centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname); domain->online = original_online_state; if (centry == NULL) { - return False; + return false; } if (NT_STATUS_IS_OK(centry->status)) { @@ -2555,7 +2572,7 @@ void cache_name2sid(struct winbindd_domain *domain, const char *domain_name, const char *name, enum lsa_SidType type, const DOM_SID *sid) { - refresh_sequence_number(domain, False); + refresh_sequence_number(domain, false); wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name, sid, type); } @@ -2769,17 +2786,17 @@ bool set_global_winbindd_state_offline(void) if (wcache == NULL || wcache->tdb == NULL) { DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n")); - return False; + return false; } if (!lp_winbind_offline_logon()) { DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n")); - return False; + return false; } if (global_winbindd_offline_state) { /* Already offline. */ - return True; + return true; } data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" ); @@ -2787,12 +2804,12 @@ bool set_global_winbindd_state_offline(void) if (!data.dptr || data.dsize != 4) { DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n")); SAFE_FREE(data.dptr); - return False; + return false; } else { DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n")); - global_winbindd_offline_state = True; + global_winbindd_offline_state = true; SAFE_FREE(data.dptr); - return True; + return true; } } @@ -2809,7 +2826,7 @@ void set_global_winbindd_state_online(void) /* Already online. */ return; } - global_winbindd_offline_state = False; + global_winbindd_offline_state = false; if (!wcache->tdb) { return; @@ -2846,8 +2863,8 @@ static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA dat /* huh? corrupt cache? */ DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr)); centry_free(centry); - state->bad_entry = True; - state->success = False; + state->bad_entry = true; + state->success = false; return NULL; } @@ -2862,7 +2879,7 @@ static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbu if (dbuf.dsize != 8) { DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n", keystr, (unsigned int)dbuf.dsize )); - state->bad_entry = True; + state->bad_entry = true; return 1; } return 0; @@ -3157,8 +3174,8 @@ static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, if (dbuf.dsize == 0) { DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n", keystr)); - state->bad_entry = True; - state->success = False; + state->bad_entry = true; + state->success = false; return 1; } @@ -3173,8 +3190,8 @@ static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, if (dbuf.dsize == 0) { DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n", keystr)); - state->bad_entry = True; - state->success = False; + state->bad_entry = true; + state->success = false; return 1; } @@ -3217,8 +3234,8 @@ static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr, if (dbuf.dsize == 0) { DEBUG(0, ("validate_trustdomcache: Corrupt cache for " "key %s (len ==0) ?\n", keystr)); - state->bad_entry = True; - state->success = False; + state->bad_entry = true; + state->success = false; return 1; } @@ -3233,8 +3250,8 @@ static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA db if (dbuf.dsize != 4) { DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n", keystr, (unsigned int)dbuf.dsize )); - state->bad_entry = True; - state->success = False; + state->bad_entry = true; + state->success = false; return 1; } DEBUG(10,("validate_offline: %s ok\n", keystr)); @@ -3248,8 +3265,8 @@ static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_D DEBUG(0, ("validate_cache_version: Corrupt cache for " "key %s (len %u != 4) ?\n", keystr, (unsigned int)dbuf.dsize)); - state->bad_entry = True; - state->success = False; + state->bad_entry = true; + state->success = false; return 1; } @@ -3338,8 +3355,8 @@ static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_D dump_data(0, (uint8 *)kbuf.dptr, kbuf.dsize); DEBUG(0,("data :\n")); dump_data(0, (uint8 *)dbuf.dptr, dbuf.dsize); - v_state->unknown_key = True; - v_state->success = False; + v_state->unknown_key = true; + v_state->success = false; return 1; /* terminate. */ } @@ -3433,7 +3450,7 @@ static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom, struct winbindd_tdc_domain *list = NULL; size_t idx; int i; - bool set_only = False; + bool set_only = false; /* don't allow duplicates */ @@ -3445,7 +3462,7 @@ static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom, DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n", new_dom->name)); idx = i; - set_only = True; + set_only = true; break; } @@ -3466,7 +3483,7 @@ static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom, } if ( !list ) - return False; + return false; list[idx].domain_name = talloc_strdup( list, new_dom->name ); list[idx].dns_name = talloc_strdup( list, new_dom->alt_name ); @@ -3488,7 +3505,7 @@ static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom, *num_domains = idx + 1; } - return True; + return true; } /********************************************************************* @@ -3644,7 +3661,7 @@ static bool wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t n int ret; if ( !key.dptr ) - return False; + return false; /* See if we were asked to delete the cache entry */ @@ -3681,23 +3698,23 @@ bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_do *num_domains = 0; if ( !key.dptr ) - return False; + return false; data = tdb_fetch( wcache->tdb, key ); SAFE_FREE( key.dptr ); if ( !data.dptr ) - return False; + return false; *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains ); SAFE_FREE( data.dptr ); if ( !*domains ) - return False; + return false; - return True; + return true; } /********************************************************************* @@ -3707,7 +3724,7 @@ bool wcache_tdc_add_domain( struct winbindd_domain *domain ) { struct winbindd_tdc_domain *dom_list = NULL; size_t num_domains = 0; - bool ret = False; + bool ret = false; DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, " "flags = 0x%x, attributes = 0x%x, type = 0x%x\n", @@ -3718,7 +3735,7 @@ bool wcache_tdc_add_domain( struct winbindd_domain *domain ) domain->domain_type)); if ( !init_wcache() ) { - return False; + return false; } /* fetch the list */ @@ -3739,7 +3756,7 @@ bool wcache_tdc_add_domain( struct winbindd_domain *domain ) /* Success */ - ret = True; + ret = true; done: TALLOC_FREE( dom_list ); @@ -3759,7 +3776,7 @@ struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const cha DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name)); if ( !init_wcache() ) { - return False; + return false; } /* fetch the list */ @@ -3892,7 +3909,7 @@ do_query: /* the cache backend methods are exposed via this structure */ struct winbindd_methods cache_methods = { - True, + true, query_user_list, enum_dom_groups, enum_local_groups, diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c index cb366a293c..d2a7663002 100644 --- a/source3/winbindd/winbindd_cm.c +++ b/source3/winbindd/winbindd_cm.c @@ -74,7 +74,7 @@ extern bool override_logfile; static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain); static void set_dc_type_and_flags( struct winbindd_domain *domain ); -static bool get_dcs(TALLOC_CTX *mem_ctx, const struct winbindd_domain *domain, +static bool get_dcs(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain, struct dc_name_ip **dcs, int *num_dcs); /**************************************************************** @@ -560,7 +560,7 @@ static void cm_get_ipc_userpass(char **username, char **domain, char **password) } } -static bool get_dc_name_via_netlogon(const struct winbindd_domain *domain, +static bool get_dc_name_via_netlogon(struct winbindd_domain *domain, fstring dcname, struct sockaddr_storage *dc_ss) { @@ -570,7 +570,7 @@ static bool get_dc_name_via_netlogon(const struct winbindd_domain *domain, WERROR werr; TALLOC_CTX *mem_ctx; unsigned int orig_timeout; - fstring tmp; + char *tmp = NULL; char *p; /* Hmmmm. We can only open one connection to the NETLOGON pipe at the @@ -600,18 +600,51 @@ static bool get_dc_name_via_netlogon(const struct winbindd_domain *domain, 35 seconds should do it. */ orig_timeout = cli_set_timeout(netlogon_pipe->cli, 35000); - - werr = rpccli_netlogon_getanydcname(netlogon_pipe, mem_ctx, our_domain->dcname, - domain->name, tmp); + + if (our_domain->active_directory) { + struct DS_DOMAIN_CONTROLLER_INFO *domain_info = NULL; + + werr = rpccli_netlogon_dsr_getdcname(netlogon_pipe, + mem_ctx, + our_domain->dcname, + domain->name, + NULL, + NULL, + DS_RETURN_DNS_NAME, + &domain_info); + if (W_ERROR_IS_OK(werr)) { + tmp = talloc_strdup( + mem_ctx, domain_info->domain_controller_name); + if (tmp == NULL) { + DEBUG(0, ("talloc_strdup failed\n")); + talloc_destroy(mem_ctx); + return false; + } + if (strlen(domain->alt_name) == 0) { + fstrcpy(domain->alt_name, + domain_info->domain_name); + } + if (strlen(domain->forest_name) == 0) { + fstrcpy(domain->forest_name, + domain_info->dns_forest_name); + } + } + } else { + + werr = rpccli_netlogon_getanydcname(netlogon_pipe, + mem_ctx, + our_domain->dcname, + domain->name, + &tmp); + } /* And restore our original timeout. */ cli_set_timeout(netlogon_pipe->cli, orig_timeout); - talloc_destroy(mem_ctx); - if (!W_ERROR_IS_OK(werr)) { DEBUG(10, ("rpccli_netlogon_getanydcname failed: %s\n", dos_errstr(werr))); + talloc_destroy(mem_ctx); return False; } @@ -626,6 +659,8 @@ static bool get_dc_name_via_netlogon(const struct winbindd_domain *domain, fstrcpy(dcname, p); + talloc_destroy(mem_ctx); + DEBUG(10, ("rpccli_netlogon_getanydcname returned %s\n", dcname)); if (!resolve_name(dcname, dc_ss, 0x20)) { @@ -644,8 +679,22 @@ static NTSTATUS get_trust_creds(const struct winbindd_domain *domain, char **machine_krb5_principal) { const char *account_name; + const char *name = NULL; + + /* If we are a DC and this is not our own domain */ - if (!get_trust_pw_clear(domain->name, machine_password, + if (IS_DC) { + name = domain->name; + } else { + struct winbindd_domain *our_domain = find_our_domain(); + + if (!our_domain) + return NT_STATUS_INVALID_SERVER_STATE; + + name = our_domain->name; + } + + if (!get_trust_pw_clear(name, machine_password, &account_name, NULL)) { return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; @@ -659,11 +708,15 @@ static NTSTATUS get_trust_creds(const struct winbindd_domain *domain, /* this is at least correct when domain is our domain, * which is the only case, when this is currently used: */ - if ((machine_krb5_principal != NULL) && - (asprintf(machine_krb5_principal, "%s$@%s", account_name, - domain->alt_name) == -1)) + if (machine_krb5_principal != NULL) { - return NT_STATUS_NO_MEMORY; + if (asprintf(machine_krb5_principal, "%s$@%s", + account_name, domain->alt_name) == -1) + { + return NT_STATUS_NO_MEMORY; + } + + strupper_m(*machine_krb5_principal); } return NT_STATUS_OK; @@ -978,6 +1031,7 @@ static bool send_getdc_request(struct sockaddr_storage *dc_ss, char *p; fstring my_acct_name; fstring my_mailslot; + size_t sid_size; if (dc_ss->ss_family != AF_INET) { return false; @@ -1019,7 +1073,9 @@ static bool send_getdc_request(struct sockaddr_storage *dc_ss, SIVAL(p, 0, 0x80); p+=4; - SIVAL(p, 0, sid_size(sid)); + sid_size = ndr_size_dom_sid(sid, 0); + + SIVAL(p, 0, sid_size); p+=4; p = ALIGN4(p, outbuf); @@ -1027,12 +1083,12 @@ static bool send_getdc_request(struct sockaddr_storage *dc_ss, return false; } - sid_linearize(p, sid_size(sid), sid); - if (sid_size(sid) + 8 > sizeof(outbuf) - PTR_DIFF(p, outbuf)) { + if (sid_size + 8 > sizeof(outbuf) - PTR_DIFF(p, outbuf)) { return false; } + sid_linearize(p, sizeof(outbuf) - PTR_DIFF(p, outbuf), sid); - p += sid_size(sid); + p += sid_size; SIVAL(p, 0, 1); SSVAL(p, 4, 0xffff); @@ -1216,7 +1272,7 @@ static bool dcip_to_name(const struct winbindd_domain *domain, the dcs[] with results. *******************************************************************/ -static bool get_dcs(TALLOC_CTX *mem_ctx, const struct winbindd_domain *domain, +static bool get_dcs(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain, struct dc_name_ip **dcs, int *num_dcs) { fstring dcname; @@ -1319,7 +1375,7 @@ static bool get_dcs(TALLOC_CTX *mem_ctx, const struct winbindd_domain *domain, } static bool find_new_dc(TALLOC_CTX *mem_ctx, - const struct winbindd_domain *domain, + struct winbindd_domain *domain, fstring dcname, struct sockaddr_storage *pss, int *fd) { struct dc_name_ip *dcs = NULL; @@ -1660,12 +1716,11 @@ static bool set_dc_type_and_flags_trustinfo( struct winbindd_domain *domain ) { struct winbindd_domain *our_domain; NTSTATUS result = NT_STATUS_UNSUCCESSFUL; - struct ds_domain_trust *domains = NULL; - int count = 0; + struct netr_DomainTrustList trusts; int i; - uint32 flags = (DS_DOMAIN_IN_FOREST | - DS_DOMAIN_DIRECT_OUTBOUND | - DS_DOMAIN_DIRECT_INBOUND); + uint32 flags = (NETR_TRUST_FLAG_IN_FOREST | + NETR_TRUST_FLAG_OUTBOUND | + NETR_TRUST_FLAG_INBOUND); struct rpc_pipe_client *cli; TALLOC_CTX *mem_ctx = NULL; @@ -1707,27 +1762,35 @@ static bool set_dc_type_and_flags_trustinfo( struct winbindd_domain *domain ) return False; } - result = rpccli_ds_enum_domain_trusts(cli, mem_ctx, - cli->cli->desthost, - flags, &domains, - (unsigned int *)&count); + result = rpccli_netr_DsrEnumerateDomainTrusts(cli, mem_ctx, + cli->cli->desthost, + flags, + &trusts, + NULL); + if (!NT_STATUS_IS_OK(result)) { + DEBUG(0,("set_dc_type_and_flags_trustinfo: " + "failed to query trusted domain list: %s\n", + nt_errstr(result))); + talloc_destroy(mem_ctx); + return false; + } /* Now find the domain name and get the flags */ - for ( i=0; i<count; i++ ) { - if ( strequal( domain->name, domains[i].netbios_domain ) ) { - domain->domain_flags = domains[i].flags; - domain->domain_type = domains[i].trust_type; - domain->domain_trust_attribs = domains[i].trust_attributes; - - if ( domain->domain_type == DS_DOMAIN_TRUST_TYPE_UPLEVEL ) + for ( i=0; i<trusts.count; i++ ) { + if ( strequal( domain->name, trusts.array[i].netbios_name) ) { + domain->domain_flags = trusts.array[i].trust_flags; + domain->domain_type = trusts.array[i].trust_type; + domain->domain_trust_attribs = trusts.array[i].trust_attributes; + + if ( domain->domain_type == NETR_TRUST_TYPE_UPLEVEL ) domain->active_directory = True; /* This flag is only set if the domain is *our* primary domain and the primary domain is in native mode */ - domain->native_mode = (domain->domain_flags & DS_DOMAIN_NATIVE_MODE); + domain->native_mode = (domain->domain_flags & NETR_TRUST_FLAG_NATIVE); DEBUG(5, ("set_dc_type_and_flags_trustinfo: domain %s is %sin " "native mode.\n", domain->name, @@ -1763,17 +1826,17 @@ static bool set_dc_type_and_flags_trustinfo( struct winbindd_domain *domain ) static void set_dc_type_and_flags_connect( struct winbindd_domain *domain ) { NTSTATUS result; - DS_DOMINFO_CTR ctr; + WERROR werr; TALLOC_CTX *mem_ctx = NULL; struct rpc_pipe_client *cli; POLICY_HND pol; + union dssetup_DsRoleInfo info; - char *domain_name = NULL; - char *dns_name = NULL; - char *forest_name = NULL; + const char *domain_name = NULL; + const char *dns_name = NULL; + const char *forest_name = NULL; DOM_SID *dom_sid = NULL; - ZERO_STRUCT( ctr ); if (!connection_ok(domain)) { return; @@ -1788,24 +1851,25 @@ static void set_dc_type_and_flags_connect( struct winbindd_domain *domain ) DEBUG(5, ("set_dc_type_and_flags_connect: domain %s\n", domain->name )); - cli = cli_rpc_pipe_open_noauth(domain->conn.cli, PI_LSARPC_DS, + cli = cli_rpc_pipe_open_noauth(domain->conn.cli, PI_DSSETUP, &result); if (cli == NULL) { DEBUG(5, ("set_dc_type_and_flags_connect: Could not bind to " - "PI_LSARPC_DS on domain %s: (%s)\n", + "PI_DSSETUP on domain %s: (%s)\n", domain->name, nt_errstr(result))); /* if this is just a non-AD domain we need to continue * identifying so that we can in the end return with * domain->initialized = True - gd */ - goto no_lsarpc_ds; + goto no_dssetup; } - result = rpccli_ds_getprimarydominfo(cli, mem_ctx, - DsRolePrimaryDomainInfoBasic, - &ctr); + result = rpccli_dssetup_DsRoleGetPrimaryDomainInformation(cli, mem_ctx, + DS_ROLE_BASIC_INFORMATION, + &info, + &werr); cli_rpc_pipe_close(cli); if (!NT_STATUS_IS_OK(result)) { @@ -1814,26 +1878,26 @@ static void set_dc_type_and_flags_connect( struct winbindd_domain *domain ) domain->name, nt_errstr(result))); /* older samba3 DCs will return DCERPC_FAULT_OP_RNG_ERROR for - * every opcode on the LSARPC_DS pipe, continue with - * no_lsarpc_ds mode here as well to get domain->initialized + * every opcode on the DSSETUP pipe, continue with + * no_dssetup mode here as well to get domain->initialized * set - gd */ if (NT_STATUS_V(result) == DCERPC_FAULT_OP_RNG_ERROR) { - goto no_lsarpc_ds; + goto no_dssetup; } TALLOC_FREE(mem_ctx); return; } - - if ((ctr.basic->flags & DSROLE_PRIMARY_DS_RUNNING) && - !(ctr.basic->flags & DSROLE_PRIMARY_DS_MIXED_MODE)) { + + if ((info.basic.flags & DS_ROLE_PRIMARY_DS_RUNNING) && + !(info.basic.flags & DS_ROLE_PRIMARY_DS_MIXED_MODE)) { domain->native_mode = True; } else { domain->native_mode = False; } -no_lsarpc_ds: +no_dssetup: cli = cli_rpc_pipe_open_noauth(domain->conn.cli, PI_LSARPC, &result); if (cli == NULL) { @@ -1866,9 +1930,17 @@ no_lsarpc_ds: if (dns_name) fstrcpy(domain->alt_name, dns_name); - if ( forest_name ) + /* See if we can set some domain trust flags about + ourself */ + + if ( forest_name ) { fstrcpy(domain->forest_name, forest_name); + if (strequal(domain->forest_name, domain->alt_name)) { + domain->domain_flags = NETR_TRUST_FLAG_TREEROOT; + } + } + if (dom_sid) sid_copy(&domain->sid, dom_sid); } else { @@ -2003,13 +2075,16 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, goto schannel; } domain_name = domain->name; - goto schannel; } else { - machine_password = conn_pwd; - machine_account = conn->cli->user_name; + machine_password = SMB_STRDUP(conn_pwd); + machine_account = SMB_STRDUP(conn->cli->user_name); domain_name = conn->cli->domain; } + if (!machine_password || !machine_account) { + result = NT_STATUS_NO_MEMORY; + goto done; + } /* We have an authenticated connection. Use a NTLMSSP SPNEGO authenticated SAMR pipe with sign & seal. */ @@ -2101,12 +2176,12 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, } open_domain: - result = rpccli_samr_open_domain(conn->samr_pipe, - mem_ctx, - &conn->sam_connect_handle, - SEC_RIGHTS_MAXIMUM_ALLOWED, - &domain->sid, - &conn->sam_domain_handle); + result = rpccli_samr_OpenDomain(conn->samr_pipe, + mem_ctx, + &conn->sam_connect_handle, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &domain->sid, + &conn->sam_domain_handle); done: @@ -2249,7 +2324,7 @@ NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain, struct winbindd_cm_conn *conn; NTSTATUS result; - uint32 neg_flags = NETLOGON_NEG_AUTH2_FLAGS; + uint32 neg_flags = NETLOGON_NEG_SELECT_AUTH2_FLAGS; uint8 mach_pwd[16]; uint32 sec_chan_type; const char *account_name; diff --git a/source3/winbindd/winbindd_creds.c b/source3/winbindd/winbindd_creds.c index 62facb6769..4dbace5bcc 100644 --- a/source3/winbindd/winbindd_creds.c +++ b/source3/winbindd/winbindd_creds.c @@ -69,7 +69,7 @@ NTSTATUS winbindd_store_creds(struct winbindd_domain *domain, sid_copy(&sid, &(info3->dom_sid.sid)); sid_append_rid(&sid, info3->user_rid); sid_copy(&cred_sid, &sid); - info3->user_flgs |= LOGON_CACHED_ACCOUNT; + info3->user_flgs |= NETLOGON_CACHED_ACCOUNT; } else if (user_sid != NULL) { diff --git a/source3/winbindd/winbindd_dual.c b/source3/winbindd/winbindd_dual.c index 2739ab542e..1f2972f9b2 100644 --- a/source3/winbindd/winbindd_dual.c +++ b/source3/winbindd/winbindd_dual.c @@ -481,7 +481,6 @@ void winbind_child_died(pid_t pid) child->event.fd = 0; child->event.flags = 0; child->pid = 0; - SAFE_FREE(child->logfilename); schedule_async_request(child); } @@ -678,6 +677,88 @@ void winbind_msg_dump_event_list(struct messaging_context *msg_ctx, } +void winbind_msg_dump_domain_list(struct messaging_context *msg_ctx, + void *private_data, + uint32_t msg_type, + struct server_id server_id, + DATA_BLOB *data) +{ + TALLOC_CTX *mem_ctx; + const char *message = NULL; + struct server_id *sender = NULL; + const char *domain = NULL; + char *s = NULL; + NTSTATUS status; + struct winbindd_domain *dom = NULL; + + DEBUG(5,("winbind_msg_dump_domain_list received.\n")); + + if (!data || !data->data) { + return; + } + + if (data->length < sizeof(struct server_id)) { + return; + } + + mem_ctx = talloc_init("winbind_msg_dump_domain_list"); + if (!mem_ctx) { + return; + } + + sender = (struct server_id *)data->data; + if (data->length > sizeof(struct server_id)) { + domain = (const char *)data->data+sizeof(struct server_id); + } + + if (domain) { + + DEBUG(5,("winbind_msg_dump_domain_list for domain: %s\n", + domain)); + + message = NDR_PRINT_STRUCT_STRING(mem_ctx, winbindd_domain, + find_domain_from_name_noinit(domain)); + if (!message) { + talloc_destroy(mem_ctx); + return; + } + + messaging_send_buf(msg_ctx, *sender, + MSG_WINBIND_DUMP_DOMAIN_LIST, + (uint8_t *)message, strlen(message) + 1); + + talloc_destroy(mem_ctx); + + return; + } + + DEBUG(5,("winbind_msg_dump_domain_list all domains\n")); + + for (dom = domain_list(); dom; dom=dom->next) { + message = NDR_PRINT_STRUCT_STRING(mem_ctx, winbindd_domain, dom); + if (!message) { + talloc_destroy(mem_ctx); + return; + } + + s = talloc_asprintf_append(s, "%s\n", message); + if (!s) { + talloc_destroy(mem_ctx); + return; + } + } + + status = messaging_send_buf(msg_ctx, *sender, + MSG_WINBIND_DUMP_DOMAIN_LIST, + (uint8_t *)s, strlen(s) + 1); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("failed to send message: %s\n", + nt_errstr(status))); + } + + talloc_destroy(mem_ctx); +} + static void account_lockout_policy_handler(struct event_context *ctx, struct timed_event *te, const struct timeval *now, @@ -879,6 +960,13 @@ static bool fork_domain_child(struct winbindd_child *child) struct winbindd_cli_state state; struct winbindd_domain *domain; + if (child->domain) { + DEBUG(10, ("fork_domain_child called for domain '%s'\n", + child->domain->name)); + } else { + DEBUG(10, ("fork_domain_child called without domain.\n")); + } + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair) != 0) { DEBUG(0, ("Could not open child pipe: %s\n", strerror(errno))); @@ -948,6 +1036,8 @@ static bool fork_domain_child(struct winbindd_child *child) MSG_WINBIND_ONLINESTATUS, NULL); messaging_deregister(winbind_messaging_context(), MSG_DUMP_EVENT_LIST, NULL); + messaging_deregister(winbind_messaging_context(), + MSG_WINBIND_DUMP_DOMAIN_LIST, NULL); /* Handle online/offline messages. */ messaging_register(winbind_messaging_context(), NULL, diff --git a/source3/winbindd/winbindd_group.c b/source3/winbindd/winbindd_group.c index 140943cc2c..6a704cf290 100644 --- a/source3/winbindd/winbindd_group.c +++ b/source3/winbindd/winbindd_group.c @@ -438,18 +438,15 @@ static NTSTATUS expand_groups( TALLOC_CTX *ctx, if ( name_types[j] == SID_NAME_DOM_GRP || name_types[j] == SID_NAME_ALIAS ) { - bool ret; - - ret = add_sid_to_array_unique( ctx, - &sid_mem[j], - &new_groups, - &new_groups_size ); - if ( !ret ) { - status = NT_STATUS_NO_MEMORY; + status = add_sid_to_array_unique(ctx, + &sid_mem[j], + &new_groups, + &new_groups_size); + if (NT_STATUS_IS_OK(status)) { goto out; } - continue; + continue; } } @@ -1045,7 +1042,10 @@ static bool get_sam_group_entries(struct getent_state *ent) status = domain->methods->enum_local_groups(domain, mem_ctx, &num_entries, &sam_grp_entries); if ( !NT_STATUS_IS_OK(status) ) { - DEBUG(3,("get_sam_group_entries: Failed to enumerate domain local groups!\n")); + DEBUG(3,("get_sam_group_entries: " + "Failed to enumerate " + "domain local groups with error %s!\n", + nt_errstr(status))); num_entries = 0; } else @@ -1491,9 +1491,18 @@ void winbindd_getgroups(struct winbindd_cli_state *state) s->username = talloc_strdup( state->mem_ctx, state->request.data.username ); } - /* Get info for the domain */ + /* Get info for the domain (either by short domain name or + DNS name in the case of a UPN) */ s->domain = find_domain_from_name_noinit(s->domname); + if (!s->domain) { + char *p = strchr(s->username, '@'); + + if (p) { + s->domain = find_domain_from_name_noinit(p+1); + } + + } if (s->domain == NULL) { DEBUG(7, ("could not find domain entry for domain %s\n", diff --git a/source3/winbindd/winbindd_locator.c b/source3/winbindd/winbindd_locator.c index ee497ebf32..6b1cff99e0 100644 --- a/source3/winbindd/winbindd_locator.c +++ b/source3/winbindd/winbindd_locator.c @@ -48,7 +48,7 @@ void winbindd_dsgetdcname(struct winbindd_cli_state *state) state->request.domain_name [sizeof(state->request.domain_name)-1] = '\0'; - DEBUG(3, ("[%5lu]: DsGetDcName for %s\n", (unsigned long)state->pid, + DEBUG(3, ("[%5lu]: dsgetdcname for %s\n", (unsigned long)state->pid, state->request.domain_name)); sendto_child(state, locator_child()); @@ -64,10 +64,10 @@ static enum winbindd_result dual_dsgetdcname(struct winbindd_domain *domain, state->request.domain_name [sizeof(state->request.domain_name)-1] = '\0'; - DEBUG(3, ("[%5lu]: DsGetDcName for %s\n", (unsigned long)state->pid, + DEBUG(3, ("[%5lu]: dsgetdcname for %s\n", (unsigned long)state->pid, state->request.domain_name)); - result = DsGetDcName(state->mem_ctx, NULL, state->request.domain_name, + result = dsgetdcname(state->mem_ctx, state->request.domain_name, NULL, NULL, state->request.flags, &info); if (!NT_STATUS_IS_OK(result)) { diff --git a/source3/winbindd/winbindd_misc.c b/source3/winbindd/winbindd_misc.c index 8c3ef5bb6f..76f2554122 100644 --- a/source3/winbindd/winbindd_misc.c +++ b/source3/winbindd/winbindd_misc.c @@ -231,7 +231,7 @@ void winbindd_getdcname(struct winbindd_cli_state *state) enum winbindd_result winbindd_dual_getdcname(struct winbindd_domain *domain, struct winbindd_cli_state *state) { - fstring dcname_slash; + char *dcname_slash = NULL; char *p; struct rpc_pipe_client *netlogon_pipe; NTSTATUS result; @@ -262,12 +262,12 @@ enum winbindd_result winbindd_dual_getdcname(struct winbindd_domain *domain, werr = rpccli_netlogon_getdcname(netlogon_pipe, state->mem_ctx, domain->dcname, state->request.domain_name, - dcname_slash); + &dcname_slash); } else { werr = rpccli_netlogon_getanydcname(netlogon_pipe, state->mem_ctx, domain->dcname, state->request.domain_name, - dcname_slash); + &dcname_slash); } /* And restore our original timeout. */ cli_set_timeout(netlogon_pipe->cli, orig_timeout); diff --git a/source3/winbindd/winbindd_ndr.c b/source3/winbindd/winbindd_ndr.c new file mode 100644 index 0000000000..842c915c5f --- /dev/null +++ b/source3/winbindd/winbindd_ndr.c @@ -0,0 +1,153 @@ +/* + * Unix SMB/CIFS implementation. + * winbindd debug helper + * Copyright (C) Guenther Deschner 2008 + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + */ + +#include "includes.h" +#include "winbindd.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_WINBIND + +/**************************************************************** +****************************************************************/ + +void ndr_print_winbindd_child(struct ndr_print *ndr, + const char *name, + const struct winbindd_child *r) +{ + ndr_print_struct(ndr, name, "winbindd_child"); + ndr->depth++; + ndr_print_ptr(ndr, "next", r->next); + ndr_print_ptr(ndr, "prev", r->prev); + ndr_print_uint32(ndr, "pid", (uint32_t)r->pid); +#if 0 + ndr_print_winbindd_domain(ndr, "domain", r->domain); +#else + ndr_print_ptr(ndr, "domain", r->domain); +#endif + ndr_print_string(ndr, "logfilename", r->logfilename); + /* struct fd_event event; */ + ndr_print_ptr(ndr, "lockout_policy_event", r->lockout_policy_event); + ndr_print_ptr(ndr, "requests", r->requests); + ndr_print_ptr(ndr, "table", r->table); + ndr->depth--; +} + +/**************************************************************** +****************************************************************/ + +void ndr_print_winbindd_cm_conn(struct ndr_print *ndr, + const char *name, + const struct winbindd_cm_conn *r) +{ + ndr_print_struct(ndr, name, "winbindd_cm_conn"); + ndr->depth++; + ndr_print_ptr(ndr, "cli", r->cli); + ndr_print_ptr(ndr, "samr_pipe", r->samr_pipe); + ndr_print_policy_handle(ndr, "sam_connect_handle", &r->sam_connect_handle); + ndr_print_policy_handle(ndr, "sam_domain_handle", &r->sam_domain_handle); + ndr_print_ptr(ndr, "lsa_pipe", r->lsa_pipe); + ndr_print_policy_handle(ndr, "lsa_policy", &r->lsa_policy); + ndr_print_ptr(ndr, "netlogon_pipe", r->netlogon_pipe); + ndr->depth--; +} + +/**************************************************************** +****************************************************************/ + +void ndr_print_winbindd_methods(struct ndr_print *ndr, + const char *name, + const struct winbindd_methods *r) +{ +#ifdef HAVE_ADS + extern struct winbindd_methods ads_methods; +#endif + extern struct winbindd_methods msrpc_methods; + extern struct winbindd_methods passdb_methods; + extern struct winbindd_methods reconnect_methods; + extern struct winbindd_methods cache_methods; + + ndr_print_struct(ndr, name, "winbindd_methods"); + ndr->depth++; + + if (r == NULL) { + ndr_print_string(ndr, name, "(NULL)"); + ndr->depth--; + return; + } + + if (r == &msrpc_methods) { + ndr_print_string(ndr, name, "msrpc_methods"); +#ifdef HAVE_ADS + } else if (r == &ads_methods) { + ndr_print_string(ndr, name, "ads_methods"); +#endif + } else if (r == &passdb_methods) { + ndr_print_string(ndr, name, "passdb_methods"); + } else if (r == &reconnect_methods) { + ndr_print_string(ndr, name, "reconnect_methods"); + } else if (r == &cache_methods) { + ndr_print_string(ndr, name, "cache_methods"); + } else { + ndr_print_string(ndr, name, "UNKNOWN"); + } + ndr->depth--; +} + +/**************************************************************** +****************************************************************/ + +void ndr_print_winbindd_domain(struct ndr_print *ndr, + const char *name, + const struct winbindd_domain *r) +{ + if (!r) { + return; + } + + ndr_print_struct(ndr, name, "winbindd_domain"); + ndr->depth++; + ndr_print_string(ndr, "name", r->name); + ndr_print_string(ndr, "alt_name", r->alt_name); + ndr_print_string(ndr, "forest_name", r->forest_name); + ndr_print_dom_sid(ndr, "sid", &r->sid); + ndr_print_netr_TrustFlags(ndr, "domain_flags", r->domain_flags); + ndr_print_netr_TrustType(ndr, "domain_type", r->domain_type); + ndr_print_netr_TrustAttributes(ndr, "domain_trust_attribs", r->domain_trust_attribs); + ndr_print_bool(ndr, "initialized", r->initialized); + ndr_print_bool(ndr, "native_mode", r->native_mode); + ndr_print_bool(ndr, "active_directory", r->active_directory); + ndr_print_bool(ndr, "primary", r->primary); + ndr_print_bool(ndr, "internal", r->internal); + ndr_print_bool(ndr, "online", r->online); + ndr_print_time_t(ndr, "startup_time", r->startup_time); + ndr_print_bool(ndr, "startup", r->startup); + ndr_print_winbindd_methods(ndr, "methods", r->methods); + ndr_print_winbindd_methods(ndr, "backend", r->backend); + ndr_print_ptr(ndr, "private_data", r->private_data); + ndr_print_string(ndr, "dcname", r->dcname); + ndr_print_sockaddr_storage(ndr, "dcaddr", &r->dcaddr); + ndr_print_time_t(ndr, "last_seq_check", r->last_seq_check); + ndr_print_uint32(ndr, "sequence_number", r->sequence_number); + ndr_print_NTSTATUS(ndr, "last_status", r->last_status); + ndr_print_winbindd_cm_conn(ndr, "conn", &r->conn); + ndr_print_winbindd_child(ndr, "child", &r->child); + ndr_print_uint32(ndr, "check_online_timeout", r->check_online_timeout); + ndr_print_ptr(ndr, "check_online_event", r->check_online_event); + ndr->depth--; +} diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c index 5133239258..14b1621fc9 100644 --- a/source3/winbindd/winbindd_pam.c +++ b/source3/winbindd/winbindd_pam.c @@ -31,8 +31,6 @@ static NTSTATUS append_info3_as_txt(TALLOC_CTX *mem_ctx, struct winbindd_cli_state *state, NET_USER_INFO_3 *info3) { - fstring str_sid; - state->response.data.auth.info3.logon_time = nt_time_to_unix(info3->logon_time); state->response.data.auth.info3.logoff_time = @@ -51,8 +49,7 @@ static NTSTATUS append_info3_as_txt(TALLOC_CTX *mem_ctx, state->response.data.auth.info3.user_rid = info3->user_rid; state->response.data.auth.info3.group_rid = info3->group_rid; - sid_to_fstring(str_sid, &(info3->dom_sid.sid)); - fstrcpy(state->response.data.auth.info3.dom_sid, str_sid); + sid_to_fstring(state->response.data.auth.info3.dom_sid, &(info3->dom_sid.sid)); state->response.data.auth.info3.num_groups = info3->num_groups; state->response.data.auth.info3.user_flgs = info3->user_flgs; @@ -273,12 +270,13 @@ static NTSTATUS check_info3_in_group(TALLOC_CTX *mem_ctx, return NT_STATUS_INVALID_PARAMETER; } - if (!add_sid_to_array(mem_ctx, &sid, - &require_membership_of_sid, - &num_require_membership_of_sid)) { + status = add_sid_to_array(mem_ctx, &sid, + &require_membership_of_sid, + &num_require_membership_of_sid); + if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("add_sid_to_array failed\n")); TALLOC_FREE(frame); - return NT_STATUS_NO_MEMORY; + return status; } } @@ -922,7 +920,7 @@ NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain, /* User *DOES* know the password, update logon_time and reset * bad_pw_count */ - my_info3->user_flgs |= LOGON_CACHED_ACCOUNT; + my_info3->user_flgs |= NETLOGON_CACHED_ACCOUNT; if (my_info3->acct_flags & ACB_AUTOLOCK) { return NT_STATUS_ACCOUNT_LOCKED_OUT; @@ -958,7 +956,7 @@ NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain, must_change_time = nt_time_to_unix(my_info3->pass_must_change_time); if (must_change_time != 0 && must_change_time < time(NULL)) { /* we allow grace logons when the password has expired */ - my_info3->user_flgs |= LOGON_GRACE_LOGON; + my_info3->user_flgs |= NETLOGON_GRACE_LOGON; /* return NT_STATUS_PASSWORD_EXPIRED; */ goto success; } @@ -966,7 +964,7 @@ NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain, #ifdef HAVE_KRB5 if ((state->request.flags & WBFLAG_PAM_KRB5) && ((tdc_domain = wcache_tdc_fetch_domain(state->mem_ctx, name_domain)) != NULL) && - (tdc_domain->trust_type & DS_DOMAIN_TRUST_TYPE_UPLEVEL)) { + (tdc_domain->trust_type & NETR_TRUST_TYPE_UPLEVEL)) { uid_t uid = -1; const char *cc = NULL; @@ -1074,7 +1072,7 @@ NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain, } if ((my_info3->user_rid != DOMAIN_USER_RID_ADMIN) || - (password_properties & DOMAIN_LOCKOUT_ADMINS)) { + (password_properties & DOMAIN_PASSWORD_LOCKOUT_ADMINS)) { my_info3->acct_flags |= ACB_AUTOLOCK; } } @@ -1341,10 +1339,11 @@ NTSTATUS winbindd_dual_pam_auth_samlogon(struct winbindd_domain *domain, goto done; } - status_tmp = rpccli_samr_open_user(samr_pipe, state->mem_ctx, - &samr_domain_handle, - MAXIMUM_ALLOWED_ACCESS, - my_info3->user_rid, &user_pol); + status_tmp = rpccli_samr_OpenUser(samr_pipe, state->mem_ctx, + &samr_domain_handle, + MAXIMUM_ALLOWED_ACCESS, + my_info3->user_rid, + &user_pol); if (!NT_STATUS_IS_OK(status_tmp)) { DEBUG(3, ("could not open user handle on SAMR pipe: %s\n", @@ -1358,14 +1357,14 @@ NTSTATUS winbindd_dual_pam_auth_samlogon(struct winbindd_domain *domain, if (!NT_STATUS_IS_OK(status_tmp)) { DEBUG(3, ("could not query user info on SAMR pipe: %s\n", nt_errstr(status_tmp))); - rpccli_samr_close(samr_pipe, state->mem_ctx, &user_pol); + rpccli_samr_Close(samr_pipe, state->mem_ctx, &user_pol); goto done; } acct_flags = user_ctr->info.id16->acb_info; if (acct_flags == 0) { - rpccli_samr_close(samr_pipe, state->mem_ctx, &user_pol); + rpccli_samr_Close(samr_pipe, state->mem_ctx, &user_pol); goto done; } @@ -1373,7 +1372,7 @@ NTSTATUS winbindd_dual_pam_auth_samlogon(struct winbindd_domain *domain, DEBUG(10,("successfully retrieved acct_flags 0x%x\n", acct_flags)); - rpccli_samr_close(samr_pipe, state->mem_ctx, &user_pol); + rpccli_samr_Close(samr_pipe, state->mem_ctx, &user_pol); } *info3 = my_info3; @@ -1593,13 +1592,16 @@ process_result: } } - result = fillup_password_policy(domain, state); - if (!NT_STATUS_IS_OK(result) - && !NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) ) - { - DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(result))); - goto done; + if (state->request.flags & WBFLAG_PAM_GET_PWD_POLICY) { + result = fillup_password_policy(domain, state); + + if (!NT_STATUS_IS_OK(result) + && !NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) ) + { + DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(result))); + goto done; + } } result = NT_STATUS_OK; diff --git a/source3/winbindd/winbindd_rpc.c b/source3/winbindd/winbindd_rpc.c index ffb47692cb..0d937ef30e 100644 --- a/source3/winbindd/winbindd_rpc.c +++ b/source3/winbindd/winbindd_rpc.c @@ -308,7 +308,7 @@ NTSTATUS msrpc_sid_to_name(struct winbindd_domain *domain, { char **domains; char **names; - enum lsa_SidType *types; + enum lsa_SidType *types = NULL; NTSTATUS result; struct rpc_pipe_client *cli; POLICY_HND lsa_policy; @@ -456,6 +456,12 @@ static NTSTATUS query_user(struct winbindd_domain *domain, return NT_STATUS_OK; } + if ( !winbindd_can_contact_domain( domain ) ) { + DEBUG(10,("query_user: No incoming trust for domain %s\n", + domain->name)); + return NT_STATUS_OK; + } + /* no cache; hit the wire */ result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol); @@ -463,9 +469,11 @@ static NTSTATUS query_user(struct winbindd_domain *domain, return result; /* Get user handle */ - result = rpccli_samr_open_user(cli, mem_ctx, &dom_pol, - SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, - &user_pol); + result = rpccli_samr_OpenUser(cli, mem_ctx, + &dom_pol, + SEC_RIGHTS_MAXIMUM_ALLOWED, + user_rid, + &user_pol); if (!NT_STATUS_IS_OK(result)) return result; @@ -474,7 +482,7 @@ static NTSTATUS query_user(struct winbindd_domain *domain, result = rpccli_samr_query_userinfo(cli, mem_ctx, &user_pol, 0x15, &ctr); - rpccli_samr_close(cli, mem_ctx, &user_pol); + rpccli_samr_Close(cli, mem_ctx, &user_pol); if (!NT_STATUS_IS_OK(result)) return result; @@ -539,8 +547,11 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, return result; /* Get user handle */ - result = rpccli_samr_open_user(cli, mem_ctx, &dom_pol, - des_access, user_rid, &user_pol); + result = rpccli_samr_OpenUser(cli, mem_ctx, + &dom_pol, + des_access, + user_rid, + &user_pol); if (!NT_STATUS_IS_OK(result)) return result; @@ -549,7 +560,7 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, result = rpccli_samr_query_usergroups(cli, mem_ctx, &user_pol, num_groups, &user_groups); - rpccli_samr_close(cli, mem_ctx, &user_pol); + rpccli_samr_Close(cli, mem_ctx, &user_pol); if (!NT_STATUS_IS_OK(result) || (*num_groups) == 0) return result; @@ -694,8 +705,11 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, if (!NT_STATUS_IS_OK(result)) return result; - result = rpccli_samr_open_group(cli, mem_ctx, &dom_pol, - des_access, group_rid, &group_pol); + result = rpccli_samr_OpenGroup(cli, mem_ctx, + &dom_pol, + des_access, + group_rid, + &group_pol); if (!NT_STATUS_IS_OK(result)) return result; @@ -715,7 +729,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, /* And restore our original timeout. */ cli_set_timeout(cli->cli, orig_timeout); - rpccli_samr_close(cli, mem_ctx, &group_pol); + rpccli_samr_Close(cli, mem_ctx, &group_pol); if (!NT_STATUS_IS_OK(result)) return result; diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c index 795209619c..7933ecf63e 100644 --- a/source3/winbindd/winbindd_util.c +++ b/source3/winbindd/winbindd_util.c @@ -41,7 +41,7 @@ extern struct winbindd_methods passdb_methods; individual winbindd_domain structures cannot be made. Keep a copy of the domain name instead. */ -static struct winbindd_domain *_domain_list; +static struct winbindd_domain *_domain_list = NULL; /** When was the last scan of trusted domains done? @@ -212,7 +212,7 @@ static void add_trusted_domains( struct winbindd_domain *domain ) TALLOC_CTX *mem_ctx; struct winbindd_request *request; struct winbindd_response *response; - uint32 fr_flags = (DS_DOMAIN_TREE_ROOT|DS_DOMAIN_IN_FOREST); + uint32 fr_flags = (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST); struct trustdom_state *state; @@ -385,8 +385,8 @@ static void rescan_forest_root_trusts( void ) the domain_list() as our primary domain may not have been initialized. */ - if ( !(dom_list[i].trust_flags & DS_DOMAIN_TREE_ROOT) ) { - continue; + if ( !(dom_list[i].trust_flags & NETR_TRUST_FLAG_TREEROOT) ) { + continue; } /* Here's the forest root */ @@ -450,10 +450,10 @@ static void rescan_forest_trusts( void ) if ( d && (d->internal || d->primary ) ) continue; - - if ( (flags & DS_DOMAIN_DIRECT_INBOUND) && - (type == DS_DOMAIN_TRUST_TYPE_UPLEVEL) && - (attribs == DS_DOMAIN_TRUST_ATTRIB_FOREST_TRANSITIVE) ) + + if ( (flags & NETR_TRUST_FLAG_INBOUND) && + (type == NETR_TRUST_TYPE_UPLEVEL) && + (attribs == NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) ) { /* add the trusted domain if we don't know about it */ @@ -494,9 +494,13 @@ void rescan_trusted_domains( void ) ((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) ) return; - /* clear the TRUSTDOM cache first */ - - wcache_tdc_clear(); + /* I use to clear the cache here and start over but that + caused problems in child processes that needed the + trust dom list early on. Removing it means we + could have some trusted domains listed that have been + removed from our primary domain's DC until a full + restart. This should be ok since I think this is what + Windows does as well. */ /* this will only add new domains we didn't already know about in the domain_list()*/ @@ -561,7 +565,7 @@ enum winbindd_result init_child_connection(struct winbindd_domain *domain, /* The primary domain has to find the DC name itself */ request->cmd = WINBINDD_INIT_CONNECTION; fstrcpy(request->domain_name, domain->name); - request->data.init_conn.is_primary = domain->internal ? False : True; + request->data.init_conn.is_primary = domain->primary ? true : false; fstrcpy(request->data.init_conn.dcname, ""); async_request(mem_ctx, &domain->child, request, response, init_child_recv, state); @@ -760,8 +764,8 @@ void check_domain_trusted( const char *name, const DOM_SID *user_sid ) forest trust */ domain->active_directory = True; - domain->domain_flags = DS_DOMAIN_DIRECT_OUTBOUND; - domain->domain_type = DS_DOMAIN_TRUST_TYPE_UPLEVEL; + domain->domain_flags = NETR_TRUST_FLAG_OUTBOUND; + domain->domain_type = NETR_TRUST_TYPE_UPLEVEL; domain->internal = False; domain->online = True; @@ -1294,19 +1298,22 @@ NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain, /* always add the primary group to the sid array */ sid_compose(&primary_group, &info3->dom_sid.sid, info3->user_rid); - if (!add_sid_to_array(mem_ctx, &primary_group, user_sids, &num_groups)) { + status = add_sid_to_array(mem_ctx, &primary_group, user_sids, + &num_groups); + if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(info3); - return NT_STATUS_NO_MEMORY; + return status; } for (i=0; i<info3->num_groups; i++) { sid_copy(&group_sid, &info3->dom_sid.sid); sid_append_rid(&group_sid, info3->gids[i].g_rid); - if (!add_sid_to_array(mem_ctx, &group_sid, user_sids, - &num_groups)) { + status = add_sid_to_array(mem_ctx, &group_sid, user_sids, + &num_groups); + if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(info3); - return NT_STATUS_NO_MEMORY; + return status; } } @@ -1318,11 +1325,11 @@ NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain, if (info3->other_sids_attrib[i] & SE_GROUP_RESOURCE) continue; - if (!add_sid_to_array(mem_ctx, &info3->other_sids[i].sid, - user_sids, &num_groups)) - { + status = add_sid_to_array(mem_ctx, &info3->other_sids[i].sid, + user_sids, &num_groups); + if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(info3); - return NT_STATUS_NO_MEMORY; + return status; } } @@ -1373,31 +1380,56 @@ void ws_name_return( char *name, char replace ) /********************************************************************* ********************************************************************/ -bool winbindd_can_contact_domain( struct winbindd_domain *domain ) +bool winbindd_can_contact_domain(struct winbindd_domain *domain) { + struct winbindd_tdc_domain *tdc = NULL; + TALLOC_CTX *frame = talloc_stackframe(); + bool ret = false; + /* We can contact the domain if it is our primary domain */ - if ( domain->primary ) - return True; + if (domain->primary) { + return true; + } - /* Can always contact a domain that is in out forest */ + /* Trust the TDC cache and not the winbindd_domain flags */ - if ( domain->domain_flags & DS_DOMAIN_IN_FOREST ) - return True; + if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) { + DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n", + domain->name)); + return false; + } - /* We cannot contact the domain if it is running AD and - we have no inbound trust */ + /* Can always contact a domain that is in out forest */ - if ( domain->active_directory && - ((domain->domain_flags&DS_DOMAIN_DIRECT_INBOUND) != DS_DOMAIN_DIRECT_INBOUND) ) - { - return False; + if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) { + ret = true; + goto done; } + /* + * On a _member_ server, we cannot contact the domain if it + * is running AD and we have no inbound trust. + */ + + if (!IS_DC && + domain->active_directory && + ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND)) + { + DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain " + "and we have no inbound trust.\n", domain->name)); + goto done; + } + /* Assume everything else is ok (probably not true but what can you do?) */ + + ret = true; + +done: + talloc_destroy(frame); - return True; + return ret; } /********************************************************************* |