2 Unix SMB/CIFS implementation.
3 async implementation of WINBINDD_PAM_AUTH_CRAP
4 Copyright (C) Volker Lendecke 2010
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "rpc_client/util_netlogon.h"
23 #include "libcli/security/dom_sid.h"
24 #include "lib/util/string_wrappers.h"
25 #include "lib/global_contexts.h"
26 #include "librpc/gen_ndr/ndr_winbind_c.h"
28 struct winbindd_pam_auth_crap_state
{
29 uint8_t authoritative
;
34 struct wbint_PamAuthCrapValidation validation
;
38 static void winbindd_pam_auth_crap_done(struct tevent_req
*subreq
);
40 struct tevent_req
*winbindd_pam_auth_crap_send(
42 struct tevent_context
*ev
,
43 struct winbindd_cli_state
*cli
,
44 struct winbindd_request
*request
)
46 struct tevent_req
*req
, *subreq
;
47 struct winbindd_pam_auth_crap_state
*state
;
48 struct winbindd_domain
*domain
;
49 const char *auth_domain
= NULL
;
50 DATA_BLOB lm_resp
= data_blob_null
;
51 DATA_BLOB nt_resp
= data_blob_null
;
52 DATA_BLOB chal
= data_blob_null
;
53 struct wbint_SidArray
*require_membership_of_sid
= NULL
;
55 bool lmlength_ok
= false;
56 bool ntlength_ok
= false;
57 bool pwlength_ok
= false;
59 req
= tevent_req_create(mem_ctx
, &state
,
60 struct winbindd_pam_auth_crap_state
);
64 state
->authoritative
= 1;
65 state
->flags
= request
->flags
;
67 if (state
->flags
& WBFLAG_PAM_AUTH_PAC
) {
68 state
->result
= winbindd_pam_auth_pac_verify(cli
,
70 &state
->pac_is_trusted
,
71 &state
->validation
.level
,
72 &state
->validation
.validation
);
73 if (tevent_req_nterror(req
, state
->result
)) {
74 return tevent_req_post(req
, ev
);
78 return tevent_req_post(req
, ev
);
81 /* Ensure null termination */
82 request
->data
.auth_crap
.user
[
83 sizeof(request
->data
.auth_crap
.user
)-1] = '\0';
84 request
->data
.auth_crap
.domain
[
85 sizeof(request
->data
.auth_crap
.domain
)-1] = '\0';
86 request
->data
.auth_crap
.workstation
[
87 sizeof(request
->data
.auth_crap
.workstation
)-1] = '\0';
89 DBG_NOTICE("[%5lu]: pam auth crap domain: [%s] user: [%s] "
90 "workstation: [%s]\n",
91 (unsigned long)cli
->pid
,
92 request
->data
.auth_crap
.domain
,
93 request
->data
.auth_crap
.user
,
94 request
->data
.auth_crap
.workstation
);
96 if (!check_request_flags(request
->flags
)) {
97 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
98 return tevent_req_post(req
, ev
);
101 auth_domain
= request
->data
.auth_crap
.domain
;
102 if (auth_domain
[0] == '\0') {
103 auth_domain
= lp_workgroup();
106 domain
= find_auth_domain(request
->flags
, auth_domain
);
107 if (domain
== NULL
) {
109 * We don't know the domain so
110 * we're not authoritative
112 state
->authoritative
= 0;
113 tevent_req_nterror(req
, NT_STATUS_NO_SUCH_USER
);
114 return tevent_req_post(req
, ev
);
117 if (request
->data
.auth_crap
.workstation
[0] == '\0') {
118 fstrcpy(request
->data
.auth_crap
.workstation
, lp_netbios_name());
121 lmlength_ok
= (request
->data
.auth_crap
.lm_resp_len
<=
122 sizeof(request
->data
.auth_crap
.lm_resp
));
124 ntlength_ok
= (request
->data
.auth_crap
.nt_resp_len
<=
125 sizeof(request
->data
.auth_crap
.nt_resp
));
128 ((request
->flags
& WBFLAG_BIG_NTLMV2_BLOB
) &&
129 (request
->extra_len
== request
->data
.auth_crap
.nt_resp_len
));
131 pwlength_ok
= lmlength_ok
&& ntlength_ok
;
134 DBG_ERR("Invalid password length %u/%u\n",
135 request
->data
.auth_crap
.lm_resp_len
,
136 request
->data
.auth_crap
.nt_resp_len
);
137 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
138 return tevent_req_post(req
, ev
);
141 state
->domain
= talloc_strdup(state
, request
->data
.auth_crap
.domain
);
142 if (tevent_req_nomem(state
->domain
, req
)) {
143 return tevent_req_post(req
, ev
);
146 state
->user
= talloc_strdup(state
, request
->data
.auth_crap
.user
);
147 if (tevent_req_nomem(state
->user
, req
)) {
148 return tevent_req_post(req
, ev
);
151 status
= extra_data_to_sid_array(
152 request
->data
.auth_crap
.require_membership_of_sid
,
154 &require_membership_of_sid
);
155 if (tevent_req_nterror(req
, status
)) {
156 return tevent_req_post(req
, ev
);
159 lm_resp
= data_blob_talloc(state
,
160 request
->data
.auth_crap
.lm_resp
,
161 request
->data
.auth_crap
.lm_resp_len
);
162 if (tevent_req_nomem(lm_resp
.data
, req
)) {
163 return tevent_req_post(req
, ev
);
166 if (request
->flags
& WBFLAG_BIG_NTLMV2_BLOB
) {
167 nt_resp
= data_blob_talloc(state
,
168 request
->extra_data
.data
,
169 request
->data
.auth_crap
.nt_resp_len
);
171 nt_resp
= data_blob_talloc(state
,
172 request
->data
.auth_crap
.nt_resp
,
173 request
->data
.auth_crap
.nt_resp_len
);
175 if (tevent_req_nomem(nt_resp
.data
, req
)) {
176 return tevent_req_post(req
, ev
);
179 chal
= data_blob_talloc(state
,
180 request
->data
.auth_crap
.chal
,
182 if (tevent_req_nomem(chal
.data
, req
)) {
183 return tevent_req_post(req
, ev
);
186 subreq
= dcerpc_wbint_PamAuthCrap_send(state
,
187 global_event_context(),
188 dom_child_handle(domain
),
189 request
->client_name
,
192 request
->data
.auth_crap
.user
,
193 request
->data
.auth_crap
.domain
,
194 request
->data
.auth_crap
.workstation
,
198 request
->data
.auth_crap
.logon_parameters
,
199 require_membership_of_sid
,
200 &state
->authoritative
,
202 if (tevent_req_nomem(subreq
, req
)) {
203 return tevent_req_post(req
, ev
);
205 tevent_req_set_callback(subreq
, winbindd_pam_auth_crap_done
, req
);
209 static void winbindd_pam_auth_crap_done(struct tevent_req
*subreq
)
211 struct tevent_req
*req
= tevent_req_callback_data(
212 subreq
, struct tevent_req
);
213 struct winbindd_pam_auth_crap_state
*state
= tevent_req_data(
214 req
, struct winbindd_pam_auth_crap_state
);
217 status
= dcerpc_wbint_PamAuthCrap_recv(subreq
, state
, &state
->result
);
219 if (tevent_req_nterror(req
, status
)) {
223 tevent_req_done(req
);
226 NTSTATUS
winbindd_pam_auth_crap_recv(struct tevent_req
*req
,
227 struct winbindd_response
*response
)
229 struct winbindd_pam_auth_crap_state
*state
= tevent_req_data(
230 req
, struct winbindd_pam_auth_crap_state
);
233 if (tevent_req_is_nterror(req
, &status
)) {
237 if (NT_STATUS_IS_ERR(state
->result
)) {
238 status
= state
->result
;
242 status
= append_auth_data(response
,
245 state
->validation
.level
,
246 state
->validation
.validation
,
249 if (NT_STATUS_IS_ERR(status
)) {
253 if (state
->flags
& WBFLAG_PAM_AUTH_PAC
&& !state
->pac_is_trusted
) {
255 * Clear the flag just in state to do no add the domain
258 state
->flags
&= ~WBFLAG_PAM_INFO3_TEXT
;
261 if (state
->flags
& WBFLAG_PAM_INFO3_TEXT
) {
264 ok
= add_trusted_domain_from_auth(
265 response
->data
.auth
.validation_level
,
266 &response
->data
.auth
.info3
,
267 &response
->data
.auth
.info6
);
269 status
= NT_STATUS_LOGON_FAILURE
;
270 DBG_ERR("add_trusted_domain_from_auth failed\n");
271 set_auth_errors(response
, status
);
272 response
->data
.auth
.authoritative
=
273 state
->authoritative
;
278 status
= NT_STATUS_OK
;
281 set_auth_errors(response
, status
);
282 response
->data
.auth
.authoritative
= state
->authoritative
;
283 response
->result
= WINBINDD_PENDING
;
284 return NT_STATUS(response
->data
.auth
.nt_status
);