summaryrefslogtreecommitdiffstats
path: root/source/nsswitch
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2004-04-06 16:44:24 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 10:51:07 -0500
commiteb1c1b5eb086f49a230142ad2de45dc0e9691df3 (patch)
treec1902326707d0afe531ee69a7b8fe00d871bb565 /source/nsswitch
parent0661357484a33329c75457527416667feaf57ef9 (diff)
downloadsamba-eb1c1b5eb086f49a230142ad2de45dc0e9691df3.tar.gz
samba-eb1c1b5eb086f49a230142ad2de45dc0e9691df3.tar.xz
samba-eb1c1b5eb086f49a230142ad2de45dc0e9691df3.zip
r84: Implement --required-membership-of=, an ntlm_auth option that restricts
all authentication to members of this particular group. Also implement an option to allow ntlm_auth to get 'squashed' error codes, which are safer to communicate to remote network clients. Andrew Bartlett
Diffstat (limited to 'source/nsswitch')
-rw-r--r--source/nsswitch/winbindd_nss.h3
-rw-r--r--source/nsswitch/winbindd_pam.c119
2 files changed, 117 insertions, 5 deletions
diff --git a/source/nsswitch/winbindd_nss.h b/source/nsswitch/winbindd_nss.h
index d0c80412dfe..4ddce119518 100644
--- a/source/nsswitch/winbindd_nss.h
+++ b/source/nsswitch/winbindd_nss.h
@@ -157,6 +157,7 @@ typedef struct winbindd_gr {
#define WBFLAG_ALLOCATE_RID 0x0040
#define WBFLAG_PAM_UNIX_NAME 0x0080
#define WBFLAG_PAM_AFS_TOKEN 0x0100
+#define WBFLAG_PAM_NT_STATUS_SQUASH 0x0200
/* Winbind request structure */
@@ -179,6 +180,7 @@ struct winbindd_request {
character is. */
fstring user;
fstring pass;
+ fstring required_membership_sid;
} auth; /* pam_winbind auth module */
struct {
unsigned char chal[8];
@@ -189,6 +191,7 @@ struct winbindd_request {
fstring nt_resp;
uint16 nt_resp_len;
fstring workstation;
+ fstring required_membership_sid;
} auth_crap;
struct {
fstring user;
diff --git a/source/nsswitch/winbindd_pam.c b/source/nsswitch/winbindd_pam.c
index f3e7daa6bf4..a2ebe0ddbc8 100644
--- a/source/nsswitch/winbindd_pam.c
+++ b/source/nsswitch/winbindd_pam.c
@@ -54,8 +54,98 @@ static NTSTATUS append_info3_as_ndr(TALLOC_CTX *mem_ctx,
return NT_STATUS_OK;
}
+static NTSTATUS check_info3_in_group(TALLOC_CTX *mem_ctx,
+ NET_USER_INFO_3 *info3,
+ const char *group_sid)
+{
+ DOM_SID required_membership_sid;
+ DOM_SID *all_sids;
+ size_t num_all_sids = (2 + info3->num_groups2 + info3->num_other_sids);
+ size_t i, j = 0;
+
+ /* Parse the 'required group' SID */
+
+ if (!group_sid || !group_sid[0]) {
+ /* NO sid supplied, all users may access */
+ return NT_STATUS_OK;
+ }
+
+ if (!string_to_sid(&required_membership_sid, group_sid)) {
+ DEBUG(0, ("winbindd_pam_auth: could not parse %s as a SID!",
+ group_sid));
+
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ all_sids = talloc(mem_ctx, sizeof(DOM_SID) * num_all_sids);
+ if (!all_sids)
+ return NT_STATUS_NO_MEMORY;
+
+ /* and create (by appending rids) the 'domain' sids */
+
+ sid_copy(&all_sids[0], &(info3->dom_sid.sid));
+
+ if (!sid_append_rid(&all_sids[0], info3->user_rid)) {
+ DEBUG(3,("could not append user's primary RID 0x%x\n",
+ info3->user_rid));
+
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ j++;
+
+ sid_copy(&all_sids[1], &(info3->dom_sid.sid));
+
+ if (!sid_append_rid(&all_sids[1], info3->group_rid)) {
+ DEBUG(3,("could not append additional group rid 0x%x\n",
+ info3->group_rid));
+
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ j++;
+
+ for (i = 0; i < info3->num_groups2; i++) {
+
+ sid_copy(&all_sids[j], &(info3->dom_sid.sid));
+
+ if (!sid_append_rid(&all_sids[j], info3->gids[j].g_rid)) {
+ DEBUG(3,("could not append additional group rid 0x%x\n",
+ info3->gids[j].g_rid));
+
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ j++;
+ }
+
+ /* Copy 'other' sids. We need to do sid filtering here to
+ prevent possible elevation of privileges. See:
+
+ http://www.microsoft.com/windows2000/techinfo/administration/security/sidfilter.asp
+ */
+
+ for (i = 0; i < info3->num_other_sids; j++) {
+ sid_copy(&all_sids[info3->num_groups2 + i + 2],
+ &info3->other_sids[j].sid);
+ j++;
+ }
+
+ for (i = 0; i < j; i++) {
+ fstring sid1, sid2;
+ DEBUG(10, ("User has SID: %s\n",
+ sid_to_string(sid1, &all_sids[i])));
+ if (sid_equal(&required_membership_sid, &all_sids[i])) {
+ DEBUG(10, ("SID %s matches %s - user permitted to authenticate!\n",
+ sid_to_string(sid1, &required_membership_sid), sid_to_string(sid2, &all_sids[i])));
+ return NT_STATUS_OK;
+ }
+ }
+
+ /* Do not distinguish this error from a wrong username/pw */
+
+ return NT_STATUS_LOGON_FAILURE;
+}
+
/**********************************************************************
- Authenticate a user with a clear test password
+ Authenticate a user with a clear text password
**********************************************************************/
enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
@@ -125,7 +215,7 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
}
if (!(contact_domain = find_our_domain())) {
- DEBUG(1, ("Authenticatoin for [%s] -> [%s]\\[%s] in our domain failed - we can't find our domain!\n",
+ DEBUG(1, ("Authentication for [%s] -> [%s]\\[%s] in our domain failed - we can't find our domain!\n",
state->request.data.auth.user, name_domain, name_user));
result = NT_STATUS_NO_SUCH_USER;
goto done;
@@ -190,8 +280,16 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
if (NT_STATUS_IS_OK(result)) {
netsamlogon_cache_store( cli->mem_ctx, &info3 );
wcache_invalidate_samlogon(find_domain_from_name(name_domain), &info3);
+
+ /* Check if the user is in the right group */
+
+ if (!NT_STATUS_IS_OK(result = check_info3_in_group(mem_ctx, &info3, state->request.data.auth.required_membership_sid))) {
+ DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
+ state->request.data.auth.user,
+ state->request.data.auth.required_membership_sid));
+ }
}
-
+
done:
/* give us a more useful (more correct?) error code */
if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) || (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
@@ -355,7 +453,7 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
if ( IS_DC ) {
if (!(contact_domain = find_domain_from_name(name_domain))) {
DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
- state->request.data.auth.user, name_domain, name_user, name_domain));
+ state->request.data.auth_crap.user, name_domain, name_user, name_domain));
result = NT_STATUS_NO_SUCH_USER;
goto done;
}
@@ -369,7 +467,7 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
if (!(contact_domain = find_our_domain())) {
DEBUG(1, ("Authenticatoin for [%s] -> [%s]\\[%s] in our domain failed - we can't find our domain!\n",
- state->request.data.auth.user, name_domain, name_user));
+ state->request.data.auth_crap.user, name_domain, name_user));
result = NT_STATUS_NO_SUCH_USER;
goto done;
}
@@ -434,6 +532,13 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
netsamlogon_cache_store( cli->mem_ctx, &info3 );
wcache_invalidate_samlogon(find_domain_from_name(name_domain), &info3);
+ if (!NT_STATUS_IS_OK(result = check_info3_in_group(mem_ctx, &info3, state->request.data.auth_crap.required_membership_sid))) {
+ DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
+ state->request.data.auth_crap.user,
+ state->request.data.auth_crap.required_membership_sid));
+ goto done;
+ }
+
if (state->request.flags & WBFLAG_PAM_INFO3_NDR) {
result = append_info3_as_ndr(mem_ctx, state, &info3);
} else if (state->request.flags & WBFLAG_PAM_UNIX_NAME) {
@@ -477,6 +582,10 @@ done:
if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) || (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
result = NT_STATUS_NO_LOGON_SERVERS;
}
+
+ if (state->request.flags & WBFLAG_PAM_NT_STATUS_SQUASH) {
+ result = nt_status_squash(result);
+ }
state->response.data.auth.nt_status = NT_STATUS_V(result);
push_utf8_fstring(state->response.data.auth.nt_status_string, nt_errstr(result));