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"
48 #include "lib/param/loadparm.h"
51 #include "auth/kerberos/pac_utils.h"
54 #ifndef PAM_WINBIND_CONFIG_FILE
55 #define PAM_WINBIND_CONFIG_FILE "/etc/security/pam_winbind.conf"
58 #define WINBIND_KRB5_AUTH 0x00000080
61 #define DBGC_CLASS DBGC_WINBIND
63 #define INITIAL_BUFFER_SIZE 300
64 #define MAX_BUFFER_SIZE 630000
66 enum stdio_helper_mode
{
74 NTLM_CHANGE_PASSWORD_1
,
78 enum ntlm_auth_cli_state
{
85 struct ntlm_auth_state
{
87 enum stdio_helper_mode helper_mode
;
88 enum ntlm_auth_cli_state cli_state
;
89 struct ntlmssp_state
*ntlmssp_state
;
91 char *want_feature_list
;
92 bool have_session_key
;
93 DATA_BLOB session_key
;
94 DATA_BLOB initial_message
;
95 void *gensec_private_1
;
97 typedef void (*stdio_helper_function
)(enum stdio_helper_mode stdio_helper_mode
,
98 struct loadparm_context
*lp_ctx
,
99 struct ntlm_auth_state
*state
, char *buf
,
100 int length
, void **private2
);
102 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode
,
103 struct loadparm_context
*lp_ctx
,
104 struct ntlm_auth_state
*state
,
105 stdio_helper_function fn
, void **private2
);
107 static void manage_squid_basic_request (enum stdio_helper_mode stdio_helper_mode
,
108 struct loadparm_context
*lp_ctx
,
109 struct ntlm_auth_state
*state
,
110 char *buf
, int length
, void **private2
);
112 static void manage_squid_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode
,
113 struct loadparm_context
*lp_ctx
,
114 struct ntlm_auth_state
*state
,
115 char *buf
, int length
, void **private2
);
117 static void manage_client_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode
,
118 struct loadparm_context
*lp_ctx
,
119 struct ntlm_auth_state
*state
,
120 char *buf
, int length
, void **private2
);
122 static void manage_gss_spnego_request (enum stdio_helper_mode stdio_helper_mode
,
123 struct loadparm_context
*lp_ctx
,
124 struct ntlm_auth_state
*state
,
125 char *buf
, int length
, void **private2
);
127 static void manage_gss_spnego_client_request (enum stdio_helper_mode stdio_helper_mode
,
128 struct loadparm_context
*lp_ctx
,
129 struct ntlm_auth_state
*state
,
130 char *buf
, int length
, void **private2
);
132 static void manage_ntlm_server_1_request (enum stdio_helper_mode stdio_helper_mode
,
133 struct loadparm_context
*lp_ctx
,
134 struct ntlm_auth_state
*state
,
135 char *buf
, int length
, void **private2
);
137 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode
,
138 struct loadparm_context
*lp_ctx
,
139 struct ntlm_auth_state
*state
,
140 char *buf
, int length
, void **private2
);
142 static const struct {
143 enum stdio_helper_mode mode
;
145 stdio_helper_function fn
;
146 } stdio_helper_protocols
[] = {
147 { SQUID_2_4_BASIC
, "squid-2.4-basic", manage_squid_basic_request
},
148 { SQUID_2_5_BASIC
, "squid-2.5-basic", manage_squid_basic_request
},
149 { SQUID_2_5_NTLMSSP
, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request
},
150 { NTLMSSP_CLIENT_1
, "ntlmssp-client-1", manage_client_ntlmssp_request
},
151 { GSS_SPNEGO_SERVER
, "gss-spnego", manage_gss_spnego_request
},
152 { GSS_SPNEGO_CLIENT
, "gss-spnego-client", manage_gss_spnego_client_request
},
153 { NTLM_SERVER_1
, "ntlm-server-1", manage_ntlm_server_1_request
},
154 { NTLM_CHANGE_PASSWORD_1
, "ntlm-change-password-1", manage_ntlm_change_password_1_request
},
155 { NUM_HELPER_MODES
, NULL
, NULL
}
158 const char *opt_username
;
159 const char *opt_domain
;
160 const char *opt_workstation
;
161 const char *opt_password
;
162 static DATA_BLOB opt_challenge
;
163 static DATA_BLOB opt_lm_response
;
164 static DATA_BLOB opt_nt_response
;
165 static int request_lm_key
;
166 static int request_user_session_key
;
167 static int use_cached_creds
;
169 static const char *require_membership_of
;
170 static const char *require_membership_of_sid
;
171 static const char *opt_pam_winbind_conf
;
173 const char *opt_target_service
;
174 const char *opt_target_hostname
;
177 /* This is a bit hairy, but the basic idea is to do a password callback
178 to the calling application. The callback comes from within gensec */
180 static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mode
,
181 struct loadparm_context
*lp_ctx
,
182 struct ntlm_auth_state
*state
, char *buf
, int length
,
186 if (strlen(buf
) < 2) {
187 DEBUG(1, ("query [%s] invalid", buf
));
188 x_fprintf(x_stdout
, "BH Query invalid\n");
192 if (strlen(buf
) > 3) {
193 in
= base64_decode_data_blob(buf
+ 3);
195 in
= data_blob(NULL
, 0);
198 if (strncmp(buf
, "PW ", 3) == 0) {
200 *password
= talloc_strndup(NULL
,
201 (const char *)in
.data
, in
.length
);
203 if (*password
== NULL
) {
204 DEBUG(1, ("Out of memory\n"));
205 x_fprintf(x_stdout
, "BH Out of memory\n");
210 x_fprintf(x_stdout
, "OK\n");
214 DEBUG(1, ("Asked for (and expected) a password\n"));
215 x_fprintf(x_stdout
, "BH Expected a password\n");
220 * Callback for password credentials. This is not async, and when
221 * GENSEC and the credentials code is made async, it will look rather
225 static const char *get_password(struct cli_credentials
*credentials
)
227 char *password
= NULL
;
229 /* Ask for a password */
230 x_fprintf(x_stdout
, "PW\n");
231 credentials
->priv_data
= NULL
;
233 manage_squid_request(NUM_HELPER_MODES
/* bogus */, NULL
, NULL
, manage_gensec_get_pw_request
, (void **)&password
);
234 talloc_steal(credentials
, password
);
239 * A limited set of features are defined with text strings as needed
243 static void gensec_want_feature_list(struct gensec_security
*state
, char* feature_list
)
245 if (in_list("NTLMSSP_FEATURE_SESSION_KEY", feature_list
, true)) {
246 DEBUG(10, ("want GENSEC_FEATURE_SESSION_KEY\n"));
247 gensec_want_feature(state
, GENSEC_FEATURE_SESSION_KEY
);
249 if (in_list("NTLMSSP_FEATURE_SIGN", feature_list
, true)) {
250 DEBUG(10, ("want GENSEC_FEATURE_SIGN\n"));
251 gensec_want_feature(state
, GENSEC_FEATURE_SIGN
);
253 if (in_list("NTLMSSP_FEATURE_SEAL", feature_list
, true)) {
254 DEBUG(10, ("want GENSEC_FEATURE_SEAL\n"));
255 gensec_want_feature(state
, GENSEC_FEATURE_SEAL
);
259 static char winbind_separator(void)
261 struct winbindd_response response
;
268 ZERO_STRUCT(response
);
270 /* Send off request */
272 if (winbindd_request_response(WINBINDD_INFO
, NULL
, &response
) !=
273 NSS_STATUS_SUCCESS
) {
274 d_printf("could not obtain winbind separator!\n");
275 return *lp_winbind_separator();
278 sep
= response
.data
.info
.winbind_separator
;
282 d_printf("winbind separator was NULL!\n");
283 return *lp_winbind_separator();
289 const char *get_winbind_domain(void)
291 struct winbindd_response response
;
293 static fstring winbind_domain
;
294 if (*winbind_domain
) {
295 return winbind_domain
;
298 ZERO_STRUCT(response
);
300 /* Send off request */
302 if (winbindd_request_response(WINBINDD_DOMAIN_NAME
, NULL
, &response
) !=
303 NSS_STATUS_SUCCESS
) {
304 DEBUG(1, ("could not obtain winbind domain name!\n"));
305 return lp_workgroup();
308 fstrcpy(winbind_domain
, response
.data
.domain_name
);
310 return winbind_domain
;
314 const char *get_winbind_netbios_name(void)
316 struct winbindd_response response
;
318 static fstring winbind_netbios_name
;
320 if (*winbind_netbios_name
) {
321 return winbind_netbios_name
;
324 ZERO_STRUCT(response
);
326 /* Send off request */
328 if (winbindd_request_response(WINBINDD_NETBIOS_NAME
, NULL
, &response
) !=
329 NSS_STATUS_SUCCESS
) {
330 DEBUG(1, ("could not obtain winbind netbios name!\n"));
331 return lp_netbios_name();
334 fstrcpy(winbind_netbios_name
, response
.data
.netbios_name
);
336 return winbind_netbios_name
;
340 DATA_BLOB
get_challenge(void)
342 static DATA_BLOB chal
;
343 if (opt_challenge
.length
)
344 return opt_challenge
;
346 chal
= data_blob(NULL
, 8);
348 generate_random_buffer(chal
.data
, chal
.length
);
352 /* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
353 form DOMAIN/user into a domain and a user */
355 static bool parse_ntlm_auth_domain_user(const char *domuser
, fstring domain
,
359 char *p
= strchr(domuser
,winbind_separator());
366 fstrcpy(domain
, domuser
);
367 domain
[PTR_DIFF(p
, domuser
)] = 0;
368 return strupper_m(domain
);
371 static bool get_require_membership_sid(void) {
372 struct winbindd_request request
;
373 struct winbindd_response response
;
375 if (!require_membership_of
) {
379 if (require_membership_of_sid
) {
383 /* Otherwise, ask winbindd for the name->sid request */
385 ZERO_STRUCT(request
);
386 ZERO_STRUCT(response
);
388 if (!parse_ntlm_auth_domain_user(require_membership_of
,
389 request
.data
.name
.dom_name
,
390 request
.data
.name
.name
)) {
391 DEBUG(0, ("Could not parse %s into seperate domain/name parts!\n",
392 require_membership_of
));
396 if (winbindd_request_response(WINBINDD_LOOKUPNAME
, &request
, &response
) !=
397 NSS_STATUS_SUCCESS
) {
398 DEBUG(0, ("Winbindd lookupname failed to resolve %s into a SID!\n",
399 require_membership_of
));
403 require_membership_of_sid
= SMB_STRDUP(response
.data
.sid
.sid
);
405 if (require_membership_of_sid
)
412 * Get some configuration from pam_winbind.conf to see if we
413 * need to contact trusted domain
416 int get_pam_winbind_config()
419 dictionary
*d
= NULL
;
421 if (!opt_pam_winbind_conf
|| !*opt_pam_winbind_conf
) {
422 opt_pam_winbind_conf
= PAM_WINBIND_CONFIG_FILE
;
425 d
= iniparser_load(discard_const_p(char, opt_pam_winbind_conf
));
431 if (iniparser_getboolean(d
, discard_const_p(char, "global:krb5_auth"), false)) {
432 ctrl
|= WINBIND_KRB5_AUTH
;
435 iniparser_freedict(d
);
440 /* Authenticate a user with a plaintext password */
442 static bool check_plaintext_auth(const char *user
, const char *pass
,
443 bool stdout_diagnostics
)
445 struct winbindd_request request
;
446 struct winbindd_response response
;
449 if (!get_require_membership_sid()) {
453 /* Send off request */
455 ZERO_STRUCT(request
);
456 ZERO_STRUCT(response
);
458 fstrcpy(request
.data
.auth
.user
, user
);
459 fstrcpy(request
.data
.auth
.pass
, pass
);
460 if (require_membership_of_sid
) {
461 strlcpy(request
.data
.auth
.require_membership_of_sid
,
462 require_membership_of_sid
,
463 sizeof(request
.data
.auth
.require_membership_of_sid
));
466 result
= winbindd_request_response(WINBINDD_PAM_AUTH
, &request
, &response
);
468 /* Display response */
470 if (stdout_diagnostics
) {
471 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
472 d_printf("Reading winbind reply failed! (0x01)\n");
475 d_printf("%s: %s (0x%x)\n",
476 response
.data
.auth
.nt_status_string
,
477 response
.data
.auth
.error_string
,
478 response
.data
.auth
.nt_status
);
480 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
481 DEBUG(1, ("Reading winbind reply failed! (0x01)\n"));
484 DEBUG(3, ("%s: %s (0x%x)\n",
485 response
.data
.auth
.nt_status_string
,
486 response
.data
.auth
.error_string
,
487 response
.data
.auth
.nt_status
));
490 return (result
== NSS_STATUS_SUCCESS
);
493 /* authenticate a user with an encrypted username/password */
495 NTSTATUS
contact_winbind_auth_crap(const char *username
,
497 const char *workstation
,
498 const DATA_BLOB
*challenge
,
499 const DATA_BLOB
*lm_response
,
500 const DATA_BLOB
*nt_response
,
502 uint32 extra_logon_parameters
,
504 uint8 user_session_key
[16],
510 struct winbindd_request request
;
511 struct winbindd_response response
;
513 if (!get_require_membership_sid()) {
514 return NT_STATUS_INVALID_PARAMETER
;
517 ZERO_STRUCT(request
);
518 ZERO_STRUCT(response
);
520 request
.flags
= flags
;
522 request
.data
.auth_crap
.logon_parameters
= extra_logon_parameters
523 | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
| MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT
;
525 if (require_membership_of_sid
)
526 fstrcpy(request
.data
.auth_crap
.require_membership_of_sid
, require_membership_of_sid
);
528 fstrcpy(request
.data
.auth_crap
.user
, username
);
529 fstrcpy(request
.data
.auth_crap
.domain
, domain
);
531 fstrcpy(request
.data
.auth_crap
.workstation
,
534 memcpy(request
.data
.auth_crap
.chal
, challenge
->data
, MIN(challenge
->length
, 8));
536 if (lm_response
&& lm_response
->length
) {
537 memcpy(request
.data
.auth_crap
.lm_resp
,
539 MIN(lm_response
->length
, sizeof(request
.data
.auth_crap
.lm_resp
)));
540 request
.data
.auth_crap
.lm_resp_len
= lm_response
->length
;
543 if (nt_response
&& nt_response
->length
) {
544 if (nt_response
->length
> sizeof(request
.data
.auth_crap
.nt_resp
)) {
545 request
.flags
= request
.flags
| WBFLAG_BIG_NTLMV2_BLOB
;
546 request
.extra_len
= nt_response
->length
;
547 request
.extra_data
.data
= SMB_MALLOC_ARRAY(char, request
.extra_len
);
548 if (request
.extra_data
.data
== NULL
) {
549 return NT_STATUS_NO_MEMORY
;
551 memcpy(request
.extra_data
.data
, nt_response
->data
,
552 nt_response
->length
);
555 memcpy(request
.data
.auth_crap
.nt_resp
,
556 nt_response
->data
, nt_response
->length
);
558 request
.data
.auth_crap
.nt_resp_len
= nt_response
->length
;
561 result
= winbindd_request_response(WINBINDD_PAM_AUTH_CRAP
, &request
, &response
);
562 SAFE_FREE(request
.extra_data
.data
);
564 /* Display response */
566 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
567 nt_status
= NT_STATUS_UNSUCCESSFUL
;
569 *error_string
= smb_xstrdup("Reading winbind reply failed!");
570 winbindd_free_response(&response
);
574 nt_status
= (NT_STATUS(response
.data
.auth
.nt_status
));
575 if (!NT_STATUS_IS_OK(nt_status
)) {
577 *error_string
= smb_xstrdup(response
.data
.auth
.error_string
);
578 winbindd_free_response(&response
);
582 if ((flags
& WBFLAG_PAM_LMKEY
) && lm_key
) {
583 memcpy(lm_key
, response
.data
.auth
.first_8_lm_hash
,
584 sizeof(response
.data
.auth
.first_8_lm_hash
));
586 if ((flags
& WBFLAG_PAM_USER_SESSION_KEY
) && user_session_key
) {
587 memcpy(user_session_key
, response
.data
.auth
.user_session_key
,
588 sizeof(response
.data
.auth
.user_session_key
));
591 if (flags
& WBFLAG_PAM_UNIX_NAME
) {
592 *unix_name
= SMB_STRDUP(response
.data
.auth
.unix_username
);
594 winbindd_free_response(&response
);
595 return NT_STATUS_NO_MEMORY
;
599 winbindd_free_response(&response
);
603 /* contact server to change user password using auth crap */
604 static NTSTATUS
contact_winbind_change_pswd_auth_crap(const char *username
,
606 const DATA_BLOB new_nt_pswd
,
607 const DATA_BLOB old_nt_hash_enc
,
608 const DATA_BLOB new_lm_pswd
,
609 const DATA_BLOB old_lm_hash_enc
,
614 struct winbindd_request request
;
615 struct winbindd_response response
;
617 if (!get_require_membership_sid())
620 *error_string
= smb_xstrdup("Can't get membership sid.");
621 return NT_STATUS_INVALID_PARAMETER
;
624 ZERO_STRUCT(request
);
625 ZERO_STRUCT(response
);
628 fstrcpy(request
.data
.chng_pswd_auth_crap
.user
, username
);
630 fstrcpy(request
.data
.chng_pswd_auth_crap
.domain
,domain
);
632 if(new_nt_pswd
.length
)
634 memcpy(request
.data
.chng_pswd_auth_crap
.new_nt_pswd
, new_nt_pswd
.data
, sizeof(request
.data
.chng_pswd_auth_crap
.new_nt_pswd
));
635 request
.data
.chng_pswd_auth_crap
.new_nt_pswd_len
= new_nt_pswd
.length
;
638 if(old_nt_hash_enc
.length
)
640 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
));
641 request
.data
.chng_pswd_auth_crap
.old_nt_hash_enc_len
= old_nt_hash_enc
.length
;
644 if(new_lm_pswd
.length
)
646 memcpy(request
.data
.chng_pswd_auth_crap
.new_lm_pswd
, new_lm_pswd
.data
, sizeof(request
.data
.chng_pswd_auth_crap
.new_lm_pswd
));
647 request
.data
.chng_pswd_auth_crap
.new_lm_pswd_len
= new_lm_pswd
.length
;
650 if(old_lm_hash_enc
.length
)
652 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
));
653 request
.data
.chng_pswd_auth_crap
.old_lm_hash_enc_len
= old_lm_hash_enc
.length
;
656 result
= winbindd_request_response(WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP
, &request
, &response
);
658 /* Display response */
660 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0))
662 nt_status
= NT_STATUS_UNSUCCESSFUL
;
664 *error_string
= smb_xstrdup("Reading winbind reply failed!");
665 winbindd_free_response(&response
);
669 nt_status
= (NT_STATUS(response
.data
.auth
.nt_status
));
670 if (!NT_STATUS_IS_OK(nt_status
))
673 *error_string
= smb_xstrdup(response
.data
.auth
.error_string
);
674 winbindd_free_response(&response
);
678 winbindd_free_response(&response
);
683 static NTSTATUS
ntlm_auth_generate_session_info(struct auth4_context
*auth_context
,
685 void *server_returned_info
,
686 const char *original_user_name
,
687 uint32_t session_info_flags
,
688 struct auth_session_info
**session_info_out
)
690 char *unix_username
= (char *)server_returned_info
;
691 struct auth_session_info
*session_info
= talloc_zero(mem_ctx
, struct auth_session_info
);
693 return NT_STATUS_NO_MEMORY
;
696 session_info
->unix_info
= talloc_zero(session_info
, struct auth_user_info_unix
);
697 if (!session_info
->unix_info
) {
698 TALLOC_FREE(session_info
);
699 return NT_STATUS_NO_MEMORY
;
701 session_info
->unix_info
->unix_name
= talloc_steal(session_info
->unix_info
, unix_username
);
703 *session_info_out
= session_info
;
708 static NTSTATUS
ntlm_auth_generate_session_info_pac(struct auth4_context
*auth_ctx
,
710 struct smb_krb5_context
*smb_krb5_context
,
712 const char *princ_name
,
713 const struct tsocket_address
*remote_address
,
714 uint32_t session_info_flags
,
715 struct auth_session_info
**session_info
)
718 struct PAC_LOGON_INFO
*logon_info
= NULL
;
726 tmp_ctx
= talloc_new(mem_ctx
);
728 return NT_STATUS_NO_MEMORY
;
733 status
= kerberos_pac_logon_info(tmp_ctx
, *pac_blob
, NULL
, NULL
,
734 NULL
, NULL
, 0, &logon_info
);
736 status
= NT_STATUS_ACCESS_DENIED
;
738 if (!NT_STATUS_IS_OK(status
)) {
743 DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name
));
745 p
= strchr_m(princ_name
, '@');
747 DEBUG(3, ("[%s] Doesn't look like a valid principal\n",
749 return NT_STATUS_LOGON_FAILURE
;
752 user
= talloc_strndup(mem_ctx
, princ_name
, p
- princ_name
);
754 return NT_STATUS_NO_MEMORY
;
757 realm
= talloc_strdup(talloc_tos(), p
+ 1);
759 return NT_STATUS_NO_MEMORY
;
762 if (!strequal(realm
, lp_realm())) {
763 DEBUG(3, ("Ticket for foreign realm %s@%s\n", user
, realm
));
764 if (!lp_allow_trusted_domains()) {
765 return NT_STATUS_LOGON_FAILURE
;
769 if (logon_info
&& logon_info
->info3
.base
.logon_domain
.string
) {
770 domain
= talloc_strdup(mem_ctx
,
771 logon_info
->info3
.base
.logon_domain
.string
);
773 return NT_STATUS_NO_MEMORY
;
775 DEBUG(10, ("Domain is [%s] (using PAC)\n", domain
));
778 /* If we have winbind running, we can (and must) shorten the
779 username by using the short netbios name. Otherwise we will
780 have inconsistent user names. With Kerberos, we get the
781 fully qualified realm, with ntlmssp we get the short
782 name. And even w2k3 does use ntlmssp if you for example
783 connect to an ip address. */
786 struct wbcDomainInfo
*info
= NULL
;
788 DEBUG(10, ("Mapping [%s] to short name using winbindd\n",
791 wbc_status
= wbcDomainInfo(realm
, &info
);
793 if (WBC_ERROR_IS_OK(wbc_status
)) {
794 domain
= talloc_strdup(mem_ctx
,
798 DEBUG(3, ("Could not find short name: %s\n",
799 wbcErrorString(wbc_status
)));
800 domain
= talloc_strdup(mem_ctx
, realm
);
803 return NT_STATUS_NO_MEMORY
;
805 DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain
));
808 unixuser
= talloc_asprintf(tmp_ctx
, "%s%c%s", domain
, winbind_separator(), user
);
810 status
= NT_STATUS_NO_MEMORY
;
814 status
= ntlm_auth_generate_session_info(auth_ctx
, mem_ctx
, unixuser
, NULL
, session_info_flags
, session_info
);
817 TALLOC_FREE(tmp_ctx
);
824 * Return the challenge as determined by the authentication subsystem
825 * @return an 8 byte random challenge
828 static NTSTATUS
ntlm_auth_get_challenge(struct auth4_context
*auth_ctx
,
831 if (auth_ctx
->challenge
.data
.length
== 8) {
832 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
833 auth_ctx
->challenge
.set_by
));
834 memcpy(chal
, auth_ctx
->challenge
.data
.data
, 8);
838 if (!auth_ctx
->challenge
.set_by
) {
839 generate_random_buffer(chal
, 8);
841 auth_ctx
->challenge
.data
= data_blob_talloc(auth_ctx
, chal
, 8);
842 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.data
.data
);
843 auth_ctx
->challenge
.set_by
= "random";
846 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
847 auth_ctx
->challenge
.set_by
));
853 * NTLM2 authentication modifies the effective challenge,
854 * @param challenge The new challenge value
856 static NTSTATUS
ntlm_auth_set_challenge(struct auth4_context
*auth_ctx
, const uint8_t chal
[8], const char *set_by
)
858 auth_ctx
->challenge
.set_by
= talloc_strdup(auth_ctx
, set_by
);
859 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.set_by
);
861 auth_ctx
->challenge
.data
= data_blob_talloc(auth_ctx
, chal
, 8);
862 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.data
.data
);
868 * Check the password on an NTLMSSP login.
870 * Return the session keys used on the connection.
873 static NTSTATUS
winbind_pw_check(struct auth4_context
*auth4_context
,
875 const struct auth_usersupplied_info
*user_info
,
876 void **server_returned_info
,
877 DATA_BLOB
*session_key
, DATA_BLOB
*lm_session_key
)
879 static const char zeros
[16] = { 0, };
881 char *error_string
= NULL
;
883 uint8 user_sess_key
[16];
884 char *unix_name
= NULL
;
886 nt_status
= contact_winbind_auth_crap(user_info
->client
.account_name
, user_info
->client
.domain_name
,
887 user_info
->workstation_name
,
888 &auth4_context
->challenge
.data
,
889 &user_info
->password
.response
.lanman
,
890 &user_info
->password
.response
.nt
,
891 WBFLAG_PAM_LMKEY
| WBFLAG_PAM_USER_SESSION_KEY
| WBFLAG_PAM_UNIX_NAME
,
893 lm_key
, user_sess_key
,
894 &error_string
, &unix_name
);
896 if (NT_STATUS_IS_OK(nt_status
)) {
897 if (memcmp(lm_key
, zeros
, 8) != 0) {
898 *lm_session_key
= data_blob_talloc(mem_ctx
, NULL
, 16);
899 memcpy(lm_session_key
->data
, lm_key
, 8);
900 memset(lm_session_key
->data
+8, '\0', 8);
903 if (memcmp(user_sess_key
, zeros
, 16) != 0) {
904 *session_key
= data_blob_talloc(mem_ctx
, user_sess_key
, 16);
906 *server_returned_info
= talloc_strdup(mem_ctx
,
909 DEBUG(NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCESS_DENIED
) ? 0 : 3,
910 ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
911 user_info
->client
.domain_name
, user_info
->client
.account_name
,
912 user_info
->workstation_name
,
913 error_string
? error_string
: "unknown error (NULL)"));
916 SAFE_FREE(error_string
);
917 SAFE_FREE(unix_name
);
921 static NTSTATUS
local_pw_check(struct auth4_context
*auth4_context
,
923 const struct auth_usersupplied_info
*user_info
,
924 void **server_returned_info
,
925 DATA_BLOB
*session_key
, DATA_BLOB
*lm_session_key
)
928 struct samr_Password lm_pw
, nt_pw
;
930 nt_lm_owf_gen (opt_password
, nt_pw
.hash
, lm_pw
.hash
);
932 nt_status
= ntlm_password_check(mem_ctx
,
934 &auth4_context
->challenge
.data
,
935 &user_info
->password
.response
.lanman
,
936 &user_info
->password
.response
.nt
,
937 user_info
->client
.account_name
,
938 user_info
->client
.account_name
,
939 user_info
->client
.domain_name
,
940 &lm_pw
, &nt_pw
, session_key
, lm_session_key
);
942 if (NT_STATUS_IS_OK(nt_status
)) {
943 *server_returned_info
= talloc_asprintf(mem_ctx
,
944 "%s%c%s", user_info
->client
.domain_name
,
945 *lp_winbind_separator(),
946 user_info
->client
.account_name
);
948 DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
949 user_info
->client
.domain_name
, user_info
->client
.account_name
,
950 user_info
->workstation_name
,
951 nt_errstr(nt_status
)));
956 static NTSTATUS
ntlm_auth_start_ntlmssp_client(struct ntlmssp_state
**client_ntlmssp_state
)
959 if ( (opt_username
== NULL
) || (opt_domain
== NULL
) ) {
960 status
= NT_STATUS_UNSUCCESSFUL
;
961 DEBUG(1, ("Need username and domain for NTLMSSP\n"));
962 return NT_STATUS_INVALID_PARAMETER
;
965 status
= ntlmssp_client_start(NULL
,
968 lp_client_ntlmv2_auth(),
969 client_ntlmssp_state
);
971 if (!NT_STATUS_IS_OK(status
)) {
972 DEBUG(1, ("Could not start NTLMSSP client: %s\n",
974 TALLOC_FREE(*client_ntlmssp_state
);
978 status
= ntlmssp_set_username(*client_ntlmssp_state
, opt_username
);
980 if (!NT_STATUS_IS_OK(status
)) {
981 DEBUG(1, ("Could not set username: %s\n",
983 TALLOC_FREE(*client_ntlmssp_state
);
987 status
= ntlmssp_set_domain(*client_ntlmssp_state
, opt_domain
);
989 if (!NT_STATUS_IS_OK(status
)) {
990 DEBUG(1, ("Could not set domain: %s\n",
992 TALLOC_FREE(*client_ntlmssp_state
);
997 status
= ntlmssp_set_password(*client_ntlmssp_state
, opt_password
);
999 if (!NT_STATUS_IS_OK(status
)) {
1000 DEBUG(1, ("Could not set password: %s\n",
1001 nt_errstr(status
)));
1002 TALLOC_FREE(*client_ntlmssp_state
);
1007 return NT_STATUS_OK
;
1010 static struct auth4_context
*make_auth4_context_ntlm_auth(TALLOC_CTX
*mem_ctx
, bool local_pw
)
1012 struct auth4_context
*auth4_context
= talloc_zero(mem_ctx
, struct auth4_context
);
1013 if (auth4_context
== NULL
) {
1014 DEBUG(10, ("failed to allocate auth4_context failed\n"));
1017 auth4_context
->generate_session_info
= ntlm_auth_generate_session_info
;
1018 auth4_context
->generate_session_info_pac
= ntlm_auth_generate_session_info_pac
;
1019 auth4_context
->get_ntlm_challenge
= ntlm_auth_get_challenge
;
1020 auth4_context
->set_ntlm_challenge
= ntlm_auth_set_challenge
;
1022 auth4_context
->check_ntlm_password
= local_pw_check
;
1024 auth4_context
->check_ntlm_password
= winbind_pw_check
;
1026 auth4_context
->private_data
= NULL
;
1027 return auth4_context
;
1030 static NTSTATUS
ntlm_auth_start_ntlmssp_server(TALLOC_CTX
*mem_ctx
,
1031 struct loadparm_context
*lp_ctx
,
1032 struct gensec_security
**gensec_security_out
)
1034 struct gensec_security
*gensec_security
;
1037 TALLOC_CTX
*tmp_ctx
;
1039 struct gensec_settings
*gensec_settings
;
1041 struct cli_credentials
*server_credentials
;
1043 struct auth4_context
*auth4_context
;
1045 tmp_ctx
= talloc_new(mem_ctx
);
1046 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx
);
1048 auth4_context
= make_auth4_context_ntlm_auth(tmp_ctx
, opt_password
);
1049 if (auth4_context
== NULL
) {
1050 TALLOC_FREE(tmp_ctx
);
1051 return NT_STATUS_NO_MEMORY
;
1054 gensec_settings
= lpcfg_gensec_settings(tmp_ctx
, lp_ctx
);
1055 if (lp_ctx
== NULL
) {
1056 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1057 TALLOC_FREE(tmp_ctx
);
1058 return NT_STATUS_NO_MEMORY
;
1062 * This should be a 'netbios domain -> DNS domain'
1063 * mapping, and can currently validly return NULL on
1064 * poorly configured systems.
1066 * This is used for the NTLMSSP server
1070 gensec_settings
->server_netbios_name
= lp_netbios_name();
1071 gensec_settings
->server_netbios_domain
= lp_workgroup();
1073 gensec_settings
->server_netbios_name
= get_winbind_netbios_name();
1074 gensec_settings
->server_netbios_domain
= get_winbind_domain();
1077 gensec_settings
->server_dns_domain
= strlower_talloc(gensec_settings
,
1078 get_mydnsdomname(talloc_tos()));
1079 gensec_settings
->server_dns_name
= strlower_talloc(gensec_settings
,
1080 get_mydnsfullname());
1082 gensec_settings
->backends
= talloc_zero_array(gensec_settings
,
1083 struct gensec_security_ops
*, 4);
1085 if (gensec_settings
->backends
== NULL
) {
1086 TALLOC_FREE(tmp_ctx
);
1087 return NT_STATUS_NO_MEMORY
;
1092 /* These need to be in priority order, krb5 before NTLMSSP */
1093 #if defined(HAVE_KRB5)
1094 gensec_settings
->backends
[idx
++] = &gensec_gse_krb5_security_ops
;
1097 gensec_settings
->backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_NTLMSSP
);
1099 gensec_settings
->backends
[idx
++] = gensec_security_by_oid(NULL
,
1103 * This is anonymous for now, because we just use it
1104 * to set the kerberos state at the moment
1106 server_credentials
= cli_credentials_init_anon(tmp_ctx
);
1107 if (!server_credentials
) {
1108 DEBUG(0, ("auth_generic_prepare: Failed to init server credentials\n"));
1109 return NT_STATUS_NO_MEMORY
;
1112 cli_credentials_set_conf(server_credentials
, lp_ctx
);
1114 if (lp_security() == SEC_ADS
|| USE_KERBEROS_KEYTAB
) {
1115 cli_credentials_set_kerberos_state(server_credentials
, CRED_AUTO_USE_KERBEROS
);
1117 cli_credentials_set_kerberos_state(server_credentials
, CRED_DONT_USE_KERBEROS
);
1120 nt_status
= gensec_server_start(tmp_ctx
, gensec_settings
,
1121 auth4_context
, &gensec_security
);
1123 if (!NT_STATUS_IS_OK(nt_status
)) {
1124 TALLOC_FREE(tmp_ctx
);
1128 gensec_set_credentials(gensec_security
, server_credentials
);
1130 gensec_want_feature(gensec_security
, GENSEC_FEATURE_SIGN
);
1131 gensec_want_feature(gensec_security
, GENSEC_FEATURE_SEAL
);
1133 talloc_unlink(tmp_ctx
, lp_ctx
);
1134 talloc_unlink(tmp_ctx
, server_credentials
);
1135 talloc_unlink(tmp_ctx
, gensec_settings
);
1136 talloc_unlink(tmp_ctx
, auth4_context
);
1138 nt_status
= gensec_start_mech_by_oid(gensec_security
, GENSEC_OID_NTLMSSP
);
1139 if (!NT_STATUS_IS_OK(nt_status
)) {
1140 TALLOC_FREE(tmp_ctx
);
1144 *gensec_security_out
= talloc_steal(mem_ctx
, gensec_security
);
1145 TALLOC_FREE(tmp_ctx
);
1146 return NT_STATUS_OK
;
1149 /*******************************************************************
1150 Used by firefox to drive NTLM auth to IIS servers.
1151 *******************************************************************/
1153 static NTSTATUS
do_ccache_ntlm_auth(DATA_BLOB initial_msg
, DATA_BLOB challenge_msg
,
1156 struct winbindd_request wb_request
;
1157 struct winbindd_response wb_response
;
1161 /* get winbindd to do the ntlmssp step on our behalf */
1162 ZERO_STRUCT(wb_request
);
1163 ZERO_STRUCT(wb_response
);
1166 * This is tricky here. If we set krb5_auth in pam_winbind.conf
1167 * creds for users in trusted domain will be stored the winbindd
1168 * child of the trusted domain. If we ask the primary domain for
1169 * ntlm_ccache_auth, it will fail. So, we have to ask the trusted
1170 * domain's child for ccache_ntlm_auth. that is to say, we have to
1171 * set WBFLAG_PAM_CONTACT_TRUSTDOM in request.flags.
1173 ctrl
= get_pam_winbind_config();
1175 if (ctrl
& WINBIND_KRB5_AUTH
) {
1176 wb_request
.flags
|= WBFLAG_PAM_CONTACT_TRUSTDOM
;
1179 fstr_sprintf(wb_request
.data
.ccache_ntlm_auth
.user
,
1180 "%s%c%s", opt_domain
, winbind_separator(), opt_username
);
1181 wb_request
.data
.ccache_ntlm_auth
.uid
= geteuid();
1182 wb_request
.data
.ccache_ntlm_auth
.initial_blob_len
= initial_msg
.length
;
1183 wb_request
.data
.ccache_ntlm_auth
.challenge_blob_len
= challenge_msg
.length
;
1184 wb_request
.extra_len
= initial_msg
.length
+ challenge_msg
.length
;
1186 if (wb_request
.extra_len
> 0) {
1187 wb_request
.extra_data
.data
= SMB_MALLOC_ARRAY(char, wb_request
.extra_len
);
1188 if (wb_request
.extra_data
.data
== NULL
) {
1189 return NT_STATUS_NO_MEMORY
;
1192 memcpy(wb_request
.extra_data
.data
, initial_msg
.data
, initial_msg
.length
);
1193 memcpy(wb_request
.extra_data
.data
+ initial_msg
.length
,
1194 challenge_msg
.data
, challenge_msg
.length
);
1197 result
= winbindd_request_response(WINBINDD_CCACHE_NTLMAUTH
, &wb_request
, &wb_response
);
1198 SAFE_FREE(wb_request
.extra_data
.data
);
1200 if (result
!= NSS_STATUS_SUCCESS
) {
1201 winbindd_free_response(&wb_response
);
1202 return NT_STATUS_UNSUCCESSFUL
;
1206 *reply
= data_blob(wb_response
.extra_data
.data
,
1207 wb_response
.data
.ccache_ntlm_auth
.auth_blob_len
);
1208 if (wb_response
.data
.ccache_ntlm_auth
.auth_blob_len
> 0 &&
1209 reply
->data
== NULL
) {
1210 winbindd_free_response(&wb_response
);
1211 return NT_STATUS_NO_MEMORY
;
1215 winbindd_free_response(&wb_response
);
1216 return NT_STATUS_MORE_PROCESSING_REQUIRED
;
1219 static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode
,
1220 struct loadparm_context
*lp_ctx
,
1221 struct ntlm_auth_state
*state
,
1222 char *buf
, int length
, void **private2
)
1224 DATA_BLOB request
, reply
;
1227 if (!opt_username
|| !*opt_username
) {
1228 x_fprintf(x_stderr
, "username must be specified!\n\n");
1232 if (strlen(buf
) < 2) {
1233 DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf
));
1234 x_fprintf(x_stdout
, "BH NTLMSSP query invalid\n");
1238 if (strlen(buf
) > 3) {
1239 if(strncmp(buf
, "SF ", 3) == 0) {
1240 DEBUG(10, ("Looking for flags to negotiate\n"));
1241 talloc_free(state
->want_feature_list
);
1242 state
->want_feature_list
= talloc_strdup(state
->mem_ctx
,
1244 x_fprintf(x_stdout
, "OK\n");
1247 request
= base64_decode_data_blob(buf
+ 3);
1249 request
= data_blob_null
;
1252 if (strncmp(buf
, "PW ", 3) == 0) {
1253 /* We asked for a password and obviously got it :-) */
1255 opt_password
= SMB_STRNDUP((const char *)request
.data
,
1258 if (opt_password
== NULL
) {
1259 DEBUG(1, ("Out of memory\n"));
1260 x_fprintf(x_stdout
, "BH Out of memory\n");
1261 data_blob_free(&request
);
1265 x_fprintf(x_stdout
, "OK\n");
1266 data_blob_free(&request
);
1270 if (!state
->ntlmssp_state
&& use_cached_creds
) {
1271 /* check whether cached credentials are usable. */
1272 DATA_BLOB empty_blob
= data_blob_null
;
1274 nt_status
= do_ccache_ntlm_auth(empty_blob
, empty_blob
, NULL
);
1275 if (!NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1276 /* failed to use cached creds */
1277 use_cached_creds
= False
;
1281 if (opt_password
== NULL
&& !use_cached_creds
) {
1282 /* Request a password from the calling process. After
1283 sending it, the calling process should retry asking for the
1286 DEBUG(10, ("Requesting password\n"));
1287 x_fprintf(x_stdout
, "PW\n");
1291 if (strncmp(buf
, "YR", 2) == 0) {
1292 TALLOC_FREE(state
->ntlmssp_state
);
1293 state
->cli_state
= CLIENT_INITIAL
;
1294 } else if (strncmp(buf
, "TT", 2) == 0) {
1295 /* No special preprocessing required */
1296 } else if (strncmp(buf
, "GF", 2) == 0) {
1297 DEBUG(10, ("Requested negotiated NTLMSSP flags\n"));
1299 if(state
->cli_state
== CLIENT_FINISHED
) {
1300 x_fprintf(x_stdout
, "GF 0x%08x\n", state
->neg_flags
);
1303 x_fprintf(x_stdout
, "BH\n");
1306 data_blob_free(&request
);
1308 } else if (strncmp(buf
, "GK", 2) == 0 ) {
1309 DEBUG(10, ("Requested session key\n"));
1311 if(state
->cli_state
== CLIENT_FINISHED
) {
1312 char *key64
= base64_encode_data_blob(state
->mem_ctx
,
1313 state
->session_key
);
1314 x_fprintf(x_stdout
, "GK %s\n", key64
?key64
:"<NULL>");
1318 x_fprintf(x_stdout
, "BH\n");
1321 data_blob_free(&request
);
1324 DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf
));
1325 x_fprintf(x_stdout
, "BH NTLMSSP query invalid\n");
1329 if (!state
->ntlmssp_state
) {
1330 nt_status
= ntlm_auth_start_ntlmssp_client(
1331 &state
->ntlmssp_state
);
1332 if (!NT_STATUS_IS_OK(nt_status
)) {
1333 x_fprintf(x_stdout
, "BH %s\n", nt_errstr(nt_status
));
1336 ntlmssp_want_feature_list(state
->ntlmssp_state
,
1337 state
->want_feature_list
);
1338 state
->initial_message
= data_blob_null
;
1341 DEBUG(10, ("got NTLMSSP packet:\n"));
1342 dump_data(10, request
.data
, request
.length
);
1344 if (use_cached_creds
&& !opt_password
&&
1345 (state
->cli_state
== CLIENT_RESPONSE
)) {
1346 nt_status
= do_ccache_ntlm_auth(state
->initial_message
, request
,
1349 nt_status
= ntlmssp_update(state
->ntlmssp_state
, request
,
1353 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1354 char *reply_base64
= base64_encode_data_blob(state
->mem_ctx
,
1356 if (state
->cli_state
== CLIENT_INITIAL
) {
1357 x_fprintf(x_stdout
, "YR %s\n", reply_base64
);
1358 state
->initial_message
= reply
;
1359 state
->cli_state
= CLIENT_RESPONSE
;
1361 x_fprintf(x_stdout
, "KK %s\n", reply_base64
);
1362 data_blob_free(&reply
);
1364 TALLOC_FREE(reply_base64
);
1365 DEBUG(10, ("NTLMSSP challenge\n"));
1366 } else if (NT_STATUS_IS_OK(nt_status
)) {
1367 char *reply_base64
= base64_encode_data_blob(talloc_tos(),
1369 x_fprintf(x_stdout
, "AF %s\n", reply_base64
);
1370 TALLOC_FREE(reply_base64
);
1372 if(state
->have_session_key
)
1373 data_blob_free(&state
->session_key
);
1375 state
->session_key
= data_blob(
1376 state
->ntlmssp_state
->session_key
.data
,
1377 state
->ntlmssp_state
->session_key
.length
);
1378 state
->neg_flags
= state
->ntlmssp_state
->neg_flags
;
1379 state
->have_session_key
= true;
1381 DEBUG(10, ("NTLMSSP OK!\n"));
1382 state
->cli_state
= CLIENT_FINISHED
;
1383 TALLOC_FREE(state
->ntlmssp_state
);
1385 x_fprintf(x_stdout
, "BH %s\n", nt_errstr(nt_status
));
1386 DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status
)));
1387 state
->cli_state
= CLIENT_ERROR
;
1388 TALLOC_FREE(state
->ntlmssp_state
);
1391 data_blob_free(&request
);
1394 static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode
,
1395 struct loadparm_context
*lp_ctx
,
1396 struct ntlm_auth_state
*state
,
1397 char *buf
, int length
, void **private2
)
1402 pass
=(char *)memchr(buf
,' ',length
);
1404 DEBUG(2, ("Password not found. Denying access\n"));
1405 x_fprintf(x_stdout
, "ERR\n");
1411 if (state
->helper_mode
== SQUID_2_5_BASIC
) {
1412 rfc1738_unescape(user
);
1413 rfc1738_unescape(pass
);
1416 if (check_plaintext_auth(user
, pass
, False
)) {
1417 x_fprintf(x_stdout
, "OK\n");
1419 x_fprintf(x_stdout
, "ERR\n");
1423 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode
,
1424 struct loadparm_context
*lp_ctx
,
1425 char *buf
, int length
, void **private1
)
1428 DATA_BLOB out
= data_blob(NULL
, 0);
1429 char *out_base64
= NULL
;
1430 const char *reply_arg
= NULL
;
1431 struct gensec_ntlm_state
{
1432 struct gensec_security
*gensec_state
;
1433 const char *set_password
;
1435 struct gensec_ntlm_state
*state
;
1439 const char *reply_code
;
1440 struct cli_credentials
*creds
;
1442 static char *want_feature_list
= NULL
;
1443 static DATA_BLOB session_key
;
1445 TALLOC_CTX
*mem_ctx
;
1448 state
= (struct gensec_ntlm_state
*)*private1
;
1450 state
= talloc_zero(NULL
, struct gensec_ntlm_state
);
1452 x_fprintf(x_stdout
, "BH No Memory\n");
1457 state
->set_password
= opt_password
;
1461 if (strlen(buf
) < 2) {
1462 DEBUG(1, ("query [%s] invalid", buf
));
1463 x_fprintf(x_stdout
, "BH Query invalid\n");
1467 if (strlen(buf
) > 3) {
1468 if(strncmp(buf
, "SF ", 3) == 0) {
1469 DEBUG(10, ("Setting flags to negotiate\n"));
1470 talloc_free(want_feature_list
);
1471 want_feature_list
= talloc_strndup(state
, buf
+3, strlen(buf
)-3);
1472 x_fprintf(x_stdout
, "OK\n");
1475 in
= base64_decode_data_blob(buf
+ 3);
1477 in
= data_blob(NULL
, 0);
1480 if (strncmp(buf
, "YR", 2) == 0) {
1481 if (state
->gensec_state
) {
1482 talloc_free(state
->gensec_state
);
1483 state
->gensec_state
= NULL
;
1485 } else if ( (strncmp(buf
, "OK", 2) == 0)) {
1486 /* Just return BH, like ntlm_auth from Samba 3 does. */
1487 x_fprintf(x_stdout
, "BH Command expected\n");
1488 data_blob_free(&in
);
1490 } else if ( (strncmp(buf
, "TT ", 3) != 0) &&
1491 (strncmp(buf
, "KK ", 3) != 0) &&
1492 (strncmp(buf
, "AF ", 3) != 0) &&
1493 (strncmp(buf
, "NA ", 3) != 0) &&
1494 (strncmp(buf
, "UG", 2) != 0) &&
1495 (strncmp(buf
, "PW ", 3) != 0) &&
1496 (strncmp(buf
, "GK", 2) != 0) &&
1497 (strncmp(buf
, "GF", 2) != 0)) {
1498 DEBUG(1, ("SPNEGO request [%s] invalid prefix\n", buf
));
1499 x_fprintf(x_stdout
, "BH SPNEGO request invalid prefix\n");
1500 data_blob_free(&in
);
1504 mem_ctx
= talloc_named(NULL
, 0, "manage_gensec_request internal mem_ctx");
1507 if (!(state
->gensec_state
)) {
1508 switch (stdio_helper_mode
) {
1509 case GSS_SPNEGO_CLIENT
:
1510 case NTLMSSP_CLIENT_1
:
1511 /* setup the client side */
1513 nt_status
= gensec_client_start(NULL
, &state
->gensec_state
,
1514 lpcfg_gensec_settings(NULL
, lp_ctx
));
1515 if (!NT_STATUS_IS_OK(nt_status
)) {
1516 x_fprintf(x_stdout
, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status
));
1517 talloc_free(mem_ctx
);
1521 creds
= cli_credentials_init(state
->gensec_state
);
1522 cli_credentials_set_conf(creds
, lp_ctx
);
1524 cli_credentials_set_username(creds
, opt_username
, CRED_SPECIFIED
);
1527 cli_credentials_set_domain(creds
, opt_domain
, CRED_SPECIFIED
);
1529 if (state
->set_password
) {
1530 cli_credentials_set_password(creds
, state
->set_password
, CRED_SPECIFIED
);
1532 cli_credentials_set_password_callback(creds
, get_password
);
1534 if (opt_workstation
) {
1535 cli_credentials_set_workstation(creds
, opt_workstation
, CRED_SPECIFIED
);
1538 gensec_set_credentials(state
->gensec_state
, creds
);
1541 case GSS_SPNEGO_SERVER
:
1542 case SQUID_2_5_NTLMSSP
:
1544 nt_status
= ntlm_auth_start_ntlmssp_server(state
, lp_ctx
,
1545 &state
->gensec_state
);
1546 if (!NT_STATUS_IS_OK(nt_status
)) {
1547 x_fprintf(x_stdout
, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status
));
1548 talloc_free(mem_ctx
);
1554 talloc_free(mem_ctx
);
1558 gensec_want_feature_list(state
->gensec_state
, want_feature_list
);
1560 switch (stdio_helper_mode
) {
1561 case GSS_SPNEGO_CLIENT
:
1562 case GSS_SPNEGO_SERVER
:
1563 nt_status
= gensec_start_mech_by_oid(state
->gensec_state
, GENSEC_OID_SPNEGO
);
1568 case NTLMSSP_CLIENT_1
:
1573 case SQUID_2_5_NTLMSSP
:
1574 nt_status
= gensec_start_mech_by_oid(state
->gensec_state
, GENSEC_OID_NTLMSSP
);
1577 talloc_free(mem_ctx
);
1581 if (!NT_STATUS_IS_OK(nt_status
)) {
1582 DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status
)));
1583 x_fprintf(x_stdout
, "BH GENSEC mech failed to start\n");
1584 talloc_free(mem_ctx
);
1592 if (strncmp(buf
, "PW ", 3) == 0) {
1593 state
->set_password
= talloc_strndup(state
,
1594 (const char *)in
.data
,
1597 cli_credentials_set_password(gensec_get_credentials(state
->gensec_state
),
1598 state
->set_password
,
1600 x_fprintf(x_stdout
, "OK\n");
1601 data_blob_free(&in
);
1602 talloc_free(mem_ctx
);
1606 if (strncmp(buf
, "GK", 2) == 0) {
1608 DEBUG(10, ("Requested session key\n"));
1609 nt_status
= gensec_session_key(state
->gensec_state
, mem_ctx
, &session_key
);
1610 if(!NT_STATUS_IS_OK(nt_status
)) {
1611 DEBUG(1, ("gensec_session_key failed: %s\n", nt_errstr(nt_status
)));
1612 x_fprintf(x_stdout
, "BH No session key\n");
1613 talloc_free(mem_ctx
);
1616 base64_key
= base64_encode_data_blob(state
, session_key
);
1617 x_fprintf(x_stdout
, "GK %s\n", base64_key
);
1618 talloc_free(base64_key
);
1620 talloc_free(mem_ctx
);
1624 if (stdio_helper_mode
== SQUID_2_5_NTLMSSP
&& strncmp(buf
, "GF", 2) == 0) {
1627 neg_flags
= gensec_ntlmssp_neg_flags(state
->gensec_state
);
1629 DEBUG(10, ("Requested negotiated feature flags\n"));
1630 x_fprintf(x_stdout
, "GF 0x%08x\n", neg_flags
);
1634 nt_status
= gensec_update(state
->gensec_state
, mem_ctx
, NULL
, in
, &out
);
1636 /* don't leak 'bad password'/'no such user' info to the network client */
1637 nt_status
= nt_status_squash(nt_status
);
1640 out_base64
= base64_encode_data_blob(mem_ctx
, out
);
1645 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1647 if (first
&& state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1649 } else if (state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1651 } else if (state
->gensec_state
->gensec_role
== GENSEC_SERVER
) {
1658 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCESS_DENIED
)) {
1659 reply_code
= "BH NT_STATUS_ACCESS_DENIED";
1660 reply_arg
= nt_errstr(nt_status
);
1661 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1662 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_UNSUCCESSFUL
)) {
1663 reply_code
= "BH NT_STATUS_UNSUCCESSFUL";
1664 reply_arg
= nt_errstr(nt_status
);
1665 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1666 } else if (!NT_STATUS_IS_OK(nt_status
)) {
1668 reply_arg
= nt_errstr(nt_status
);
1669 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1670 } else if /* OK */ (state
->gensec_state
->gensec_role
== GENSEC_SERVER
) {
1671 struct auth_session_info
*session_info
;
1673 nt_status
= gensec_session_info(state
->gensec_state
, mem_ctx
, &session_info
);
1674 if (!NT_STATUS_IS_OK(nt_status
)) {
1675 reply_code
= "BH Failed to retrive session info";
1676 reply_arg
= nt_errstr(nt_status
);
1677 DEBUG(1, ("GENSEC failed to retrieve the session info: %s\n", nt_errstr(nt_status
)));
1681 reply_arg
= session_info
->unix_info
->unix_name
;
1682 talloc_free(session_info
);
1684 } else if (state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1686 reply_arg
= out_base64
;
1691 switch (stdio_helper_mode
) {
1692 case GSS_SPNEGO_SERVER
:
1693 x_fprintf(x_stdout
, "%s %s %s\n", reply_code
,
1694 out_base64
? out_base64
: "*",
1695 reply_arg
? reply_arg
: "*");
1699 x_fprintf(x_stdout
, "%s %s\n", reply_code
, out_base64
);
1700 } else if (reply_arg
) {
1701 x_fprintf(x_stdout
, "%s %s\n", reply_code
, reply_arg
);
1703 x_fprintf(x_stdout
, "%s\n", reply_code
);
1707 talloc_free(mem_ctx
);
1711 static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode
,
1712 struct loadparm_context
*lp_ctx
,
1713 struct ntlm_auth_state
*state
,
1714 char *buf
, int length
, void **private2
)
1716 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1720 static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode
,
1721 struct loadparm_context
*lp_ctx
,
1722 struct ntlm_auth_state
*state
,
1723 char *buf
, int length
, void **private2
)
1725 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1729 static struct ntlmssp_state
*client_ntlmssp_state
= NULL
;
1731 static bool manage_client_ntlmssp_init(struct spnego_data spnego
)
1734 DATA_BLOB null_blob
= data_blob_null
;
1735 DATA_BLOB to_server
;
1736 char *to_server_base64
;
1737 const char *my_mechs
[] = {OID_NTLMSSP
, NULL
};
1738 TALLOC_CTX
*ctx
= talloc_tos();
1740 DEBUG(10, ("Got spnego negTokenInit with NTLMSSP\n"));
1742 if (client_ntlmssp_state
!= NULL
) {
1743 DEBUG(1, ("Request for initial SPNEGO request where "
1744 "we already have a state\n"));
1748 if (!client_ntlmssp_state
) {
1749 if (!NT_STATUS_IS_OK(status
= ntlm_auth_start_ntlmssp_client(&client_ntlmssp_state
))) {
1750 x_fprintf(x_stdout
, "BH %s\n", nt_errstr(status
));
1756 if (opt_password
== NULL
) {
1758 /* Request a password from the calling process. After
1759 sending it, the calling process should retry with
1760 the negTokenInit. */
1762 DEBUG(10, ("Requesting password\n"));
1763 x_fprintf(x_stdout
, "PW\n");
1767 spnego
.type
= SPNEGO_NEG_TOKEN_INIT
;
1768 spnego
.negTokenInit
.mechTypes
= my_mechs
;
1769 spnego
.negTokenInit
.reqFlags
= data_blob_null
;
1770 spnego
.negTokenInit
.reqFlagsPadding
= 0;
1771 spnego
.negTokenInit
.mechListMIC
= null_blob
;
1773 status
= ntlmssp_update(client_ntlmssp_state
, null_blob
,
1774 &spnego
.negTokenInit
.mechToken
);
1776 if ( !(NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
) ||
1777 NT_STATUS_IS_OK(status
)) ) {
1778 DEBUG(1, ("Expected OK or MORE_PROCESSING_REQUIRED, got: %s\n",
1779 nt_errstr(status
)));
1780 TALLOC_FREE(client_ntlmssp_state
);
1784 spnego_write_data(ctx
, &to_server
, &spnego
);
1785 data_blob_free(&spnego
.negTokenInit
.mechToken
);
1787 to_server_base64
= base64_encode_data_blob(talloc_tos(), to_server
);
1788 data_blob_free(&to_server
);
1789 x_fprintf(x_stdout
, "KK %s\n", to_server_base64
);
1790 TALLOC_FREE(to_server_base64
);
1794 static void manage_client_ntlmssp_targ(struct spnego_data spnego
)
1797 DATA_BLOB null_blob
= data_blob_null
;
1799 DATA_BLOB to_server
;
1800 char *to_server_base64
;
1801 TALLOC_CTX
*ctx
= talloc_tos();
1803 DEBUG(10, ("Got spnego negTokenTarg with NTLMSSP\n"));
1805 if (client_ntlmssp_state
== NULL
) {
1806 DEBUG(1, ("Got NTLMSSP tArg without a client state\n"));
1807 x_fprintf(x_stdout
, "BH Got NTLMSSP tArg without a client state\n");
1811 if (spnego
.negTokenTarg
.negResult
== SPNEGO_REJECT
) {
1812 x_fprintf(x_stdout
, "NA\n");
1813 TALLOC_FREE(client_ntlmssp_state
);
1817 if (spnego
.negTokenTarg
.negResult
== SPNEGO_ACCEPT_COMPLETED
) {
1818 x_fprintf(x_stdout
, "AF\n");
1819 TALLOC_FREE(client_ntlmssp_state
);
1823 status
= ntlmssp_update(client_ntlmssp_state
,
1824 spnego
.negTokenTarg
.responseToken
,
1827 if (!NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
) && !NT_STATUS_IS_OK(status
)) {
1828 DEBUG(1, ("Expected MORE_PROCESSING_REQUIRED or OK from "
1829 "ntlmssp_client_update, got: %s\n",
1830 nt_errstr(status
)));
1831 x_fprintf(x_stdout
, "BH Expected MORE_PROCESSING_REQUIRED from "
1832 "ntlmssp_client_update\n");
1833 data_blob_free(&request
);
1834 TALLOC_FREE(client_ntlmssp_state
);
1838 spnego
.type
= SPNEGO_NEG_TOKEN_TARG
;
1839 spnego
.negTokenTarg
.negResult
= SPNEGO_ACCEPT_INCOMPLETE
;
1840 spnego
.negTokenTarg
.supportedMech
= (const char *)OID_NTLMSSP
;
1841 spnego
.negTokenTarg
.responseToken
= request
;
1842 spnego
.negTokenTarg
.mechListMIC
= null_blob
;
1844 spnego_write_data(ctx
, &to_server
, &spnego
);
1845 data_blob_free(&request
);
1847 to_server_base64
= base64_encode_data_blob(talloc_tos(), to_server
);
1848 data_blob_free(&to_server
);
1849 x_fprintf(x_stdout
, "KK %s\n", to_server_base64
);
1850 TALLOC_FREE(to_server_base64
);
1856 static bool manage_client_krb5_init(struct spnego_data spnego
)
1859 DATA_BLOB tkt
, tkt_wrapped
, to_server
;
1860 DATA_BLOB session_key_krb5
= data_blob_null
;
1861 struct spnego_data reply
;
1865 const char *my_mechs
[] = {OID_KERBEROS5_OLD
, NULL
};
1867 TALLOC_CTX
*ctx
= talloc_tos();
1869 principal
= spnego
.negTokenInit
.targetPrincipal
;
1871 /* We may not be allowed to use the server-supplied SPNEGO principal, or it may not have been supplied to us
1873 if (!lp_client_use_spnego_principal() || strequal(principal
, ADS_IGNORE_PRINCIPAL
)) {
1877 if (principal
== NULL
&&
1878 opt_target_service
&& opt_target_hostname
&& !is_ipaddress(opt_target_hostname
)) {
1879 DEBUG(3,("manage_client_krb5_init: using target "
1880 "hostname not SPNEGO principal\n"));
1882 principal
= kerberos_get_principal_from_service_hostname(talloc_tos(),
1884 opt_target_hostname
,
1891 DEBUG(3,("manage_client_krb5_init: guessed "
1892 "server principal=%s\n",
1893 principal
? principal
: "<null>"));
1896 if (principal
== NULL
) {
1897 DEBUG(3,("manage_client_krb5_init: could not guess server principal\n"));
1901 retval
= cli_krb5_get_ticket(ctx
, principal
, 0,
1902 &tkt
, &session_key_krb5
,
1903 0, NULL
, NULL
, NULL
);
1907 /* Let's try to first get the TGT, for that we need a
1910 if (opt_password
== NULL
) {
1911 DEBUG(10, ("Requesting password\n"));
1912 x_fprintf(x_stdout
, "PW\n");
1916 user
= talloc_asprintf(talloc_tos(), "%s@%s", opt_username
, opt_domain
);
1921 if ((retval
= kerberos_kinit_password(user
, opt_password
, 0, NULL
))) {
1922 DEBUG(10, ("Requesting TGT failed: %s\n", error_message(retval
)));
1926 retval
= cli_krb5_get_ticket(ctx
, principal
, 0,
1927 &tkt
, &session_key_krb5
,
1928 0, NULL
, NULL
, NULL
);
1930 DEBUG(10, ("Kinit suceeded, but getting a ticket failed: %s\n", error_message(retval
)));
1936 /* wrap that up in a nice GSS-API wrapping */
1937 tkt_wrapped
= spnego_gen_krb5_wrap(ctx
, tkt
, TOK_ID_KRB_AP_REQ
);
1939 data_blob_free(&session_key_krb5
);
1943 reply
.type
= SPNEGO_NEG_TOKEN_INIT
;
1944 reply
.negTokenInit
.mechTypes
= my_mechs
;
1945 reply
.negTokenInit
.reqFlags
= data_blob_null
;
1946 reply
.negTokenInit
.reqFlagsPadding
= 0;
1947 reply
.negTokenInit
.mechToken
= tkt_wrapped
;
1948 reply
.negTokenInit
.mechListMIC
= data_blob_null
;
1950 len
= spnego_write_data(ctx
, &to_server
, &reply
);
1951 data_blob_free(&tkt
);
1954 DEBUG(1, ("Could not write SPNEGO data blob\n"));
1958 reply_base64
= base64_encode_data_blob(talloc_tos(), to_server
);
1959 x_fprintf(x_stdout
, "KK %s *\n", reply_base64
);
1961 TALLOC_FREE(reply_base64
);
1962 data_blob_free(&to_server
);
1963 DEBUG(10, ("sent GSS-SPNEGO KERBEROS5 negTokenInit\n"));
1967 static void manage_client_krb5_targ(struct spnego_data spnego
)
1969 switch (spnego
.negTokenTarg
.negResult
) {
1970 case SPNEGO_ACCEPT_INCOMPLETE
:
1971 DEBUG(1, ("Got a Kerberos negTokenTarg with ACCEPT_INCOMPLETE\n"));
1972 x_fprintf(x_stdout
, "BH Got a Kerberos negTokenTarg with "
1973 "ACCEPT_INCOMPLETE\n");
1975 case SPNEGO_ACCEPT_COMPLETED
:
1976 DEBUG(10, ("Accept completed\n"));
1977 x_fprintf(x_stdout
, "AF\n");
1980 DEBUG(10, ("Rejected\n"));
1981 x_fprintf(x_stdout
, "NA\n");
1984 DEBUG(1, ("Got an invalid negTokenTarg\n"));
1985 x_fprintf(x_stdout
, "AF\n");
1991 static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode
,
1992 struct loadparm_context
*lp_ctx
,
1993 struct ntlm_auth_state
*state
,
1994 char *buf
, int length
, void **private2
)
1997 struct spnego_data spnego
;
1999 TALLOC_CTX
*ctx
= talloc_tos();
2001 if (!opt_username
|| !*opt_username
) {
2002 x_fprintf(x_stderr
, "username must be specified!\n\n");
2006 if (strlen(buf
) <= 3) {
2007 DEBUG(1, ("SPNEGO query [%s] too short\n", buf
));
2008 x_fprintf(x_stdout
, "BH SPNEGO query too short\n");
2012 request
= base64_decode_data_blob(buf
+3);
2014 if (strncmp(buf
, "PW ", 3) == 0) {
2016 /* We asked for a password and obviously got it :-) */
2018 opt_password
= SMB_STRNDUP((const char *)request
.data
, request
.length
);
2020 if (opt_password
== NULL
) {
2021 DEBUG(1, ("Out of memory\n"));
2022 x_fprintf(x_stdout
, "BH Out of memory\n");
2023 data_blob_free(&request
);
2027 x_fprintf(x_stdout
, "OK\n");
2028 data_blob_free(&request
);
2032 if ( (strncmp(buf
, "TT ", 3) != 0) &&
2033 (strncmp(buf
, "AF ", 3) != 0) &&
2034 (strncmp(buf
, "NA ", 3) != 0) ) {
2035 DEBUG(1, ("SPNEGO request [%s] invalid\n", buf
));
2036 x_fprintf(x_stdout
, "BH SPNEGO request invalid\n");
2037 data_blob_free(&request
);
2041 /* So we got a server challenge to generate a SPNEGO
2042 client-to-server request... */
2044 len
= spnego_read_data(ctx
, request
, &spnego
);
2045 data_blob_free(&request
);
2048 DEBUG(1, ("Could not read SPNEGO data for [%s]\n", buf
));
2049 x_fprintf(x_stdout
, "BH Could not read SPNEGO data\n");
2053 if (spnego
.type
== SPNEGO_NEG_TOKEN_INIT
) {
2055 /* The server offers a list of mechanisms */
2057 const char **mechType
= (const char **)spnego
.negTokenInit
.mechTypes
;
2059 while (*mechType
!= NULL
) {
2062 if ( (strcmp(*mechType
, OID_KERBEROS5_OLD
) == 0) ||
2063 (strcmp(*mechType
, OID_KERBEROS5
) == 0) ) {
2064 if (manage_client_krb5_init(spnego
))
2069 if (strcmp(*mechType
, OID_NTLMSSP
) == 0) {
2070 if (manage_client_ntlmssp_init(spnego
))
2077 DEBUG(1, ("Server offered no compatible mechanism\n"));
2078 x_fprintf(x_stdout
, "BH Server offered no compatible mechanism\n");
2082 if (spnego
.type
== SPNEGO_NEG_TOKEN_TARG
) {
2084 if (spnego
.negTokenTarg
.supportedMech
== NULL
) {
2085 /* On accept/reject Windows does not send the
2086 mechanism anymore. Handle that here and
2087 shut down the mechanisms. */
2089 switch (spnego
.negTokenTarg
.negResult
) {
2090 case SPNEGO_ACCEPT_COMPLETED
:
2091 x_fprintf(x_stdout
, "AF\n");
2094 x_fprintf(x_stdout
, "NA\n");
2097 DEBUG(1, ("Got a negTokenTarg with no mech and an "
2098 "unknown negResult: %d\n",
2099 spnego
.negTokenTarg
.negResult
));
2100 x_fprintf(x_stdout
, "BH Got a negTokenTarg with"
2101 " no mech and an unknown "
2105 TALLOC_FREE(client_ntlmssp_state
);
2109 if (strcmp(spnego
.negTokenTarg
.supportedMech
,
2110 OID_NTLMSSP
) == 0) {
2111 manage_client_ntlmssp_targ(spnego
);
2116 if (strcmp(spnego
.negTokenTarg
.supportedMech
,
2117 OID_KERBEROS5_OLD
) == 0) {
2118 manage_client_krb5_targ(spnego
);
2125 DEBUG(1, ("Got an SPNEGO token I could not handle [%s]!\n", buf
));
2126 x_fprintf(x_stdout
, "BH Got an SPNEGO token I could not handle\n");
2130 spnego_free_data(&spnego
);
2134 static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode
,
2135 struct loadparm_context
*lp_ctx
,
2136 struct ntlm_auth_state
*state
,
2137 char *buf
, int length
, void **private2
)
2139 char *request
, *parameter
;
2140 static DATA_BLOB challenge
;
2141 static DATA_BLOB lm_response
;
2142 static DATA_BLOB nt_response
;
2143 static char *full_username
;
2144 static char *username
;
2145 static char *domain
;
2146 static char *plaintext_password
;
2147 static bool ntlm_server_1_user_session_key
;
2148 static bool ntlm_server_1_lm_session_key
;
2150 if (strequal(buf
, ".")) {
2151 if (!full_username
&& !username
) {
2152 x_fprintf(x_stdout
, "Error: No username supplied!\n");
2153 } else if (plaintext_password
) {
2154 /* handle this request as plaintext */
2155 if (!full_username
) {
2156 if (asprintf(&full_username
, "%s%c%s", domain
, winbind_separator(), username
) == -1) {
2157 x_fprintf(x_stdout
, "Error: Out of memory in asprintf!\n.\n");
2161 if (check_plaintext_auth(full_username
, plaintext_password
, False
)) {
2162 x_fprintf(x_stdout
, "Authenticated: Yes\n");
2164 x_fprintf(x_stdout
, "Authenticated: No\n");
2166 } else if (!lm_response
.data
&& !nt_response
.data
) {
2167 x_fprintf(x_stdout
, "Error: No password supplied!\n");
2168 } else if (!challenge
.data
) {
2169 x_fprintf(x_stdout
, "Error: No lanman-challenge supplied!\n");
2171 char *error_string
= NULL
;
2173 uchar user_session_key
[16];
2176 if (full_username
&& !username
) {
2178 fstring fstr_domain
;
2180 if (!parse_ntlm_auth_domain_user(full_username
, fstr_user
, fstr_domain
)) {
2181 /* username might be 'tainted', don't print into our new-line deleimianted stream */
2182 x_fprintf(x_stdout
, "Error: Could not parse into domain and username\n");
2184 SAFE_FREE(username
);
2186 username
= smb_xstrdup(fstr_user
);
2187 domain
= smb_xstrdup(fstr_domain
);
2191 domain
= smb_xstrdup(get_winbind_domain());
2194 if (ntlm_server_1_lm_session_key
)
2195 flags
|= WBFLAG_PAM_LMKEY
;
2197 if (ntlm_server_1_user_session_key
)
2198 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
2200 if (!NT_STATUS_IS_OK(
2201 contact_winbind_auth_crap(username
,
2213 x_fprintf(x_stdout
, "Authenticated: No\n");
2214 x_fprintf(x_stdout
, "Authentication-Error: %s\n.\n", error_string
);
2216 static char zeros
[16];
2218 char *hex_user_session_key
;
2220 x_fprintf(x_stdout
, "Authenticated: Yes\n");
2222 if (ntlm_server_1_lm_session_key
2223 && (memcmp(zeros
, lm_key
,
2224 sizeof(lm_key
)) != 0)) {
2225 hex_lm_key
= hex_encode_talloc(NULL
,
2226 (const unsigned char *)lm_key
,
2228 x_fprintf(x_stdout
, "LANMAN-Session-Key: %s\n", hex_lm_key
);
2229 TALLOC_FREE(hex_lm_key
);
2232 if (ntlm_server_1_user_session_key
2233 && (memcmp(zeros
, user_session_key
,
2234 sizeof(user_session_key
)) != 0)) {
2235 hex_user_session_key
= hex_encode_talloc(NULL
,
2236 (const unsigned char *)user_session_key
,
2237 sizeof(user_session_key
));
2238 x_fprintf(x_stdout
, "User-Session-Key: %s\n", hex_user_session_key
);
2239 TALLOC_FREE(hex_user_session_key
);
2242 SAFE_FREE(error_string
);
2244 /* clear out the state */
2245 challenge
= data_blob_null
;
2246 nt_response
= data_blob_null
;
2247 lm_response
= data_blob_null
;
2248 SAFE_FREE(full_username
);
2249 SAFE_FREE(username
);
2251 SAFE_FREE(plaintext_password
);
2252 ntlm_server_1_user_session_key
= False
;
2253 ntlm_server_1_lm_session_key
= False
;
2254 x_fprintf(x_stdout
, ".\n");
2261 /* Indicates a base64 encoded structure */
2262 parameter
= strstr_m(request
, ":: ");
2264 parameter
= strstr_m(request
, ": ");
2267 DEBUG(0, ("Parameter not found!\n"));
2268 x_fprintf(x_stdout
, "Error: Parameter not found!\n.\n");
2285 base64_decode_inplace(parameter
);
2288 if (strequal(request
, "LANMAN-Challenge")) {
2289 challenge
= strhex_to_data_blob(NULL
, parameter
);
2290 if (challenge
.length
!= 8) {
2291 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (got %d bytes, expected 8)\n.\n",
2293 (int)challenge
.length
);
2294 challenge
= data_blob_null
;
2296 } else if (strequal(request
, "NT-Response")) {
2297 nt_response
= strhex_to_data_blob(NULL
, parameter
);
2298 if (nt_response
.length
< 24) {
2299 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (only got %d bytes, needed at least 24)\n.\n",
2301 (int)nt_response
.length
);
2302 nt_response
= data_blob_null
;
2304 } else if (strequal(request
, "LANMAN-Response")) {
2305 lm_response
= strhex_to_data_blob(NULL
, parameter
);
2306 if (lm_response
.length
!= 24) {
2307 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (got %d bytes, expected 24)\n.\n",
2309 (int)lm_response
.length
);
2310 lm_response
= data_blob_null
;
2312 } else if (strequal(request
, "Password")) {
2313 plaintext_password
= smb_xstrdup(parameter
);
2314 } else if (strequal(request
, "NT-Domain")) {
2315 domain
= smb_xstrdup(parameter
);
2316 } else if (strequal(request
, "Username")) {
2317 username
= smb_xstrdup(parameter
);
2318 } else if (strequal(request
, "Full-Username")) {
2319 full_username
= smb_xstrdup(parameter
);
2320 } else if (strequal(request
, "Request-User-Session-Key")) {
2321 ntlm_server_1_user_session_key
= strequal(parameter
, "Yes");
2322 } else if (strequal(request
, "Request-LanMan-Session-Key")) {
2323 ntlm_server_1_lm_session_key
= strequal(parameter
, "Yes");
2325 x_fprintf(x_stdout
, "Error: Unknown request %s\n.\n", request
);
2329 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode
,
2330 struct loadparm_context
*lp_ctx
,
2331 struct ntlm_auth_state
*state
,
2332 char *buf
, int length
, void **private2
)
2334 char *request
, *parameter
;
2335 static DATA_BLOB new_nt_pswd
;
2336 static DATA_BLOB old_nt_hash_enc
;
2337 static DATA_BLOB new_lm_pswd
;
2338 static DATA_BLOB old_lm_hash_enc
;
2339 static char *full_username
= NULL
;
2340 static char *username
= NULL
;
2341 static char *domain
= NULL
;
2342 static char *newpswd
= NULL
;
2343 static char *oldpswd
= NULL
;
2345 if (strequal(buf
, ".")) {
2346 if(newpswd
&& oldpswd
) {
2347 uchar old_nt_hash
[16];
2348 uchar old_lm_hash
[16];
2349 uchar new_nt_hash
[16];
2350 uchar new_lm_hash
[16];
2352 new_nt_pswd
= data_blob(NULL
, 516);
2353 old_nt_hash_enc
= data_blob(NULL
, 16);
2355 /* Calculate the MD4 hash (NT compatible) of the
2357 E_md4hash(oldpswd
, old_nt_hash
);
2358 E_md4hash(newpswd
, new_nt_hash
);
2360 /* E_deshash returns false for 'long'
2361 passwords (> 14 DOS chars).
2363 Therefore, don't send a buffer
2364 encrypted with the truncated hash
2365 (it could allow an even easier
2366 attack on the password)
2368 Likewise, obey the admin's restriction
2371 if (lp_client_lanman_auth() &&
2372 E_deshash(newpswd
, new_lm_hash
) &&
2373 E_deshash(oldpswd
, old_lm_hash
)) {
2374 new_lm_pswd
= data_blob(NULL
, 516);
2375 old_lm_hash_enc
= data_blob(NULL
, 16);
2376 encode_pw_buffer(new_lm_pswd
.data
, newpswd
,
2379 arcfour_crypt(new_lm_pswd
.data
, old_nt_hash
, 516);
2380 E_old_pw_hash(new_nt_hash
, old_lm_hash
,
2381 old_lm_hash_enc
.data
);
2383 new_lm_pswd
.data
= NULL
;
2384 new_lm_pswd
.length
= 0;
2385 old_lm_hash_enc
.data
= NULL
;
2386 old_lm_hash_enc
.length
= 0;
2389 encode_pw_buffer(new_nt_pswd
.data
, newpswd
,
2392 arcfour_crypt(new_nt_pswd
.data
, old_nt_hash
, 516);
2393 E_old_pw_hash(new_nt_hash
, old_nt_hash
,
2394 old_nt_hash_enc
.data
);
2397 if (!full_username
&& !username
) {
2398 x_fprintf(x_stdout
, "Error: No username supplied!\n");
2399 } else if ((!new_nt_pswd
.data
|| !old_nt_hash_enc
.data
) &&
2400 (!new_lm_pswd
.data
|| old_lm_hash_enc
.data
) ) {
2401 x_fprintf(x_stdout
, "Error: No NT or LM password "
2402 "blobs supplied!\n");
2404 char *error_string
= NULL
;
2406 if (full_username
&& !username
) {
2408 fstring fstr_domain
;
2410 if (!parse_ntlm_auth_domain_user(full_username
,
2413 /* username might be 'tainted', don't
2414 * print into our new-line
2415 * deleimianted stream */
2416 x_fprintf(x_stdout
, "Error: Could not "
2417 "parse into domain and "
2419 SAFE_FREE(username
);
2420 username
= smb_xstrdup(full_username
);
2422 SAFE_FREE(username
);
2424 username
= smb_xstrdup(fstr_user
);
2425 domain
= smb_xstrdup(fstr_domain
);
2430 if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
2437 x_fprintf(x_stdout
, "Password-Change: No\n");
2438 x_fprintf(x_stdout
, "Password-Change-Error: "
2439 "%s\n.\n", error_string
);
2441 x_fprintf(x_stdout
, "Password-Change: Yes\n");
2444 SAFE_FREE(error_string
);
2446 /* clear out the state */
2447 new_nt_pswd
= data_blob_null
;
2448 old_nt_hash_enc
= data_blob_null
;
2449 new_lm_pswd
= data_blob_null
;
2450 old_nt_hash_enc
= data_blob_null
;
2451 SAFE_FREE(full_username
);
2452 SAFE_FREE(username
);
2456 x_fprintf(x_stdout
, ".\n");
2463 /* Indicates a base64 encoded structure */
2464 parameter
= strstr_m(request
, ":: ");
2466 parameter
= strstr_m(request
, ": ");
2469 DEBUG(0, ("Parameter not found!\n"));
2470 x_fprintf(x_stdout
, "Error: Parameter not found!\n.\n");
2486 base64_decode_inplace(parameter
);
2489 if (strequal(request
, "new-nt-password-blob")) {
2490 new_nt_pswd
= strhex_to_data_blob(NULL
, parameter
);
2491 if (new_nt_pswd
.length
!= 516) {
2492 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2493 "(got %d bytes, expected 516)\n.\n",
2495 (int)new_nt_pswd
.length
);
2496 new_nt_pswd
= data_blob_null
;
2498 } else if (strequal(request
, "old-nt-hash-blob")) {
2499 old_nt_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2500 if (old_nt_hash_enc
.length
!= 16) {
2501 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2502 "(got %d bytes, expected 16)\n.\n",
2504 (int)old_nt_hash_enc
.length
);
2505 old_nt_hash_enc
= data_blob_null
;
2507 } else if (strequal(request
, "new-lm-password-blob")) {
2508 new_lm_pswd
= strhex_to_data_blob(NULL
, parameter
);
2509 if (new_lm_pswd
.length
!= 516) {
2510 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2511 "(got %d bytes, expected 516)\n.\n",
2513 (int)new_lm_pswd
.length
);
2514 new_lm_pswd
= data_blob_null
;
2517 else if (strequal(request
, "old-lm-hash-blob")) {
2518 old_lm_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2519 if (old_lm_hash_enc
.length
!= 16)
2521 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2522 "(got %d bytes, expected 16)\n.\n",
2524 (int)old_lm_hash_enc
.length
);
2525 old_lm_hash_enc
= data_blob_null
;
2527 } else if (strequal(request
, "nt-domain")) {
2528 domain
= smb_xstrdup(parameter
);
2529 } else if(strequal(request
, "username")) {
2530 username
= smb_xstrdup(parameter
);
2531 } else if(strequal(request
, "full-username")) {
2532 username
= smb_xstrdup(parameter
);
2533 } else if(strequal(request
, "new-password")) {
2534 newpswd
= smb_xstrdup(parameter
);
2535 } else if (strequal(request
, "old-password")) {
2536 oldpswd
= smb_xstrdup(parameter
);
2538 x_fprintf(x_stdout
, "Error: Unknown request %s\n.\n", request
);
2542 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode
,
2543 struct loadparm_context
*lp_ctx
,
2544 struct ntlm_auth_state
*state
,
2545 stdio_helper_function fn
, void **private2
)
2548 char tmp
[INITIAL_BUFFER_SIZE
+1];
2549 int length
, buf_size
= 0;
2552 buf
= talloc_strdup(state
->mem_ctx
, "");
2554 DEBUG(0, ("Failed to allocate input buffer.\n"));
2555 x_fprintf(x_stderr
, "ERR\n");
2561 /* this is not a typo - x_fgets doesn't work too well under
2563 if (fgets(tmp
, sizeof(tmp
)-1, stdin
) == NULL
) {
2564 if (ferror(stdin
)) {
2565 DEBUG(1, ("fgets() failed! dying..... errno=%d "
2566 "(%s)\n", ferror(stdin
),
2567 strerror(ferror(stdin
))));
2574 buf
= talloc_strdup_append_buffer(buf
, tmp
);
2575 buf_size
+= INITIAL_BUFFER_SIZE
;
2577 if (buf_size
> MAX_BUFFER_SIZE
) {
2578 DEBUG(2, ("Oversized message\n"));
2579 x_fprintf(x_stderr
, "ERR\n");
2584 c
= strchr(buf
, '\n');
2585 } while (c
== NULL
);
2590 DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf
,length
));
2592 if (buf
[0] == '\0') {
2593 DEBUG(2, ("Invalid Request\n"));
2594 x_fprintf(x_stderr
, "ERR\n");
2599 fn(stdio_helper_mode
, lp_ctx
, state
, buf
, length
, private2
);
2604 static void squid_stream(enum stdio_helper_mode stdio_mode
,
2605 struct loadparm_context
*lp_ctx
,
2606 stdio_helper_function fn
) {
2607 TALLOC_CTX
*mem_ctx
;
2608 struct ntlm_auth_state
*state
;
2610 /* initialize FDescs */
2611 x_setbuf(x_stdout
, NULL
);
2612 x_setbuf(x_stderr
, NULL
);
2614 mem_ctx
= talloc_init("ntlm_auth");
2616 DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
2617 x_fprintf(x_stderr
, "ERR\n");
2621 state
= talloc_zero(mem_ctx
, struct ntlm_auth_state
);
2623 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
2624 x_fprintf(x_stderr
, "ERR\n");
2628 state
->mem_ctx
= mem_ctx
;
2629 state
->helper_mode
= stdio_mode
;
2632 TALLOC_CTX
*frame
= talloc_stackframe();
2633 manage_squid_request(stdio_mode
, lp_ctx
, state
, fn
, NULL
);
2639 /* Authenticate a user with a challenge/response */
2641 static bool check_auth_crap(void)
2646 char user_session_key
[16];
2648 char *hex_user_session_key
;
2650 static uint8 zeros
[16];
2652 x_setbuf(x_stdout
, NULL
);
2655 flags
|= WBFLAG_PAM_LMKEY
;
2657 if (request_user_session_key
)
2658 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
2660 flags
|= WBFLAG_PAM_NT_STATUS_SQUASH
;
2662 nt_status
= contact_winbind_auth_crap(opt_username
, opt_domain
,
2668 (unsigned char *)lm_key
,
2669 (unsigned char *)user_session_key
,
2670 &error_string
, NULL
);
2672 if (!NT_STATUS_IS_OK(nt_status
)) {
2673 x_fprintf(x_stdout
, "%s (0x%x)\n",
2675 NT_STATUS_V(nt_status
));
2676 SAFE_FREE(error_string
);
2681 && (memcmp(zeros
, lm_key
,
2682 sizeof(lm_key
)) != 0)) {
2683 hex_lm_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)lm_key
,
2685 x_fprintf(x_stdout
, "LM_KEY: %s\n", hex_lm_key
);
2686 TALLOC_FREE(hex_lm_key
);
2688 if (request_user_session_key
2689 && (memcmp(zeros
, user_session_key
,
2690 sizeof(user_session_key
)) != 0)) {
2691 hex_user_session_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)user_session_key
,
2692 sizeof(user_session_key
));
2693 x_fprintf(x_stdout
, "NT_KEY: %s\n", hex_user_session_key
);
2694 TALLOC_FREE(hex_user_session_key
);
2703 OPT_USERNAME
= 1000,
2712 OPT_USER_SESSION_KEY
,
2714 OPT_REQUIRE_MEMBERSHIP
,
2715 OPT_USE_CACHED_CREDS
,
2716 OPT_PAM_WINBIND_CONF
,
2721 int main(int argc
, const char **argv
)
2723 TALLOC_CTX
*frame
= talloc_stackframe();
2725 static const char *helper_protocol
;
2726 static int diagnostics
;
2728 static const char *hex_challenge
;
2729 static const char *hex_lm_response
;
2730 static const char *hex_nt_response
;
2731 struct loadparm_context
*lp_ctx
;
2734 /* NOTE: DO NOT change this interface without considering the implications!
2735 This is an external interface, which other programs will use to interact
2739 /* We do not use single-letter command abbreviations, because they harm future
2740 interface stability. */
2742 struct poptOption long_options
[] = {
2744 { "helper-protocol", 0, POPT_ARG_STRING
, &helper_protocol
, OPT_DOMAIN
, "operate as a stdio-based helper", "helper protocol to use"},
2745 { "username", 0, POPT_ARG_STRING
, &opt_username
, OPT_USERNAME
, "username"},
2746 { "domain", 0, POPT_ARG_STRING
, &opt_domain
, OPT_DOMAIN
, "domain name"},
2747 { "workstation", 0, POPT_ARG_STRING
, &opt_workstation
, OPT_WORKSTATION
, "workstation"},
2748 { "challenge", 0, POPT_ARG_STRING
, &hex_challenge
, OPT_CHALLENGE
, "challenge (HEX encoded)"},
2749 { "lm-response", 0, POPT_ARG_STRING
, &hex_lm_response
, OPT_LM
, "LM Response to the challenge (HEX encoded)"},
2750 { "nt-response", 0, POPT_ARG_STRING
, &hex_nt_response
, OPT_NT
, "NT or NTLMv2 Response to the challenge (HEX encoded)"},
2751 { "password", 0, POPT_ARG_STRING
, &opt_password
, OPT_PASSWORD
, "User's plaintext password"},
2752 { "request-lm-key", 0, POPT_ARG_NONE
, &request_lm_key
, OPT_LM_KEY
, "Retrieve LM session key"},
2753 { "request-nt-key", 0, POPT_ARG_NONE
, &request_user_session_key
, OPT_USER_SESSION_KEY
, "Retrieve User (NT) session key"},
2754 { "use-cached-creds", 0, POPT_ARG_NONE
, &use_cached_creds
, OPT_USE_CACHED_CREDS
, "Use cached credentials if no password is given"},
2755 { "diagnostics", 0, POPT_ARG_NONE
, &diagnostics
,
2757 "Perform diagnostics on the authentication chain"},
2758 { "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" },
2759 { "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" },
2760 { "target-service", 0, POPT_ARG_STRING
, &opt_target_service
, OPT_TARGET_SERVICE
, "Target service (eg http)" },
2761 { "target-hostname", 0, POPT_ARG_STRING
, &opt_target_hostname
, OPT_TARGET_HOSTNAME
, "Target hostname" },
2762 POPT_COMMON_CONFIGFILE
2767 /* Samba client initialisation */
2770 setup_logging("ntlm_auth", DEBUG_STDERR
);
2774 pc
= poptGetContext("ntlm_auth", argc
, argv
, long_options
, 0);
2776 /* Parse command line options */
2779 poptPrintHelp(pc
, stderr
, 0);
2783 while((opt
= poptGetNextOpt(pc
)) != -1) {
2784 /* Get generic config options like --configfile */
2787 poptFreeContext(pc
);
2789 if (!lp_load_global(get_dyn_CONFIGFILE())) {
2790 d_fprintf(stderr
, "ntlm_auth: error opening config file %s. Error was %s\n",
2791 get_dyn_CONFIGFILE(), strerror(errno
));
2795 pc
= poptGetContext(NULL
, argc
, (const char **)argv
, long_options
,
2796 POPT_CONTEXT_KEEP_FIRST
);
2798 while((opt
= poptGetNextOpt(pc
)) != -1) {
2801 opt_challenge
= strhex_to_data_blob(NULL
, hex_challenge
);
2802 if (opt_challenge
.length
!= 8) {
2803 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2805 (int)opt_challenge
.length
);
2810 opt_lm_response
= strhex_to_data_blob(NULL
, hex_lm_response
);
2811 if (opt_lm_response
.length
!= 24) {
2812 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2814 (int)opt_lm_response
.length
);
2820 opt_nt_response
= strhex_to_data_blob(NULL
, hex_nt_response
);
2821 if (opt_nt_response
.length
< 24) {
2822 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2824 (int)opt_nt_response
.length
);
2829 case OPT_REQUIRE_MEMBERSHIP
:
2830 if (strncasecmp_m("S-", require_membership_of
, 2) == 0) {
2831 require_membership_of_sid
= require_membership_of
;
2838 char *domain
= SMB_STRDUP(opt_username
);
2839 char *p
= strchr_m(domain
, *lp_winbind_separator());
2843 if (opt_domain
&& !strequal(opt_domain
, domain
)) {
2844 x_fprintf(x_stderr
, "Domain specified in username (%s) "
2845 "doesn't match specified domain (%s)!\n\n",
2846 domain
, opt_domain
);
2847 poptPrintHelp(pc
, stderr
, 0);
2850 opt_domain
= domain
;
2856 /* Note: if opt_domain is "" then send no domain */
2857 if (opt_domain
== NULL
) {
2858 opt_domain
= get_winbind_domain();
2861 if (opt_workstation
== NULL
) {
2862 opt_workstation
= "";
2865 lp_ctx
= loadparm_init_s3(NULL
, loadparm_s3_helpers());
2866 if (lp_ctx
== NULL
) {
2867 x_fprintf(x_stderr
, "loadparm_init_s3() failed!\n");
2871 if (helper_protocol
) {
2873 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2874 if (strcmp(helper_protocol
, stdio_helper_protocols
[i
].name
) == 0) {
2875 squid_stream(stdio_helper_protocols
[i
].mode
, lp_ctx
, stdio_helper_protocols
[i
].fn
);
2879 x_fprintf(x_stderr
, "unknown helper protocol [%s]\n\nValid helper protools:\n\n", helper_protocol
);
2881 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2882 x_fprintf(x_stderr
, "%s\n", stdio_helper_protocols
[i
].name
);
2888 if (!opt_username
|| !*opt_username
) {
2889 x_fprintf(x_stderr
, "username must be specified!\n\n");
2890 poptPrintHelp(pc
, stderr
, 0);
2894 if (opt_challenge
.length
) {
2895 if (!check_auth_crap()) {
2901 if (!opt_password
) {
2902 opt_password
= getpass("password: ");
2906 if (!diagnose_ntlm_auth()) {
2912 fstr_sprintf(user
, "%s%c%s", opt_domain
, winbind_separator(), opt_username
);
2913 if (!check_plaintext_auth(user
, opt_password
, True
)) {
2920 poptFreeContext(pc
);