2 Unix SMB/CIFS implementation.
4 Winbind authentication mechnism
6 Copyright (C) Tim Potter 2000
7 Copyright (C) Andrew Bartlett 2001 - 2002
8 Copyright (C) Stefan Metzmacher 2005
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "auth/auth.h"
26 #include "auth/ntlm/auth_proto.h"
27 #include "auth/auth_sam_reply.h"
28 #include "nsswitch/winbind_client.h"
29 #include "librpc/gen_ndr/ndr_netlogon.h"
30 #include "librpc/gen_ndr/ndr_winbind.h"
31 #include "lib/messaging/irpc.h"
32 #include "param/param.h"
33 #include "nsswitch/libwbclient/wbclient.h"
34 #include "libcli/security/dom_sid.h"
36 static NTSTATUS
get_info3_from_ndr(TALLOC_CTX
*mem_ctx
, struct smb_iconv_convenience
*iconv_convenience
, struct winbindd_response
*response
, struct netr_SamInfo3
*info3
)
38 size_t len
= response
->length
- sizeof(struct winbindd_response
);
40 enum ndr_err_code ndr_err
;
42 blob
.length
= len
- 4;
43 blob
.data
= (uint8_t *)(((char *)response
->extra_data
.data
) + 4);
45 ndr_err
= ndr_pull_struct_blob(&blob
, mem_ctx
,
46 iconv_convenience
, info3
,
47 (ndr_pull_flags_fn_t
)ndr_pull_netr_SamInfo3
);
48 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
49 return ndr_map_error2ntstatus(ndr_err
);
54 DEBUG(2, ("get_info3_from_ndr: No info3 struct found!\n"));
55 return NT_STATUS_UNSUCCESSFUL
;
59 static NTSTATUS
get_info3_from_wbcAuthUserInfo(TALLOC_CTX
*mem_ctx
,
60 struct smb_iconv_convenience
*ic
,
61 struct wbcAuthUserInfo
*info
,
62 struct netr_SamInfo3
*info3
)
65 struct samr_RidWithAttribute
*rids
= NULL
;
67 info3
->base
.last_logon
= info
->logon_time
;
68 info3
->base
.last_logoff
= info
->logoff_time
;
69 info3
->base
.acct_expiry
= info
->kickoff_time
;
70 info3
->base
.last_password_change
= info
->pass_last_set_time
;
71 info3
->base
.allow_password_change
= info
->pass_can_change_time
;
72 info3
->base
.force_password_change
= info
->pass_must_change_time
;
74 info3
->base
.account_name
.string
= talloc_strdup(mem_ctx
,
76 info3
->base
.full_name
.string
= talloc_strdup(mem_ctx
,
78 info3
->base
.logon_script
.string
= talloc_strdup(mem_ctx
,
80 info3
->base
.profile_path
.string
= talloc_strdup(mem_ctx
,
82 info3
->base
.home_directory
.string
= talloc_strdup(mem_ctx
,
83 info
->home_directory
);
84 info3
->base
.home_drive
.string
= talloc_strdup(mem_ctx
,
86 info3
->base
.logon_server
.string
= talloc_strdup(mem_ctx
,
88 info3
->base
.domain
.string
= talloc_strdup(mem_ctx
,
91 info3
->base
.logon_count
= info
->logon_count
;
92 info3
->base
.bad_password_count
= info
->bad_password_count
;
93 info3
->base
.user_flags
= info
->user_flags
;
94 memcpy(info3
->base
.key
.key
, info
->user_session_key
,
95 sizeof(info3
->base
.key
.key
));
96 memcpy(info3
->base
.LMSessKey
.key
, info
->lm_session_key
,
97 sizeof(info3
->base
.LMSessKey
.key
));
98 info3
->base
.acct_flags
= info
->acct_flags
;
99 memset(info3
->base
.unknown
, 0, sizeof(info3
->base
.unknown
));
101 if (info
->num_sids
< 2) {
102 return NT_STATUS_INVALID_PARAMETER
;
105 dom_sid_split_rid(mem_ctx
, (struct dom_sid2
*) &info
->sids
[0].sid
,
106 &info3
->base
.domain_sid
,
108 dom_sid_split_rid(mem_ctx
, (struct dom_sid2
*) &info
->sids
[1].sid
, NULL
,
109 &info3
->base
.primary_gid
);
111 /* We already handled the first two, now take care of the rest */
112 info3
->base
.groups
.count
= info
->num_sids
- 2;
114 rids
= talloc_array(mem_ctx
, struct samr_RidWithAttribute
,
115 info3
->base
.groups
.count
);
116 NT_STATUS_HAVE_NO_MEMORY(rids
);
118 for (i
= 2, j
= 0; i
< info
->num_sids
; ++i
, ++j
) {
119 rids
[j
].attributes
= info
->sids
[i
].attributes
;
120 dom_sid_split_rid(mem_ctx
,
121 (struct dom_sid2
*) &info
->sids
[i
].sid
,
124 info3
->base
.groups
.rids
= rids
;
130 static NTSTATUS
winbind_want_check(struct auth_method_context
*ctx
,
132 const struct auth_usersupplied_info
*user_info
)
134 if (!user_info
->mapped
.account_name
|| !*user_info
->mapped
.account_name
) {
135 return NT_STATUS_NOT_IMPLEMENTED
;
138 /* TODO: maybe limit the user scope to remote users only */
143 Authenticate a user with a challenge/response
144 using the samba3 winbind protocol
146 static NTSTATUS
winbind_check_password_samba3(struct auth_method_context
*ctx
,
148 const struct auth_usersupplied_info
*user_info
,
149 struct auth_serversupplied_info
**server_info
)
151 struct winbindd_request request
;
152 struct winbindd_response response
;
155 struct netr_SamInfo3 info3
;
157 /* Send off request */
158 const struct auth_usersupplied_info
*user_info_temp
;
159 nt_status
= encrypt_user_info(mem_ctx
, ctx
->auth_ctx
,
160 AUTH_PASSWORD_RESPONSE
,
161 user_info
, &user_info_temp
);
162 if (!NT_STATUS_IS_OK(nt_status
)) {
165 user_info
= user_info_temp
;
167 ZERO_STRUCT(request
);
168 ZERO_STRUCT(response
);
169 request
.flags
= WBFLAG_PAM_INFO3_NDR
;
171 request
.data
.auth_crap
.logon_parameters
= user_info
->logon_parameters
;
173 safe_strcpy(request
.data
.auth_crap
.user
,
174 user_info
->client
.account_name
, sizeof(fstring
));
175 safe_strcpy(request
.data
.auth_crap
.domain
,
176 user_info
->client
.domain_name
, sizeof(fstring
));
177 safe_strcpy(request
.data
.auth_crap
.workstation
,
178 user_info
->workstation_name
, sizeof(fstring
));
180 memcpy(request
.data
.auth_crap
.chal
, ctx
->auth_ctx
->challenge
.data
.data
, sizeof(request
.data
.auth_crap
.chal
));
182 request
.data
.auth_crap
.lm_resp_len
= MIN(user_info
->password
.response
.lanman
.length
,
183 sizeof(request
.data
.auth_crap
.lm_resp
));
184 request
.data
.auth_crap
.nt_resp_len
= MIN(user_info
->password
.response
.nt
.length
,
185 sizeof(request
.data
.auth_crap
.nt_resp
));
187 memcpy(request
.data
.auth_crap
.lm_resp
, user_info
->password
.response
.lanman
.data
,
188 request
.data
.auth_crap
.lm_resp_len
);
189 memcpy(request
.data
.auth_crap
.nt_resp
, user_info
->password
.response
.nt
.data
,
190 request
.data
.auth_crap
.nt_resp_len
);
192 result
= winbindd_request_response(WINBINDD_PAM_AUTH_CRAP
, &request
, &response
);
194 nt_status
= NT_STATUS(response
.data
.auth
.nt_status
);
195 NT_STATUS_NOT_OK_RETURN(nt_status
);
197 if (result
== NSS_STATUS_SUCCESS
&& response
.extra_data
.data
) {
198 union netr_Validation validation
;
200 nt_status
= get_info3_from_ndr(mem_ctx
, lp_iconv_convenience(ctx
->auth_ctx
->lp_ctx
), &response
, &info3
);
201 SAFE_FREE(response
.extra_data
.data
);
202 NT_STATUS_NOT_OK_RETURN(nt_status
);
204 validation
.sam3
= &info3
;
205 nt_status
= make_server_info_netlogon_validation(mem_ctx
,
206 user_info
->client
.account_name
,
210 } else if (result
== NSS_STATUS_SUCCESS
&& !response
.extra_data
.data
) {
211 DEBUG(0, ("Winbindd authenticated the user [%s]\\[%s], "
212 "but did not include the required info3 reply!\n",
213 user_info
->client
.domain_name
, user_info
->client
.account_name
));
214 return NT_STATUS_INSUFFICIENT_LOGON_INFO
;
215 } else if (NT_STATUS_IS_OK(nt_status
)) {
216 DEBUG(1, ("Winbindd authentication for [%s]\\[%s] failed, "
217 "but no error code is available!\n",
218 user_info
->client
.domain_name
, user_info
->client
.account_name
));
219 return NT_STATUS_NO_LOGON_SERVERS
;
225 struct winbind_check_password_state
{
226 struct winbind_SamLogon req
;
230 Authenticate a user with a challenge/response
231 using IRPC to the winbind task
233 static NTSTATUS
winbind_check_password(struct auth_method_context
*ctx
,
235 const struct auth_usersupplied_info
*user_info
,
236 struct auth_serversupplied_info
**server_info
)
239 struct server_id
*winbind_servers
;
240 struct winbind_check_password_state
*s
;
241 const struct auth_usersupplied_info
*user_info_new
;
242 struct netr_IdentityInfo
*identity_info
;
244 s
= talloc(mem_ctx
, struct winbind_check_password_state
);
245 NT_STATUS_HAVE_NO_MEMORY(s
);
247 winbind_servers
= irpc_servers_byname(ctx
->auth_ctx
->msg_ctx
, s
, "winbind_server");
248 if ((winbind_servers
== NULL
) || (winbind_servers
[0].id
== 0)) {
249 DEBUG(0, ("Winbind authentication for [%s]\\[%s] failed, "
250 "no winbind_server running!\n",
251 user_info
->client
.domain_name
, user_info
->client
.account_name
));
252 return NT_STATUS_NO_LOGON_SERVERS
;
255 if (user_info
->flags
& USER_INFO_INTERACTIVE_LOGON
) {
256 struct netr_PasswordInfo
*password_info
;
258 status
= encrypt_user_info(s
, ctx
->auth_ctx
, AUTH_PASSWORD_HASH
,
259 user_info
, &user_info_new
);
260 NT_STATUS_NOT_OK_RETURN(status
);
261 user_info
= user_info_new
;
263 password_info
= talloc(s
, struct netr_PasswordInfo
);
264 NT_STATUS_HAVE_NO_MEMORY(password_info
);
266 password_info
->lmpassword
= *user_info
->password
.hash
.lanman
;
267 password_info
->ntpassword
= *user_info
->password
.hash
.nt
;
269 identity_info
= &password_info
->identity_info
;
270 s
->req
.in
.logon_level
= 1;
271 s
->req
.in
.logon
.password
= password_info
;
273 struct netr_NetworkInfo
*network_info
;
274 const uint8_t *challenge
;
276 status
= encrypt_user_info(s
, ctx
->auth_ctx
, AUTH_PASSWORD_RESPONSE
,
277 user_info
, &user_info_new
);
278 NT_STATUS_NOT_OK_RETURN(status
);
279 user_info
= user_info_new
;
281 network_info
= talloc(s
, struct netr_NetworkInfo
);
282 NT_STATUS_HAVE_NO_MEMORY(network_info
);
284 status
= auth_get_challenge(ctx
->auth_ctx
, &challenge
);
285 NT_STATUS_NOT_OK_RETURN(status
);
287 memcpy(network_info
->challenge
, challenge
, sizeof(network_info
->challenge
));
289 network_info
->nt
.length
= user_info
->password
.response
.nt
.length
;
290 network_info
->nt
.data
= user_info
->password
.response
.nt
.data
;
292 network_info
->lm
.length
= user_info
->password
.response
.lanman
.length
;
293 network_info
->lm
.data
= user_info
->password
.response
.lanman
.data
;
295 identity_info
= &network_info
->identity_info
;
296 s
->req
.in
.logon_level
= 2;
297 s
->req
.in
.logon
.network
= network_info
;
300 identity_info
->domain_name
.string
= user_info
->client
.domain_name
;
301 identity_info
->parameter_control
= user_info
->logon_parameters
; /* see MSV1_0_* */
302 identity_info
->logon_id_low
= 0;
303 identity_info
->logon_id_high
= 0;
304 identity_info
->account_name
.string
= user_info
->client
.account_name
;
305 identity_info
->workstation
.string
= user_info
->workstation_name
;
307 s
->req
.in
.validation_level
= 3;
309 status
= IRPC_CALL(ctx
->auth_ctx
->msg_ctx
, winbind_servers
[0],
310 winbind
, WINBIND_SAMLOGON
,
312 NT_STATUS_NOT_OK_RETURN(status
);
314 status
= make_server_info_netlogon_validation(mem_ctx
,
315 user_info
->client
.account_name
,
316 s
->req
.in
.validation_level
,
317 &s
->req
.out
.validation
,
319 NT_STATUS_NOT_OK_RETURN(status
);
325 Authenticate a user with a challenge/response
326 using the samba3 winbind protocol via libwbclient
328 static NTSTATUS
winbind_check_password_wbclient(struct auth_method_context
*ctx
,
330 const struct auth_usersupplied_info
*user_info
,
331 struct auth_serversupplied_info
**server_info
)
333 struct wbcAuthUserParams params
;
334 struct wbcAuthUserInfo
*info
= NULL
;
335 struct wbcAuthErrorInfo
*err
= NULL
;
338 struct netr_SamInfo3 info3
;
339 union netr_Validation validation
;
342 /* Send off request */
343 const struct auth_usersupplied_info
*user_info_temp
;
344 nt_status
= encrypt_user_info(mem_ctx
, ctx
->auth_ctx
,
345 AUTH_PASSWORD_RESPONSE
,
346 user_info
, &user_info_temp
);
347 if (!NT_STATUS_IS_OK(nt_status
)) {
350 user_info
= user_info_temp
;
354 /*params.flags = WBFLAG_PAM_INFO3_NDR;*/
356 params
.parameter_control
= user_info
->logon_parameters
;
357 params
.parameter_control
|= WBC_MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
|
358 WBC_MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT
;
359 params
.level
= WBC_AUTH_USER_LEVEL_RESPONSE
;
361 params
.account_name
= user_info
->client
.account_name
;
362 params
.domain_name
= user_info
->client
.domain_name
;
363 params
.workstation_name
= user_info
->workstation_name
;
365 d_fprintf(stderr
, "looking up %s@%s logging in from %s\n",
366 params
.account_name
, params
.domain_name
,
367 params
.workstation_name
);
369 memcpy(params
.password
.response
.challenge
,
370 ctx
->auth_ctx
->challenge
.data
.data
,
371 sizeof(params
.password
.response
.challenge
));
373 params
.password
.response
.lm_length
=
374 user_info
->password
.response
.lanman
.length
;
375 params
.password
.response
.nt_length
=
376 user_info
->password
.response
.nt
.length
;
378 params
.password
.response
.lm_data
=
379 user_info
->password
.response
.lanman
.data
;
380 params
.password
.response
.nt_data
=
381 user_info
->password
.response
.nt
.data
;
383 wbc_status
= wbcAuthenticateUserEx(¶ms
, &info
, &err
);
384 if (!WBC_ERROR_IS_OK(wbc_status
)) {
385 DEBUG(1, ("error was %s (0x%08x)\nerror message was '%s'\n",
386 err
->nt_string
, err
->nt_status
, err
->display_string
));
388 nt_status
= NT_STATUS(err
->nt_status
);
390 NT_STATUS_NOT_OK_RETURN(nt_status
);
392 nt_status
= get_info3_from_wbcAuthUserInfo(mem_ctx
,
393 lp_iconv_convenience(ctx
->auth_ctx
->lp_ctx
),
396 NT_STATUS_NOT_OK_RETURN(nt_status
);
398 validation
.sam3
= &info3
;
399 nt_status
= make_server_info_netlogon_validation(mem_ctx
,
400 user_info
->client
.account_name
,
401 3, &validation
, server_info
);
406 static const struct auth_operations winbind_samba3_ops
= {
407 .name
= "winbind_samba3",
408 .get_challenge
= auth_get_challenge_not_implemented
,
409 .want_check
= winbind_want_check
,
410 .check_password
= winbind_check_password_samba3
413 static const struct auth_operations winbind_ops
= {
415 .get_challenge
= auth_get_challenge_not_implemented
,
416 .want_check
= winbind_want_check
,
417 .check_password
= winbind_check_password
420 static const struct auth_operations winbind_wbclient_ops
= {
421 .name
= "winbind_wbclient",
422 .get_challenge
= auth_get_challenge_not_implemented
,
423 .want_check
= winbind_want_check
,
424 .check_password
= winbind_check_password_wbclient
427 _PUBLIC_ NTSTATUS
auth_winbind_init(void)
431 ret
= auth_register(&winbind_samba3_ops
);
432 if (!NT_STATUS_IS_OK(ret
)) {
433 DEBUG(0,("Failed to register 'winbind_samba3' auth backend!\n"));
437 ret
= auth_register(&winbind_ops
);
438 if (!NT_STATUS_IS_OK(ret
)) {
439 DEBUG(0,("Failed to register 'winbind' auth backend!\n"));
443 ret
= auth_register(&winbind_wbclient_ops
);
444 if (!NT_STATUS_IS_OK(ret
)) {
445 DEBUG(0,("Failed to register 'winbind_wbclient' auth backend!\n"));