diff --git a/source/auth/auth_sam.c b/source/auth/auth_sam.c index 80e02c3..57e16d9 100644 --- a/source/auth/auth_sam.c +++ b/source/auth/auth_sam.c @@ -167,8 +167,9 @@ static NTSTATUS sam_account_ok(TALLOC_CTX *mem_ctx, time_t must_change_time = pdb_get_pass_must_change_time(sampass); time_t last_set_time = pdb_get_pass_last_set_time(sampass); - /* check for immediate expiry "must change at next logon" */ - if (last_set_time == 0) { + /* check for immediate expiry "must change at next logon" + * for a user account. */ + if (((acct_ctrl & (ACB_WSTRUST|ACB_SVRTRUST)) == 0) && (last_set_time == 0)) { DEBUG(1,("sam_account_ok: Account for user '%s' password must change!.\n", pdb_get_username(sampass))); return NT_STATUS_PASSWORD_MUST_CHANGE; } diff --git a/source/auth/auth_util.c b/source/auth/auth_util.c index b3a3d39..7897a92 100644 --- a/source/auth/auth_util.c +++ b/source/auth/auth_util.c @@ -546,24 +546,47 @@ static auth_serversupplied_info *make_server_info(TALLOC_CTX *mem_ctx) } /*************************************************************************** + Is the incoming username our own machine account ? + If so, the connection is almost certainly from winbindd. +***************************************************************************/ + +static BOOL is_our_machine_account(const char *username) +{ + BOOL ret; + char *truncname = NULL; + size_t ulen = strlen(username); + + if (ulen == 0 || username[ulen-1] != '$') { + return False; + } + truncname = SMB_STRDUP(username); + if (!truncname) { + return False; + } + truncname[ulen-1] = '\0'; + ret = strequal(truncname, global_myname()); + SAFE_FREE(truncname); + return ret; +} + +/*************************************************************************** Make (and fill) a user_info struct from a struct samu ***************************************************************************/ NTSTATUS make_server_info_sam(auth_serversupplied_info **server_info, struct samu *sampass) { - NTSTATUS status; struct passwd *pwd; gid_t *gids; auth_serversupplied_info *result; int i; size_t num_gids; DOM_SID unix_group_sid; - + const char *username = pdb_get_username(sampass); - if ( !(pwd = getpwnam_alloc(NULL, pdb_get_username(sampass))) ) { + if ( !(pwd = getpwnam_alloc(NULL, username)) ) { DEBUG(1, ("User %s in passdb, but getpwnam() fails!\n", - pdb_get_username(sampass))); + username)); return NT_STATUS_NO_SUCH_USER; } @@ -579,18 +602,47 @@ NTSTATUS make_server_info_sam(auth_serversupplied_info **server_info, TALLOC_FREE(pwd); - status = pdb_enum_group_memberships(result, sampass, + if (IS_DC && is_our_machine_account(username)) { + /* + * Ensure for a connection from our own + * machine account (from winbindd on a DC) + * there are no supplementary groups. + * Prevents loops in calling gid_to_sid(). + */ + result->sids = NULL; + gids = NULL; + result->num_sids = 0; + + /* + * This is a hack of monstrous proportions. + * If we know it's winbindd talking to us, + * we know we must never recurse into it, + * so turn off contacting winbindd for this + * entire process. This will get fixed when + * winbindd doesn't need to talk to smbd on + * a PDC. JRA. + */ + + winbind_off(); + + DEBUG(10, ("make_server_info_sam: our machine account %s " + "setting supplementary group list empty and " + "turning off winbindd requests.\n", + username)); + } else { + NTSTATUS status = pdb_enum_group_memberships(result, sampass, &result->sids, &gids, &result->num_sids); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(10, ("pdb_enum_group_memberships failed: %s\n", - nt_errstr(status))); - result->sam_account = NULL; /* Don't free on error exit. */ - TALLOC_FREE(result); - return status; + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("pdb_enum_group_memberships failed: %s\n", + nt_errstr(status))); + result->sam_account = NULL; /* Don't free on error exit. */ + TALLOC_FREE(result); + return status; + } } - + /* Add the "Unix Group" SID for each gid to catch mapped groups and their Unix equivalent. This is to solve the backwards compatibility problem of 'valid users = +ntadmin' where