2 Unix SMB/CIFS implementation.
4 Winbind status program.
6 Copyright (C) Tim Potter 2000-2003
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003-2004
8 Copyright (C) Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it> 2000
9 Copyright (C) Robert O'Callahan 2006 (added cached credential code).
10 Copyright (C) Kai Blin <kai@samba.org> 2008
11 Copyright (C) Simo Sorce 2010
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 3 of the License, or
16 (at your option) any later version.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 #include "lib/param/param.h"
29 #include "popt_common.h"
30 #include "libcli/security/security.h"
31 #include "utils/ntlm_auth.h"
32 #include "../libcli/auth/libcli_auth.h"
33 #include "auth/ntlmssp/ntlmssp.h"
34 #include "auth/gensec/gensec.h"
35 #include "auth/gensec/gensec_internal.h"
36 #include "auth/credentials/credentials.h"
37 #include "librpc/crypto/gse.h"
39 #include "lib/util/tiniparser.h"
40 #include "../lib/crypto/arcfour.h"
41 #include "nsswitch/winbind_client.h"
42 #include "librpc/gen_ndr/krb5pac.h"
43 #include "../lib/util/asn1.h"
44 #include "auth/common_auth.h"
45 #include "source3/include/auth.h"
46 #include "source3/auth/proto.h"
47 #include "nsswitch/libwbclient/wbclient.h"
48 #include "lib/param/loadparm.h"
49 #include "lib/util/base64.h"
50 #include "lib/util/xfile.h"
53 #include "auth/kerberos/pac_utils.h"
56 #ifndef PAM_WINBIND_CONFIG_FILE
57 #define PAM_WINBIND_CONFIG_FILE "/etc/security/pam_winbind.conf"
60 #define WINBIND_KRB5_AUTH 0x00000080
63 #define DBGC_CLASS DBGC_WINBIND
65 #define INITIAL_BUFFER_SIZE 300
66 #define MAX_BUFFER_SIZE 630000
68 enum stdio_helper_mode
{
76 NTLM_CHANGE_PASSWORD_1
,
80 enum ntlm_auth_cli_state
{
87 struct ntlm_auth_state
{
89 enum stdio_helper_mode helper_mode
;
90 enum ntlm_auth_cli_state cli_state
;
91 struct ntlmssp_state
*ntlmssp_state
;
93 char *want_feature_list
;
94 bool have_session_key
;
95 DATA_BLOB session_key
;
96 DATA_BLOB initial_message
;
97 void *gensec_private_1
;
99 typedef void (*stdio_helper_function
)(enum stdio_helper_mode stdio_helper_mode
,
100 struct loadparm_context
*lp_ctx
,
101 struct ntlm_auth_state
*state
, char *buf
,
102 int length
, void **private2
);
104 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode
,
105 struct loadparm_context
*lp_ctx
,
106 char *buf
, int length
, void **private1
);
108 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode
,
109 struct loadparm_context
*lp_ctx
,
110 struct ntlm_auth_state
*state
,
111 stdio_helper_function fn
, void **private2
);
113 static void manage_squid_basic_request (enum stdio_helper_mode stdio_helper_mode
,
114 struct loadparm_context
*lp_ctx
,
115 struct ntlm_auth_state
*state
,
116 char *buf
, int length
, void **private2
);
118 static void manage_squid_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode
,
119 struct loadparm_context
*lp_ctx
,
120 struct ntlm_auth_state
*state
,
121 char *buf
, int length
, void **private2
);
123 static void manage_client_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode
,
124 struct loadparm_context
*lp_ctx
,
125 struct ntlm_auth_state
*state
,
126 char *buf
, int length
, void **private2
);
128 static void manage_gss_spnego_request (enum stdio_helper_mode stdio_helper_mode
,
129 struct loadparm_context
*lp_ctx
,
130 struct ntlm_auth_state
*state
,
131 char *buf
, int length
, void **private2
);
133 static void manage_gss_spnego_client_request (enum stdio_helper_mode stdio_helper_mode
,
134 struct loadparm_context
*lp_ctx
,
135 struct ntlm_auth_state
*state
,
136 char *buf
, int length
, void **private2
);
138 static void manage_ntlm_server_1_request (enum stdio_helper_mode stdio_helper_mode
,
139 struct loadparm_context
*lp_ctx
,
140 struct ntlm_auth_state
*state
,
141 char *buf
, int length
, void **private2
);
143 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode
,
144 struct loadparm_context
*lp_ctx
,
145 struct ntlm_auth_state
*state
,
146 char *buf
, int length
, void **private2
);
148 static const struct {
149 enum stdio_helper_mode mode
;
151 stdio_helper_function fn
;
152 } stdio_helper_protocols
[] = {
153 { SQUID_2_4_BASIC
, "squid-2.4-basic", manage_squid_basic_request
},
154 { SQUID_2_5_BASIC
, "squid-2.5-basic", manage_squid_basic_request
},
155 { SQUID_2_5_NTLMSSP
, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request
},
156 { NTLMSSP_CLIENT_1
, "ntlmssp-client-1", manage_client_ntlmssp_request
},
157 { GSS_SPNEGO_SERVER
, "gss-spnego", manage_gss_spnego_request
},
158 { GSS_SPNEGO_CLIENT
, "gss-spnego-client", manage_gss_spnego_client_request
},
159 { NTLM_SERVER_1
, "ntlm-server-1", manage_ntlm_server_1_request
},
160 { NTLM_CHANGE_PASSWORD_1
, "ntlm-change-password-1", manage_ntlm_change_password_1_request
},
161 { NUM_HELPER_MODES
, NULL
, NULL
}
164 const char *opt_username
;
165 const char *opt_domain
;
166 const char *opt_workstation
;
167 const char *opt_password
;
168 static DATA_BLOB opt_challenge
;
169 static DATA_BLOB opt_lm_response
;
170 static DATA_BLOB opt_nt_response
;
171 static int request_lm_key
;
172 static int request_user_session_key
;
173 static int use_cached_creds
;
174 static int offline_logon
;
175 static int opt_allow_mschapv2
;
177 static const char *require_membership_of
;
178 static const char *require_membership_of_sid
;
179 static const char *opt_pam_winbind_conf
;
181 const char *opt_target_service
;
182 const char *opt_target_hostname
;
185 /* This is a bit hairy, but the basic idea is to do a password callback
186 to the calling application. The callback comes from within gensec */
188 static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mode
,
189 struct loadparm_context
*lp_ctx
,
190 struct ntlm_auth_state
*state
, char *buf
, int length
,
194 if (strlen(buf
) < 2) {
195 DEBUG(1, ("query [%s] invalid", buf
));
196 x_fprintf(x_stdout
, "BH Query invalid\n");
200 if (strlen(buf
) > 3) {
201 in
= base64_decode_data_blob(buf
+ 3);
203 in
= data_blob(NULL
, 0);
206 if (strncmp(buf
, "PW ", 3) == 0) {
208 *password
= talloc_strndup(NULL
,
209 (const char *)in
.data
, in
.length
);
211 if (*password
== NULL
) {
212 DEBUG(1, ("Out of memory\n"));
213 x_fprintf(x_stdout
, "BH Out of memory\n");
218 x_fprintf(x_stdout
, "OK\n");
222 DEBUG(1, ("Asked for (and expected) a password\n"));
223 x_fprintf(x_stdout
, "BH Expected a password\n");
228 * Callback for password credentials. This is not async, and when
229 * GENSEC and the credentials code is made async, it will look rather
233 static const char *get_password(struct cli_credentials
*credentials
)
235 TALLOC_CTX
*frame
= talloc_stackframe();
236 char *password
= NULL
;
237 struct ntlm_auth_state
*state
;
239 state
= talloc_zero(frame
, struct ntlm_auth_state
);
241 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
242 x_fprintf(x_stderr
, "ERR\n");
246 state
->mem_ctx
= state
;
248 /* Ask for a password */
249 x_fprintf(x_stdout
, "PW\n");
251 manage_squid_request(NUM_HELPER_MODES
/* bogus */, NULL
, state
, manage_gensec_get_pw_request
, (void **)&password
);
252 talloc_steal(credentials
, password
);
258 * A limited set of features are defined with text strings as needed
262 static void gensec_want_feature_list(struct gensec_security
*state
, char* feature_list
)
264 if (in_list("NTLMSSP_FEATURE_SESSION_KEY", feature_list
, true)) {
265 DEBUG(10, ("want GENSEC_FEATURE_SESSION_KEY\n"));
266 gensec_want_feature(state
, GENSEC_FEATURE_SESSION_KEY
);
268 if (in_list("NTLMSSP_FEATURE_SIGN", feature_list
, true)) {
269 DEBUG(10, ("want GENSEC_FEATURE_SIGN\n"));
270 gensec_want_feature(state
, GENSEC_FEATURE_SIGN
);
272 if (in_list("NTLMSSP_FEATURE_SEAL", feature_list
, true)) {
273 DEBUG(10, ("want GENSEC_FEATURE_SEAL\n"));
274 gensec_want_feature(state
, GENSEC_FEATURE_SEAL
);
276 if (in_list("NTLMSSP_FEATURE_CCACHE", feature_list
, true)) {
277 DEBUG(10, ("want GENSEC_FEATURE_NTLM_CCACHE\n"));
278 gensec_want_feature(state
, GENSEC_FEATURE_NTLM_CCACHE
);
282 static char winbind_separator(void)
284 struct winbindd_response response
;
291 ZERO_STRUCT(response
);
293 /* Send off request */
295 if (winbindd_request_response(NULL
, WINBINDD_INFO
, NULL
, &response
) !=
296 NSS_STATUS_SUCCESS
) {
297 d_printf("could not obtain winbind separator!\n");
298 return *lp_winbind_separator();
301 sep
= response
.data
.info
.winbind_separator
;
305 d_printf("winbind separator was NULL!\n");
306 return *lp_winbind_separator();
312 const char *get_winbind_domain(void)
314 struct winbindd_response response
;
316 static fstring winbind_domain
;
317 if (*winbind_domain
) {
318 return winbind_domain
;
321 ZERO_STRUCT(response
);
323 /* Send off request */
325 if (winbindd_request_response(NULL
, WINBINDD_DOMAIN_NAME
, NULL
, &response
) !=
326 NSS_STATUS_SUCCESS
) {
327 DEBUG(1, ("could not obtain winbind domain name!\n"));
328 return lp_workgroup();
331 fstrcpy(winbind_domain
, response
.data
.domain_name
);
333 return winbind_domain
;
337 const char *get_winbind_netbios_name(void)
339 struct winbindd_response response
;
341 static fstring winbind_netbios_name
;
343 if (*winbind_netbios_name
) {
344 return winbind_netbios_name
;
347 ZERO_STRUCT(response
);
349 /* Send off request */
351 if (winbindd_request_response(NULL
, WINBINDD_NETBIOS_NAME
, NULL
, &response
) !=
352 NSS_STATUS_SUCCESS
) {
353 DEBUG(1, ("could not obtain winbind netbios name!\n"));
354 return lp_netbios_name();
357 fstrcpy(winbind_netbios_name
, response
.data
.netbios_name
);
359 return winbind_netbios_name
;
363 DATA_BLOB
get_challenge(void)
365 static DATA_BLOB chal
;
366 if (opt_challenge
.length
)
367 return opt_challenge
;
369 chal
= data_blob(NULL
, 8);
371 generate_random_buffer(chal
.data
, chal
.length
);
375 /* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
376 form DOMAIN/user into a domain and a user */
378 static bool parse_ntlm_auth_domain_user(const char *domuser
, fstring domain
,
382 char *p
= strchr(domuser
,winbind_separator());
389 fstrcpy(domain
, domuser
);
390 domain
[PTR_DIFF(p
, domuser
)] = 0;
391 return strupper_m(domain
);
394 static bool get_require_membership_sid(void) {
395 struct winbindd_request request
;
396 struct winbindd_response response
;
398 if (!require_membership_of
) {
402 if (require_membership_of_sid
) {
406 /* Otherwise, ask winbindd for the name->sid request */
408 ZERO_STRUCT(request
);
409 ZERO_STRUCT(response
);
411 if (!parse_ntlm_auth_domain_user(require_membership_of
,
412 request
.data
.name
.dom_name
,
413 request
.data
.name
.name
)) {
414 DEBUG(0, ("Could not parse %s into separate domain/name parts!\n",
415 require_membership_of
));
419 if (winbindd_request_response(NULL
, WINBINDD_LOOKUPNAME
, &request
, &response
) !=
420 NSS_STATUS_SUCCESS
) {
421 DEBUG(0, ("Winbindd lookupname failed to resolve %s into a SID!\n",
422 require_membership_of
));
426 require_membership_of_sid
= SMB_STRDUP(response
.data
.sid
.sid
);
428 if (require_membership_of_sid
)
435 * Get some configuration from pam_winbind.conf to see if we
436 * need to contact trusted domain
439 int get_pam_winbind_config()
442 struct tiniparser_dictionary
*d
= NULL
;
444 if (!opt_pam_winbind_conf
|| !*opt_pam_winbind_conf
) {
445 opt_pam_winbind_conf
= PAM_WINBIND_CONFIG_FILE
;
448 d
= tiniparser_load(opt_pam_winbind_conf
);
454 if (tiniparser_getboolean(d
, "global:krb5_auth", false)) {
455 ctrl
|= WINBIND_KRB5_AUTH
;
458 tiniparser_freedict(d
);
463 /* Authenticate a user with a plaintext password */
465 static bool check_plaintext_auth(const char *user
, const char *pass
,
466 bool stdout_diagnostics
)
468 struct winbindd_request request
;
469 struct winbindd_response response
;
472 if (!get_require_membership_sid()) {
476 /* Send off request */
478 ZERO_STRUCT(request
);
479 ZERO_STRUCT(response
);
481 fstrcpy(request
.data
.auth
.user
, user
);
482 fstrcpy(request
.data
.auth
.pass
, pass
);
483 if (require_membership_of_sid
) {
484 strlcpy(request
.data
.auth
.require_membership_of_sid
,
485 require_membership_of_sid
,
486 sizeof(request
.data
.auth
.require_membership_of_sid
));
490 request
.flags
|= WBFLAG_PAM_CACHED_LOGIN
;
493 result
= winbindd_request_response(NULL
, WINBINDD_PAM_AUTH
, &request
, &response
);
495 /* Display response */
497 if (stdout_diagnostics
) {
498 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
499 d_printf("Reading winbind reply failed! (0x01)\n");
502 d_printf("%s: %s (0x%x)\n",
503 response
.data
.auth
.nt_status_string
,
504 response
.data
.auth
.error_string
,
505 response
.data
.auth
.nt_status
);
507 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
508 DEBUG(1, ("Reading winbind reply failed! (0x01)\n"));
511 DEBUG(3, ("%s: %s (0x%x)\n",
512 response
.data
.auth
.nt_status_string
,
513 response
.data
.auth
.error_string
,
514 response
.data
.auth
.nt_status
));
517 return (result
== NSS_STATUS_SUCCESS
);
520 /* authenticate a user with an encrypted username/password */
522 NTSTATUS
contact_winbind_auth_crap(const char *username
,
524 const char *workstation
,
525 const DATA_BLOB
*challenge
,
526 const DATA_BLOB
*lm_response
,
527 const DATA_BLOB
*nt_response
,
529 uint32_t extra_logon_parameters
,
531 uint8_t user_session_key
[16],
537 struct winbindd_request request
;
538 struct winbindd_response response
;
540 if (!get_require_membership_sid()) {
541 return NT_STATUS_INVALID_PARAMETER
;
544 ZERO_STRUCT(request
);
545 ZERO_STRUCT(response
);
547 request
.flags
= flags
;
549 request
.data
.auth_crap
.logon_parameters
= extra_logon_parameters
550 | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
| MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT
;
552 if (opt_allow_mschapv2
) {
553 request
.data
.auth_crap
.logon_parameters
|= MSV1_0_ALLOW_MSVCHAPV2
;
556 if (require_membership_of_sid
)
557 fstrcpy(request
.data
.auth_crap
.require_membership_of_sid
, require_membership_of_sid
);
559 fstrcpy(request
.data
.auth_crap
.user
, username
);
560 fstrcpy(request
.data
.auth_crap
.domain
, domain
);
562 fstrcpy(request
.data
.auth_crap
.workstation
,
565 memcpy(request
.data
.auth_crap
.chal
, challenge
->data
, MIN(challenge
->length
, 8));
567 if (lm_response
&& lm_response
->length
) {
568 memcpy(request
.data
.auth_crap
.lm_resp
,
570 MIN(lm_response
->length
, sizeof(request
.data
.auth_crap
.lm_resp
)));
571 request
.data
.auth_crap
.lm_resp_len
= lm_response
->length
;
574 if (nt_response
&& nt_response
->length
) {
575 if (nt_response
->length
> sizeof(request
.data
.auth_crap
.nt_resp
)) {
576 request
.flags
= request
.flags
| WBFLAG_BIG_NTLMV2_BLOB
;
577 request
.extra_len
= nt_response
->length
;
578 request
.extra_data
.data
= SMB_MALLOC_ARRAY(char, request
.extra_len
);
579 if (request
.extra_data
.data
== NULL
) {
580 return NT_STATUS_NO_MEMORY
;
582 memcpy(request
.extra_data
.data
, nt_response
->data
,
583 nt_response
->length
);
586 memcpy(request
.data
.auth_crap
.nt_resp
,
587 nt_response
->data
, nt_response
->length
);
589 request
.data
.auth_crap
.nt_resp_len
= nt_response
->length
;
592 result
= winbindd_request_response(NULL
, WINBINDD_PAM_AUTH_CRAP
, &request
, &response
);
593 SAFE_FREE(request
.extra_data
.data
);
595 /* Display response */
597 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
598 nt_status
= NT_STATUS_UNSUCCESSFUL
;
600 *error_string
= smb_xstrdup("Reading winbind reply failed!");
601 winbindd_free_response(&response
);
605 nt_status
= (NT_STATUS(response
.data
.auth
.nt_status
));
606 if (!NT_STATUS_IS_OK(nt_status
)) {
608 *error_string
= smb_xstrdup(response
.data
.auth
.error_string
);
609 winbindd_free_response(&response
);
613 if ((flags
& WBFLAG_PAM_LMKEY
) && lm_key
) {
614 memcpy(lm_key
, response
.data
.auth
.first_8_lm_hash
,
615 sizeof(response
.data
.auth
.first_8_lm_hash
));
617 if ((flags
& WBFLAG_PAM_USER_SESSION_KEY
) && user_session_key
) {
618 memcpy(user_session_key
, response
.data
.auth
.user_session_key
,
619 sizeof(response
.data
.auth
.user_session_key
));
622 if (flags
& WBFLAG_PAM_UNIX_NAME
) {
623 *unix_name
= SMB_STRDUP(response
.data
.auth
.unix_username
);
625 winbindd_free_response(&response
);
626 return NT_STATUS_NO_MEMORY
;
630 winbindd_free_response(&response
);
634 /* contact server to change user password using auth crap */
635 static NTSTATUS
contact_winbind_change_pswd_auth_crap(const char *username
,
637 const DATA_BLOB new_nt_pswd
,
638 const DATA_BLOB old_nt_hash_enc
,
639 const DATA_BLOB new_lm_pswd
,
640 const DATA_BLOB old_lm_hash_enc
,
645 struct winbindd_request request
;
646 struct winbindd_response response
;
648 if (!get_require_membership_sid())
651 *error_string
= smb_xstrdup("Can't get membership sid.");
652 return NT_STATUS_INVALID_PARAMETER
;
655 ZERO_STRUCT(request
);
656 ZERO_STRUCT(response
);
659 fstrcpy(request
.data
.chng_pswd_auth_crap
.user
, username
);
661 fstrcpy(request
.data
.chng_pswd_auth_crap
.domain
,domain
);
663 if(new_nt_pswd
.length
)
665 memcpy(request
.data
.chng_pswd_auth_crap
.new_nt_pswd
, new_nt_pswd
.data
, sizeof(request
.data
.chng_pswd_auth_crap
.new_nt_pswd
));
666 request
.data
.chng_pswd_auth_crap
.new_nt_pswd_len
= new_nt_pswd
.length
;
669 if(old_nt_hash_enc
.length
)
671 memcpy(request
.data
.chng_pswd_auth_crap
.old_nt_hash_enc
, old_nt_hash_enc
.data
, sizeof(request
.data
.chng_pswd_auth_crap
.old_nt_hash_enc
));
672 request
.data
.chng_pswd_auth_crap
.old_nt_hash_enc_len
= old_nt_hash_enc
.length
;
675 if(new_lm_pswd
.length
)
677 memcpy(request
.data
.chng_pswd_auth_crap
.new_lm_pswd
, new_lm_pswd
.data
, sizeof(request
.data
.chng_pswd_auth_crap
.new_lm_pswd
));
678 request
.data
.chng_pswd_auth_crap
.new_lm_pswd_len
= new_lm_pswd
.length
;
681 if(old_lm_hash_enc
.length
)
683 memcpy(request
.data
.chng_pswd_auth_crap
.old_lm_hash_enc
, old_lm_hash_enc
.data
, sizeof(request
.data
.chng_pswd_auth_crap
.old_lm_hash_enc
));
684 request
.data
.chng_pswd_auth_crap
.old_lm_hash_enc_len
= old_lm_hash_enc
.length
;
687 result
= winbindd_request_response(NULL
, WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP
, &request
, &response
);
689 /* Display response */
691 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0))
693 nt_status
= NT_STATUS_UNSUCCESSFUL
;
695 *error_string
= smb_xstrdup("Reading winbind reply failed!");
696 winbindd_free_response(&response
);
700 nt_status
= (NT_STATUS(response
.data
.auth
.nt_status
));
701 if (!NT_STATUS_IS_OK(nt_status
))
704 *error_string
= smb_xstrdup(response
.data
.auth
.error_string
);
705 winbindd_free_response(&response
);
709 winbindd_free_response(&response
);
714 static NTSTATUS
ntlm_auth_generate_session_info(struct auth4_context
*auth_context
,
716 void *server_returned_info
,
717 const char *original_user_name
,
718 uint32_t session_info_flags
,
719 struct auth_session_info
**session_info_out
)
721 const char *unix_username
= (const char *)server_returned_info
;
723 struct dom_sid
*sids
= NULL
;
724 struct auth_session_info
*session_info
= NULL
;
726 session_info
= talloc_zero(mem_ctx
, struct auth_session_info
);
727 if (session_info
== NULL
) {
728 return NT_STATUS_NO_MEMORY
;
731 session_info
->unix_info
= talloc_zero(session_info
, struct auth_user_info_unix
);
732 if (session_info
->unix_info
== NULL
) {
733 TALLOC_FREE(session_info
);
734 return NT_STATUS_NO_MEMORY
;
736 session_info
->unix_info
->unix_name
= talloc_strdup(session_info
->unix_info
,
738 if (session_info
->unix_info
->unix_name
== NULL
) {
739 TALLOC_FREE(session_info
);
740 return NT_STATUS_NO_MEMORY
;
743 session_info
->security_token
= talloc_zero(session_info
, struct security_token
);
744 if (session_info
->security_token
== NULL
) {
745 TALLOC_FREE(session_info
);
746 return NT_STATUS_NO_MEMORY
;
749 sids
= talloc_zero_array(session_info
->security_token
,
752 TALLOC_FREE(session_info
);
753 return NT_STATUS_NO_MEMORY
;
755 ok
= dom_sid_parse(SID_WORLD
, &sids
[0]);
757 TALLOC_FREE(session_info
);
758 return NT_STATUS_INTERNAL_ERROR
;
760 ok
= dom_sid_parse(SID_NT_NETWORK
, &sids
[1]);
762 TALLOC_FREE(session_info
);
763 return NT_STATUS_INTERNAL_ERROR
;
765 ok
= dom_sid_parse(SID_NT_AUTHENTICATED_USERS
, &sids
[2]);
767 TALLOC_FREE(session_info
);
768 return NT_STATUS_INTERNAL_ERROR
;
771 session_info
->security_token
->num_sids
= talloc_array_length(sids
);
772 session_info
->security_token
->sids
= sids
;
774 *session_info_out
= session_info
;
779 static NTSTATUS
ntlm_auth_generate_session_info_pac(struct auth4_context
*auth_ctx
,
781 struct smb_krb5_context
*smb_krb5_context
,
783 const char *princ_name
,
784 const struct tsocket_address
*remote_address
,
785 uint32_t session_info_flags
,
786 struct auth_session_info
**session_info
)
789 struct PAC_LOGON_INFO
*logon_info
= NULL
;
797 tmp_ctx
= talloc_new(mem_ctx
);
799 return NT_STATUS_NO_MEMORY
;
804 status
= kerberos_pac_logon_info(tmp_ctx
, *pac_blob
, NULL
, NULL
,
805 NULL
, NULL
, 0, &logon_info
);
807 status
= NT_STATUS_ACCESS_DENIED
;
809 if (!NT_STATUS_IS_OK(status
)) {
814 DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name
));
816 p
= strchr_m(princ_name
, '@');
818 DEBUG(3, ("[%s] Doesn't look like a valid principal\n",
820 return NT_STATUS_LOGON_FAILURE
;
823 user
= talloc_strndup(mem_ctx
, princ_name
, p
- princ_name
);
825 return NT_STATUS_NO_MEMORY
;
828 realm
= talloc_strdup(talloc_tos(), p
+ 1);
830 return NT_STATUS_NO_MEMORY
;
833 if (!strequal(realm
, lp_realm())) {
834 DEBUG(3, ("Ticket for foreign realm %s@%s\n", user
, realm
));
835 if (!lp_allow_trusted_domains()) {
836 return NT_STATUS_LOGON_FAILURE
;
840 if (logon_info
&& logon_info
->info3
.base
.logon_domain
.string
) {
841 domain
= talloc_strdup(mem_ctx
,
842 logon_info
->info3
.base
.logon_domain
.string
);
844 return NT_STATUS_NO_MEMORY
;
846 DEBUG(10, ("Domain is [%s] (using PAC)\n", domain
));
849 /* If we have winbind running, we can (and must) shorten the
850 username by using the short netbios name. Otherwise we will
851 have inconsistent user names. With Kerberos, we get the
852 fully qualified realm, with ntlmssp we get the short
853 name. And even w2k3 does use ntlmssp if you for example
854 connect to an ip address. */
857 struct wbcDomainInfo
*info
= NULL
;
859 DEBUG(10, ("Mapping [%s] to short name using winbindd\n",
862 wbc_status
= wbcDomainInfo(realm
, &info
);
864 if (WBC_ERROR_IS_OK(wbc_status
)) {
865 domain
= talloc_strdup(mem_ctx
,
869 DEBUG(3, ("Could not find short name: %s\n",
870 wbcErrorString(wbc_status
)));
871 domain
= talloc_strdup(mem_ctx
, realm
);
874 return NT_STATUS_NO_MEMORY
;
876 DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain
));
879 unixuser
= talloc_asprintf(tmp_ctx
, "%s%c%s", domain
, winbind_separator(), user
);
881 status
= NT_STATUS_NO_MEMORY
;
885 status
= ntlm_auth_generate_session_info(auth_ctx
, mem_ctx
, unixuser
, NULL
, session_info_flags
, session_info
);
888 TALLOC_FREE(tmp_ctx
);
895 * Return the challenge as determined by the authentication subsystem
896 * @return an 8 byte random challenge
899 static NTSTATUS
ntlm_auth_get_challenge(struct auth4_context
*auth_ctx
,
902 if (auth_ctx
->challenge
.data
.length
== 8) {
903 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
904 auth_ctx
->challenge
.set_by
));
905 memcpy(chal
, auth_ctx
->challenge
.data
.data
, 8);
909 if (!auth_ctx
->challenge
.set_by
) {
910 generate_random_buffer(chal
, 8);
912 auth_ctx
->challenge
.data
= data_blob_talloc(auth_ctx
, chal
, 8);
913 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.data
.data
);
914 auth_ctx
->challenge
.set_by
= "random";
917 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
918 auth_ctx
->challenge
.set_by
));
924 * NTLM2 authentication modifies the effective challenge,
925 * @param challenge The new challenge value
927 static NTSTATUS
ntlm_auth_set_challenge(struct auth4_context
*auth_ctx
, const uint8_t chal
[8], const char *set_by
)
929 auth_ctx
->challenge
.set_by
= talloc_strdup(auth_ctx
, set_by
);
930 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.set_by
);
932 auth_ctx
->challenge
.data
= data_blob_talloc(auth_ctx
, chal
, 8);
933 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.data
.data
);
939 * Check the password on an NTLMSSP login.
941 * Return the session keys used on the connection.
944 static NTSTATUS
winbind_pw_check(struct auth4_context
*auth4_context
,
946 const struct auth_usersupplied_info
*user_info
,
947 void **server_returned_info
,
948 DATA_BLOB
*session_key
, DATA_BLOB
*lm_session_key
)
950 static const char zeros
[16] = { 0, };
952 char *error_string
= NULL
;
954 uint8_t user_sess_key
[16];
955 char *unix_name
= NULL
;
957 nt_status
= contact_winbind_auth_crap(user_info
->client
.account_name
, user_info
->client
.domain_name
,
958 user_info
->workstation_name
,
959 &auth4_context
->challenge
.data
,
960 &user_info
->password
.response
.lanman
,
961 &user_info
->password
.response
.nt
,
962 WBFLAG_PAM_LMKEY
| WBFLAG_PAM_USER_SESSION_KEY
| WBFLAG_PAM_UNIX_NAME
,
964 lm_key
, user_sess_key
,
965 &error_string
, &unix_name
);
967 if (NT_STATUS_IS_OK(nt_status
)) {
968 if (memcmp(lm_key
, zeros
, 8) != 0) {
969 *lm_session_key
= data_blob_talloc(mem_ctx
, NULL
, 16);
970 memcpy(lm_session_key
->data
, lm_key
, 8);
971 memset(lm_session_key
->data
+8, '\0', 8);
974 if (memcmp(user_sess_key
, zeros
, 16) != 0) {
975 *session_key
= data_blob_talloc(mem_ctx
, user_sess_key
, 16);
977 *server_returned_info
= talloc_strdup(mem_ctx
,
980 DEBUG(NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCESS_DENIED
) ? 0 : 3,
981 ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
982 user_info
->client
.domain_name
, user_info
->client
.account_name
,
983 user_info
->workstation_name
,
984 error_string
? error_string
: "unknown error (NULL)"));
987 SAFE_FREE(error_string
);
988 SAFE_FREE(unix_name
);
992 static NTSTATUS
local_pw_check(struct auth4_context
*auth4_context
,
994 const struct auth_usersupplied_info
*user_info
,
995 void **server_returned_info
,
996 DATA_BLOB
*session_key
, DATA_BLOB
*lm_session_key
)
999 struct samr_Password lm_pw
, nt_pw
;
1001 nt_lm_owf_gen (opt_password
, nt_pw
.hash
, lm_pw
.hash
);
1003 nt_status
= ntlm_password_check(mem_ctx
,
1005 &auth4_context
->challenge
.data
,
1006 &user_info
->password
.response
.lanman
,
1007 &user_info
->password
.response
.nt
,
1008 user_info
->client
.account_name
,
1009 user_info
->client
.account_name
,
1010 user_info
->client
.domain_name
,
1011 &lm_pw
, &nt_pw
, session_key
, lm_session_key
);
1013 if (NT_STATUS_IS_OK(nt_status
)) {
1014 *server_returned_info
= talloc_asprintf(mem_ctx
,
1015 "%s%c%s", user_info
->client
.domain_name
,
1016 *lp_winbind_separator(),
1017 user_info
->client
.account_name
);
1019 DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
1020 user_info
->client
.domain_name
, user_info
->client
.account_name
,
1021 user_info
->workstation_name
,
1022 nt_errstr(nt_status
)));
1027 static NTSTATUS
ntlm_auth_prepare_gensec_client(TALLOC_CTX
*mem_ctx
,
1028 struct loadparm_context
*lp_ctx
,
1029 struct gensec_security
**gensec_security_out
)
1031 struct gensec_security
*gensec_security
= NULL
;
1033 TALLOC_CTX
*tmp_ctx
;
1034 const struct gensec_security_ops
**backends
= NULL
;
1035 struct gensec_settings
*gensec_settings
= NULL
;
1038 tmp_ctx
= talloc_new(mem_ctx
);
1039 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx
);
1041 gensec_settings
= lpcfg_gensec_settings(tmp_ctx
, lp_ctx
);
1042 if (gensec_settings
== NULL
) {
1043 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1044 TALLOC_FREE(tmp_ctx
);
1045 return NT_STATUS_NO_MEMORY
;
1048 backends
= talloc_zero_array(gensec_settings
,
1049 const struct gensec_security_ops
*, 4);
1050 if (backends
== NULL
) {
1051 TALLOC_FREE(tmp_ctx
);
1052 return NT_STATUS_NO_MEMORY
;
1054 gensec_settings
->backends
= backends
;
1058 /* These need to be in priority order, krb5 before NTLMSSP */
1059 #if defined(HAVE_KRB5)
1060 backends
[idx
++] = &gensec_gse_krb5_security_ops
;
1063 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_NTLMSSP
);
1065 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_SPNEGO
);
1067 nt_status
= gensec_client_start(NULL
, &gensec_security
,
1069 if (!NT_STATUS_IS_OK(nt_status
)) {
1070 TALLOC_FREE(tmp_ctx
);
1074 talloc_unlink(tmp_ctx
, gensec_settings
);
1076 if (opt_target_service
!= NULL
) {
1077 nt_status
= gensec_set_target_service(gensec_security
,
1078 opt_target_service
);
1079 if (!NT_STATUS_IS_OK(nt_status
)) {
1080 TALLOC_FREE(tmp_ctx
);
1085 if (opt_target_hostname
!= NULL
) {
1086 nt_status
= gensec_set_target_hostname(gensec_security
,
1087 opt_target_hostname
);
1088 if (!NT_STATUS_IS_OK(nt_status
)) {
1089 TALLOC_FREE(tmp_ctx
);
1094 *gensec_security_out
= talloc_steal(mem_ctx
, gensec_security
);
1095 TALLOC_FREE(tmp_ctx
);
1096 return NT_STATUS_OK
;
1099 static struct auth4_context
*make_auth4_context_ntlm_auth(TALLOC_CTX
*mem_ctx
, bool local_pw
)
1101 struct auth4_context
*auth4_context
= talloc_zero(mem_ctx
, struct auth4_context
);
1102 if (auth4_context
== NULL
) {
1103 DEBUG(10, ("failed to allocate auth4_context failed\n"));
1106 auth4_context
->generate_session_info
= ntlm_auth_generate_session_info
;
1107 auth4_context
->generate_session_info_pac
= ntlm_auth_generate_session_info_pac
;
1108 auth4_context
->get_ntlm_challenge
= ntlm_auth_get_challenge
;
1109 auth4_context
->set_ntlm_challenge
= ntlm_auth_set_challenge
;
1111 auth4_context
->check_ntlm_password
= local_pw_check
;
1113 auth4_context
->check_ntlm_password
= winbind_pw_check
;
1115 auth4_context
->private_data
= NULL
;
1116 return auth4_context
;
1119 static NTSTATUS
ntlm_auth_prepare_gensec_server(TALLOC_CTX
*mem_ctx
,
1120 struct loadparm_context
*lp_ctx
,
1121 struct gensec_security
**gensec_security_out
)
1123 struct gensec_security
*gensec_security
;
1126 TALLOC_CTX
*tmp_ctx
;
1127 const struct gensec_security_ops
**backends
;
1128 struct gensec_settings
*gensec_settings
;
1130 struct cli_credentials
*server_credentials
;
1132 struct auth4_context
*auth4_context
;
1134 tmp_ctx
= talloc_new(mem_ctx
);
1135 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx
);
1137 auth4_context
= make_auth4_context_ntlm_auth(tmp_ctx
, opt_password
);
1138 if (auth4_context
== NULL
) {
1139 TALLOC_FREE(tmp_ctx
);
1140 return NT_STATUS_NO_MEMORY
;
1143 gensec_settings
= lpcfg_gensec_settings(tmp_ctx
, lp_ctx
);
1144 if (lp_ctx
== NULL
) {
1145 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1146 TALLOC_FREE(tmp_ctx
);
1147 return NT_STATUS_NO_MEMORY
;
1151 * This should be a 'netbios domain -> DNS domain'
1152 * mapping, and can currently validly return NULL on
1153 * poorly configured systems.
1155 * This is used for the NTLMSSP server
1159 gensec_settings
->server_netbios_name
= lp_netbios_name();
1160 gensec_settings
->server_netbios_domain
= lp_workgroup();
1162 gensec_settings
->server_netbios_name
= get_winbind_netbios_name();
1163 gensec_settings
->server_netbios_domain
= get_winbind_domain();
1166 gensec_settings
->server_dns_domain
= strlower_talloc(gensec_settings
,
1167 get_mydnsdomname(talloc_tos()));
1168 gensec_settings
->server_dns_name
= strlower_talloc(gensec_settings
,
1169 get_mydnsfullname());
1171 backends
= talloc_zero_array(gensec_settings
,
1172 const struct gensec_security_ops
*, 4);
1174 if (backends
== NULL
) {
1175 TALLOC_FREE(tmp_ctx
);
1176 return NT_STATUS_NO_MEMORY
;
1178 gensec_settings
->backends
= backends
;
1182 /* These need to be in priority order, krb5 before NTLMSSP */
1183 #if defined(HAVE_KRB5)
1184 backends
[idx
++] = &gensec_gse_krb5_security_ops
;
1187 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_NTLMSSP
);
1189 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_SPNEGO
);
1192 * This is anonymous for now, because we just use it
1193 * to set the kerberos state at the moment
1195 server_credentials
= cli_credentials_init_anon(tmp_ctx
);
1196 if (!server_credentials
) {
1197 DEBUG(0, ("auth_generic_prepare: Failed to init server credentials\n"));
1198 return NT_STATUS_NO_MEMORY
;
1201 cli_credentials_set_conf(server_credentials
, lp_ctx
);
1203 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC
|| lp_security() == SEC_ADS
|| USE_KERBEROS_KEYTAB
) {
1204 cli_credentials_set_kerberos_state(server_credentials
, CRED_AUTO_USE_KERBEROS
);
1206 cli_credentials_set_kerberos_state(server_credentials
, CRED_DONT_USE_KERBEROS
);
1209 nt_status
= gensec_server_start(tmp_ctx
, gensec_settings
,
1210 auth4_context
, &gensec_security
);
1212 if (!NT_STATUS_IS_OK(nt_status
)) {
1213 TALLOC_FREE(tmp_ctx
);
1217 gensec_set_credentials(gensec_security
, server_credentials
);
1219 talloc_unlink(tmp_ctx
, lp_ctx
);
1220 talloc_unlink(tmp_ctx
, server_credentials
);
1221 talloc_unlink(tmp_ctx
, gensec_settings
);
1222 talloc_unlink(tmp_ctx
, auth4_context
);
1224 *gensec_security_out
= talloc_steal(mem_ctx
, gensec_security
);
1225 TALLOC_FREE(tmp_ctx
);
1226 return NT_STATUS_OK
;
1229 static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode
,
1230 struct loadparm_context
*lp_ctx
,
1231 struct ntlm_auth_state
*state
,
1232 char *buf
, int length
, void **private2
)
1234 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1238 static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode
,
1239 struct loadparm_context
*lp_ctx
,
1240 struct ntlm_auth_state
*state
,
1241 char *buf
, int length
, void **private2
)
1246 pass
=(char *)memchr(buf
,' ',length
);
1248 DEBUG(2, ("Password not found. Denying access\n"));
1249 x_fprintf(x_stdout
, "ERR\n");
1255 if (state
->helper_mode
== SQUID_2_5_BASIC
) {
1256 rfc1738_unescape(user
);
1257 rfc1738_unescape(pass
);
1260 if (check_plaintext_auth(user
, pass
, False
)) {
1261 x_fprintf(x_stdout
, "OK\n");
1263 x_fprintf(x_stdout
, "ERR\n");
1267 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode
,
1268 struct loadparm_context
*lp_ctx
,
1269 char *buf
, int length
, void **private1
)
1272 DATA_BLOB out
= data_blob(NULL
, 0);
1273 char *out_base64
= NULL
;
1274 const char *reply_arg
= NULL
;
1275 struct gensec_ntlm_state
{
1276 struct gensec_security
*gensec_state
;
1277 const char *set_password
;
1279 struct gensec_ntlm_state
*state
;
1283 const char *reply_code
;
1284 struct cli_credentials
*creds
;
1286 static char *want_feature_list
= NULL
;
1287 static DATA_BLOB session_key
;
1289 TALLOC_CTX
*mem_ctx
;
1292 state
= (struct gensec_ntlm_state
*)*private1
;
1294 state
= talloc_zero(NULL
, struct gensec_ntlm_state
);
1296 x_fprintf(x_stdout
, "BH No Memory\n");
1301 state
->set_password
= opt_password
;
1305 if (strlen(buf
) < 2) {
1306 DEBUG(1, ("query [%s] invalid", buf
));
1307 x_fprintf(x_stdout
, "BH Query invalid\n");
1311 if (strlen(buf
) > 3) {
1312 if(strncmp(buf
, "SF ", 3) == 0) {
1313 DEBUG(10, ("Setting flags to negotiate\n"));
1314 talloc_free(want_feature_list
);
1315 want_feature_list
= talloc_strndup(state
, buf
+3, strlen(buf
)-3);
1316 x_fprintf(x_stdout
, "OK\n");
1319 in
= base64_decode_data_blob(buf
+ 3);
1321 in
= data_blob(NULL
, 0);
1324 if (strncmp(buf
, "YR", 2) == 0) {
1325 if (state
->gensec_state
) {
1326 talloc_free(state
->gensec_state
);
1327 state
->gensec_state
= NULL
;
1329 } else if ( (strncmp(buf
, "OK", 2) == 0)) {
1330 /* Just return BH, like ntlm_auth from Samba 3 does. */
1331 x_fprintf(x_stdout
, "BH Command expected\n");
1332 data_blob_free(&in
);
1334 } else if ( (strncmp(buf
, "TT ", 3) != 0) &&
1335 (strncmp(buf
, "KK ", 3) != 0) &&
1336 (strncmp(buf
, "AF ", 3) != 0) &&
1337 (strncmp(buf
, "NA ", 3) != 0) &&
1338 (strncmp(buf
, "UG", 2) != 0) &&
1339 (strncmp(buf
, "PW ", 3) != 0) &&
1340 (strncmp(buf
, "GK", 2) != 0) &&
1341 (strncmp(buf
, "GF", 2) != 0)) {
1342 DEBUG(1, ("SPNEGO request [%s] invalid prefix\n", buf
));
1343 x_fprintf(x_stdout
, "BH SPNEGO request invalid prefix\n");
1344 data_blob_free(&in
);
1348 mem_ctx
= talloc_named(NULL
, 0, "manage_gensec_request internal mem_ctx");
1351 if (!(state
->gensec_state
)) {
1352 switch (stdio_helper_mode
) {
1353 case GSS_SPNEGO_CLIENT
:
1355 * cached credentials are only supported by
1356 * NTLMSSP_CLIENT_1 for now.
1358 use_cached_creds
= false;
1360 case NTLMSSP_CLIENT_1
:
1361 /* setup the client side */
1363 if (state
->set_password
!= NULL
) {
1364 use_cached_creds
= false;
1367 if (use_cached_creds
) {
1368 struct wbcCredentialCacheParams params
;
1369 struct wbcCredentialCacheInfo
*info
= NULL
;
1370 struct wbcAuthErrorInfo
*error
= NULL
;
1373 params
.account_name
= opt_username
;
1374 params
.domain_name
= opt_domain
;
1375 params
.level
= WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP
;
1376 params
.num_blobs
= 0;
1377 params
.blobs
= NULL
;
1379 wbc_status
= wbcCredentialCache(¶ms
, &info
,
1381 wbcFreeMemory(error
);
1382 if (!WBC_ERROR_IS_OK(wbc_status
)) {
1383 use_cached_creds
= false;
1385 wbcFreeMemory(info
);
1388 nt_status
= ntlm_auth_prepare_gensec_client(state
, lp_ctx
,
1389 &state
->gensec_state
);
1390 if (!NT_STATUS_IS_OK(nt_status
)) {
1391 x_fprintf(x_stdout
, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status
));
1392 talloc_free(mem_ctx
);
1396 creds
= cli_credentials_init(state
->gensec_state
);
1397 cli_credentials_set_conf(creds
, lp_ctx
);
1399 cli_credentials_set_username(creds
, opt_username
, CRED_SPECIFIED
);
1402 cli_credentials_set_domain(creds
, opt_domain
, CRED_SPECIFIED
);
1404 if (use_cached_creds
) {
1405 gensec_want_feature(state
->gensec_state
,
1406 GENSEC_FEATURE_NTLM_CCACHE
);
1407 } else if (state
->set_password
) {
1408 cli_credentials_set_password(creds
, state
->set_password
, CRED_SPECIFIED
);
1410 cli_credentials_set_password_callback(creds
, get_password
);
1412 if (opt_workstation
) {
1413 cli_credentials_set_workstation(creds
, opt_workstation
, CRED_SPECIFIED
);
1416 gensec_set_credentials(state
->gensec_state
, creds
);
1419 case GSS_SPNEGO_SERVER
:
1420 case SQUID_2_5_NTLMSSP
:
1422 nt_status
= ntlm_auth_prepare_gensec_server(state
, lp_ctx
,
1423 &state
->gensec_state
);
1424 if (!NT_STATUS_IS_OK(nt_status
)) {
1425 x_fprintf(x_stdout
, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status
));
1426 talloc_free(mem_ctx
);
1432 talloc_free(mem_ctx
);
1436 gensec_want_feature_list(state
->gensec_state
, want_feature_list
);
1438 switch (stdio_helper_mode
) {
1439 case GSS_SPNEGO_CLIENT
:
1440 case GSS_SPNEGO_SERVER
:
1441 nt_status
= gensec_start_mech_by_oid(state
->gensec_state
, GENSEC_OID_SPNEGO
);
1446 case NTLMSSP_CLIENT_1
:
1451 case SQUID_2_5_NTLMSSP
:
1452 nt_status
= gensec_start_mech_by_oid(state
->gensec_state
, GENSEC_OID_NTLMSSP
);
1455 talloc_free(mem_ctx
);
1459 if (!NT_STATUS_IS_OK(nt_status
)) {
1460 DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status
)));
1461 x_fprintf(x_stdout
, "BH GENSEC mech failed to start\n");
1462 talloc_free(mem_ctx
);
1470 if (strncmp(buf
, "PW ", 3) == 0) {
1471 state
->set_password
= talloc_strndup(state
,
1472 (const char *)in
.data
,
1475 cli_credentials_set_password(gensec_get_credentials(state
->gensec_state
),
1476 state
->set_password
,
1478 x_fprintf(x_stdout
, "OK\n");
1479 data_blob_free(&in
);
1480 talloc_free(mem_ctx
);
1484 if (strncmp(buf
, "GK", 2) == 0) {
1486 DEBUG(10, ("Requested session key\n"));
1487 nt_status
= gensec_session_key(state
->gensec_state
, mem_ctx
, &session_key
);
1488 if(!NT_STATUS_IS_OK(nt_status
)) {
1489 DEBUG(1, ("gensec_session_key failed: %s\n", nt_errstr(nt_status
)));
1490 x_fprintf(x_stdout
, "BH No session key\n");
1491 talloc_free(mem_ctx
);
1494 base64_key
= base64_encode_data_blob(state
, session_key
);
1495 SMB_ASSERT(base64_key
!= NULL
);
1496 x_fprintf(x_stdout
, "GK %s\n", base64_key
);
1497 talloc_free(base64_key
);
1499 talloc_free(mem_ctx
);
1503 if (strncmp(buf
, "GF", 2) == 0) {
1506 DEBUG(10, ("Requested negotiated NTLMSSP feature flags\n"));
1508 neg_flags
= gensec_ntlmssp_neg_flags(state
->gensec_state
);
1509 if (neg_flags
== 0) {
1510 x_fprintf(x_stdout
, "BH\n");
1514 x_fprintf(x_stdout
, "GF 0x%08x\n", neg_flags
);
1518 nt_status
= gensec_update(state
->gensec_state
, mem_ctx
, in
, &out
);
1520 /* don't leak 'bad password'/'no such user' info to the network client */
1521 nt_status
= nt_status_squash(nt_status
);
1524 out_base64
= base64_encode_data_blob(mem_ctx
, out
);
1525 SMB_ASSERT(out_base64
!= NULL
);
1530 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1532 if (first
&& state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1534 } else if (state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1536 } else if (state
->gensec_state
->gensec_role
== GENSEC_SERVER
) {
1543 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCESS_DENIED
)) {
1544 reply_code
= "BH NT_STATUS_ACCESS_DENIED";
1545 reply_arg
= nt_errstr(nt_status
);
1546 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1547 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_UNSUCCESSFUL
)) {
1548 reply_code
= "BH NT_STATUS_UNSUCCESSFUL";
1549 reply_arg
= nt_errstr(nt_status
);
1550 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1551 } else if (!NT_STATUS_IS_OK(nt_status
)) {
1553 reply_arg
= nt_errstr(nt_status
);
1554 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1555 } else if /* OK */ (state
->gensec_state
->gensec_role
== GENSEC_SERVER
) {
1556 struct auth_session_info
*session_info
;
1558 nt_status
= gensec_session_info(state
->gensec_state
, mem_ctx
, &session_info
);
1559 if (!NT_STATUS_IS_OK(nt_status
)) {
1560 reply_code
= "BH Failed to retrive session info";
1561 reply_arg
= nt_errstr(nt_status
);
1562 DEBUG(1, ("GENSEC failed to retrieve the session info: %s\n", nt_errstr(nt_status
)));
1566 reply_arg
= talloc_strdup(state
->gensec_state
, session_info
->unix_info
->unix_name
);
1567 if (reply_arg
== NULL
) {
1568 reply_code
= "BH out of memory";
1569 reply_arg
= nt_errstr(NT_STATUS_NO_MEMORY
);
1571 talloc_free(session_info
);
1573 } else if (state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1575 reply_arg
= out_base64
;
1580 switch (stdio_helper_mode
) {
1581 case GSS_SPNEGO_SERVER
:
1582 x_fprintf(x_stdout
, "%s %s %s\n", reply_code
,
1583 out_base64
? out_base64
: "*",
1584 reply_arg
? reply_arg
: "*");
1588 x_fprintf(x_stdout
, "%s %s\n", reply_code
, out_base64
);
1589 } else if (reply_arg
) {
1590 x_fprintf(x_stdout
, "%s %s\n", reply_code
, reply_arg
);
1592 x_fprintf(x_stdout
, "%s\n", reply_code
);
1596 talloc_free(mem_ctx
);
1600 static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode
,
1601 struct loadparm_context
*lp_ctx
,
1602 struct ntlm_auth_state
*state
,
1603 char *buf
, int length
, void **private2
)
1605 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1609 static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode
,
1610 struct loadparm_context
*lp_ctx
,
1611 struct ntlm_auth_state
*state
,
1612 char *buf
, int length
, void **private2
)
1614 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1618 static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode
,
1619 struct loadparm_context
*lp_ctx
,
1620 struct ntlm_auth_state
*state
,
1621 char *buf
, int length
, void **private2
)
1623 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1627 static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode
,
1628 struct loadparm_context
*lp_ctx
,
1629 struct ntlm_auth_state
*state
,
1630 char *buf
, int length
, void **private2
)
1632 char *request
, *parameter
;
1633 static DATA_BLOB challenge
;
1634 static DATA_BLOB lm_response
;
1635 static DATA_BLOB nt_response
;
1636 static char *full_username
;
1637 static char *username
;
1638 static char *domain
;
1639 static char *plaintext_password
;
1640 static bool ntlm_server_1_user_session_key
;
1641 static bool ntlm_server_1_lm_session_key
;
1643 if (strequal(buf
, ".")) {
1644 if (!full_username
&& !username
) {
1645 x_fprintf(x_stdout
, "Error: No username supplied!\n");
1646 } else if (plaintext_password
) {
1647 /* handle this request as plaintext */
1648 if (!full_username
) {
1649 if (asprintf(&full_username
, "%s%c%s", domain
, winbind_separator(), username
) == -1) {
1650 x_fprintf(x_stdout
, "Error: Out of memory in asprintf!\n.\n");
1654 if (check_plaintext_auth(full_username
, plaintext_password
, False
)) {
1655 x_fprintf(x_stdout
, "Authenticated: Yes\n");
1657 x_fprintf(x_stdout
, "Authenticated: No\n");
1659 } else if (!lm_response
.data
&& !nt_response
.data
) {
1660 x_fprintf(x_stdout
, "Error: No password supplied!\n");
1661 } else if (!challenge
.data
) {
1662 x_fprintf(x_stdout
, "Error: No lanman-challenge supplied!\n");
1664 char *error_string
= NULL
;
1666 uchar user_session_key
[16];
1669 if (full_username
&& !username
) {
1671 fstring fstr_domain
;
1673 if (!parse_ntlm_auth_domain_user(full_username
, fstr_user
, fstr_domain
)) {
1674 /* username might be 'tainted', don't print into our new-line deleimianted stream */
1675 x_fprintf(x_stdout
, "Error: Could not parse into domain and username\n");
1677 SAFE_FREE(username
);
1679 username
= smb_xstrdup(fstr_user
);
1680 domain
= smb_xstrdup(fstr_domain
);
1684 DATA_BLOB nt_session_key
, lm_session_key
;
1685 struct samr_Password lm_pw
, nt_pw
;
1686 TALLOC_CTX
*mem_ctx
= talloc_new(NULL
);
1687 ZERO_STRUCT(user_session_key
);
1688 ZERO_STRUCT(lm_key
);
1690 nt_lm_owf_gen (opt_password
, nt_pw
.hash
, lm_pw
.hash
);
1691 nt_status
= ntlm_password_check(mem_ctx
,
1702 error_string
= smb_xstrdup(get_friendly_nt_error_msg(nt_status
));
1703 if (ntlm_server_1_user_session_key
) {
1704 if (nt_session_key
.length
== sizeof(user_session_key
)) {
1705 memcpy(user_session_key
,
1706 nt_session_key
.data
,
1707 sizeof(user_session_key
));
1710 if (ntlm_server_1_lm_session_key
) {
1711 if (lm_session_key
.length
== sizeof(lm_key
)) {
1713 lm_session_key
.data
,
1717 TALLOC_FREE(mem_ctx
);
1721 domain
= smb_xstrdup(get_winbind_domain());
1724 if (ntlm_server_1_lm_session_key
)
1725 flags
|= WBFLAG_PAM_LMKEY
;
1727 if (ntlm_server_1_user_session_key
)
1728 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
1730 nt_status
= contact_winbind_auth_crap(username
,
1743 if (!NT_STATUS_IS_OK(nt_status
)) {
1744 x_fprintf(x_stdout
, "Authenticated: No\n");
1745 x_fprintf(x_stdout
, "Authentication-Error: %s\n.\n", error_string
);
1747 static char zeros
[16];
1749 char *hex_user_session_key
;
1751 x_fprintf(x_stdout
, "Authenticated: Yes\n");
1753 if (ntlm_server_1_lm_session_key
1754 && (memcmp(zeros
, lm_key
,
1755 sizeof(lm_key
)) != 0)) {
1756 hex_lm_key
= hex_encode_talloc(NULL
,
1757 (const unsigned char *)lm_key
,
1759 x_fprintf(x_stdout
, "LANMAN-Session-Key: %s\n", hex_lm_key
);
1760 TALLOC_FREE(hex_lm_key
);
1763 if (ntlm_server_1_user_session_key
1764 && (memcmp(zeros
, user_session_key
,
1765 sizeof(user_session_key
)) != 0)) {
1766 hex_user_session_key
= hex_encode_talloc(NULL
,
1767 (const unsigned char *)user_session_key
,
1768 sizeof(user_session_key
));
1769 x_fprintf(x_stdout
, "User-Session-Key: %s\n", hex_user_session_key
);
1770 TALLOC_FREE(hex_user_session_key
);
1773 SAFE_FREE(error_string
);
1775 /* clear out the state */
1776 challenge
= data_blob_null
;
1777 nt_response
= data_blob_null
;
1778 lm_response
= data_blob_null
;
1779 SAFE_FREE(full_username
);
1780 SAFE_FREE(username
);
1782 SAFE_FREE(plaintext_password
);
1783 ntlm_server_1_user_session_key
= False
;
1784 ntlm_server_1_lm_session_key
= False
;
1785 x_fprintf(x_stdout
, ".\n");
1792 /* Indicates a base64 encoded structure */
1793 parameter
= strstr_m(request
, ":: ");
1795 parameter
= strstr_m(request
, ": ");
1798 DEBUG(0, ("Parameter not found!\n"));
1799 x_fprintf(x_stdout
, "Error: Parameter not found!\n.\n");
1816 base64_decode_inplace(parameter
);
1819 if (strequal(request
, "LANMAN-Challenge")) {
1820 challenge
= strhex_to_data_blob(NULL
, parameter
);
1821 if (challenge
.length
!= 8) {
1822 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (got %d bytes, expected 8)\n.\n",
1824 (int)challenge
.length
);
1825 challenge
= data_blob_null
;
1827 } else if (strequal(request
, "NT-Response")) {
1828 nt_response
= strhex_to_data_blob(NULL
, parameter
);
1829 if (nt_response
.length
< 24) {
1830 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (only got %d bytes, needed at least 24)\n.\n",
1832 (int)nt_response
.length
);
1833 nt_response
= data_blob_null
;
1835 } else if (strequal(request
, "LANMAN-Response")) {
1836 lm_response
= strhex_to_data_blob(NULL
, parameter
);
1837 if (lm_response
.length
!= 24) {
1838 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (got %d bytes, expected 24)\n.\n",
1840 (int)lm_response
.length
);
1841 lm_response
= data_blob_null
;
1843 } else if (strequal(request
, "Password")) {
1844 plaintext_password
= smb_xstrdup(parameter
);
1845 } else if (strequal(request
, "NT-Domain")) {
1846 domain
= smb_xstrdup(parameter
);
1847 } else if (strequal(request
, "Username")) {
1848 username
= smb_xstrdup(parameter
);
1849 } else if (strequal(request
, "Full-Username")) {
1850 full_username
= smb_xstrdup(parameter
);
1851 } else if (strequal(request
, "Request-User-Session-Key")) {
1852 ntlm_server_1_user_session_key
= strequal(parameter
, "Yes");
1853 } else if (strequal(request
, "Request-LanMan-Session-Key")) {
1854 ntlm_server_1_lm_session_key
= strequal(parameter
, "Yes");
1856 x_fprintf(x_stdout
, "Error: Unknown request %s\n.\n", request
);
1860 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode
,
1861 struct loadparm_context
*lp_ctx
,
1862 struct ntlm_auth_state
*state
,
1863 char *buf
, int length
, void **private2
)
1865 char *request
, *parameter
;
1866 static DATA_BLOB new_nt_pswd
;
1867 static DATA_BLOB old_nt_hash_enc
;
1868 static DATA_BLOB new_lm_pswd
;
1869 static DATA_BLOB old_lm_hash_enc
;
1870 static char *full_username
= NULL
;
1871 static char *username
= NULL
;
1872 static char *domain
= NULL
;
1873 static char *newpswd
= NULL
;
1874 static char *oldpswd
= NULL
;
1876 if (strequal(buf
, ".")) {
1877 if(newpswd
&& oldpswd
) {
1878 uchar old_nt_hash
[16];
1879 uchar old_lm_hash
[16];
1880 uchar new_nt_hash
[16];
1881 uchar new_lm_hash
[16];
1883 new_nt_pswd
= data_blob(NULL
, 516);
1884 old_nt_hash_enc
= data_blob(NULL
, 16);
1886 /* Calculate the MD4 hash (NT compatible) of the
1888 E_md4hash(oldpswd
, old_nt_hash
);
1889 E_md4hash(newpswd
, new_nt_hash
);
1891 /* E_deshash returns false for 'long'
1892 passwords (> 14 DOS chars).
1894 Therefore, don't send a buffer
1895 encrypted with the truncated hash
1896 (it could allow an even easier
1897 attack on the password)
1899 Likewise, obey the admin's restriction
1902 if (lp_client_lanman_auth() &&
1903 E_deshash(newpswd
, new_lm_hash
) &&
1904 E_deshash(oldpswd
, old_lm_hash
)) {
1905 new_lm_pswd
= data_blob(NULL
, 516);
1906 old_lm_hash_enc
= data_blob(NULL
, 16);
1907 encode_pw_buffer(new_lm_pswd
.data
, newpswd
,
1910 arcfour_crypt(new_lm_pswd
.data
, old_nt_hash
, 516);
1911 E_old_pw_hash(new_nt_hash
, old_lm_hash
,
1912 old_lm_hash_enc
.data
);
1914 new_lm_pswd
.data
= NULL
;
1915 new_lm_pswd
.length
= 0;
1916 old_lm_hash_enc
.data
= NULL
;
1917 old_lm_hash_enc
.length
= 0;
1920 encode_pw_buffer(new_nt_pswd
.data
, newpswd
,
1923 arcfour_crypt(new_nt_pswd
.data
, old_nt_hash
, 516);
1924 E_old_pw_hash(new_nt_hash
, old_nt_hash
,
1925 old_nt_hash_enc
.data
);
1928 if (!full_username
&& !username
) {
1929 x_fprintf(x_stdout
, "Error: No username supplied!\n");
1930 } else if ((!new_nt_pswd
.data
|| !old_nt_hash_enc
.data
) &&
1931 (!new_lm_pswd
.data
|| old_lm_hash_enc
.data
) ) {
1932 x_fprintf(x_stdout
, "Error: No NT or LM password "
1933 "blobs supplied!\n");
1935 char *error_string
= NULL
;
1937 if (full_username
&& !username
) {
1939 fstring fstr_domain
;
1941 if (!parse_ntlm_auth_domain_user(full_username
,
1944 /* username might be 'tainted', don't
1945 * print into our new-line
1946 * deleimianted stream */
1947 x_fprintf(x_stdout
, "Error: Could not "
1948 "parse into domain and "
1950 SAFE_FREE(username
);
1951 username
= smb_xstrdup(full_username
);
1953 SAFE_FREE(username
);
1955 username
= smb_xstrdup(fstr_user
);
1956 domain
= smb_xstrdup(fstr_domain
);
1961 if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
1968 x_fprintf(x_stdout
, "Password-Change: No\n");
1969 x_fprintf(x_stdout
, "Password-Change-Error: "
1970 "%s\n.\n", error_string
);
1972 x_fprintf(x_stdout
, "Password-Change: Yes\n");
1975 SAFE_FREE(error_string
);
1977 /* clear out the state */
1978 new_nt_pswd
= data_blob_null
;
1979 old_nt_hash_enc
= data_blob_null
;
1980 new_lm_pswd
= data_blob_null
;
1981 old_nt_hash_enc
= data_blob_null
;
1982 SAFE_FREE(full_username
);
1983 SAFE_FREE(username
);
1987 x_fprintf(x_stdout
, ".\n");
1994 /* Indicates a base64 encoded structure */
1995 parameter
= strstr_m(request
, ":: ");
1997 parameter
= strstr_m(request
, ": ");
2000 DEBUG(0, ("Parameter not found!\n"));
2001 x_fprintf(x_stdout
, "Error: Parameter not found!\n.\n");
2017 base64_decode_inplace(parameter
);
2020 if (strequal(request
, "new-nt-password-blob")) {
2021 new_nt_pswd
= strhex_to_data_blob(NULL
, parameter
);
2022 if (new_nt_pswd
.length
!= 516) {
2023 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2024 "(got %d bytes, expected 516)\n.\n",
2026 (int)new_nt_pswd
.length
);
2027 new_nt_pswd
= data_blob_null
;
2029 } else if (strequal(request
, "old-nt-hash-blob")) {
2030 old_nt_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2031 if (old_nt_hash_enc
.length
!= 16) {
2032 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2033 "(got %d bytes, expected 16)\n.\n",
2035 (int)old_nt_hash_enc
.length
);
2036 old_nt_hash_enc
= data_blob_null
;
2038 } else if (strequal(request
, "new-lm-password-blob")) {
2039 new_lm_pswd
= strhex_to_data_blob(NULL
, parameter
);
2040 if (new_lm_pswd
.length
!= 516) {
2041 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2042 "(got %d bytes, expected 516)\n.\n",
2044 (int)new_lm_pswd
.length
);
2045 new_lm_pswd
= data_blob_null
;
2048 else if (strequal(request
, "old-lm-hash-blob")) {
2049 old_lm_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2050 if (old_lm_hash_enc
.length
!= 16)
2052 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2053 "(got %d bytes, expected 16)\n.\n",
2055 (int)old_lm_hash_enc
.length
);
2056 old_lm_hash_enc
= data_blob_null
;
2058 } else if (strequal(request
, "nt-domain")) {
2059 domain
= smb_xstrdup(parameter
);
2060 } else if(strequal(request
, "username")) {
2061 username
= smb_xstrdup(parameter
);
2062 } else if(strequal(request
, "full-username")) {
2063 username
= smb_xstrdup(parameter
);
2064 } else if(strequal(request
, "new-password")) {
2065 newpswd
= smb_xstrdup(parameter
);
2066 } else if (strequal(request
, "old-password")) {
2067 oldpswd
= smb_xstrdup(parameter
);
2069 x_fprintf(x_stdout
, "Error: Unknown request %s\n.\n", request
);
2073 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode
,
2074 struct loadparm_context
*lp_ctx
,
2075 struct ntlm_auth_state
*state
,
2076 stdio_helper_function fn
, void **private2
)
2079 char tmp
[INITIAL_BUFFER_SIZE
+1];
2080 int length
, buf_size
= 0;
2083 buf
= talloc_strdup(state
->mem_ctx
, "");
2085 DEBUG(0, ("Failed to allocate input buffer.\n"));
2086 x_fprintf(x_stderr
, "ERR\n");
2092 /* this is not a typo - x_fgets doesn't work too well under
2094 if (fgets(tmp
, sizeof(tmp
)-1, stdin
) == NULL
) {
2095 if (ferror(stdin
)) {
2096 DEBUG(1, ("fgets() failed! dying..... errno=%d "
2097 "(%s)\n", ferror(stdin
),
2098 strerror(ferror(stdin
))));
2105 buf
= talloc_strdup_append_buffer(buf
, tmp
);
2106 buf_size
+= INITIAL_BUFFER_SIZE
;
2108 if (buf_size
> MAX_BUFFER_SIZE
) {
2109 DEBUG(2, ("Oversized message\n"));
2110 x_fprintf(x_stderr
, "ERR\n");
2115 c
= strchr(buf
, '\n');
2116 } while (c
== NULL
);
2121 DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf
,length
));
2123 if (buf
[0] == '\0') {
2124 DEBUG(2, ("Invalid Request\n"));
2125 x_fprintf(x_stderr
, "ERR\n");
2130 fn(stdio_helper_mode
, lp_ctx
, state
, buf
, length
, private2
);
2135 static void squid_stream(enum stdio_helper_mode stdio_mode
,
2136 struct loadparm_context
*lp_ctx
,
2137 stdio_helper_function fn
) {
2138 TALLOC_CTX
*mem_ctx
;
2139 struct ntlm_auth_state
*state
;
2141 /* initialize FDescs */
2142 x_setbuf(x_stdout
, NULL
);
2143 x_setbuf(x_stderr
, NULL
);
2145 mem_ctx
= talloc_init("ntlm_auth");
2147 DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
2148 x_fprintf(x_stderr
, "ERR\n");
2152 state
= talloc_zero(mem_ctx
, struct ntlm_auth_state
);
2154 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
2155 x_fprintf(x_stderr
, "ERR\n");
2159 state
->mem_ctx
= mem_ctx
;
2160 state
->helper_mode
= stdio_mode
;
2163 TALLOC_CTX
*frame
= talloc_stackframe();
2164 manage_squid_request(stdio_mode
, lp_ctx
, state
, fn
, NULL
);
2170 /* Authenticate a user with a challenge/response */
2172 static bool check_auth_crap(void)
2177 char user_session_key
[16];
2179 char *hex_user_session_key
;
2181 static uint8_t zeros
[16];
2183 x_setbuf(x_stdout
, NULL
);
2186 flags
|= WBFLAG_PAM_LMKEY
;
2188 if (request_user_session_key
)
2189 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
2191 flags
|= WBFLAG_PAM_NT_STATUS_SQUASH
;
2193 nt_status
= contact_winbind_auth_crap(opt_username
, opt_domain
,
2199 (unsigned char *)lm_key
,
2200 (unsigned char *)user_session_key
,
2201 &error_string
, NULL
);
2203 if (!NT_STATUS_IS_OK(nt_status
)) {
2204 x_fprintf(x_stdout
, "%s (0x%x)\n",
2206 NT_STATUS_V(nt_status
));
2207 SAFE_FREE(error_string
);
2212 && (memcmp(zeros
, lm_key
,
2213 sizeof(lm_key
)) != 0)) {
2214 hex_lm_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)lm_key
,
2216 x_fprintf(x_stdout
, "LM_KEY: %s\n", hex_lm_key
);
2217 TALLOC_FREE(hex_lm_key
);
2219 if (request_user_session_key
2220 && (memcmp(zeros
, user_session_key
,
2221 sizeof(user_session_key
)) != 0)) {
2222 hex_user_session_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)user_session_key
,
2223 sizeof(user_session_key
));
2224 x_fprintf(x_stdout
, "NT_KEY: %s\n", hex_user_session_key
);
2225 TALLOC_FREE(hex_user_session_key
);
2234 OPT_USERNAME
= 1000,
2243 OPT_USER_SESSION_KEY
,
2245 OPT_REQUIRE_MEMBERSHIP
,
2246 OPT_USE_CACHED_CREDS
,
2248 OPT_PAM_WINBIND_CONF
,
2250 OPT_TARGET_HOSTNAME
,
2254 int main(int argc
, const char **argv
)
2256 TALLOC_CTX
*frame
= talloc_stackframe();
2258 const char *helper_protocol
= NULL
;
2259 int diagnostics
= 0;
2261 const char *hex_challenge
= NULL
;
2262 const char *hex_lm_response
= NULL
;
2263 const char *hex_nt_response
= NULL
;
2264 struct loadparm_context
*lp_ctx
;
2267 /* NOTE: DO NOT change this interface without considering the implications!
2268 This is an external interface, which other programs will use to interact
2272 /* We do not use single-letter command abbreviations, because they harm future
2273 interface stability. */
2275 struct poptOption long_options
[] = {
2277 { "helper-protocol", 0, POPT_ARG_STRING
, &helper_protocol
, OPT_DOMAIN
, "operate as a stdio-based helper", "helper protocol to use"},
2278 { "username", 0, POPT_ARG_STRING
, &opt_username
, OPT_USERNAME
, "username"},
2279 { "domain", 0, POPT_ARG_STRING
, &opt_domain
, OPT_DOMAIN
, "domain name"},
2280 { "workstation", 0, POPT_ARG_STRING
, &opt_workstation
, OPT_WORKSTATION
, "workstation"},
2281 { "challenge", 0, POPT_ARG_STRING
, &hex_challenge
, OPT_CHALLENGE
, "challenge (HEX encoded)"},
2282 { "lm-response", 0, POPT_ARG_STRING
, &hex_lm_response
, OPT_LM
, "LM Response to the challenge (HEX encoded)"},
2283 { "nt-response", 0, POPT_ARG_STRING
, &hex_nt_response
, OPT_NT
, "NT or NTLMv2 Response to the challenge (HEX encoded)"},
2284 { "password", 0, POPT_ARG_STRING
, &opt_password
, OPT_PASSWORD
, "User's plaintext password"},
2285 { "request-lm-key", 0, POPT_ARG_NONE
, &request_lm_key
, OPT_LM_KEY
, "Retrieve LM session key"},
2286 { "request-nt-key", 0, POPT_ARG_NONE
, &request_user_session_key
, OPT_USER_SESSION_KEY
, "Retrieve User (NT) session key"},
2287 { "use-cached-creds", 0, POPT_ARG_NONE
, &use_cached_creds
, OPT_USE_CACHED_CREDS
, "Use cached credentials if no password is given"},
2288 { "allow-mschapv2", 0, POPT_ARG_NONE
, &opt_allow_mschapv2
, OPT_ALLOW_MSCHAPV2
, "Explicitly allow MSCHAPv2" },
2289 { "offline-logon", 0, POPT_ARG_NONE
, &offline_logon
,
2291 "Use cached passwords when DC is offline"},
2292 { "diagnostics", 0, POPT_ARG_NONE
, &diagnostics
,
2294 "Perform diagnostics on the authentication chain"},
2295 { "require-membership-of", 0, POPT_ARG_STRING
, &require_membership_of
, OPT_REQUIRE_MEMBERSHIP
, "Require that a user be a member of this group (either name or SID) for authentication to succeed" },
2296 { "pam-winbind-conf", 0, POPT_ARG_STRING
, &opt_pam_winbind_conf
, OPT_PAM_WINBIND_CONF
, "Require that request must set WBFLAG_PAM_CONTACT_TRUSTDOM when krb5 auth is required" },
2297 { "target-service", 0, POPT_ARG_STRING
, &opt_target_service
, OPT_TARGET_SERVICE
, "Target service (eg http)" },
2298 { "target-hostname", 0, POPT_ARG_STRING
, &opt_target_hostname
, OPT_TARGET_HOSTNAME
, "Target hostname" },
2299 POPT_COMMON_CONFIGFILE
2305 /* Samba client initialisation */
2308 setup_logging("ntlm_auth", DEBUG_STDERR
);
2313 pc
= poptGetContext("ntlm_auth", argc
, argv
, long_options
, 0);
2315 /* Parse command line options */
2318 poptPrintHelp(pc
, stderr
, 0);
2322 while((opt
= poptGetNextOpt(pc
)) != -1) {
2323 /* Get generic config options like --configfile */
2326 poptFreeContext(pc
);
2328 if (!lp_load_global(get_dyn_CONFIGFILE())) {
2329 d_fprintf(stderr
, "ntlm_auth: error opening config file %s. Error was %s\n",
2330 get_dyn_CONFIGFILE(), strerror(errno
));
2334 pc
= poptGetContext(NULL
, argc
, (const char **)argv
, long_options
,
2335 POPT_CONTEXT_KEEP_FIRST
);
2337 while((opt
= poptGetNextOpt(pc
)) != -1) {
2340 opt_challenge
= strhex_to_data_blob(NULL
, hex_challenge
);
2341 if (opt_challenge
.length
!= 8) {
2342 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2344 (int)opt_challenge
.length
);
2349 opt_lm_response
= strhex_to_data_blob(NULL
, hex_lm_response
);
2350 if (opt_lm_response
.length
!= 24) {
2351 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2353 (int)opt_lm_response
.length
);
2359 opt_nt_response
= strhex_to_data_blob(NULL
, hex_nt_response
);
2360 if (opt_nt_response
.length
< 24) {
2361 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2363 (int)opt_nt_response
.length
);
2368 case OPT_REQUIRE_MEMBERSHIP
:
2369 if (strncasecmp_m("S-", require_membership_of
, 2) == 0) {
2370 require_membership_of_sid
= require_membership_of
;
2377 char *domain
= SMB_STRDUP(opt_username
);
2378 char *p
= strchr_m(domain
, *lp_winbind_separator());
2382 if (opt_domain
&& !strequal(opt_domain
, domain
)) {
2383 x_fprintf(x_stderr
, "Domain specified in username (%s) "
2384 "doesn't match specified domain (%s)!\n\n",
2385 domain
, opt_domain
);
2386 poptPrintHelp(pc
, stderr
, 0);
2389 opt_domain
= domain
;
2395 /* Note: if opt_domain is "" then send no domain */
2396 if (opt_domain
== NULL
) {
2397 opt_domain
= get_winbind_domain();
2400 if (opt_workstation
== NULL
) {
2401 opt_workstation
= "";
2404 lp_ctx
= loadparm_init_s3(NULL
, loadparm_s3_helpers());
2405 if (lp_ctx
== NULL
) {
2406 x_fprintf(x_stderr
, "loadparm_init_s3() failed!\n");
2410 if (helper_protocol
) {
2412 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2413 if (strcmp(helper_protocol
, stdio_helper_protocols
[i
].name
) == 0) {
2414 squid_stream(stdio_helper_protocols
[i
].mode
, lp_ctx
, stdio_helper_protocols
[i
].fn
);
2418 x_fprintf(x_stderr
, "unknown helper protocol [%s]\n\nValid helper protools:\n\n", helper_protocol
);
2420 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2421 x_fprintf(x_stderr
, "%s\n", stdio_helper_protocols
[i
].name
);
2427 if (!opt_username
|| !*opt_username
) {
2428 x_fprintf(x_stderr
, "username must be specified!\n\n");
2429 poptPrintHelp(pc
, stderr
, 0);
2433 if (opt_challenge
.length
) {
2434 if (!check_auth_crap()) {
2440 if (!opt_password
) {
2441 char pwd
[256] = {0};
2444 rc
= samba_getpass("Password: ", pwd
, sizeof(pwd
), false, false);
2446 opt_password
= SMB_STRDUP(pwd
);
2451 if (!diagnose_ntlm_auth()) {
2457 fstr_sprintf(user
, "%s%c%s", opt_domain
, winbind_separator(), opt_username
);
2458 if (!check_plaintext_auth(user
, opt_password
, True
)) {
2465 poptFreeContext(pc
);