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 "utils/ntlm_auth.h"
31 #include "../libcli/auth/libcli_auth.h"
32 #include "../libcli/auth/spnego.h"
33 #include "auth/ntlmssp/ntlmssp.h"
34 #include "auth/gensec/gensec.h"
35 #include "auth/credentials/credentials.h"
36 #include "librpc/crypto/gse.h"
38 #include <iniparser.h>
39 #include "../lib/crypto/arcfour.h"
40 #include "libads/kerberos_proto.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"
50 #include "auth/kerberos/pac_utils.h"
53 #ifndef PAM_WINBIND_CONFIG_FILE
54 #define PAM_WINBIND_CONFIG_FILE "/etc/security/pam_winbind.conf"
57 #define WINBIND_KRB5_AUTH 0x00000080
60 #define DBGC_CLASS DBGC_WINBIND
62 #define INITIAL_BUFFER_SIZE 300
63 #define MAX_BUFFER_SIZE 630000
65 enum stdio_helper_mode
{
73 NTLM_CHANGE_PASSWORD_1
,
77 enum ntlm_auth_cli_state
{
84 struct ntlm_auth_state
{
86 enum stdio_helper_mode helper_mode
;
87 enum ntlm_auth_cli_state cli_state
;
88 struct ntlmssp_state
*ntlmssp_state
;
90 char *want_feature_list
;
91 bool have_session_key
;
92 DATA_BLOB session_key
;
93 DATA_BLOB initial_message
;
94 void *gensec_private_1
;
96 typedef void (*stdio_helper_function
)(enum stdio_helper_mode stdio_helper_mode
,
97 struct loadparm_context
*lp_ctx
,
98 struct ntlm_auth_state
*state
, char *buf
,
99 int length
, void **private2
);
101 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode
,
102 struct loadparm_context
*lp_ctx
,
103 struct ntlm_auth_state
*state
,
104 stdio_helper_function fn
, void **private2
);
106 static void manage_squid_basic_request (enum stdio_helper_mode stdio_helper_mode
,
107 struct loadparm_context
*lp_ctx
,
108 struct ntlm_auth_state
*state
,
109 char *buf
, int length
, void **private2
);
111 static void manage_squid_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode
,
112 struct loadparm_context
*lp_ctx
,
113 struct ntlm_auth_state
*state
,
114 char *buf
, int length
, void **private2
);
116 static void manage_client_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode
,
117 struct loadparm_context
*lp_ctx
,
118 struct ntlm_auth_state
*state
,
119 char *buf
, int length
, void **private2
);
121 static void manage_gss_spnego_request (enum stdio_helper_mode stdio_helper_mode
,
122 struct loadparm_context
*lp_ctx
,
123 struct ntlm_auth_state
*state
,
124 char *buf
, int length
, void **private2
);
126 static void manage_gss_spnego_client_request (enum stdio_helper_mode stdio_helper_mode
,
127 struct loadparm_context
*lp_ctx
,
128 struct ntlm_auth_state
*state
,
129 char *buf
, int length
, void **private2
);
131 static void manage_ntlm_server_1_request (enum stdio_helper_mode stdio_helper_mode
,
132 struct loadparm_context
*lp_ctx
,
133 struct ntlm_auth_state
*state
,
134 char *buf
, int length
, void **private2
);
136 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode
,
137 struct loadparm_context
*lp_ctx
,
138 struct ntlm_auth_state
*state
,
139 char *buf
, int length
, void **private2
);
141 static const struct {
142 enum stdio_helper_mode mode
;
144 stdio_helper_function fn
;
145 } stdio_helper_protocols
[] = {
146 { SQUID_2_4_BASIC
, "squid-2.4-basic", manage_squid_basic_request
},
147 { SQUID_2_5_BASIC
, "squid-2.5-basic", manage_squid_basic_request
},
148 { SQUID_2_5_NTLMSSP
, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request
},
149 { NTLMSSP_CLIENT_1
, "ntlmssp-client-1", manage_client_ntlmssp_request
},
150 { GSS_SPNEGO_SERVER
, "gss-spnego", manage_gss_spnego_request
},
151 { GSS_SPNEGO_CLIENT
, "gss-spnego-client", manage_gss_spnego_client_request
},
152 { NTLM_SERVER_1
, "ntlm-server-1", manage_ntlm_server_1_request
},
153 { NTLM_CHANGE_PASSWORD_1
, "ntlm-change-password-1", manage_ntlm_change_password_1_request
},
154 { NUM_HELPER_MODES
, NULL
, NULL
}
157 const char *opt_username
;
158 const char *opt_domain
;
159 const char *opt_workstation
;
160 const char *opt_password
;
161 static DATA_BLOB opt_challenge
;
162 static DATA_BLOB opt_lm_response
;
163 static DATA_BLOB opt_nt_response
;
164 static int request_lm_key
;
165 static int request_user_session_key
;
166 static int use_cached_creds
;
168 static const char *require_membership_of
;
169 static const char *require_membership_of_sid
;
170 static const char *opt_pam_winbind_conf
;
172 const char *opt_target_service
;
173 const char *opt_target_hostname
;
176 /* This is a bit hairy, but the basic idea is to do a password callback
177 to the calling application. The callback comes from within gensec */
179 static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mode
,
180 struct loadparm_context
*lp_ctx
,
181 struct ntlm_auth_state
*state
, char *buf
, int length
,
185 if (strlen(buf
) < 2) {
186 DEBUG(1, ("query [%s] invalid", buf
));
187 x_fprintf(x_stdout
, "BH Query invalid\n");
191 if (strlen(buf
) > 3) {
192 in
= base64_decode_data_blob(buf
+ 3);
194 in
= data_blob(NULL
, 0);
197 if (strncmp(buf
, "PW ", 3) == 0) {
199 *password
= talloc_strndup(NULL
,
200 (const char *)in
.data
, in
.length
);
202 if (*password
== NULL
) {
203 DEBUG(1, ("Out of memory\n"));
204 x_fprintf(x_stdout
, "BH Out of memory\n");
209 x_fprintf(x_stdout
, "OK\n");
213 DEBUG(1, ("Asked for (and expected) a password\n"));
214 x_fprintf(x_stdout
, "BH Expected a password\n");
219 * Callback for password credentials. This is not async, and when
220 * GENSEC and the credentials code is made async, it will look rather
224 static const char *get_password(struct cli_credentials
*credentials
)
226 char *password
= NULL
;
228 /* Ask for a password */
229 x_fprintf(x_stdout
, "PW\n");
230 credentials
->priv_data
= NULL
;
232 manage_squid_request(NUM_HELPER_MODES
/* bogus */, NULL
, NULL
, manage_gensec_get_pw_request
, (void **)&password
);
233 talloc_steal(credentials
, password
);
238 * A limited set of features are defined with text strings as needed
242 static void gensec_want_feature_list(struct gensec_security
*state
, char* feature_list
)
244 if (in_list("NTLMSSP_FEATURE_SESSION_KEY", feature_list
, true)) {
245 DEBUG(10, ("want GENSEC_FEATURE_SESSION_KEY\n"));
246 gensec_want_feature(state
, GENSEC_FEATURE_SESSION_KEY
);
248 if (in_list("NTLMSSP_FEATURE_SIGN", feature_list
, true)) {
249 DEBUG(10, ("want GENSEC_FEATURE_SIGN\n"));
250 gensec_want_feature(state
, GENSEC_FEATURE_SIGN
);
252 if (in_list("NTLMSSP_FEATURE_SEAL", feature_list
, true)) {
253 DEBUG(10, ("want GENSEC_FEATURE_SEAL\n"));
254 gensec_want_feature(state
, GENSEC_FEATURE_SEAL
);
258 static char winbind_separator(void)
260 struct winbindd_response response
;
267 ZERO_STRUCT(response
);
269 /* Send off request */
271 if (winbindd_request_response(WINBINDD_INFO
, NULL
, &response
) !=
272 NSS_STATUS_SUCCESS
) {
273 d_printf("could not obtain winbind separator!\n");
274 return *lp_winbind_separator();
277 sep
= response
.data
.info
.winbind_separator
;
281 d_printf("winbind separator was NULL!\n");
282 return *lp_winbind_separator();
288 const char *get_winbind_domain(void)
290 struct winbindd_response response
;
292 static fstring winbind_domain
;
293 if (*winbind_domain
) {
294 return winbind_domain
;
297 ZERO_STRUCT(response
);
299 /* Send off request */
301 if (winbindd_request_response(WINBINDD_DOMAIN_NAME
, NULL
, &response
) !=
302 NSS_STATUS_SUCCESS
) {
303 DEBUG(0, ("could not obtain winbind domain name!\n"));
304 return lp_workgroup();
307 fstrcpy(winbind_domain
, response
.data
.domain_name
);
309 return winbind_domain
;
313 const char *get_winbind_netbios_name(void)
315 struct winbindd_response response
;
317 static fstring winbind_netbios_name
;
319 if (*winbind_netbios_name
) {
320 return winbind_netbios_name
;
323 ZERO_STRUCT(response
);
325 /* Send off request */
327 if (winbindd_request_response(WINBINDD_NETBIOS_NAME
, NULL
, &response
) !=
328 NSS_STATUS_SUCCESS
) {
329 DEBUG(0, ("could not obtain winbind netbios name!\n"));
330 return lp_netbios_name();
333 fstrcpy(winbind_netbios_name
, response
.data
.netbios_name
);
335 return winbind_netbios_name
;
339 DATA_BLOB
get_challenge(void)
341 static DATA_BLOB chal
;
342 if (opt_challenge
.length
)
343 return opt_challenge
;
345 chal
= data_blob(NULL
, 8);
347 generate_random_buffer(chal
.data
, chal
.length
);
351 /* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
352 form DOMAIN/user into a domain and a user */
354 static bool parse_ntlm_auth_domain_user(const char *domuser
, fstring domain
,
358 char *p
= strchr(domuser
,winbind_separator());
365 fstrcpy(domain
, domuser
);
366 domain
[PTR_DIFF(p
, domuser
)] = 0;
372 static bool get_require_membership_sid(void) {
373 struct winbindd_request request
;
374 struct winbindd_response response
;
376 if (!require_membership_of
) {
380 if (require_membership_of_sid
) {
384 /* Otherwise, ask winbindd for the name->sid request */
386 ZERO_STRUCT(request
);
387 ZERO_STRUCT(response
);
389 if (!parse_ntlm_auth_domain_user(require_membership_of
,
390 request
.data
.name
.dom_name
,
391 request
.data
.name
.name
)) {
392 DEBUG(0, ("Could not parse %s into seperate domain/name parts!\n",
393 require_membership_of
));
397 if (winbindd_request_response(WINBINDD_LOOKUPNAME
, &request
, &response
) !=
398 NSS_STATUS_SUCCESS
) {
399 DEBUG(0, ("Winbindd lookupname failed to resolve %s into a SID!\n",
400 require_membership_of
));
404 require_membership_of_sid
= SMB_STRDUP(response
.data
.sid
.sid
);
406 if (require_membership_of_sid
)
413 * Get some configuration from pam_winbind.conf to see if we
414 * need to contact trusted domain
417 int get_pam_winbind_config()
420 dictionary
*d
= NULL
;
422 if (!opt_pam_winbind_conf
|| !*opt_pam_winbind_conf
) {
423 opt_pam_winbind_conf
= PAM_WINBIND_CONFIG_FILE
;
426 d
= iniparser_load(discard_const_p(char, opt_pam_winbind_conf
));
432 if (iniparser_getboolean(d
, discard_const_p(char, "global:krb5_auth"), false)) {
433 ctrl
|= WINBIND_KRB5_AUTH
;
436 iniparser_freedict(d
);
441 /* Authenticate a user with a plaintext password */
443 static bool check_plaintext_auth(const char *user
, const char *pass
,
444 bool stdout_diagnostics
)
446 struct winbindd_request request
;
447 struct winbindd_response response
;
450 if (!get_require_membership_sid()) {
454 /* Send off request */
456 ZERO_STRUCT(request
);
457 ZERO_STRUCT(response
);
459 fstrcpy(request
.data
.auth
.user
, user
);
460 fstrcpy(request
.data
.auth
.pass
, pass
);
461 if (require_membership_of_sid
) {
462 strlcpy(request
.data
.auth
.require_membership_of_sid
,
463 require_membership_of_sid
,
464 sizeof(request
.data
.auth
.require_membership_of_sid
));
467 result
= winbindd_request_response(WINBINDD_PAM_AUTH
, &request
, &response
);
469 /* Display response */
471 if (stdout_diagnostics
) {
472 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
473 d_printf("Reading winbind reply failed! (0x01)\n");
476 d_printf("%s: %s (0x%x)\n",
477 response
.data
.auth
.nt_status_string
,
478 response
.data
.auth
.error_string
,
479 response
.data
.auth
.nt_status
);
481 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
482 DEBUG(1, ("Reading winbind reply failed! (0x01)\n"));
485 DEBUG(3, ("%s: %s (0x%x)\n",
486 response
.data
.auth
.nt_status_string
,
487 response
.data
.auth
.error_string
,
488 response
.data
.auth
.nt_status
));
491 return (result
== NSS_STATUS_SUCCESS
);
494 /* authenticate a user with an encrypted username/password */
496 NTSTATUS
contact_winbind_auth_crap(const char *username
,
498 const char *workstation
,
499 const DATA_BLOB
*challenge
,
500 const DATA_BLOB
*lm_response
,
501 const DATA_BLOB
*nt_response
,
503 uint32 extra_logon_parameters
,
505 uint8 user_session_key
[16],
511 struct winbindd_request request
;
512 struct winbindd_response response
;
514 if (!get_require_membership_sid()) {
515 return NT_STATUS_INVALID_PARAMETER
;
518 ZERO_STRUCT(request
);
519 ZERO_STRUCT(response
);
521 request
.flags
= flags
;
523 request
.data
.auth_crap
.logon_parameters
= extra_logon_parameters
524 | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
| MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT
;
526 if (require_membership_of_sid
)
527 fstrcpy(request
.data
.auth_crap
.require_membership_of_sid
, require_membership_of_sid
);
529 fstrcpy(request
.data
.auth_crap
.user
, username
);
530 fstrcpy(request
.data
.auth_crap
.domain
, domain
);
532 fstrcpy(request
.data
.auth_crap
.workstation
,
535 memcpy(request
.data
.auth_crap
.chal
, challenge
->data
, MIN(challenge
->length
, 8));
537 if (lm_response
&& lm_response
->length
) {
538 memcpy(request
.data
.auth_crap
.lm_resp
,
540 MIN(lm_response
->length
, sizeof(request
.data
.auth_crap
.lm_resp
)));
541 request
.data
.auth_crap
.lm_resp_len
= lm_response
->length
;
544 if (nt_response
&& nt_response
->length
) {
545 if (nt_response
->length
> sizeof(request
.data
.auth_crap
.nt_resp
)) {
546 request
.flags
= request
.flags
| WBFLAG_BIG_NTLMV2_BLOB
;
547 request
.extra_len
= nt_response
->length
;
548 request
.extra_data
.data
= SMB_MALLOC_ARRAY(char, request
.extra_len
);
549 if (request
.extra_data
.data
== NULL
) {
550 return NT_STATUS_NO_MEMORY
;
552 memcpy(request
.extra_data
.data
, nt_response
->data
,
553 nt_response
->length
);
556 memcpy(request
.data
.auth_crap
.nt_resp
,
557 nt_response
->data
, nt_response
->length
);
559 request
.data
.auth_crap
.nt_resp_len
= nt_response
->length
;
562 result
= winbindd_request_response(WINBINDD_PAM_AUTH_CRAP
, &request
, &response
);
563 SAFE_FREE(request
.extra_data
.data
);
565 /* Display response */
567 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
568 nt_status
= NT_STATUS_UNSUCCESSFUL
;
570 *error_string
= smb_xstrdup("Reading winbind reply failed!");
571 winbindd_free_response(&response
);
575 nt_status
= (NT_STATUS(response
.data
.auth
.nt_status
));
576 if (!NT_STATUS_IS_OK(nt_status
)) {
578 *error_string
= smb_xstrdup(response
.data
.auth
.error_string
);
579 winbindd_free_response(&response
);
583 if ((flags
& WBFLAG_PAM_LMKEY
) && lm_key
) {
584 memcpy(lm_key
, response
.data
.auth
.first_8_lm_hash
,
585 sizeof(response
.data
.auth
.first_8_lm_hash
));
587 if ((flags
& WBFLAG_PAM_USER_SESSION_KEY
) && user_session_key
) {
588 memcpy(user_session_key
, response
.data
.auth
.user_session_key
,
589 sizeof(response
.data
.auth
.user_session_key
));
592 if (flags
& WBFLAG_PAM_UNIX_NAME
) {
593 *unix_name
= SMB_STRDUP(response
.data
.auth
.unix_username
);
595 winbindd_free_response(&response
);
596 return NT_STATUS_NO_MEMORY
;
600 winbindd_free_response(&response
);
604 /* contact server to change user password using auth crap */
605 static NTSTATUS
contact_winbind_change_pswd_auth_crap(const char *username
,
607 const DATA_BLOB new_nt_pswd
,
608 const DATA_BLOB old_nt_hash_enc
,
609 const DATA_BLOB new_lm_pswd
,
610 const DATA_BLOB old_lm_hash_enc
,
615 struct winbindd_request request
;
616 struct winbindd_response response
;
618 if (!get_require_membership_sid())
621 *error_string
= smb_xstrdup("Can't get membership sid.");
622 return NT_STATUS_INVALID_PARAMETER
;
625 ZERO_STRUCT(request
);
626 ZERO_STRUCT(response
);
629 fstrcpy(request
.data
.chng_pswd_auth_crap
.user
, username
);
631 fstrcpy(request
.data
.chng_pswd_auth_crap
.domain
,domain
);
633 if(new_nt_pswd
.length
)
635 memcpy(request
.data
.chng_pswd_auth_crap
.new_nt_pswd
, new_nt_pswd
.data
, sizeof(request
.data
.chng_pswd_auth_crap
.new_nt_pswd
));
636 request
.data
.chng_pswd_auth_crap
.new_nt_pswd_len
= new_nt_pswd
.length
;
639 if(old_nt_hash_enc
.length
)
641 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
));
642 request
.data
.chng_pswd_auth_crap
.old_nt_hash_enc_len
= old_nt_hash_enc
.length
;
645 if(new_lm_pswd
.length
)
647 memcpy(request
.data
.chng_pswd_auth_crap
.new_lm_pswd
, new_lm_pswd
.data
, sizeof(request
.data
.chng_pswd_auth_crap
.new_lm_pswd
));
648 request
.data
.chng_pswd_auth_crap
.new_lm_pswd_len
= new_lm_pswd
.length
;
651 if(old_lm_hash_enc
.length
)
653 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
));
654 request
.data
.chng_pswd_auth_crap
.old_lm_hash_enc_len
= old_lm_hash_enc
.length
;
657 result
= winbindd_request_response(WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP
, &request
, &response
);
659 /* Display response */
661 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0))
663 nt_status
= NT_STATUS_UNSUCCESSFUL
;
665 *error_string
= smb_xstrdup("Reading winbind reply failed!");
666 winbindd_free_response(&response
);
670 nt_status
= (NT_STATUS(response
.data
.auth
.nt_status
));
671 if (!NT_STATUS_IS_OK(nt_status
))
674 *error_string
= smb_xstrdup(response
.data
.auth
.error_string
);
675 winbindd_free_response(&response
);
679 winbindd_free_response(&response
);
684 static NTSTATUS
ntlm_auth_generate_session_info(struct auth4_context
*auth_context
,
686 void *server_returned_info
,
687 const char *original_user_name
,
688 uint32_t session_info_flags
,
689 struct auth_session_info
**session_info_out
)
691 char *unix_username
= (char *)server_returned_info
;
692 struct auth_session_info
*session_info
= talloc_zero(mem_ctx
, struct auth_session_info
);
694 return NT_STATUS_NO_MEMORY
;
697 session_info
->unix_info
= talloc_zero(session_info
, struct auth_user_info_unix
);
698 if (!session_info
->unix_info
) {
699 TALLOC_FREE(session_info
);
700 return NT_STATUS_NO_MEMORY
;
702 session_info
->unix_info
->unix_name
= talloc_steal(session_info
->unix_info
, unix_username
);
704 *session_info_out
= session_info
;
709 static NTSTATUS
ntlm_auth_generate_session_info_pac(struct auth4_context
*auth_ctx
,
711 struct smb_krb5_context
*smb_krb5_context
,
713 const char *princ_name
,
714 const struct tsocket_address
*remote_address
,
715 uint32_t session_info_flags
,
716 struct auth_session_info
**session_info
)
719 struct PAC_LOGON_INFO
*logon_info
= NULL
;
727 tmp_ctx
= talloc_new(mem_ctx
);
729 return NT_STATUS_NO_MEMORY
;
734 status
= kerberos_pac_logon_info(tmp_ctx
, *pac_blob
, NULL
, NULL
,
735 NULL
, NULL
, 0, &logon_info
);
737 status
= NT_STATUS_ACCESS_DENIED
;
739 if (!NT_STATUS_IS_OK(status
)) {
744 DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name
));
746 p
= strchr_m(princ_name
, '@');
748 DEBUG(3, ("[%s] Doesn't look like a valid principal\n",
750 return NT_STATUS_LOGON_FAILURE
;
753 user
= talloc_strndup(mem_ctx
, princ_name
, p
- princ_name
);
755 return NT_STATUS_NO_MEMORY
;
758 realm
= talloc_strdup(talloc_tos(), p
+ 1);
760 return NT_STATUS_NO_MEMORY
;
763 if (!strequal(realm
, lp_realm())) {
764 DEBUG(3, ("Ticket for foreign realm %s@%s\n", user
, realm
));
765 if (!lp_allow_trusted_domains()) {
766 return NT_STATUS_LOGON_FAILURE
;
770 if (logon_info
&& logon_info
->info3
.base
.logon_domain
.string
) {
771 domain
= talloc_strdup(mem_ctx
,
772 logon_info
->info3
.base
.logon_domain
.string
);
774 return NT_STATUS_NO_MEMORY
;
776 DEBUG(10, ("Domain is [%s] (using PAC)\n", domain
));
779 /* If we have winbind running, we can (and must) shorten the
780 username by using the short netbios name. Otherwise we will
781 have inconsistent user names. With Kerberos, we get the
782 fully qualified realm, with ntlmssp we get the short
783 name. And even w2k3 does use ntlmssp if you for example
784 connect to an ip address. */
787 struct wbcDomainInfo
*info
= NULL
;
789 DEBUG(10, ("Mapping [%s] to short name using winbindd\n",
792 wbc_status
= wbcDomainInfo(realm
, &info
);
794 if (WBC_ERROR_IS_OK(wbc_status
)) {
795 domain
= talloc_strdup(mem_ctx
,
799 DEBUG(3, ("Could not find short name: %s\n",
800 wbcErrorString(wbc_status
)));
801 domain
= talloc_strdup(mem_ctx
, realm
);
804 return NT_STATUS_NO_MEMORY
;
806 DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain
));
809 unixuser
= talloc_asprintf(tmp_ctx
, "%s%c%s", domain
, winbind_separator(), user
);
811 status
= NT_STATUS_NO_MEMORY
;
815 status
= ntlm_auth_generate_session_info(auth_ctx
, mem_ctx
, unixuser
, NULL
, session_info_flags
, session_info
);
818 TALLOC_FREE(tmp_ctx
);
825 * Return the challenge as determined by the authentication subsystem
826 * @return an 8 byte random challenge
829 static NTSTATUS
ntlm_auth_get_challenge(struct auth4_context
*auth_ctx
,
832 if (auth_ctx
->challenge
.data
.length
== 8) {
833 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
834 auth_ctx
->challenge
.set_by
));
835 memcpy(chal
, auth_ctx
->challenge
.data
.data
, 8);
839 if (!auth_ctx
->challenge
.set_by
) {
840 generate_random_buffer(chal
, 8);
842 auth_ctx
->challenge
.data
= data_blob_talloc(auth_ctx
, chal
, 8);
843 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.data
.data
);
844 auth_ctx
->challenge
.set_by
= "random";
847 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
848 auth_ctx
->challenge
.set_by
));
854 * NTLM2 authentication modifies the effective challenge,
855 * @param challenge The new challenge value
857 static NTSTATUS
ntlm_auth_set_challenge(struct auth4_context
*auth_ctx
, const uint8_t chal
[8], const char *set_by
)
859 auth_ctx
->challenge
.set_by
= talloc_strdup(auth_ctx
, set_by
);
860 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.set_by
);
862 auth_ctx
->challenge
.data
= data_blob_talloc(auth_ctx
, chal
, 8);
863 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.data
.data
);
869 * Check the password on an NTLMSSP login.
871 * Return the session keys used on the connection.
874 static NTSTATUS
winbind_pw_check(struct auth4_context
*auth4_context
,
876 const struct auth_usersupplied_info
*user_info
,
877 void **server_returned_info
,
878 DATA_BLOB
*session_key
, DATA_BLOB
*lm_session_key
)
880 static const char zeros
[16] = { 0, };
882 char *error_string
= NULL
;
884 uint8 user_sess_key
[16];
885 char *unix_name
= NULL
;
887 nt_status
= contact_winbind_auth_crap(user_info
->client
.account_name
, user_info
->client
.domain_name
,
888 user_info
->workstation_name
,
889 &auth4_context
->challenge
.data
,
890 &user_info
->password
.response
.lanman
,
891 &user_info
->password
.response
.nt
,
892 WBFLAG_PAM_LMKEY
| WBFLAG_PAM_USER_SESSION_KEY
| WBFLAG_PAM_UNIX_NAME
,
894 lm_key
, user_sess_key
,
895 &error_string
, &unix_name
);
897 if (NT_STATUS_IS_OK(nt_status
)) {
898 if (memcmp(lm_key
, zeros
, 8) != 0) {
899 *lm_session_key
= data_blob_talloc(mem_ctx
, NULL
, 16);
900 memcpy(lm_session_key
->data
, lm_key
, 8);
901 memset(lm_session_key
->data
+8, '\0', 8);
904 if (memcmp(user_sess_key
, zeros
, 16) != 0) {
905 *session_key
= data_blob_talloc(mem_ctx
, user_sess_key
, 16);
907 *server_returned_info
= talloc_strdup(mem_ctx
,
910 DEBUG(NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCESS_DENIED
) ? 0 : 3,
911 ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
912 user_info
->client
.domain_name
, user_info
->client
.account_name
,
913 user_info
->workstation_name
,
914 error_string
? error_string
: "unknown error (NULL)"));
917 SAFE_FREE(error_string
);
918 SAFE_FREE(unix_name
);
922 static NTSTATUS
local_pw_check(struct auth4_context
*auth4_context
,
924 const struct auth_usersupplied_info
*user_info
,
925 void **server_returned_info
,
926 DATA_BLOB
*session_key
, DATA_BLOB
*lm_session_key
)
929 struct samr_Password lm_pw
, nt_pw
;
931 nt_lm_owf_gen (opt_password
, nt_pw
.hash
, lm_pw
.hash
);
933 nt_status
= ntlm_password_check(mem_ctx
,
935 &auth4_context
->challenge
.data
,
936 &user_info
->password
.response
.lanman
,
937 &user_info
->password
.response
.nt
,
938 user_info
->client
.account_name
,
939 user_info
->client
.account_name
,
940 user_info
->client
.domain_name
,
941 &lm_pw
, &nt_pw
, session_key
, lm_session_key
);
943 if (NT_STATUS_IS_OK(nt_status
)) {
944 *server_returned_info
= talloc_asprintf(mem_ctx
,
945 "%s%c%s", user_info
->client
.domain_name
,
946 *lp_winbind_separator(),
947 user_info
->client
.account_name
);
949 DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
950 user_info
->client
.domain_name
, user_info
->client
.account_name
,
951 user_info
->workstation_name
,
952 nt_errstr(nt_status
)));
957 static NTSTATUS
ntlm_auth_start_ntlmssp_client(struct ntlmssp_state
**client_ntlmssp_state
)
960 if ( (opt_username
== NULL
) || (opt_domain
== NULL
) ) {
961 status
= NT_STATUS_UNSUCCESSFUL
;
962 DEBUG(1, ("Need username and domain for NTLMSSP\n"));
963 return NT_STATUS_INVALID_PARAMETER
;
966 status
= ntlmssp_client_start(NULL
,
969 lp_client_ntlmv2_auth(),
970 client_ntlmssp_state
);
972 if (!NT_STATUS_IS_OK(status
)) {
973 DEBUG(1, ("Could not start NTLMSSP client: %s\n",
975 TALLOC_FREE(*client_ntlmssp_state
);
979 status
= ntlmssp_set_username(*client_ntlmssp_state
, opt_username
);
981 if (!NT_STATUS_IS_OK(status
)) {
982 DEBUG(1, ("Could not set username: %s\n",
984 TALLOC_FREE(*client_ntlmssp_state
);
988 status
= ntlmssp_set_domain(*client_ntlmssp_state
, opt_domain
);
990 if (!NT_STATUS_IS_OK(status
)) {
991 DEBUG(1, ("Could not set domain: %s\n",
993 TALLOC_FREE(*client_ntlmssp_state
);
998 status
= ntlmssp_set_password(*client_ntlmssp_state
, opt_password
);
1000 if (!NT_STATUS_IS_OK(status
)) {
1001 DEBUG(1, ("Could not set password: %s\n",
1002 nt_errstr(status
)));
1003 TALLOC_FREE(*client_ntlmssp_state
);
1008 return NT_STATUS_OK
;
1011 static struct auth4_context
*make_auth4_context_ntlm_auth(TALLOC_CTX
*mem_ctx
, bool local_pw
)
1013 struct auth4_context
*auth4_context
= talloc_zero(mem_ctx
, struct auth4_context
);
1014 if (auth4_context
== NULL
) {
1015 DEBUG(10, ("failed to allocate auth4_context failed\n"));
1018 auth4_context
->generate_session_info
= ntlm_auth_generate_session_info
;
1019 auth4_context
->generate_session_info_pac
= ntlm_auth_generate_session_info_pac
;
1020 auth4_context
->get_ntlm_challenge
= ntlm_auth_get_challenge
;
1021 auth4_context
->set_ntlm_challenge
= ntlm_auth_set_challenge
;
1023 auth4_context
->check_ntlm_password
= local_pw_check
;
1025 auth4_context
->check_ntlm_password
= winbind_pw_check
;
1027 auth4_context
->private_data
= NULL
;
1028 return auth4_context
;
1031 static NTSTATUS
ntlm_auth_start_ntlmssp_server(TALLOC_CTX
*mem_ctx
,
1032 struct loadparm_context
*lp_ctx
,
1033 struct gensec_security
**gensec_security_out
)
1035 struct gensec_security
*gensec_security
;
1038 TALLOC_CTX
*tmp_ctx
;
1040 struct gensec_settings
*gensec_settings
;
1042 struct cli_credentials
*server_credentials
;
1044 struct auth4_context
*auth4_context
;
1046 tmp_ctx
= talloc_new(mem_ctx
);
1047 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx
);
1049 auth4_context
= make_auth4_context_ntlm_auth(tmp_ctx
, opt_password
);
1050 if (auth4_context
== NULL
) {
1051 TALLOC_FREE(tmp_ctx
);
1052 return NT_STATUS_NO_MEMORY
;
1055 gensec_settings
= lpcfg_gensec_settings(tmp_ctx
, lp_ctx
);
1056 if (lp_ctx
== NULL
) {
1057 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1058 TALLOC_FREE(tmp_ctx
);
1059 return NT_STATUS_NO_MEMORY
;
1063 * This should be a 'netbios domain -> DNS domain'
1064 * mapping, and can currently validly return NULL on
1065 * poorly configured systems.
1067 * This is used for the NTLMSSP server
1071 gensec_settings
->server_netbios_name
= lp_netbios_name();
1072 gensec_settings
->server_netbios_domain
= lp_workgroup();
1074 gensec_settings
->server_netbios_name
= get_winbind_netbios_name();
1075 gensec_settings
->server_netbios_domain
= get_winbind_domain();
1078 gensec_settings
->server_dns_domain
= strlower_talloc(gensec_settings
,
1079 get_mydnsdomname(talloc_tos()));
1080 gensec_settings
->server_dns_name
= strlower_talloc(gensec_settings
,
1081 get_mydnsfullname());
1083 gensec_settings
->backends
= talloc_zero_array(gensec_settings
,
1084 struct gensec_security_ops
*, 4);
1086 if (gensec_settings
->backends
== NULL
) {
1087 TALLOC_FREE(tmp_ctx
);
1088 return NT_STATUS_NO_MEMORY
;
1093 /* These need to be in priority order, krb5 before NTLMSSP */
1094 #if defined(HAVE_KRB5)
1095 gensec_settings
->backends
[idx
++] = &gensec_gse_krb5_security_ops
;
1098 gensec_settings
->backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_NTLMSSP
);
1100 gensec_settings
->backends
[idx
++] = gensec_security_by_oid(NULL
,
1104 * This is anonymous for now, because we just use it
1105 * to set the kerberos state at the moment
1107 server_credentials
= cli_credentials_init_anon(tmp_ctx
);
1108 if (!server_credentials
) {
1109 DEBUG(0, ("auth_generic_prepare: Failed to init server credentials\n"));
1110 return NT_STATUS_NO_MEMORY
;
1113 cli_credentials_set_conf(server_credentials
, lp_ctx
);
1115 if (lp_security() == SEC_ADS
|| USE_KERBEROS_KEYTAB
) {
1116 cli_credentials_set_kerberos_state(server_credentials
, CRED_AUTO_USE_KERBEROS
);
1118 cli_credentials_set_kerberos_state(server_credentials
, CRED_DONT_USE_KERBEROS
);
1121 nt_status
= gensec_server_start(tmp_ctx
, gensec_settings
,
1122 auth4_context
, &gensec_security
);
1124 if (!NT_STATUS_IS_OK(nt_status
)) {
1125 TALLOC_FREE(tmp_ctx
);
1129 gensec_set_credentials(gensec_security
, server_credentials
);
1131 gensec_want_feature(gensec_security
, GENSEC_FEATURE_SIGN
);
1132 gensec_want_feature(gensec_security
, GENSEC_FEATURE_SEAL
);
1134 talloc_unlink(tmp_ctx
, lp_ctx
);
1135 talloc_unlink(tmp_ctx
, server_credentials
);
1136 talloc_unlink(tmp_ctx
, gensec_settings
);
1137 talloc_unlink(tmp_ctx
, auth4_context
);
1139 nt_status
= gensec_start_mech_by_oid(gensec_security
, GENSEC_OID_NTLMSSP
);
1140 if (!NT_STATUS_IS_OK(nt_status
)) {
1141 TALLOC_FREE(tmp_ctx
);
1145 *gensec_security_out
= talloc_steal(mem_ctx
, gensec_security
);
1146 TALLOC_FREE(tmp_ctx
);
1147 return NT_STATUS_OK
;
1150 /*******************************************************************
1151 Used by firefox to drive NTLM auth to IIS servers.
1152 *******************************************************************/
1154 static NTSTATUS
do_ccache_ntlm_auth(DATA_BLOB initial_msg
, DATA_BLOB challenge_msg
,
1157 struct winbindd_request wb_request
;
1158 struct winbindd_response wb_response
;
1162 /* get winbindd to do the ntlmssp step on our behalf */
1163 ZERO_STRUCT(wb_request
);
1164 ZERO_STRUCT(wb_response
);
1167 * This is tricky here. If we set krb5_auth in pam_winbind.conf
1168 * creds for users in trusted domain will be stored the winbindd
1169 * child of the trusted domain. If we ask the primary domain for
1170 * ntlm_ccache_auth, it will fail. So, we have to ask the trusted
1171 * domain's child for ccache_ntlm_auth. that is to say, we have to
1172 * set WBFLAG_PAM_CONTACT_TRUSTDOM in request.flags.
1174 ctrl
= get_pam_winbind_config();
1176 if (ctrl
& WINBIND_KRB5_AUTH
) {
1177 wb_request
.flags
|= WBFLAG_PAM_CONTACT_TRUSTDOM
;
1180 fstr_sprintf(wb_request
.data
.ccache_ntlm_auth
.user
,
1181 "%s%c%s", opt_domain
, winbind_separator(), opt_username
);
1182 wb_request
.data
.ccache_ntlm_auth
.uid
= geteuid();
1183 wb_request
.data
.ccache_ntlm_auth
.initial_blob_len
= initial_msg
.length
;
1184 wb_request
.data
.ccache_ntlm_auth
.challenge_blob_len
= challenge_msg
.length
;
1185 wb_request
.extra_len
= initial_msg
.length
+ challenge_msg
.length
;
1187 if (wb_request
.extra_len
> 0) {
1188 wb_request
.extra_data
.data
= SMB_MALLOC_ARRAY(char, wb_request
.extra_len
);
1189 if (wb_request
.extra_data
.data
== NULL
) {
1190 return NT_STATUS_NO_MEMORY
;
1193 memcpy(wb_request
.extra_data
.data
, initial_msg
.data
, initial_msg
.length
);
1194 memcpy(wb_request
.extra_data
.data
+ initial_msg
.length
,
1195 challenge_msg
.data
, challenge_msg
.length
);
1198 result
= winbindd_request_response(WINBINDD_CCACHE_NTLMAUTH
, &wb_request
, &wb_response
);
1199 SAFE_FREE(wb_request
.extra_data
.data
);
1201 if (result
!= NSS_STATUS_SUCCESS
) {
1202 winbindd_free_response(&wb_response
);
1203 return NT_STATUS_UNSUCCESSFUL
;
1207 *reply
= data_blob(wb_response
.extra_data
.data
,
1208 wb_response
.data
.ccache_ntlm_auth
.auth_blob_len
);
1209 if (wb_response
.data
.ccache_ntlm_auth
.auth_blob_len
> 0 &&
1210 reply
->data
== NULL
) {
1211 winbindd_free_response(&wb_response
);
1212 return NT_STATUS_NO_MEMORY
;
1216 winbindd_free_response(&wb_response
);
1217 return NT_STATUS_MORE_PROCESSING_REQUIRED
;
1220 static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode
,
1221 struct loadparm_context
*lp_ctx
,
1222 struct ntlm_auth_state
*state
,
1223 char *buf
, int length
, void **private2
)
1225 DATA_BLOB request
, reply
;
1228 if (!opt_username
|| !*opt_username
) {
1229 x_fprintf(x_stderr
, "username must be specified!\n\n");
1233 if (strlen(buf
) < 2) {
1234 DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf
));
1235 x_fprintf(x_stdout
, "BH NTLMSSP query invalid\n");
1239 if (strlen(buf
) > 3) {
1240 if(strncmp(buf
, "SF ", 3) == 0) {
1241 DEBUG(10, ("Looking for flags to negotiate\n"));
1242 talloc_free(state
->want_feature_list
);
1243 state
->want_feature_list
= talloc_strdup(state
->mem_ctx
,
1245 x_fprintf(x_stdout
, "OK\n");
1248 request
= base64_decode_data_blob(buf
+ 3);
1250 request
= data_blob_null
;
1253 if (strncmp(buf
, "PW ", 3) == 0) {
1254 /* We asked for a password and obviously got it :-) */
1256 opt_password
= SMB_STRNDUP((const char *)request
.data
,
1259 if (opt_password
== NULL
) {
1260 DEBUG(1, ("Out of memory\n"));
1261 x_fprintf(x_stdout
, "BH Out of memory\n");
1262 data_blob_free(&request
);
1266 x_fprintf(x_stdout
, "OK\n");
1267 data_blob_free(&request
);
1271 if (!state
->ntlmssp_state
&& use_cached_creds
) {
1272 /* check whether cached credentials are usable. */
1273 DATA_BLOB empty_blob
= data_blob_null
;
1275 nt_status
= do_ccache_ntlm_auth(empty_blob
, empty_blob
, NULL
);
1276 if (!NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1277 /* failed to use cached creds */
1278 use_cached_creds
= False
;
1282 if (opt_password
== NULL
&& !use_cached_creds
) {
1283 /* Request a password from the calling process. After
1284 sending it, the calling process should retry asking for the
1287 DEBUG(10, ("Requesting password\n"));
1288 x_fprintf(x_stdout
, "PW\n");
1292 if (strncmp(buf
, "YR", 2) == 0) {
1293 TALLOC_FREE(state
->ntlmssp_state
);
1294 state
->cli_state
= CLIENT_INITIAL
;
1295 } else if (strncmp(buf
, "TT", 2) == 0) {
1296 /* No special preprocessing required */
1297 } else if (strncmp(buf
, "GF", 2) == 0) {
1298 DEBUG(10, ("Requested negotiated NTLMSSP flags\n"));
1300 if(state
->cli_state
== CLIENT_FINISHED
) {
1301 x_fprintf(x_stdout
, "GF 0x%08x\n", state
->neg_flags
);
1304 x_fprintf(x_stdout
, "BH\n");
1307 data_blob_free(&request
);
1309 } else if (strncmp(buf
, "GK", 2) == 0 ) {
1310 DEBUG(10, ("Requested session key\n"));
1312 if(state
->cli_state
== CLIENT_FINISHED
) {
1313 char *key64
= base64_encode_data_blob(state
->mem_ctx
,
1314 state
->session_key
);
1315 x_fprintf(x_stdout
, "GK %s\n", key64
?key64
:"<NULL>");
1319 x_fprintf(x_stdout
, "BH\n");
1322 data_blob_free(&request
);
1325 DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf
));
1326 x_fprintf(x_stdout
, "BH NTLMSSP query invalid\n");
1330 if (!state
->ntlmssp_state
) {
1331 nt_status
= ntlm_auth_start_ntlmssp_client(
1332 &state
->ntlmssp_state
);
1333 if (!NT_STATUS_IS_OK(nt_status
)) {
1334 x_fprintf(x_stdout
, "BH %s\n", nt_errstr(nt_status
));
1337 ntlmssp_want_feature_list(state
->ntlmssp_state
,
1338 state
->want_feature_list
);
1339 state
->initial_message
= data_blob_null
;
1342 DEBUG(10, ("got NTLMSSP packet:\n"));
1343 dump_data(10, request
.data
, request
.length
);
1345 if (use_cached_creds
&& !opt_password
&&
1346 (state
->cli_state
== CLIENT_RESPONSE
)) {
1347 nt_status
= do_ccache_ntlm_auth(state
->initial_message
, request
,
1350 nt_status
= ntlmssp_update(state
->ntlmssp_state
, request
,
1354 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1355 char *reply_base64
= base64_encode_data_blob(state
->mem_ctx
,
1357 if (state
->cli_state
== CLIENT_INITIAL
) {
1358 x_fprintf(x_stdout
, "YR %s\n", reply_base64
);
1359 state
->initial_message
= reply
;
1360 state
->cli_state
= CLIENT_RESPONSE
;
1362 x_fprintf(x_stdout
, "KK %s\n", reply_base64
);
1363 data_blob_free(&reply
);
1365 TALLOC_FREE(reply_base64
);
1366 DEBUG(10, ("NTLMSSP challenge\n"));
1367 } else if (NT_STATUS_IS_OK(nt_status
)) {
1368 char *reply_base64
= base64_encode_data_blob(talloc_tos(),
1370 x_fprintf(x_stdout
, "AF %s\n", reply_base64
);
1371 TALLOC_FREE(reply_base64
);
1373 if(state
->have_session_key
)
1374 data_blob_free(&state
->session_key
);
1376 state
->session_key
= data_blob(
1377 state
->ntlmssp_state
->session_key
.data
,
1378 state
->ntlmssp_state
->session_key
.length
);
1379 state
->neg_flags
= state
->ntlmssp_state
->neg_flags
;
1380 state
->have_session_key
= true;
1382 DEBUG(10, ("NTLMSSP OK!\n"));
1383 state
->cli_state
= CLIENT_FINISHED
;
1384 TALLOC_FREE(state
->ntlmssp_state
);
1386 x_fprintf(x_stdout
, "BH %s\n", nt_errstr(nt_status
));
1387 DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status
)));
1388 state
->cli_state
= CLIENT_ERROR
;
1389 TALLOC_FREE(state
->ntlmssp_state
);
1392 data_blob_free(&request
);
1395 static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode
,
1396 struct loadparm_context
*lp_ctx
,
1397 struct ntlm_auth_state
*state
,
1398 char *buf
, int length
, void **private2
)
1403 pass
=(char *)memchr(buf
,' ',length
);
1405 DEBUG(2, ("Password not found. Denying access\n"));
1406 x_fprintf(x_stdout
, "ERR\n");
1412 if (state
->helper_mode
== SQUID_2_5_BASIC
) {
1413 rfc1738_unescape(user
);
1414 rfc1738_unescape(pass
);
1417 if (check_plaintext_auth(user
, pass
, False
)) {
1418 x_fprintf(x_stdout
, "OK\n");
1420 x_fprintf(x_stdout
, "ERR\n");
1424 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode
,
1425 struct loadparm_context
*lp_ctx
,
1426 char *buf
, int length
, void **private1
)
1429 DATA_BLOB out
= data_blob(NULL
, 0);
1430 char *out_base64
= NULL
;
1431 const char *reply_arg
= NULL
;
1432 struct gensec_ntlm_state
{
1433 struct gensec_security
*gensec_state
;
1434 const char *set_password
;
1436 struct gensec_ntlm_state
*state
;
1440 const char *reply_code
;
1441 struct cli_credentials
*creds
;
1443 static char *want_feature_list
= NULL
;
1444 static DATA_BLOB session_key
;
1446 TALLOC_CTX
*mem_ctx
;
1449 state
= (struct gensec_ntlm_state
*)*private1
;
1451 state
= talloc_zero(NULL
, struct gensec_ntlm_state
);
1453 x_fprintf(x_stdout
, "BH No Memory\n");
1458 state
->set_password
= opt_password
;
1462 if (strlen(buf
) < 2) {
1463 DEBUG(1, ("query [%s] invalid", buf
));
1464 x_fprintf(x_stdout
, "BH Query invalid\n");
1468 if (strlen(buf
) > 3) {
1469 if(strncmp(buf
, "SF ", 3) == 0) {
1470 DEBUG(10, ("Setting flags to negotiate\n"));
1471 talloc_free(want_feature_list
);
1472 want_feature_list
= talloc_strndup(state
, buf
+3, strlen(buf
)-3);
1473 x_fprintf(x_stdout
, "OK\n");
1476 in
= base64_decode_data_blob(buf
+ 3);
1478 in
= data_blob(NULL
, 0);
1481 if (strncmp(buf
, "YR", 2) == 0) {
1482 if (state
->gensec_state
) {
1483 talloc_free(state
->gensec_state
);
1484 state
->gensec_state
= NULL
;
1486 } else if ( (strncmp(buf
, "OK", 2) == 0)) {
1487 /* Just return BH, like ntlm_auth from Samba 3 does. */
1488 x_fprintf(x_stdout
, "BH Command expected\n");
1489 data_blob_free(&in
);
1491 } else if ( (strncmp(buf
, "TT ", 3) != 0) &&
1492 (strncmp(buf
, "KK ", 3) != 0) &&
1493 (strncmp(buf
, "AF ", 3) != 0) &&
1494 (strncmp(buf
, "NA ", 3) != 0) &&
1495 (strncmp(buf
, "UG", 2) != 0) &&
1496 (strncmp(buf
, "PW ", 3) != 0) &&
1497 (strncmp(buf
, "GK", 2) != 0) &&
1498 (strncmp(buf
, "GF", 2) != 0)) {
1499 DEBUG(1, ("SPNEGO request [%s] invalid prefix\n", buf
));
1500 x_fprintf(x_stdout
, "BH SPNEGO request invalid prefix\n");
1501 data_blob_free(&in
);
1505 mem_ctx
= talloc_named(NULL
, 0, "manage_gensec_request internal mem_ctx");
1508 if (!(state
->gensec_state
)) {
1509 switch (stdio_helper_mode
) {
1510 case GSS_SPNEGO_CLIENT
:
1511 case NTLMSSP_CLIENT_1
:
1512 /* setup the client side */
1514 nt_status
= gensec_client_start(NULL
, &state
->gensec_state
,
1515 lpcfg_gensec_settings(NULL
, lp_ctx
));
1516 if (!NT_STATUS_IS_OK(nt_status
)) {
1517 x_fprintf(x_stdout
, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status
));
1518 talloc_free(mem_ctx
);
1522 creds
= cli_credentials_init(state
->gensec_state
);
1523 cli_credentials_set_conf(creds
, lp_ctx
);
1525 cli_credentials_set_username(creds
, opt_username
, CRED_SPECIFIED
);
1528 cli_credentials_set_domain(creds
, opt_domain
, CRED_SPECIFIED
);
1530 if (state
->set_password
) {
1531 cli_credentials_set_password(creds
, state
->set_password
, CRED_SPECIFIED
);
1533 cli_credentials_set_password_callback(creds
, get_password
);
1535 if (opt_workstation
) {
1536 cli_credentials_set_workstation(creds
, opt_workstation
, CRED_SPECIFIED
);
1539 gensec_set_credentials(state
->gensec_state
, creds
);
1542 case GSS_SPNEGO_SERVER
:
1543 case SQUID_2_5_NTLMSSP
:
1545 nt_status
= ntlm_auth_start_ntlmssp_server(state
, lp_ctx
,
1546 &state
->gensec_state
);
1547 if (!NT_STATUS_IS_OK(nt_status
)) {
1548 x_fprintf(x_stdout
, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status
));
1549 talloc_free(mem_ctx
);
1555 talloc_free(mem_ctx
);
1559 gensec_want_feature_list(state
->gensec_state
, want_feature_list
);
1561 switch (stdio_helper_mode
) {
1562 case GSS_SPNEGO_CLIENT
:
1563 case GSS_SPNEGO_SERVER
:
1564 nt_status
= gensec_start_mech_by_oid(state
->gensec_state
, GENSEC_OID_SPNEGO
);
1569 case NTLMSSP_CLIENT_1
:
1574 case SQUID_2_5_NTLMSSP
:
1575 nt_status
= gensec_start_mech_by_oid(state
->gensec_state
, GENSEC_OID_NTLMSSP
);
1578 talloc_free(mem_ctx
);
1582 if (!NT_STATUS_IS_OK(nt_status
)) {
1583 DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status
)));
1584 x_fprintf(x_stdout
, "BH GENSEC mech failed to start\n");
1585 talloc_free(mem_ctx
);
1593 if (strncmp(buf
, "PW ", 3) == 0) {
1594 state
->set_password
= talloc_strndup(state
,
1595 (const char *)in
.data
,
1598 cli_credentials_set_password(gensec_get_credentials(state
->gensec_state
),
1599 state
->set_password
,
1601 x_fprintf(x_stdout
, "OK\n");
1602 data_blob_free(&in
);
1603 talloc_free(mem_ctx
);
1607 if (strncmp(buf
, "GK", 2) == 0) {
1609 DEBUG(10, ("Requested session key\n"));
1610 nt_status
= gensec_session_key(state
->gensec_state
, mem_ctx
, &session_key
);
1611 if(!NT_STATUS_IS_OK(nt_status
)) {
1612 DEBUG(1, ("gensec_session_key failed: %s\n", nt_errstr(nt_status
)));
1613 x_fprintf(x_stdout
, "BH No session key\n");
1614 talloc_free(mem_ctx
);
1617 base64_key
= base64_encode_data_blob(state
, session_key
);
1618 x_fprintf(x_stdout
, "GK %s\n", base64_key
);
1619 talloc_free(base64_key
);
1621 talloc_free(mem_ctx
);
1625 if (stdio_helper_mode
== SQUID_2_5_NTLMSSP
&& strncmp(buf
, "GF", 2) == 0) {
1628 neg_flags
= gensec_ntlmssp_neg_flags(state
->gensec_state
);
1630 DEBUG(10, ("Requested negotiated feature flags\n"));
1631 x_fprintf(x_stdout
, "GF 0x%08x\n", neg_flags
);
1635 nt_status
= gensec_update(state
->gensec_state
, mem_ctx
, NULL
, in
, &out
);
1637 /* don't leak 'bad password'/'no such user' info to the network client */
1638 nt_status
= nt_status_squash(nt_status
);
1641 out_base64
= base64_encode_data_blob(mem_ctx
, out
);
1646 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1648 if (first
&& state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1650 } else if (state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1652 } else if (state
->gensec_state
->gensec_role
== GENSEC_SERVER
) {
1659 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCESS_DENIED
)) {
1660 reply_code
= "BH NT_STATUS_ACCESS_DENIED";
1661 reply_arg
= nt_errstr(nt_status
);
1662 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1663 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_UNSUCCESSFUL
)) {
1664 reply_code
= "BH NT_STATUS_UNSUCCESSFUL";
1665 reply_arg
= nt_errstr(nt_status
);
1666 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1667 } else if (!NT_STATUS_IS_OK(nt_status
)) {
1669 reply_arg
= nt_errstr(nt_status
);
1670 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1671 } else if /* OK */ (state
->gensec_state
->gensec_role
== GENSEC_SERVER
) {
1672 struct auth_session_info
*session_info
;
1674 nt_status
= gensec_session_info(state
->gensec_state
, mem_ctx
, &session_info
);
1675 if (!NT_STATUS_IS_OK(nt_status
)) {
1676 reply_code
= "BH Failed to retrive session info";
1677 reply_arg
= nt_errstr(nt_status
);
1678 DEBUG(1, ("GENSEC failed to retrieve the session info: %s\n", nt_errstr(nt_status
)));
1682 reply_arg
= session_info
->unix_info
->unix_name
;
1683 talloc_free(session_info
);
1685 } else if (state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1687 reply_arg
= out_base64
;
1692 switch (stdio_helper_mode
) {
1693 case GSS_SPNEGO_SERVER
:
1694 x_fprintf(x_stdout
, "%s %s %s\n", reply_code
,
1695 out_base64
? out_base64
: "*",
1696 reply_arg
? reply_arg
: "*");
1700 x_fprintf(x_stdout
, "%s %s\n", reply_code
, out_base64
);
1701 } else if (reply_arg
) {
1702 x_fprintf(x_stdout
, "%s %s\n", reply_code
, reply_arg
);
1704 x_fprintf(x_stdout
, "%s\n", reply_code
);
1708 talloc_free(mem_ctx
);
1712 static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode
,
1713 struct loadparm_context
*lp_ctx
,
1714 struct ntlm_auth_state
*state
,
1715 char *buf
, int length
, void **private2
)
1717 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1721 static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode
,
1722 struct loadparm_context
*lp_ctx
,
1723 struct ntlm_auth_state
*state
,
1724 char *buf
, int length
, void **private2
)
1726 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1730 static struct ntlmssp_state
*client_ntlmssp_state
= NULL
;
1732 static bool manage_client_ntlmssp_init(struct spnego_data spnego
)
1735 DATA_BLOB null_blob
= data_blob_null
;
1736 DATA_BLOB to_server
;
1737 char *to_server_base64
;
1738 const char *my_mechs
[] = {OID_NTLMSSP
, NULL
};
1739 TALLOC_CTX
*ctx
= talloc_tos();
1741 DEBUG(10, ("Got spnego negTokenInit with NTLMSSP\n"));
1743 if (client_ntlmssp_state
!= NULL
) {
1744 DEBUG(1, ("Request for initial SPNEGO request where "
1745 "we already have a state\n"));
1749 if (!client_ntlmssp_state
) {
1750 if (!NT_STATUS_IS_OK(status
= ntlm_auth_start_ntlmssp_client(&client_ntlmssp_state
))) {
1751 x_fprintf(x_stdout
, "BH %s\n", nt_errstr(status
));
1757 if (opt_password
== NULL
) {
1759 /* Request a password from the calling process. After
1760 sending it, the calling process should retry with
1761 the negTokenInit. */
1763 DEBUG(10, ("Requesting password\n"));
1764 x_fprintf(x_stdout
, "PW\n");
1768 spnego
.type
= SPNEGO_NEG_TOKEN_INIT
;
1769 spnego
.negTokenInit
.mechTypes
= my_mechs
;
1770 spnego
.negTokenInit
.reqFlags
= data_blob_null
;
1771 spnego
.negTokenInit
.reqFlagsPadding
= 0;
1772 spnego
.negTokenInit
.mechListMIC
= null_blob
;
1774 status
= ntlmssp_update(client_ntlmssp_state
, null_blob
,
1775 &spnego
.negTokenInit
.mechToken
);
1777 if ( !(NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
) ||
1778 NT_STATUS_IS_OK(status
)) ) {
1779 DEBUG(1, ("Expected OK or MORE_PROCESSING_REQUIRED, got: %s\n",
1780 nt_errstr(status
)));
1781 TALLOC_FREE(client_ntlmssp_state
);
1785 spnego_write_data(ctx
, &to_server
, &spnego
);
1786 data_blob_free(&spnego
.negTokenInit
.mechToken
);
1788 to_server_base64
= base64_encode_data_blob(talloc_tos(), to_server
);
1789 data_blob_free(&to_server
);
1790 x_fprintf(x_stdout
, "KK %s\n", to_server_base64
);
1791 TALLOC_FREE(to_server_base64
);
1795 static void manage_client_ntlmssp_targ(struct spnego_data spnego
)
1798 DATA_BLOB null_blob
= data_blob_null
;
1800 DATA_BLOB to_server
;
1801 char *to_server_base64
;
1802 TALLOC_CTX
*ctx
= talloc_tos();
1804 DEBUG(10, ("Got spnego negTokenTarg with NTLMSSP\n"));
1806 if (client_ntlmssp_state
== NULL
) {
1807 DEBUG(1, ("Got NTLMSSP tArg without a client state\n"));
1808 x_fprintf(x_stdout
, "BH Got NTLMSSP tArg without a client state\n");
1812 if (spnego
.negTokenTarg
.negResult
== SPNEGO_REJECT
) {
1813 x_fprintf(x_stdout
, "NA\n");
1814 TALLOC_FREE(client_ntlmssp_state
);
1818 if (spnego
.negTokenTarg
.negResult
== SPNEGO_ACCEPT_COMPLETED
) {
1819 x_fprintf(x_stdout
, "AF\n");
1820 TALLOC_FREE(client_ntlmssp_state
);
1824 status
= ntlmssp_update(client_ntlmssp_state
,
1825 spnego
.negTokenTarg
.responseToken
,
1828 if (!NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
) && !NT_STATUS_IS_OK(status
)) {
1829 DEBUG(1, ("Expected MORE_PROCESSING_REQUIRED or OK from "
1830 "ntlmssp_client_update, got: %s\n",
1831 nt_errstr(status
)));
1832 x_fprintf(x_stdout
, "BH Expected MORE_PROCESSING_REQUIRED from "
1833 "ntlmssp_client_update\n");
1834 data_blob_free(&request
);
1835 TALLOC_FREE(client_ntlmssp_state
);
1839 spnego
.type
= SPNEGO_NEG_TOKEN_TARG
;
1840 spnego
.negTokenTarg
.negResult
= SPNEGO_ACCEPT_INCOMPLETE
;
1841 spnego
.negTokenTarg
.supportedMech
= (const char *)OID_NTLMSSP
;
1842 spnego
.negTokenTarg
.responseToken
= request
;
1843 spnego
.negTokenTarg
.mechListMIC
= null_blob
;
1845 spnego_write_data(ctx
, &to_server
, &spnego
);
1846 data_blob_free(&request
);
1848 to_server_base64
= base64_encode_data_blob(talloc_tos(), to_server
);
1849 data_blob_free(&to_server
);
1850 x_fprintf(x_stdout
, "KK %s\n", to_server_base64
);
1851 TALLOC_FREE(to_server_base64
);
1857 static bool manage_client_krb5_init(struct spnego_data spnego
)
1860 DATA_BLOB tkt
, tkt_wrapped
, to_server
;
1861 DATA_BLOB session_key_krb5
= data_blob_null
;
1862 struct spnego_data reply
;
1866 const char *my_mechs
[] = {OID_KERBEROS5_OLD
, NULL
};
1868 TALLOC_CTX
*ctx
= talloc_tos();
1870 principal
= spnego
.negTokenInit
.targetPrincipal
;
1872 /* We may not be allowed to use the server-supplied SPNEGO principal, or it may not have been supplied to us
1874 if (!lp_client_use_spnego_principal() || strequal(principal
, ADS_IGNORE_PRINCIPAL
)) {
1878 if (principal
== NULL
&&
1879 opt_target_service
&& opt_target_hostname
&& !is_ipaddress(opt_target_hostname
)) {
1880 DEBUG(3,("manage_client_krb5_init: using target "
1881 "hostname not SPNEGO principal\n"));
1883 principal
= kerberos_get_principal_from_service_hostname(talloc_tos(),
1885 opt_target_hostname
,
1892 DEBUG(3,("manage_client_krb5_init: guessed "
1893 "server principal=%s\n",
1894 principal
? principal
: "<null>"));
1897 if (principal
== NULL
) {
1898 DEBUG(3,("manage_client_krb5_init: could not guess server principal\n"));
1902 retval
= cli_krb5_get_ticket(ctx
, principal
, 0,
1903 &tkt
, &session_key_krb5
,
1904 0, NULL
, NULL
, NULL
);
1908 /* Let's try to first get the TGT, for that we need a
1911 if (opt_password
== NULL
) {
1912 DEBUG(10, ("Requesting password\n"));
1913 x_fprintf(x_stdout
, "PW\n");
1917 user
= talloc_asprintf(talloc_tos(), "%s@%s", opt_username
, opt_domain
);
1922 if ((retval
= kerberos_kinit_password(user
, opt_password
, 0, NULL
))) {
1923 DEBUG(10, ("Requesting TGT failed: %s\n", error_message(retval
)));
1927 retval
= cli_krb5_get_ticket(ctx
, principal
, 0,
1928 &tkt
, &session_key_krb5
,
1929 0, NULL
, NULL
, NULL
);
1931 DEBUG(10, ("Kinit suceeded, but getting a ticket failed: %s\n", error_message(retval
)));
1937 /* wrap that up in a nice GSS-API wrapping */
1938 tkt_wrapped
= spnego_gen_krb5_wrap(ctx
, tkt
, TOK_ID_KRB_AP_REQ
);
1940 data_blob_free(&session_key_krb5
);
1944 reply
.type
= SPNEGO_NEG_TOKEN_INIT
;
1945 reply
.negTokenInit
.mechTypes
= my_mechs
;
1946 reply
.negTokenInit
.reqFlags
= data_blob_null
;
1947 reply
.negTokenInit
.reqFlagsPadding
= 0;
1948 reply
.negTokenInit
.mechToken
= tkt_wrapped
;
1949 reply
.negTokenInit
.mechListMIC
= data_blob_null
;
1951 len
= spnego_write_data(ctx
, &to_server
, &reply
);
1952 data_blob_free(&tkt
);
1955 DEBUG(1, ("Could not write SPNEGO data blob\n"));
1959 reply_base64
= base64_encode_data_blob(talloc_tos(), to_server
);
1960 x_fprintf(x_stdout
, "KK %s *\n", reply_base64
);
1962 TALLOC_FREE(reply_base64
);
1963 data_blob_free(&to_server
);
1964 DEBUG(10, ("sent GSS-SPNEGO KERBEROS5 negTokenInit\n"));
1968 static void manage_client_krb5_targ(struct spnego_data spnego
)
1970 switch (spnego
.negTokenTarg
.negResult
) {
1971 case SPNEGO_ACCEPT_INCOMPLETE
:
1972 DEBUG(1, ("Got a Kerberos negTokenTarg with ACCEPT_INCOMPLETE\n"));
1973 x_fprintf(x_stdout
, "BH Got a Kerberos negTokenTarg with "
1974 "ACCEPT_INCOMPLETE\n");
1976 case SPNEGO_ACCEPT_COMPLETED
:
1977 DEBUG(10, ("Accept completed\n"));
1978 x_fprintf(x_stdout
, "AF\n");
1981 DEBUG(10, ("Rejected\n"));
1982 x_fprintf(x_stdout
, "NA\n");
1985 DEBUG(1, ("Got an invalid negTokenTarg\n"));
1986 x_fprintf(x_stdout
, "AF\n");
1992 static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode
,
1993 struct loadparm_context
*lp_ctx
,
1994 struct ntlm_auth_state
*state
,
1995 char *buf
, int length
, void **private2
)
1998 struct spnego_data spnego
;
2000 TALLOC_CTX
*ctx
= talloc_tos();
2002 if (!opt_username
|| !*opt_username
) {
2003 x_fprintf(x_stderr
, "username must be specified!\n\n");
2007 if (strlen(buf
) <= 3) {
2008 DEBUG(1, ("SPNEGO query [%s] too short\n", buf
));
2009 x_fprintf(x_stdout
, "BH SPNEGO query too short\n");
2013 request
= base64_decode_data_blob(buf
+3);
2015 if (strncmp(buf
, "PW ", 3) == 0) {
2017 /* We asked for a password and obviously got it :-) */
2019 opt_password
= SMB_STRNDUP((const char *)request
.data
, request
.length
);
2021 if (opt_password
== NULL
) {
2022 DEBUG(1, ("Out of memory\n"));
2023 x_fprintf(x_stdout
, "BH Out of memory\n");
2024 data_blob_free(&request
);
2028 x_fprintf(x_stdout
, "OK\n");
2029 data_blob_free(&request
);
2033 if ( (strncmp(buf
, "TT ", 3) != 0) &&
2034 (strncmp(buf
, "AF ", 3) != 0) &&
2035 (strncmp(buf
, "NA ", 3) != 0) ) {
2036 DEBUG(1, ("SPNEGO request [%s] invalid\n", buf
));
2037 x_fprintf(x_stdout
, "BH SPNEGO request invalid\n");
2038 data_blob_free(&request
);
2042 /* So we got a server challenge to generate a SPNEGO
2043 client-to-server request... */
2045 len
= spnego_read_data(ctx
, request
, &spnego
);
2046 data_blob_free(&request
);
2049 DEBUG(1, ("Could not read SPNEGO data for [%s]\n", buf
));
2050 x_fprintf(x_stdout
, "BH Could not read SPNEGO data\n");
2054 if (spnego
.type
== SPNEGO_NEG_TOKEN_INIT
) {
2056 /* The server offers a list of mechanisms */
2058 const char **mechType
= (const char **)spnego
.negTokenInit
.mechTypes
;
2060 while (*mechType
!= NULL
) {
2063 if ( (strcmp(*mechType
, OID_KERBEROS5_OLD
) == 0) ||
2064 (strcmp(*mechType
, OID_KERBEROS5
) == 0) ) {
2065 if (manage_client_krb5_init(spnego
))
2070 if (strcmp(*mechType
, OID_NTLMSSP
) == 0) {
2071 if (manage_client_ntlmssp_init(spnego
))
2078 DEBUG(1, ("Server offered no compatible mechanism\n"));
2079 x_fprintf(x_stdout
, "BH Server offered no compatible mechanism\n");
2083 if (spnego
.type
== SPNEGO_NEG_TOKEN_TARG
) {
2085 if (spnego
.negTokenTarg
.supportedMech
== NULL
) {
2086 /* On accept/reject Windows does not send the
2087 mechanism anymore. Handle that here and
2088 shut down the mechanisms. */
2090 switch (spnego
.negTokenTarg
.negResult
) {
2091 case SPNEGO_ACCEPT_COMPLETED
:
2092 x_fprintf(x_stdout
, "AF\n");
2095 x_fprintf(x_stdout
, "NA\n");
2098 DEBUG(1, ("Got a negTokenTarg with no mech and an "
2099 "unknown negResult: %d\n",
2100 spnego
.negTokenTarg
.negResult
));
2101 x_fprintf(x_stdout
, "BH Got a negTokenTarg with"
2102 " no mech and an unknown "
2106 TALLOC_FREE(client_ntlmssp_state
);
2110 if (strcmp(spnego
.negTokenTarg
.supportedMech
,
2111 OID_NTLMSSP
) == 0) {
2112 manage_client_ntlmssp_targ(spnego
);
2117 if (strcmp(spnego
.negTokenTarg
.supportedMech
,
2118 OID_KERBEROS5_OLD
) == 0) {
2119 manage_client_krb5_targ(spnego
);
2126 DEBUG(1, ("Got an SPNEGO token I could not handle [%s]!\n", buf
));
2127 x_fprintf(x_stdout
, "BH Got an SPNEGO token I could not handle\n");
2131 spnego_free_data(&spnego
);
2135 static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode
,
2136 struct loadparm_context
*lp_ctx
,
2137 struct ntlm_auth_state
*state
,
2138 char *buf
, int length
, void **private2
)
2140 char *request
, *parameter
;
2141 static DATA_BLOB challenge
;
2142 static DATA_BLOB lm_response
;
2143 static DATA_BLOB nt_response
;
2144 static char *full_username
;
2145 static char *username
;
2146 static char *domain
;
2147 static char *plaintext_password
;
2148 static bool ntlm_server_1_user_session_key
;
2149 static bool ntlm_server_1_lm_session_key
;
2151 if (strequal(buf
, ".")) {
2152 if (!full_username
&& !username
) {
2153 x_fprintf(x_stdout
, "Error: No username supplied!\n");
2154 } else if (plaintext_password
) {
2155 /* handle this request as plaintext */
2156 if (!full_username
) {
2157 if (asprintf(&full_username
, "%s%c%s", domain
, winbind_separator(), username
) == -1) {
2158 x_fprintf(x_stdout
, "Error: Out of memory in asprintf!\n.\n");
2162 if (check_plaintext_auth(full_username
, plaintext_password
, False
)) {
2163 x_fprintf(x_stdout
, "Authenticated: Yes\n");
2165 x_fprintf(x_stdout
, "Authenticated: No\n");
2167 } else if (!lm_response
.data
&& !nt_response
.data
) {
2168 x_fprintf(x_stdout
, "Error: No password supplied!\n");
2169 } else if (!challenge
.data
) {
2170 x_fprintf(x_stdout
, "Error: No lanman-challenge supplied!\n");
2172 char *error_string
= NULL
;
2174 uchar user_session_key
[16];
2177 if (full_username
&& !username
) {
2179 fstring fstr_domain
;
2181 if (!parse_ntlm_auth_domain_user(full_username
, fstr_user
, fstr_domain
)) {
2182 /* username might be 'tainted', don't print into our new-line deleimianted stream */
2183 x_fprintf(x_stdout
, "Error: Could not parse into domain and username\n");
2185 SAFE_FREE(username
);
2187 username
= smb_xstrdup(fstr_user
);
2188 domain
= smb_xstrdup(fstr_domain
);
2192 domain
= smb_xstrdup(get_winbind_domain());
2195 if (ntlm_server_1_lm_session_key
)
2196 flags
|= WBFLAG_PAM_LMKEY
;
2198 if (ntlm_server_1_user_session_key
)
2199 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
2201 if (!NT_STATUS_IS_OK(
2202 contact_winbind_auth_crap(username
,
2214 x_fprintf(x_stdout
, "Authenticated: No\n");
2215 x_fprintf(x_stdout
, "Authentication-Error: %s\n.\n", error_string
);
2217 static char zeros
[16];
2219 char *hex_user_session_key
;
2221 x_fprintf(x_stdout
, "Authenticated: Yes\n");
2223 if (ntlm_server_1_lm_session_key
2224 && (memcmp(zeros
, lm_key
,
2225 sizeof(lm_key
)) != 0)) {
2226 hex_lm_key
= hex_encode_talloc(NULL
,
2227 (const unsigned char *)lm_key
,
2229 x_fprintf(x_stdout
, "LANMAN-Session-Key: %s\n", hex_lm_key
);
2230 TALLOC_FREE(hex_lm_key
);
2233 if (ntlm_server_1_user_session_key
2234 && (memcmp(zeros
, user_session_key
,
2235 sizeof(user_session_key
)) != 0)) {
2236 hex_user_session_key
= hex_encode_talloc(NULL
,
2237 (const unsigned char *)user_session_key
,
2238 sizeof(user_session_key
));
2239 x_fprintf(x_stdout
, "User-Session-Key: %s\n", hex_user_session_key
);
2240 TALLOC_FREE(hex_user_session_key
);
2243 SAFE_FREE(error_string
);
2245 /* clear out the state */
2246 challenge
= data_blob_null
;
2247 nt_response
= data_blob_null
;
2248 lm_response
= data_blob_null
;
2249 SAFE_FREE(full_username
);
2250 SAFE_FREE(username
);
2252 SAFE_FREE(plaintext_password
);
2253 ntlm_server_1_user_session_key
= False
;
2254 ntlm_server_1_lm_session_key
= False
;
2255 x_fprintf(x_stdout
, ".\n");
2262 /* Indicates a base64 encoded structure */
2263 parameter
= strstr_m(request
, ":: ");
2265 parameter
= strstr_m(request
, ": ");
2268 DEBUG(0, ("Parameter not found!\n"));
2269 x_fprintf(x_stdout
, "Error: Parameter not found!\n.\n");
2286 base64_decode_inplace(parameter
);
2289 if (strequal(request
, "LANMAN-Challenge")) {
2290 challenge
= strhex_to_data_blob(NULL
, parameter
);
2291 if (challenge
.length
!= 8) {
2292 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (got %d bytes, expected 8)\n.\n",
2294 (int)challenge
.length
);
2295 challenge
= data_blob_null
;
2297 } else if (strequal(request
, "NT-Response")) {
2298 nt_response
= strhex_to_data_blob(NULL
, parameter
);
2299 if (nt_response
.length
< 24) {
2300 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (only got %d bytes, needed at least 24)\n.\n",
2302 (int)nt_response
.length
);
2303 nt_response
= data_blob_null
;
2305 } else if (strequal(request
, "LANMAN-Response")) {
2306 lm_response
= strhex_to_data_blob(NULL
, parameter
);
2307 if (lm_response
.length
!= 24) {
2308 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (got %d bytes, expected 24)\n.\n",
2310 (int)lm_response
.length
);
2311 lm_response
= data_blob_null
;
2313 } else if (strequal(request
, "Password")) {
2314 plaintext_password
= smb_xstrdup(parameter
);
2315 } else if (strequal(request
, "NT-Domain")) {
2316 domain
= smb_xstrdup(parameter
);
2317 } else if (strequal(request
, "Username")) {
2318 username
= smb_xstrdup(parameter
);
2319 } else if (strequal(request
, "Full-Username")) {
2320 full_username
= smb_xstrdup(parameter
);
2321 } else if (strequal(request
, "Request-User-Session-Key")) {
2322 ntlm_server_1_user_session_key
= strequal(parameter
, "Yes");
2323 } else if (strequal(request
, "Request-LanMan-Session-Key")) {
2324 ntlm_server_1_lm_session_key
= strequal(parameter
, "Yes");
2326 x_fprintf(x_stdout
, "Error: Unknown request %s\n.\n", request
);
2330 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode
,
2331 struct loadparm_context
*lp_ctx
,
2332 struct ntlm_auth_state
*state
,
2333 char *buf
, int length
, void **private2
)
2335 char *request
, *parameter
;
2336 static DATA_BLOB new_nt_pswd
;
2337 static DATA_BLOB old_nt_hash_enc
;
2338 static DATA_BLOB new_lm_pswd
;
2339 static DATA_BLOB old_lm_hash_enc
;
2340 static char *full_username
= NULL
;
2341 static char *username
= NULL
;
2342 static char *domain
= NULL
;
2343 static char *newpswd
= NULL
;
2344 static char *oldpswd
= NULL
;
2346 if (strequal(buf
, ".")) {
2347 if(newpswd
&& oldpswd
) {
2348 uchar old_nt_hash
[16];
2349 uchar old_lm_hash
[16];
2350 uchar new_nt_hash
[16];
2351 uchar new_lm_hash
[16];
2353 new_nt_pswd
= data_blob(NULL
, 516);
2354 old_nt_hash_enc
= data_blob(NULL
, 16);
2356 /* Calculate the MD4 hash (NT compatible) of the
2358 E_md4hash(oldpswd
, old_nt_hash
);
2359 E_md4hash(newpswd
, new_nt_hash
);
2361 /* E_deshash returns false for 'long'
2362 passwords (> 14 DOS chars).
2364 Therefore, don't send a buffer
2365 encrypted with the truncated hash
2366 (it could allow an even easier
2367 attack on the password)
2369 Likewise, obey the admin's restriction
2372 if (lp_client_lanman_auth() &&
2373 E_deshash(newpswd
, new_lm_hash
) &&
2374 E_deshash(oldpswd
, old_lm_hash
)) {
2375 new_lm_pswd
= data_blob(NULL
, 516);
2376 old_lm_hash_enc
= data_blob(NULL
, 16);
2377 encode_pw_buffer(new_lm_pswd
.data
, newpswd
,
2380 arcfour_crypt(new_lm_pswd
.data
, old_nt_hash
, 516);
2381 E_old_pw_hash(new_nt_hash
, old_lm_hash
,
2382 old_lm_hash_enc
.data
);
2384 new_lm_pswd
.data
= NULL
;
2385 new_lm_pswd
.length
= 0;
2386 old_lm_hash_enc
.data
= NULL
;
2387 old_lm_hash_enc
.length
= 0;
2390 encode_pw_buffer(new_nt_pswd
.data
, newpswd
,
2393 arcfour_crypt(new_nt_pswd
.data
, old_nt_hash
, 516);
2394 E_old_pw_hash(new_nt_hash
, old_nt_hash
,
2395 old_nt_hash_enc
.data
);
2398 if (!full_username
&& !username
) {
2399 x_fprintf(x_stdout
, "Error: No username supplied!\n");
2400 } else if ((!new_nt_pswd
.data
|| !old_nt_hash_enc
.data
) &&
2401 (!new_lm_pswd
.data
|| old_lm_hash_enc
.data
) ) {
2402 x_fprintf(x_stdout
, "Error: No NT or LM password "
2403 "blobs supplied!\n");
2405 char *error_string
= NULL
;
2407 if (full_username
&& !username
) {
2409 fstring fstr_domain
;
2411 if (!parse_ntlm_auth_domain_user(full_username
,
2414 /* username might be 'tainted', don't
2415 * print into our new-line
2416 * deleimianted stream */
2417 x_fprintf(x_stdout
, "Error: Could not "
2418 "parse into domain and "
2420 SAFE_FREE(username
);
2421 username
= smb_xstrdup(full_username
);
2423 SAFE_FREE(username
);
2425 username
= smb_xstrdup(fstr_user
);
2426 domain
= smb_xstrdup(fstr_domain
);
2431 if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
2438 x_fprintf(x_stdout
, "Password-Change: No\n");
2439 x_fprintf(x_stdout
, "Password-Change-Error: "
2440 "%s\n.\n", error_string
);
2442 x_fprintf(x_stdout
, "Password-Change: Yes\n");
2445 SAFE_FREE(error_string
);
2447 /* clear out the state */
2448 new_nt_pswd
= data_blob_null
;
2449 old_nt_hash_enc
= data_blob_null
;
2450 new_lm_pswd
= data_blob_null
;
2451 old_nt_hash_enc
= data_blob_null
;
2452 SAFE_FREE(full_username
);
2453 SAFE_FREE(username
);
2457 x_fprintf(x_stdout
, ".\n");
2464 /* Indicates a base64 encoded structure */
2465 parameter
= strstr_m(request
, ":: ");
2467 parameter
= strstr_m(request
, ": ");
2470 DEBUG(0, ("Parameter not found!\n"));
2471 x_fprintf(x_stdout
, "Error: Parameter not found!\n.\n");
2487 base64_decode_inplace(parameter
);
2490 if (strequal(request
, "new-nt-password-blob")) {
2491 new_nt_pswd
= strhex_to_data_blob(NULL
, parameter
);
2492 if (new_nt_pswd
.length
!= 516) {
2493 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2494 "(got %d bytes, expected 516)\n.\n",
2496 (int)new_nt_pswd
.length
);
2497 new_nt_pswd
= data_blob_null
;
2499 } else if (strequal(request
, "old-nt-hash-blob")) {
2500 old_nt_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2501 if (old_nt_hash_enc
.length
!= 16) {
2502 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2503 "(got %d bytes, expected 16)\n.\n",
2505 (int)old_nt_hash_enc
.length
);
2506 old_nt_hash_enc
= data_blob_null
;
2508 } else if (strequal(request
, "new-lm-password-blob")) {
2509 new_lm_pswd
= strhex_to_data_blob(NULL
, parameter
);
2510 if (new_lm_pswd
.length
!= 516) {
2511 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2512 "(got %d bytes, expected 516)\n.\n",
2514 (int)new_lm_pswd
.length
);
2515 new_lm_pswd
= data_blob_null
;
2518 else if (strequal(request
, "old-lm-hash-blob")) {
2519 old_lm_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2520 if (old_lm_hash_enc
.length
!= 16)
2522 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2523 "(got %d bytes, expected 16)\n.\n",
2525 (int)old_lm_hash_enc
.length
);
2526 old_lm_hash_enc
= data_blob_null
;
2528 } else if (strequal(request
, "nt-domain")) {
2529 domain
= smb_xstrdup(parameter
);
2530 } else if(strequal(request
, "username")) {
2531 username
= smb_xstrdup(parameter
);
2532 } else if(strequal(request
, "full-username")) {
2533 username
= smb_xstrdup(parameter
);
2534 } else if(strequal(request
, "new-password")) {
2535 newpswd
= smb_xstrdup(parameter
);
2536 } else if (strequal(request
, "old-password")) {
2537 oldpswd
= smb_xstrdup(parameter
);
2539 x_fprintf(x_stdout
, "Error: Unknown request %s\n.\n", request
);
2543 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode
,
2544 struct loadparm_context
*lp_ctx
,
2545 struct ntlm_auth_state
*state
,
2546 stdio_helper_function fn
, void **private2
)
2549 char tmp
[INITIAL_BUFFER_SIZE
+1];
2550 int length
, buf_size
= 0;
2553 buf
= talloc_strdup(state
->mem_ctx
, "");
2555 DEBUG(0, ("Failed to allocate input buffer.\n"));
2556 x_fprintf(x_stderr
, "ERR\n");
2562 /* this is not a typo - x_fgets doesn't work too well under
2564 if (fgets(tmp
, sizeof(tmp
)-1, stdin
) == NULL
) {
2565 if (ferror(stdin
)) {
2566 DEBUG(1, ("fgets() failed! dying..... errno=%d "
2567 "(%s)\n", ferror(stdin
),
2568 strerror(ferror(stdin
))));
2575 buf
= talloc_strdup_append_buffer(buf
, tmp
);
2576 buf_size
+= INITIAL_BUFFER_SIZE
;
2578 if (buf_size
> MAX_BUFFER_SIZE
) {
2579 DEBUG(2, ("Oversized message\n"));
2580 x_fprintf(x_stderr
, "ERR\n");
2585 c
= strchr(buf
, '\n');
2586 } while (c
== NULL
);
2591 DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf
,length
));
2593 if (buf
[0] == '\0') {
2594 DEBUG(2, ("Invalid Request\n"));
2595 x_fprintf(x_stderr
, "ERR\n");
2600 fn(stdio_helper_mode
, lp_ctx
, state
, buf
, length
, private2
);
2605 static void squid_stream(enum stdio_helper_mode stdio_mode
,
2606 struct loadparm_context
*lp_ctx
,
2607 stdio_helper_function fn
) {
2608 TALLOC_CTX
*mem_ctx
;
2609 struct ntlm_auth_state
*state
;
2611 /* initialize FDescs */
2612 x_setbuf(x_stdout
, NULL
);
2613 x_setbuf(x_stderr
, NULL
);
2615 mem_ctx
= talloc_init("ntlm_auth");
2617 DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
2618 x_fprintf(x_stderr
, "ERR\n");
2622 state
= talloc_zero(mem_ctx
, struct ntlm_auth_state
);
2624 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
2625 x_fprintf(x_stderr
, "ERR\n");
2629 state
->mem_ctx
= mem_ctx
;
2630 state
->helper_mode
= stdio_mode
;
2633 TALLOC_CTX
*frame
= talloc_stackframe();
2634 manage_squid_request(stdio_mode
, lp_ctx
, state
, fn
, NULL
);
2640 /* Authenticate a user with a challenge/response */
2642 static bool check_auth_crap(void)
2647 char user_session_key
[16];
2649 char *hex_user_session_key
;
2651 static uint8 zeros
[16];
2653 x_setbuf(x_stdout
, NULL
);
2656 flags
|= WBFLAG_PAM_LMKEY
;
2658 if (request_user_session_key
)
2659 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
2661 flags
|= WBFLAG_PAM_NT_STATUS_SQUASH
;
2663 nt_status
= contact_winbind_auth_crap(opt_username
, opt_domain
,
2669 (unsigned char *)lm_key
,
2670 (unsigned char *)user_session_key
,
2671 &error_string
, NULL
);
2673 if (!NT_STATUS_IS_OK(nt_status
)) {
2674 x_fprintf(x_stdout
, "%s (0x%x)\n",
2676 NT_STATUS_V(nt_status
));
2677 SAFE_FREE(error_string
);
2682 && (memcmp(zeros
, lm_key
,
2683 sizeof(lm_key
)) != 0)) {
2684 hex_lm_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)lm_key
,
2686 x_fprintf(x_stdout
, "LM_KEY: %s\n", hex_lm_key
);
2687 TALLOC_FREE(hex_lm_key
);
2689 if (request_user_session_key
2690 && (memcmp(zeros
, user_session_key
,
2691 sizeof(user_session_key
)) != 0)) {
2692 hex_user_session_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)user_session_key
,
2693 sizeof(user_session_key
));
2694 x_fprintf(x_stdout
, "NT_KEY: %s\n", hex_user_session_key
);
2695 TALLOC_FREE(hex_user_session_key
);
2704 OPT_USERNAME
= 1000,
2713 OPT_USER_SESSION_KEY
,
2715 OPT_REQUIRE_MEMBERSHIP
,
2716 OPT_USE_CACHED_CREDS
,
2717 OPT_PAM_WINBIND_CONF
,
2722 int main(int argc
, const char **argv
)
2724 TALLOC_CTX
*frame
= talloc_stackframe();
2726 static const char *helper_protocol
;
2727 static int diagnostics
;
2729 static const char *hex_challenge
;
2730 static const char *hex_lm_response
;
2731 static const char *hex_nt_response
;
2732 struct loadparm_context
*lp_ctx
;
2735 /* NOTE: DO NOT change this interface without considering the implications!
2736 This is an external interface, which other programs will use to interact
2740 /* We do not use single-letter command abbreviations, because they harm future
2741 interface stability. */
2743 struct poptOption long_options
[] = {
2745 { "helper-protocol", 0, POPT_ARG_STRING
, &helper_protocol
, OPT_DOMAIN
, "operate as a stdio-based helper", "helper protocol to use"},
2746 { "username", 0, POPT_ARG_STRING
, &opt_username
, OPT_USERNAME
, "username"},
2747 { "domain", 0, POPT_ARG_STRING
, &opt_domain
, OPT_DOMAIN
, "domain name"},
2748 { "workstation", 0, POPT_ARG_STRING
, &opt_workstation
, OPT_WORKSTATION
, "workstation"},
2749 { "challenge", 0, POPT_ARG_STRING
, &hex_challenge
, OPT_CHALLENGE
, "challenge (HEX encoded)"},
2750 { "lm-response", 0, POPT_ARG_STRING
, &hex_lm_response
, OPT_LM
, "LM Response to the challenge (HEX encoded)"},
2751 { "nt-response", 0, POPT_ARG_STRING
, &hex_nt_response
, OPT_NT
, "NT or NTLMv2 Response to the challenge (HEX encoded)"},
2752 { "password", 0, POPT_ARG_STRING
, &opt_password
, OPT_PASSWORD
, "User's plaintext password"},
2753 { "request-lm-key", 0, POPT_ARG_NONE
, &request_lm_key
, OPT_LM_KEY
, "Retrieve LM session key"},
2754 { "request-nt-key", 0, POPT_ARG_NONE
, &request_user_session_key
, OPT_USER_SESSION_KEY
, "Retrieve User (NT) session key"},
2755 { "use-cached-creds", 0, POPT_ARG_NONE
, &use_cached_creds
, OPT_USE_CACHED_CREDS
, "Use cached credentials if no password is given"},
2756 { "diagnostics", 0, POPT_ARG_NONE
, &diagnostics
,
2758 "Perform diagnostics on the authentication chain"},
2759 { "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" },
2760 { "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" },
2761 { "target-service", 0, POPT_ARG_STRING
, &opt_target_service
, OPT_TARGET_SERVICE
, "Target service (eg http)" },
2762 { "target-hostname", 0, POPT_ARG_STRING
, &opt_target_hostname
, OPT_TARGET_HOSTNAME
, "Target hostname" },
2763 POPT_COMMON_CONFIGFILE
2768 /* Samba client initialisation */
2771 setup_logging("ntlm_auth", DEBUG_STDERR
);
2775 pc
= poptGetContext("ntlm_auth", argc
, argv
, long_options
, 0);
2777 /* Parse command line options */
2780 poptPrintHelp(pc
, stderr
, 0);
2784 while((opt
= poptGetNextOpt(pc
)) != -1) {
2785 /* Get generic config options like --configfile */
2788 poptFreeContext(pc
);
2790 if (!lp_load_global(get_dyn_CONFIGFILE())) {
2791 d_fprintf(stderr
, "ntlm_auth: error opening config file %s. Error was %s\n",
2792 get_dyn_CONFIGFILE(), strerror(errno
));
2796 pc
= poptGetContext(NULL
, argc
, (const char **)argv
, long_options
,
2797 POPT_CONTEXT_KEEP_FIRST
);
2799 while((opt
= poptGetNextOpt(pc
)) != -1) {
2802 opt_challenge
= strhex_to_data_blob(NULL
, hex_challenge
);
2803 if (opt_challenge
.length
!= 8) {
2804 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2806 (int)opt_challenge
.length
);
2811 opt_lm_response
= strhex_to_data_blob(NULL
, hex_lm_response
);
2812 if (opt_lm_response
.length
!= 24) {
2813 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2815 (int)opt_lm_response
.length
);
2821 opt_nt_response
= strhex_to_data_blob(NULL
, hex_nt_response
);
2822 if (opt_nt_response
.length
< 24) {
2823 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2825 (int)opt_nt_response
.length
);
2830 case OPT_REQUIRE_MEMBERSHIP
:
2831 if (strncasecmp_m("S-", require_membership_of
, 2) == 0) {
2832 require_membership_of_sid
= require_membership_of
;
2839 char *domain
= SMB_STRDUP(opt_username
);
2840 char *p
= strchr_m(domain
, *lp_winbind_separator());
2844 if (opt_domain
&& !strequal(opt_domain
, domain
)) {
2845 x_fprintf(x_stderr
, "Domain specified in username (%s) "
2846 "doesn't match specified domain (%s)!\n\n",
2847 domain
, opt_domain
);
2848 poptPrintHelp(pc
, stderr
, 0);
2851 opt_domain
= domain
;
2857 /* Note: if opt_domain is "" then send no domain */
2858 if (opt_domain
== NULL
) {
2859 opt_domain
= get_winbind_domain();
2862 if (opt_workstation
== NULL
) {
2863 opt_workstation
= "";
2866 lp_ctx
= loadparm_init_s3(NULL
, loadparm_s3_helpers());
2867 if (lp_ctx
== NULL
) {
2868 x_fprintf(x_stderr
, "loadparm_init_s3() failed!\n");
2872 if (helper_protocol
) {
2874 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2875 if (strcmp(helper_protocol
, stdio_helper_protocols
[i
].name
) == 0) {
2876 squid_stream(stdio_helper_protocols
[i
].mode
, lp_ctx
, stdio_helper_protocols
[i
].fn
);
2880 x_fprintf(x_stderr
, "unknown helper protocol [%s]\n\nValid helper protools:\n\n", helper_protocol
);
2882 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2883 x_fprintf(x_stderr
, "%s\n", stdio_helper_protocols
[i
].name
);
2889 if (!opt_username
|| !*opt_username
) {
2890 x_fprintf(x_stderr
, "username must be specified!\n\n");
2891 poptPrintHelp(pc
, stderr
, 0);
2895 if (opt_challenge
.length
) {
2896 if (!check_auth_crap()) {
2902 if (!opt_password
) {
2903 opt_password
= getpass("password: ");
2907 if (!diagnose_ntlm_auth()) {
2913 fstr_sprintf(user
, "%s%c%s", opt_domain
, winbind_separator(), opt_username
);
2914 if (!check_plaintext_auth(user
, opt_password
, True
)) {
2921 poptFreeContext(pc
);