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_DATA
*pac_data
= NULL
;
720 struct PAC_LOGON_INFO
*logon_info
= NULL
;
729 tmp_ctx
= talloc_new(mem_ctx
);
731 return NT_STATUS_NO_MEMORY
;
736 status
= kerberos_decode_pac(tmp_ctx
,
738 NULL
, NULL
, NULL
, NULL
, 0, &pac_data
);
740 status
= NT_STATUS_ACCESS_DENIED
;
742 if (!NT_STATUS_IS_OK(status
)) {
746 /* get logon name and logon info */
747 for (i
= 0; i
< pac_data
->num_buffers
; i
++) {
748 struct PAC_BUFFER
*data_buf
= &pac_data
->buffers
[i
];
750 switch (data_buf
->type
) {
751 case PAC_TYPE_LOGON_INFO
:
752 if (!data_buf
->info
) {
755 logon_info
= data_buf
->info
->logon_info
.info
;
762 DEBUG(1, ("Invalid PAC data, missing logon info!\n"));
763 status
= NT_STATUS_NOT_FOUND
;
768 DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name
));
770 p
= strchr_m(princ_name
, '@');
772 DEBUG(3, ("[%s] Doesn't look like a valid principal\n",
774 return NT_STATUS_LOGON_FAILURE
;
777 user
= talloc_strndup(mem_ctx
, princ_name
, p
- princ_name
);
779 return NT_STATUS_NO_MEMORY
;
782 realm
= talloc_strdup(talloc_tos(), p
+ 1);
784 return NT_STATUS_NO_MEMORY
;
787 if (!strequal(realm
, lp_realm())) {
788 DEBUG(3, ("Ticket for foreign realm %s@%s\n", user
, realm
));
789 if (!lp_allow_trusted_domains()) {
790 return NT_STATUS_LOGON_FAILURE
;
794 if (logon_info
&& logon_info
->info3
.base
.logon_domain
.string
) {
795 domain
= talloc_strdup(mem_ctx
,
796 logon_info
->info3
.base
.logon_domain
.string
);
798 return NT_STATUS_NO_MEMORY
;
800 DEBUG(10, ("Domain is [%s] (using PAC)\n", domain
));
803 /* If we have winbind running, we can (and must) shorten the
804 username by using the short netbios name. Otherwise we will
805 have inconsistent user names. With Kerberos, we get the
806 fully qualified realm, with ntlmssp we get the short
807 name. And even w2k3 does use ntlmssp if you for example
808 connect to an ip address. */
811 struct wbcDomainInfo
*info
= NULL
;
813 DEBUG(10, ("Mapping [%s] to short name using winbindd\n",
816 wbc_status
= wbcDomainInfo(realm
, &info
);
818 if (WBC_ERROR_IS_OK(wbc_status
)) {
819 domain
= talloc_strdup(mem_ctx
,
823 DEBUG(3, ("Could not find short name: %s\n",
824 wbcErrorString(wbc_status
)));
825 domain
= talloc_strdup(mem_ctx
, realm
);
828 return NT_STATUS_NO_MEMORY
;
830 DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain
));
833 unixuser
= talloc_asprintf(tmp_ctx
, "%s%c%s", domain
, winbind_separator(), user
);
835 status
= NT_STATUS_NO_MEMORY
;
839 status
= ntlm_auth_generate_session_info(auth_ctx
, mem_ctx
, unixuser
, NULL
, session_info_flags
, session_info
);
842 TALLOC_FREE(tmp_ctx
);
849 * Return the challenge as determined by the authentication subsystem
850 * @return an 8 byte random challenge
853 static NTSTATUS
ntlm_auth_get_challenge(struct auth4_context
*auth_ctx
,
856 if (auth_ctx
->challenge
.data
.length
== 8) {
857 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
858 auth_ctx
->challenge
.set_by
));
859 memcpy(chal
, auth_ctx
->challenge
.data
.data
, 8);
863 if (!auth_ctx
->challenge
.set_by
) {
864 generate_random_buffer(chal
, 8);
866 auth_ctx
->challenge
.data
= data_blob_talloc(auth_ctx
, chal
, 8);
867 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.data
.data
);
868 auth_ctx
->challenge
.set_by
= "random";
871 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
872 auth_ctx
->challenge
.set_by
));
878 * NTLM2 authentication modifies the effective challenge,
879 * @param challenge The new challenge value
881 static NTSTATUS
ntlm_auth_set_challenge(struct auth4_context
*auth_ctx
, const uint8_t chal
[8], const char *set_by
)
883 auth_ctx
->challenge
.set_by
= talloc_strdup(auth_ctx
, set_by
);
884 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.set_by
);
886 auth_ctx
->challenge
.data
= data_blob_talloc(auth_ctx
, chal
, 8);
887 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.data
.data
);
893 * Check the password on an NTLMSSP login.
895 * Return the session keys used on the connection.
898 static NTSTATUS
winbind_pw_check(struct auth4_context
*auth4_context
,
900 const struct auth_usersupplied_info
*user_info
,
901 void **server_returned_info
,
902 DATA_BLOB
*session_key
, DATA_BLOB
*lm_session_key
)
904 static const char zeros
[16] = { 0, };
906 char *error_string
= NULL
;
908 uint8 user_sess_key
[16];
909 char *unix_name
= NULL
;
911 nt_status
= contact_winbind_auth_crap(user_info
->client
.account_name
, user_info
->client
.domain_name
,
912 user_info
->workstation_name
,
913 &auth4_context
->challenge
.data
,
914 &user_info
->password
.response
.lanman
,
915 &user_info
->password
.response
.nt
,
916 WBFLAG_PAM_LMKEY
| WBFLAG_PAM_USER_SESSION_KEY
| WBFLAG_PAM_UNIX_NAME
,
918 lm_key
, user_sess_key
,
919 &error_string
, &unix_name
);
921 if (NT_STATUS_IS_OK(nt_status
)) {
922 if (memcmp(lm_key
, zeros
, 8) != 0) {
923 *lm_session_key
= data_blob_talloc(mem_ctx
, NULL
, 16);
924 memcpy(lm_session_key
->data
, lm_key
, 8);
925 memset(lm_session_key
->data
+8, '\0', 8);
928 if (memcmp(user_sess_key
, zeros
, 16) != 0) {
929 *session_key
= data_blob_talloc(mem_ctx
, user_sess_key
, 16);
931 *server_returned_info
= talloc_strdup(mem_ctx
,
934 DEBUG(NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCESS_DENIED
) ? 0 : 3,
935 ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
936 user_info
->client
.domain_name
, user_info
->client
.account_name
,
937 user_info
->workstation_name
,
938 error_string
? error_string
: "unknown error (NULL)"));
941 SAFE_FREE(error_string
);
942 SAFE_FREE(unix_name
);
946 static NTSTATUS
local_pw_check(struct auth4_context
*auth4_context
,
948 const struct auth_usersupplied_info
*user_info
,
949 void **server_returned_info
,
950 DATA_BLOB
*session_key
, DATA_BLOB
*lm_session_key
)
953 struct samr_Password lm_pw
, nt_pw
;
955 nt_lm_owf_gen (opt_password
, nt_pw
.hash
, lm_pw
.hash
);
957 nt_status
= ntlm_password_check(mem_ctx
,
959 &auth4_context
->challenge
.data
,
960 &user_info
->password
.response
.lanman
,
961 &user_info
->password
.response
.nt
,
962 user_info
->client
.account_name
,
963 user_info
->client
.account_name
,
964 user_info
->client
.domain_name
,
965 &lm_pw
, &nt_pw
, session_key
, lm_session_key
);
967 if (NT_STATUS_IS_OK(nt_status
)) {
968 *server_returned_info
= talloc_asprintf(mem_ctx
,
969 "%s%c%s", user_info
->client
.domain_name
,
970 *lp_winbind_separator(),
971 user_info
->client
.account_name
);
973 DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
974 user_info
->client
.domain_name
, user_info
->client
.account_name
,
975 user_info
->workstation_name
,
976 nt_errstr(nt_status
)));
981 static NTSTATUS
ntlm_auth_start_ntlmssp_client(struct ntlmssp_state
**client_ntlmssp_state
)
984 if ( (opt_username
== NULL
) || (opt_domain
== NULL
) ) {
985 status
= NT_STATUS_UNSUCCESSFUL
;
986 DEBUG(1, ("Need username and domain for NTLMSSP\n"));
987 return NT_STATUS_INVALID_PARAMETER
;
990 status
= ntlmssp_client_start(NULL
,
993 lp_client_ntlmv2_auth(),
994 client_ntlmssp_state
);
996 if (!NT_STATUS_IS_OK(status
)) {
997 DEBUG(1, ("Could not start NTLMSSP client: %s\n",
999 TALLOC_FREE(*client_ntlmssp_state
);
1003 status
= ntlmssp_set_username(*client_ntlmssp_state
, opt_username
);
1005 if (!NT_STATUS_IS_OK(status
)) {
1006 DEBUG(1, ("Could not set username: %s\n",
1007 nt_errstr(status
)));
1008 TALLOC_FREE(*client_ntlmssp_state
);
1012 status
= ntlmssp_set_domain(*client_ntlmssp_state
, opt_domain
);
1014 if (!NT_STATUS_IS_OK(status
)) {
1015 DEBUG(1, ("Could not set domain: %s\n",
1016 nt_errstr(status
)));
1017 TALLOC_FREE(*client_ntlmssp_state
);
1022 status
= ntlmssp_set_password(*client_ntlmssp_state
, opt_password
);
1024 if (!NT_STATUS_IS_OK(status
)) {
1025 DEBUG(1, ("Could not set password: %s\n",
1026 nt_errstr(status
)));
1027 TALLOC_FREE(*client_ntlmssp_state
);
1032 return NT_STATUS_OK
;
1035 static struct auth4_context
*make_auth4_context_ntlm_auth(TALLOC_CTX
*mem_ctx
, bool local_pw
)
1037 struct auth4_context
*auth4_context
= talloc_zero(mem_ctx
, struct auth4_context
);
1038 if (auth4_context
== NULL
) {
1039 DEBUG(10, ("failed to allocate auth4_context failed\n"));
1042 auth4_context
->generate_session_info
= ntlm_auth_generate_session_info
;
1043 auth4_context
->generate_session_info_pac
= ntlm_auth_generate_session_info_pac
;
1044 auth4_context
->get_ntlm_challenge
= ntlm_auth_get_challenge
;
1045 auth4_context
->set_ntlm_challenge
= ntlm_auth_set_challenge
;
1047 auth4_context
->check_ntlm_password
= local_pw_check
;
1049 auth4_context
->check_ntlm_password
= winbind_pw_check
;
1051 auth4_context
->private_data
= NULL
;
1052 return auth4_context
;
1055 static NTSTATUS
ntlm_auth_start_ntlmssp_server(TALLOC_CTX
*mem_ctx
,
1056 struct loadparm_context
*lp_ctx
,
1057 struct gensec_security
**gensec_security_out
)
1059 struct gensec_security
*gensec_security
;
1062 TALLOC_CTX
*tmp_ctx
;
1064 struct gensec_settings
*gensec_settings
;
1066 struct cli_credentials
*server_credentials
;
1068 struct auth4_context
*auth4_context
;
1070 tmp_ctx
= talloc_new(mem_ctx
);
1071 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx
);
1073 auth4_context
= make_auth4_context_ntlm_auth(tmp_ctx
, opt_password
);
1074 if (auth4_context
== NULL
) {
1075 TALLOC_FREE(tmp_ctx
);
1076 return NT_STATUS_NO_MEMORY
;
1079 gensec_settings
= lpcfg_gensec_settings(tmp_ctx
, lp_ctx
);
1080 if (lp_ctx
== NULL
) {
1081 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1082 TALLOC_FREE(tmp_ctx
);
1083 return NT_STATUS_NO_MEMORY
;
1087 * This should be a 'netbios domain -> DNS domain'
1088 * mapping, and can currently validly return NULL on
1089 * poorly configured systems.
1091 * This is used for the NTLMSSP server
1095 gensec_settings
->server_netbios_name
= lp_netbios_name();
1096 gensec_settings
->server_netbios_domain
= lp_workgroup();
1098 gensec_settings
->server_netbios_name
= get_winbind_netbios_name();
1099 gensec_settings
->server_netbios_domain
= get_winbind_domain();
1102 gensec_settings
->server_dns_domain
= strlower_talloc(gensec_settings
,
1103 get_mydnsdomname(talloc_tos()));
1104 gensec_settings
->server_dns_name
= strlower_talloc(gensec_settings
,
1105 get_mydnsfullname());
1107 gensec_settings
->backends
= talloc_zero_array(gensec_settings
,
1108 struct gensec_security_ops
*, 4);
1110 if (gensec_settings
->backends
== NULL
) {
1111 TALLOC_FREE(tmp_ctx
);
1112 return NT_STATUS_NO_MEMORY
;
1117 /* These need to be in priority order, krb5 before NTLMSSP */
1118 #if defined(HAVE_KRB5)
1119 gensec_settings
->backends
[idx
++] = &gensec_gse_krb5_security_ops
;
1122 gensec_settings
->backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_NTLMSSP
);
1124 gensec_settings
->backends
[idx
++] = gensec_security_by_oid(NULL
,
1128 * This is anonymous for now, because we just use it
1129 * to set the kerberos state at the moment
1131 server_credentials
= cli_credentials_init_anon(tmp_ctx
);
1132 if (!server_credentials
) {
1133 DEBUG(0, ("auth_generic_prepare: Failed to init server credentials\n"));
1134 return NT_STATUS_NO_MEMORY
;
1137 cli_credentials_set_conf(server_credentials
, lp_ctx
);
1139 if (lp_security() == SEC_ADS
|| USE_KERBEROS_KEYTAB
) {
1140 cli_credentials_set_kerberos_state(server_credentials
, CRED_AUTO_USE_KERBEROS
);
1142 cli_credentials_set_kerberos_state(server_credentials
, CRED_DONT_USE_KERBEROS
);
1145 nt_status
= gensec_server_start(tmp_ctx
, gensec_settings
,
1146 auth4_context
, &gensec_security
);
1148 if (!NT_STATUS_IS_OK(nt_status
)) {
1149 TALLOC_FREE(tmp_ctx
);
1153 gensec_set_credentials(gensec_security
, server_credentials
);
1155 gensec_want_feature(gensec_security
, GENSEC_FEATURE_SIGN
);
1156 gensec_want_feature(gensec_security
, GENSEC_FEATURE_SEAL
);
1158 talloc_unlink(tmp_ctx
, lp_ctx
);
1159 talloc_unlink(tmp_ctx
, server_credentials
);
1160 talloc_unlink(tmp_ctx
, gensec_settings
);
1161 talloc_unlink(tmp_ctx
, auth4_context
);
1163 nt_status
= gensec_start_mech_by_oid(gensec_security
, GENSEC_OID_NTLMSSP
);
1164 if (!NT_STATUS_IS_OK(nt_status
)) {
1165 TALLOC_FREE(tmp_ctx
);
1169 *gensec_security_out
= talloc_steal(mem_ctx
, gensec_security
);
1170 TALLOC_FREE(tmp_ctx
);
1171 return NT_STATUS_OK
;
1174 /*******************************************************************
1175 Used by firefox to drive NTLM auth to IIS servers.
1176 *******************************************************************/
1178 static NTSTATUS
do_ccache_ntlm_auth(DATA_BLOB initial_msg
, DATA_BLOB challenge_msg
,
1181 struct winbindd_request wb_request
;
1182 struct winbindd_response wb_response
;
1186 /* get winbindd to do the ntlmssp step on our behalf */
1187 ZERO_STRUCT(wb_request
);
1188 ZERO_STRUCT(wb_response
);
1191 * This is tricky here. If we set krb5_auth in pam_winbind.conf
1192 * creds for users in trusted domain will be stored the winbindd
1193 * child of the trusted domain. If we ask the primary domain for
1194 * ntlm_ccache_auth, it will fail. So, we have to ask the trusted
1195 * domain's child for ccache_ntlm_auth. that is to say, we have to
1196 * set WBFLAG_PAM_CONTACT_TRUSTDOM in request.flags.
1198 ctrl
= get_pam_winbind_config();
1200 if (ctrl
& WINBIND_KRB5_AUTH
) {
1201 wb_request
.flags
|= WBFLAG_PAM_CONTACT_TRUSTDOM
;
1204 fstr_sprintf(wb_request
.data
.ccache_ntlm_auth
.user
,
1205 "%s%c%s", opt_domain
, winbind_separator(), opt_username
);
1206 wb_request
.data
.ccache_ntlm_auth
.uid
= geteuid();
1207 wb_request
.data
.ccache_ntlm_auth
.initial_blob_len
= initial_msg
.length
;
1208 wb_request
.data
.ccache_ntlm_auth
.challenge_blob_len
= challenge_msg
.length
;
1209 wb_request
.extra_len
= initial_msg
.length
+ challenge_msg
.length
;
1211 if (wb_request
.extra_len
> 0) {
1212 wb_request
.extra_data
.data
= SMB_MALLOC_ARRAY(char, wb_request
.extra_len
);
1213 if (wb_request
.extra_data
.data
== NULL
) {
1214 return NT_STATUS_NO_MEMORY
;
1217 memcpy(wb_request
.extra_data
.data
, initial_msg
.data
, initial_msg
.length
);
1218 memcpy(wb_request
.extra_data
.data
+ initial_msg
.length
,
1219 challenge_msg
.data
, challenge_msg
.length
);
1222 result
= winbindd_request_response(WINBINDD_CCACHE_NTLMAUTH
, &wb_request
, &wb_response
);
1223 SAFE_FREE(wb_request
.extra_data
.data
);
1225 if (result
!= NSS_STATUS_SUCCESS
) {
1226 winbindd_free_response(&wb_response
);
1227 return NT_STATUS_UNSUCCESSFUL
;
1231 *reply
= data_blob(wb_response
.extra_data
.data
,
1232 wb_response
.data
.ccache_ntlm_auth
.auth_blob_len
);
1233 if (wb_response
.data
.ccache_ntlm_auth
.auth_blob_len
> 0 &&
1234 reply
->data
== NULL
) {
1235 winbindd_free_response(&wb_response
);
1236 return NT_STATUS_NO_MEMORY
;
1240 winbindd_free_response(&wb_response
);
1241 return NT_STATUS_MORE_PROCESSING_REQUIRED
;
1244 static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode
,
1245 struct loadparm_context
*lp_ctx
,
1246 struct ntlm_auth_state
*state
,
1247 char *buf
, int length
, void **private2
)
1249 DATA_BLOB request
, reply
;
1252 if (!opt_username
|| !*opt_username
) {
1253 x_fprintf(x_stderr
, "username must be specified!\n\n");
1257 if (strlen(buf
) < 2) {
1258 DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf
));
1259 x_fprintf(x_stdout
, "BH NTLMSSP query invalid\n");
1263 if (strlen(buf
) > 3) {
1264 if(strncmp(buf
, "SF ", 3) == 0) {
1265 DEBUG(10, ("Looking for flags to negotiate\n"));
1266 talloc_free(state
->want_feature_list
);
1267 state
->want_feature_list
= talloc_strdup(state
->mem_ctx
,
1269 x_fprintf(x_stdout
, "OK\n");
1272 request
= base64_decode_data_blob(buf
+ 3);
1274 request
= data_blob_null
;
1277 if (strncmp(buf
, "PW ", 3) == 0) {
1278 /* We asked for a password and obviously got it :-) */
1280 opt_password
= SMB_STRNDUP((const char *)request
.data
,
1283 if (opt_password
== NULL
) {
1284 DEBUG(1, ("Out of memory\n"));
1285 x_fprintf(x_stdout
, "BH Out of memory\n");
1286 data_blob_free(&request
);
1290 x_fprintf(x_stdout
, "OK\n");
1291 data_blob_free(&request
);
1295 if (!state
->ntlmssp_state
&& use_cached_creds
) {
1296 /* check whether cached credentials are usable. */
1297 DATA_BLOB empty_blob
= data_blob_null
;
1299 nt_status
= do_ccache_ntlm_auth(empty_blob
, empty_blob
, NULL
);
1300 if (!NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1301 /* failed to use cached creds */
1302 use_cached_creds
= False
;
1306 if (opt_password
== NULL
&& !use_cached_creds
) {
1307 /* Request a password from the calling process. After
1308 sending it, the calling process should retry asking for the
1311 DEBUG(10, ("Requesting password\n"));
1312 x_fprintf(x_stdout
, "PW\n");
1316 if (strncmp(buf
, "YR", 2) == 0) {
1317 TALLOC_FREE(state
->ntlmssp_state
);
1318 state
->cli_state
= CLIENT_INITIAL
;
1319 } else if (strncmp(buf
, "TT", 2) == 0) {
1320 /* No special preprocessing required */
1321 } else if (strncmp(buf
, "GF", 2) == 0) {
1322 DEBUG(10, ("Requested negotiated NTLMSSP flags\n"));
1324 if(state
->cli_state
== CLIENT_FINISHED
) {
1325 x_fprintf(x_stdout
, "GF 0x%08x\n", state
->neg_flags
);
1328 x_fprintf(x_stdout
, "BH\n");
1331 data_blob_free(&request
);
1333 } else if (strncmp(buf
, "GK", 2) == 0 ) {
1334 DEBUG(10, ("Requested session key\n"));
1336 if(state
->cli_state
== CLIENT_FINISHED
) {
1337 char *key64
= base64_encode_data_blob(state
->mem_ctx
,
1338 state
->session_key
);
1339 x_fprintf(x_stdout
, "GK %s\n", key64
?key64
:"<NULL>");
1343 x_fprintf(x_stdout
, "BH\n");
1346 data_blob_free(&request
);
1349 DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf
));
1350 x_fprintf(x_stdout
, "BH NTLMSSP query invalid\n");
1354 if (!state
->ntlmssp_state
) {
1355 nt_status
= ntlm_auth_start_ntlmssp_client(
1356 &state
->ntlmssp_state
);
1357 if (!NT_STATUS_IS_OK(nt_status
)) {
1358 x_fprintf(x_stdout
, "BH %s\n", nt_errstr(nt_status
));
1361 ntlmssp_want_feature_list(state
->ntlmssp_state
,
1362 state
->want_feature_list
);
1363 state
->initial_message
= data_blob_null
;
1366 DEBUG(10, ("got NTLMSSP packet:\n"));
1367 dump_data(10, request
.data
, request
.length
);
1369 if (use_cached_creds
&& !opt_password
&&
1370 (state
->cli_state
== CLIENT_RESPONSE
)) {
1371 nt_status
= do_ccache_ntlm_auth(state
->initial_message
, request
,
1374 nt_status
= ntlmssp_update(state
->ntlmssp_state
, request
,
1378 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1379 char *reply_base64
= base64_encode_data_blob(state
->mem_ctx
,
1381 if (state
->cli_state
== CLIENT_INITIAL
) {
1382 x_fprintf(x_stdout
, "YR %s\n", reply_base64
);
1383 state
->initial_message
= reply
;
1384 state
->cli_state
= CLIENT_RESPONSE
;
1386 x_fprintf(x_stdout
, "KK %s\n", reply_base64
);
1387 data_blob_free(&reply
);
1389 TALLOC_FREE(reply_base64
);
1390 DEBUG(10, ("NTLMSSP challenge\n"));
1391 } else if (NT_STATUS_IS_OK(nt_status
)) {
1392 char *reply_base64
= base64_encode_data_blob(talloc_tos(),
1394 x_fprintf(x_stdout
, "AF %s\n", reply_base64
);
1395 TALLOC_FREE(reply_base64
);
1397 if(state
->have_session_key
)
1398 data_blob_free(&state
->session_key
);
1400 state
->session_key
= data_blob(
1401 state
->ntlmssp_state
->session_key
.data
,
1402 state
->ntlmssp_state
->session_key
.length
);
1403 state
->neg_flags
= state
->ntlmssp_state
->neg_flags
;
1404 state
->have_session_key
= true;
1406 DEBUG(10, ("NTLMSSP OK!\n"));
1407 state
->cli_state
= CLIENT_FINISHED
;
1408 TALLOC_FREE(state
->ntlmssp_state
);
1410 x_fprintf(x_stdout
, "BH %s\n", nt_errstr(nt_status
));
1411 DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status
)));
1412 state
->cli_state
= CLIENT_ERROR
;
1413 TALLOC_FREE(state
->ntlmssp_state
);
1416 data_blob_free(&request
);
1419 static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode
,
1420 struct loadparm_context
*lp_ctx
,
1421 struct ntlm_auth_state
*state
,
1422 char *buf
, int length
, void **private2
)
1427 pass
=(char *)memchr(buf
,' ',length
);
1429 DEBUG(2, ("Password not found. Denying access\n"));
1430 x_fprintf(x_stdout
, "ERR\n");
1436 if (state
->helper_mode
== SQUID_2_5_BASIC
) {
1437 rfc1738_unescape(user
);
1438 rfc1738_unescape(pass
);
1441 if (check_plaintext_auth(user
, pass
, False
)) {
1442 x_fprintf(x_stdout
, "OK\n");
1444 x_fprintf(x_stdout
, "ERR\n");
1448 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode
,
1449 struct loadparm_context
*lp_ctx
,
1450 char *buf
, int length
, void **private1
)
1453 DATA_BLOB out
= data_blob(NULL
, 0);
1454 char *out_base64
= NULL
;
1455 const char *reply_arg
= NULL
;
1456 struct gensec_ntlm_state
{
1457 struct gensec_security
*gensec_state
;
1458 const char *set_password
;
1460 struct gensec_ntlm_state
*state
;
1464 const char *reply_code
;
1465 struct cli_credentials
*creds
;
1467 static char *want_feature_list
= NULL
;
1468 static DATA_BLOB session_key
;
1470 TALLOC_CTX
*mem_ctx
;
1473 state
= (struct gensec_ntlm_state
*)*private1
;
1475 state
= talloc_zero(NULL
, struct gensec_ntlm_state
);
1477 x_fprintf(x_stdout
, "BH No Memory\n");
1482 state
->set_password
= opt_password
;
1486 if (strlen(buf
) < 2) {
1487 DEBUG(1, ("query [%s] invalid", buf
));
1488 x_fprintf(x_stdout
, "BH Query invalid\n");
1492 if (strlen(buf
) > 3) {
1493 if(strncmp(buf
, "SF ", 3) == 0) {
1494 DEBUG(10, ("Setting flags to negotiate\n"));
1495 talloc_free(want_feature_list
);
1496 want_feature_list
= talloc_strndup(state
, buf
+3, strlen(buf
)-3);
1497 x_fprintf(x_stdout
, "OK\n");
1500 in
= base64_decode_data_blob(buf
+ 3);
1502 in
= data_blob(NULL
, 0);
1505 if (strncmp(buf
, "YR", 2) == 0) {
1506 if (state
->gensec_state
) {
1507 talloc_free(state
->gensec_state
);
1508 state
->gensec_state
= NULL
;
1510 } else if ( (strncmp(buf
, "OK", 2) == 0)) {
1511 /* Just return BH, like ntlm_auth from Samba 3 does. */
1512 x_fprintf(x_stdout
, "BH Command expected\n");
1513 data_blob_free(&in
);
1515 } else if ( (strncmp(buf
, "TT ", 3) != 0) &&
1516 (strncmp(buf
, "KK ", 3) != 0) &&
1517 (strncmp(buf
, "AF ", 3) != 0) &&
1518 (strncmp(buf
, "NA ", 3) != 0) &&
1519 (strncmp(buf
, "UG", 2) != 0) &&
1520 (strncmp(buf
, "PW ", 3) != 0) &&
1521 (strncmp(buf
, "GK", 2) != 0) &&
1522 (strncmp(buf
, "GF", 2) != 0)) {
1523 DEBUG(1, ("SPNEGO request [%s] invalid prefix\n", buf
));
1524 x_fprintf(x_stdout
, "BH SPNEGO request invalid prefix\n");
1525 data_blob_free(&in
);
1529 mem_ctx
= talloc_named(NULL
, 0, "manage_gensec_request internal mem_ctx");
1532 if (!(state
->gensec_state
)) {
1533 switch (stdio_helper_mode
) {
1534 case GSS_SPNEGO_CLIENT
:
1535 case NTLMSSP_CLIENT_1
:
1536 /* setup the client side */
1538 nt_status
= gensec_client_start(NULL
, &state
->gensec_state
,
1539 lpcfg_gensec_settings(NULL
, lp_ctx
));
1540 if (!NT_STATUS_IS_OK(nt_status
)) {
1541 x_fprintf(x_stdout
, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status
));
1542 talloc_free(mem_ctx
);
1546 creds
= cli_credentials_init(state
->gensec_state
);
1547 cli_credentials_set_conf(creds
, lp_ctx
);
1549 cli_credentials_set_username(creds
, opt_username
, CRED_SPECIFIED
);
1552 cli_credentials_set_domain(creds
, opt_domain
, CRED_SPECIFIED
);
1554 if (state
->set_password
) {
1555 cli_credentials_set_password(creds
, state
->set_password
, CRED_SPECIFIED
);
1557 cli_credentials_set_password_callback(creds
, get_password
);
1559 if (opt_workstation
) {
1560 cli_credentials_set_workstation(creds
, opt_workstation
, CRED_SPECIFIED
);
1563 gensec_set_credentials(state
->gensec_state
, creds
);
1566 case GSS_SPNEGO_SERVER
:
1567 case SQUID_2_5_NTLMSSP
:
1569 nt_status
= ntlm_auth_start_ntlmssp_server(state
, lp_ctx
,
1570 &state
->gensec_state
);
1571 if (!NT_STATUS_IS_OK(nt_status
)) {
1572 x_fprintf(x_stdout
, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status
));
1573 talloc_free(mem_ctx
);
1579 talloc_free(mem_ctx
);
1583 gensec_want_feature_list(state
->gensec_state
, want_feature_list
);
1585 switch (stdio_helper_mode
) {
1586 case GSS_SPNEGO_CLIENT
:
1587 case GSS_SPNEGO_SERVER
:
1588 nt_status
= gensec_start_mech_by_oid(state
->gensec_state
, GENSEC_OID_SPNEGO
);
1593 case NTLMSSP_CLIENT_1
:
1598 case SQUID_2_5_NTLMSSP
:
1599 nt_status
= gensec_start_mech_by_oid(state
->gensec_state
, GENSEC_OID_NTLMSSP
);
1602 talloc_free(mem_ctx
);
1606 if (!NT_STATUS_IS_OK(nt_status
)) {
1607 DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status
)));
1608 x_fprintf(x_stdout
, "BH GENSEC mech failed to start\n");
1609 talloc_free(mem_ctx
);
1617 if (strncmp(buf
, "PW ", 3) == 0) {
1618 state
->set_password
= talloc_strndup(state
,
1619 (const char *)in
.data
,
1622 cli_credentials_set_password(gensec_get_credentials(state
->gensec_state
),
1623 state
->set_password
,
1625 x_fprintf(x_stdout
, "OK\n");
1626 data_blob_free(&in
);
1627 talloc_free(mem_ctx
);
1631 if (strncmp(buf
, "GK", 2) == 0) {
1633 DEBUG(10, ("Requested session key\n"));
1634 nt_status
= gensec_session_key(state
->gensec_state
, mem_ctx
, &session_key
);
1635 if(!NT_STATUS_IS_OK(nt_status
)) {
1636 DEBUG(1, ("gensec_session_key failed: %s\n", nt_errstr(nt_status
)));
1637 x_fprintf(x_stdout
, "BH No session key\n");
1638 talloc_free(mem_ctx
);
1641 base64_key
= base64_encode_data_blob(state
, session_key
);
1642 x_fprintf(x_stdout
, "GK %s\n", base64_key
);
1643 talloc_free(base64_key
);
1645 talloc_free(mem_ctx
);
1649 if (stdio_helper_mode
== SQUID_2_5_NTLMSSP
&& strncmp(buf
, "GF", 2) == 0) {
1652 neg_flags
= gensec_ntlmssp_neg_flags(state
->gensec_state
);
1654 DEBUG(10, ("Requested negotiated feature flags\n"));
1655 x_fprintf(x_stdout
, "GF 0x%08x\n", neg_flags
);
1659 nt_status
= gensec_update(state
->gensec_state
, mem_ctx
, NULL
, in
, &out
);
1661 /* don't leak 'bad password'/'no such user' info to the network client */
1662 nt_status
= nt_status_squash(nt_status
);
1665 out_base64
= base64_encode_data_blob(mem_ctx
, out
);
1670 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1672 if (first
&& state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1674 } else if (state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1676 } else if (state
->gensec_state
->gensec_role
== GENSEC_SERVER
) {
1683 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCESS_DENIED
)) {
1684 reply_code
= "BH NT_STATUS_ACCESS_DENIED";
1685 reply_arg
= nt_errstr(nt_status
);
1686 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1687 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_UNSUCCESSFUL
)) {
1688 reply_code
= "BH NT_STATUS_UNSUCCESSFUL";
1689 reply_arg
= nt_errstr(nt_status
);
1690 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1691 } else if (!NT_STATUS_IS_OK(nt_status
)) {
1693 reply_arg
= nt_errstr(nt_status
);
1694 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1695 } else if /* OK */ (state
->gensec_state
->gensec_role
== GENSEC_SERVER
) {
1696 struct auth_session_info
*session_info
;
1698 nt_status
= gensec_session_info(state
->gensec_state
, mem_ctx
, &session_info
);
1699 if (!NT_STATUS_IS_OK(nt_status
)) {
1700 reply_code
= "BH Failed to retrive session info";
1701 reply_arg
= nt_errstr(nt_status
);
1702 DEBUG(1, ("GENSEC failed to retrieve the session info: %s\n", nt_errstr(nt_status
)));
1706 reply_arg
= session_info
->unix_info
->unix_name
;
1707 talloc_free(session_info
);
1709 } else if (state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1711 reply_arg
= out_base64
;
1716 switch (stdio_helper_mode
) {
1717 case GSS_SPNEGO_SERVER
:
1718 x_fprintf(x_stdout
, "%s %s %s\n", reply_code
,
1719 out_base64
? out_base64
: "*",
1720 reply_arg
? reply_arg
: "*");
1724 x_fprintf(x_stdout
, "%s %s\n", reply_code
, out_base64
);
1725 } else if (reply_arg
) {
1726 x_fprintf(x_stdout
, "%s %s\n", reply_code
, reply_arg
);
1728 x_fprintf(x_stdout
, "%s\n", reply_code
);
1732 talloc_free(mem_ctx
);
1736 static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode
,
1737 struct loadparm_context
*lp_ctx
,
1738 struct ntlm_auth_state
*state
,
1739 char *buf
, int length
, void **private2
)
1741 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1745 static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode
,
1746 struct loadparm_context
*lp_ctx
,
1747 struct ntlm_auth_state
*state
,
1748 char *buf
, int length
, void **private2
)
1750 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1754 static struct ntlmssp_state
*client_ntlmssp_state
= NULL
;
1756 static bool manage_client_ntlmssp_init(struct spnego_data spnego
)
1759 DATA_BLOB null_blob
= data_blob_null
;
1760 DATA_BLOB to_server
;
1761 char *to_server_base64
;
1762 const char *my_mechs
[] = {OID_NTLMSSP
, NULL
};
1763 TALLOC_CTX
*ctx
= talloc_tos();
1765 DEBUG(10, ("Got spnego negTokenInit with NTLMSSP\n"));
1767 if (client_ntlmssp_state
!= NULL
) {
1768 DEBUG(1, ("Request for initial SPNEGO request where "
1769 "we already have a state\n"));
1773 if (!client_ntlmssp_state
) {
1774 if (!NT_STATUS_IS_OK(status
= ntlm_auth_start_ntlmssp_client(&client_ntlmssp_state
))) {
1775 x_fprintf(x_stdout
, "BH %s\n", nt_errstr(status
));
1781 if (opt_password
== NULL
) {
1783 /* Request a password from the calling process. After
1784 sending it, the calling process should retry with
1785 the negTokenInit. */
1787 DEBUG(10, ("Requesting password\n"));
1788 x_fprintf(x_stdout
, "PW\n");
1792 spnego
.type
= SPNEGO_NEG_TOKEN_INIT
;
1793 spnego
.negTokenInit
.mechTypes
= my_mechs
;
1794 spnego
.negTokenInit
.reqFlags
= data_blob_null
;
1795 spnego
.negTokenInit
.reqFlagsPadding
= 0;
1796 spnego
.negTokenInit
.mechListMIC
= null_blob
;
1798 status
= ntlmssp_update(client_ntlmssp_state
, null_blob
,
1799 &spnego
.negTokenInit
.mechToken
);
1801 if ( !(NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
) ||
1802 NT_STATUS_IS_OK(status
)) ) {
1803 DEBUG(1, ("Expected OK or MORE_PROCESSING_REQUIRED, got: %s\n",
1804 nt_errstr(status
)));
1805 TALLOC_FREE(client_ntlmssp_state
);
1809 spnego_write_data(ctx
, &to_server
, &spnego
);
1810 data_blob_free(&spnego
.negTokenInit
.mechToken
);
1812 to_server_base64
= base64_encode_data_blob(talloc_tos(), to_server
);
1813 data_blob_free(&to_server
);
1814 x_fprintf(x_stdout
, "KK %s\n", to_server_base64
);
1815 TALLOC_FREE(to_server_base64
);
1819 static void manage_client_ntlmssp_targ(struct spnego_data spnego
)
1822 DATA_BLOB null_blob
= data_blob_null
;
1824 DATA_BLOB to_server
;
1825 char *to_server_base64
;
1826 TALLOC_CTX
*ctx
= talloc_tos();
1828 DEBUG(10, ("Got spnego negTokenTarg with NTLMSSP\n"));
1830 if (client_ntlmssp_state
== NULL
) {
1831 DEBUG(1, ("Got NTLMSSP tArg without a client state\n"));
1832 x_fprintf(x_stdout
, "BH Got NTLMSSP tArg without a client state\n");
1836 if (spnego
.negTokenTarg
.negResult
== SPNEGO_REJECT
) {
1837 x_fprintf(x_stdout
, "NA\n");
1838 TALLOC_FREE(client_ntlmssp_state
);
1842 if (spnego
.negTokenTarg
.negResult
== SPNEGO_ACCEPT_COMPLETED
) {
1843 x_fprintf(x_stdout
, "AF\n");
1844 TALLOC_FREE(client_ntlmssp_state
);
1848 status
= ntlmssp_update(client_ntlmssp_state
,
1849 spnego
.negTokenTarg
.responseToken
,
1852 if (!NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
) && !NT_STATUS_IS_OK(status
)) {
1853 DEBUG(1, ("Expected MORE_PROCESSING_REQUIRED or OK from "
1854 "ntlmssp_client_update, got: %s\n",
1855 nt_errstr(status
)));
1856 x_fprintf(x_stdout
, "BH Expected MORE_PROCESSING_REQUIRED from "
1857 "ntlmssp_client_update\n");
1858 data_blob_free(&request
);
1859 TALLOC_FREE(client_ntlmssp_state
);
1863 spnego
.type
= SPNEGO_NEG_TOKEN_TARG
;
1864 spnego
.negTokenTarg
.negResult
= SPNEGO_ACCEPT_INCOMPLETE
;
1865 spnego
.negTokenTarg
.supportedMech
= (const char *)OID_NTLMSSP
;
1866 spnego
.negTokenTarg
.responseToken
= request
;
1867 spnego
.negTokenTarg
.mechListMIC
= null_blob
;
1869 spnego_write_data(ctx
, &to_server
, &spnego
);
1870 data_blob_free(&request
);
1872 to_server_base64
= base64_encode_data_blob(talloc_tos(), to_server
);
1873 data_blob_free(&to_server
);
1874 x_fprintf(x_stdout
, "KK %s\n", to_server_base64
);
1875 TALLOC_FREE(to_server_base64
);
1881 static bool manage_client_krb5_init(struct spnego_data spnego
)
1884 DATA_BLOB tkt
, tkt_wrapped
, to_server
;
1885 DATA_BLOB session_key_krb5
= data_blob_null
;
1886 struct spnego_data reply
;
1890 const char *my_mechs
[] = {OID_KERBEROS5_OLD
, NULL
};
1892 TALLOC_CTX
*ctx
= talloc_tos();
1894 principal
= spnego
.negTokenInit
.targetPrincipal
;
1896 /* We may not be allowed to use the server-supplied SPNEGO principal, or it may not have been supplied to us
1898 if (!lp_client_use_spnego_principal() || strequal(principal
, ADS_IGNORE_PRINCIPAL
)) {
1902 if (principal
== NULL
&&
1903 opt_target_service
&& opt_target_hostname
&& !is_ipaddress(opt_target_hostname
)) {
1904 DEBUG(3,("manage_client_krb5_init: using target "
1905 "hostname not SPNEGO principal\n"));
1907 principal
= kerberos_get_principal_from_service_hostname(talloc_tos(),
1909 opt_target_hostname
,
1916 DEBUG(3,("manage_client_krb5_init: guessed "
1917 "server principal=%s\n",
1918 principal
? principal
: "<null>"));
1921 if (principal
== NULL
) {
1922 DEBUG(3,("manage_client_krb5_init: could not guess server principal\n"));
1926 retval
= cli_krb5_get_ticket(ctx
, principal
, 0,
1927 &tkt
, &session_key_krb5
,
1928 0, NULL
, NULL
, NULL
);
1932 /* Let's try to first get the TGT, for that we need a
1935 if (opt_password
== NULL
) {
1936 DEBUG(10, ("Requesting password\n"));
1937 x_fprintf(x_stdout
, "PW\n");
1941 user
= talloc_asprintf(talloc_tos(), "%s@%s", opt_username
, opt_domain
);
1946 if ((retval
= kerberos_kinit_password(user
, opt_password
, 0, NULL
))) {
1947 DEBUG(10, ("Requesting TGT failed: %s\n", error_message(retval
)));
1951 retval
= cli_krb5_get_ticket(ctx
, principal
, 0,
1952 &tkt
, &session_key_krb5
,
1953 0, NULL
, NULL
, NULL
);
1955 DEBUG(10, ("Kinit suceeded, but getting a ticket failed: %s\n", error_message(retval
)));
1961 /* wrap that up in a nice GSS-API wrapping */
1962 tkt_wrapped
= spnego_gen_krb5_wrap(ctx
, tkt
, TOK_ID_KRB_AP_REQ
);
1964 data_blob_free(&session_key_krb5
);
1968 reply
.type
= SPNEGO_NEG_TOKEN_INIT
;
1969 reply
.negTokenInit
.mechTypes
= my_mechs
;
1970 reply
.negTokenInit
.reqFlags
= data_blob_null
;
1971 reply
.negTokenInit
.reqFlagsPadding
= 0;
1972 reply
.negTokenInit
.mechToken
= tkt_wrapped
;
1973 reply
.negTokenInit
.mechListMIC
= data_blob_null
;
1975 len
= spnego_write_data(ctx
, &to_server
, &reply
);
1976 data_blob_free(&tkt
);
1979 DEBUG(1, ("Could not write SPNEGO data blob\n"));
1983 reply_base64
= base64_encode_data_blob(talloc_tos(), to_server
);
1984 x_fprintf(x_stdout
, "KK %s *\n", reply_base64
);
1986 TALLOC_FREE(reply_base64
);
1987 data_blob_free(&to_server
);
1988 DEBUG(10, ("sent GSS-SPNEGO KERBEROS5 negTokenInit\n"));
1992 static void manage_client_krb5_targ(struct spnego_data spnego
)
1994 switch (spnego
.negTokenTarg
.negResult
) {
1995 case SPNEGO_ACCEPT_INCOMPLETE
:
1996 DEBUG(1, ("Got a Kerberos negTokenTarg with ACCEPT_INCOMPLETE\n"));
1997 x_fprintf(x_stdout
, "BH Got a Kerberos negTokenTarg with "
1998 "ACCEPT_INCOMPLETE\n");
2000 case SPNEGO_ACCEPT_COMPLETED
:
2001 DEBUG(10, ("Accept completed\n"));
2002 x_fprintf(x_stdout
, "AF\n");
2005 DEBUG(10, ("Rejected\n"));
2006 x_fprintf(x_stdout
, "NA\n");
2009 DEBUG(1, ("Got an invalid negTokenTarg\n"));
2010 x_fprintf(x_stdout
, "AF\n");
2016 static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode
,
2017 struct loadparm_context
*lp_ctx
,
2018 struct ntlm_auth_state
*state
,
2019 char *buf
, int length
, void **private2
)
2022 struct spnego_data spnego
;
2024 TALLOC_CTX
*ctx
= talloc_tos();
2026 if (!opt_username
|| !*opt_username
) {
2027 x_fprintf(x_stderr
, "username must be specified!\n\n");
2031 if (strlen(buf
) <= 3) {
2032 DEBUG(1, ("SPNEGO query [%s] too short\n", buf
));
2033 x_fprintf(x_stdout
, "BH SPNEGO query too short\n");
2037 request
= base64_decode_data_blob(buf
+3);
2039 if (strncmp(buf
, "PW ", 3) == 0) {
2041 /* We asked for a password and obviously got it :-) */
2043 opt_password
= SMB_STRNDUP((const char *)request
.data
, request
.length
);
2045 if (opt_password
== NULL
) {
2046 DEBUG(1, ("Out of memory\n"));
2047 x_fprintf(x_stdout
, "BH Out of memory\n");
2048 data_blob_free(&request
);
2052 x_fprintf(x_stdout
, "OK\n");
2053 data_blob_free(&request
);
2057 if ( (strncmp(buf
, "TT ", 3) != 0) &&
2058 (strncmp(buf
, "AF ", 3) != 0) &&
2059 (strncmp(buf
, "NA ", 3) != 0) ) {
2060 DEBUG(1, ("SPNEGO request [%s] invalid\n", buf
));
2061 x_fprintf(x_stdout
, "BH SPNEGO request invalid\n");
2062 data_blob_free(&request
);
2066 /* So we got a server challenge to generate a SPNEGO
2067 client-to-server request... */
2069 len
= spnego_read_data(ctx
, request
, &spnego
);
2070 data_blob_free(&request
);
2073 DEBUG(1, ("Could not read SPNEGO data for [%s]\n", buf
));
2074 x_fprintf(x_stdout
, "BH Could not read SPNEGO data\n");
2078 if (spnego
.type
== SPNEGO_NEG_TOKEN_INIT
) {
2080 /* The server offers a list of mechanisms */
2082 const char **mechType
= (const char **)spnego
.negTokenInit
.mechTypes
;
2084 while (*mechType
!= NULL
) {
2087 if ( (strcmp(*mechType
, OID_KERBEROS5_OLD
) == 0) ||
2088 (strcmp(*mechType
, OID_KERBEROS5
) == 0) ) {
2089 if (manage_client_krb5_init(spnego
))
2094 if (strcmp(*mechType
, OID_NTLMSSP
) == 0) {
2095 if (manage_client_ntlmssp_init(spnego
))
2102 DEBUG(1, ("Server offered no compatible mechanism\n"));
2103 x_fprintf(x_stdout
, "BH Server offered no compatible mechanism\n");
2107 if (spnego
.type
== SPNEGO_NEG_TOKEN_TARG
) {
2109 if (spnego
.negTokenTarg
.supportedMech
== NULL
) {
2110 /* On accept/reject Windows does not send the
2111 mechanism anymore. Handle that here and
2112 shut down the mechanisms. */
2114 switch (spnego
.negTokenTarg
.negResult
) {
2115 case SPNEGO_ACCEPT_COMPLETED
:
2116 x_fprintf(x_stdout
, "AF\n");
2119 x_fprintf(x_stdout
, "NA\n");
2122 DEBUG(1, ("Got a negTokenTarg with no mech and an "
2123 "unknown negResult: %d\n",
2124 spnego
.negTokenTarg
.negResult
));
2125 x_fprintf(x_stdout
, "BH Got a negTokenTarg with"
2126 " no mech and an unknown "
2130 TALLOC_FREE(client_ntlmssp_state
);
2134 if (strcmp(spnego
.negTokenTarg
.supportedMech
,
2135 OID_NTLMSSP
) == 0) {
2136 manage_client_ntlmssp_targ(spnego
);
2141 if (strcmp(spnego
.negTokenTarg
.supportedMech
,
2142 OID_KERBEROS5_OLD
) == 0) {
2143 manage_client_krb5_targ(spnego
);
2150 DEBUG(1, ("Got an SPNEGO token I could not handle [%s]!\n", buf
));
2151 x_fprintf(x_stdout
, "BH Got an SPNEGO token I could not handle\n");
2155 spnego_free_data(&spnego
);
2159 static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode
,
2160 struct loadparm_context
*lp_ctx
,
2161 struct ntlm_auth_state
*state
,
2162 char *buf
, int length
, void **private2
)
2164 char *request
, *parameter
;
2165 static DATA_BLOB challenge
;
2166 static DATA_BLOB lm_response
;
2167 static DATA_BLOB nt_response
;
2168 static char *full_username
;
2169 static char *username
;
2170 static char *domain
;
2171 static char *plaintext_password
;
2172 static bool ntlm_server_1_user_session_key
;
2173 static bool ntlm_server_1_lm_session_key
;
2175 if (strequal(buf
, ".")) {
2176 if (!full_username
&& !username
) {
2177 x_fprintf(x_stdout
, "Error: No username supplied!\n");
2178 } else if (plaintext_password
) {
2179 /* handle this request as plaintext */
2180 if (!full_username
) {
2181 if (asprintf(&full_username
, "%s%c%s", domain
, winbind_separator(), username
) == -1) {
2182 x_fprintf(x_stdout
, "Error: Out of memory in asprintf!\n.\n");
2186 if (check_plaintext_auth(full_username
, plaintext_password
, False
)) {
2187 x_fprintf(x_stdout
, "Authenticated: Yes\n");
2189 x_fprintf(x_stdout
, "Authenticated: No\n");
2191 } else if (!lm_response
.data
&& !nt_response
.data
) {
2192 x_fprintf(x_stdout
, "Error: No password supplied!\n");
2193 } else if (!challenge
.data
) {
2194 x_fprintf(x_stdout
, "Error: No lanman-challenge supplied!\n");
2196 char *error_string
= NULL
;
2198 uchar user_session_key
[16];
2201 if (full_username
&& !username
) {
2203 fstring fstr_domain
;
2205 if (!parse_ntlm_auth_domain_user(full_username
, fstr_user
, fstr_domain
)) {
2206 /* username might be 'tainted', don't print into our new-line deleimianted stream */
2207 x_fprintf(x_stdout
, "Error: Could not parse into domain and username\n");
2209 SAFE_FREE(username
);
2211 username
= smb_xstrdup(fstr_user
);
2212 domain
= smb_xstrdup(fstr_domain
);
2216 domain
= smb_xstrdup(get_winbind_domain());
2219 if (ntlm_server_1_lm_session_key
)
2220 flags
|= WBFLAG_PAM_LMKEY
;
2222 if (ntlm_server_1_user_session_key
)
2223 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
2225 if (!NT_STATUS_IS_OK(
2226 contact_winbind_auth_crap(username
,
2238 x_fprintf(x_stdout
, "Authenticated: No\n");
2239 x_fprintf(x_stdout
, "Authentication-Error: %s\n.\n", error_string
);
2241 static char zeros
[16];
2243 char *hex_user_session_key
;
2245 x_fprintf(x_stdout
, "Authenticated: Yes\n");
2247 if (ntlm_server_1_lm_session_key
2248 && (memcmp(zeros
, lm_key
,
2249 sizeof(lm_key
)) != 0)) {
2250 hex_lm_key
= hex_encode_talloc(NULL
,
2251 (const unsigned char *)lm_key
,
2253 x_fprintf(x_stdout
, "LANMAN-Session-Key: %s\n", hex_lm_key
);
2254 TALLOC_FREE(hex_lm_key
);
2257 if (ntlm_server_1_user_session_key
2258 && (memcmp(zeros
, user_session_key
,
2259 sizeof(user_session_key
)) != 0)) {
2260 hex_user_session_key
= hex_encode_talloc(NULL
,
2261 (const unsigned char *)user_session_key
,
2262 sizeof(user_session_key
));
2263 x_fprintf(x_stdout
, "User-Session-Key: %s\n", hex_user_session_key
);
2264 TALLOC_FREE(hex_user_session_key
);
2267 SAFE_FREE(error_string
);
2269 /* clear out the state */
2270 challenge
= data_blob_null
;
2271 nt_response
= data_blob_null
;
2272 lm_response
= data_blob_null
;
2273 SAFE_FREE(full_username
);
2274 SAFE_FREE(username
);
2276 SAFE_FREE(plaintext_password
);
2277 ntlm_server_1_user_session_key
= False
;
2278 ntlm_server_1_lm_session_key
= False
;
2279 x_fprintf(x_stdout
, ".\n");
2286 /* Indicates a base64 encoded structure */
2287 parameter
= strstr_m(request
, ":: ");
2289 parameter
= strstr_m(request
, ": ");
2292 DEBUG(0, ("Parameter not found!\n"));
2293 x_fprintf(x_stdout
, "Error: Parameter not found!\n.\n");
2310 base64_decode_inplace(parameter
);
2313 if (strequal(request
, "LANMAN-Challenge")) {
2314 challenge
= strhex_to_data_blob(NULL
, parameter
);
2315 if (challenge
.length
!= 8) {
2316 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (got %d bytes, expected 8)\n.\n",
2318 (int)challenge
.length
);
2319 challenge
= data_blob_null
;
2321 } else if (strequal(request
, "NT-Response")) {
2322 nt_response
= strhex_to_data_blob(NULL
, parameter
);
2323 if (nt_response
.length
< 24) {
2324 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (only got %d bytes, needed at least 24)\n.\n",
2326 (int)nt_response
.length
);
2327 nt_response
= data_blob_null
;
2329 } else if (strequal(request
, "LANMAN-Response")) {
2330 lm_response
= strhex_to_data_blob(NULL
, parameter
);
2331 if (lm_response
.length
!= 24) {
2332 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (got %d bytes, expected 24)\n.\n",
2334 (int)lm_response
.length
);
2335 lm_response
= data_blob_null
;
2337 } else if (strequal(request
, "Password")) {
2338 plaintext_password
= smb_xstrdup(parameter
);
2339 } else if (strequal(request
, "NT-Domain")) {
2340 domain
= smb_xstrdup(parameter
);
2341 } else if (strequal(request
, "Username")) {
2342 username
= smb_xstrdup(parameter
);
2343 } else if (strequal(request
, "Full-Username")) {
2344 full_username
= smb_xstrdup(parameter
);
2345 } else if (strequal(request
, "Request-User-Session-Key")) {
2346 ntlm_server_1_user_session_key
= strequal(parameter
, "Yes");
2347 } else if (strequal(request
, "Request-LanMan-Session-Key")) {
2348 ntlm_server_1_lm_session_key
= strequal(parameter
, "Yes");
2350 x_fprintf(x_stdout
, "Error: Unknown request %s\n.\n", request
);
2354 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode
,
2355 struct loadparm_context
*lp_ctx
,
2356 struct ntlm_auth_state
*state
,
2357 char *buf
, int length
, void **private2
)
2359 char *request
, *parameter
;
2360 static DATA_BLOB new_nt_pswd
;
2361 static DATA_BLOB old_nt_hash_enc
;
2362 static DATA_BLOB new_lm_pswd
;
2363 static DATA_BLOB old_lm_hash_enc
;
2364 static char *full_username
= NULL
;
2365 static char *username
= NULL
;
2366 static char *domain
= NULL
;
2367 static char *newpswd
= NULL
;
2368 static char *oldpswd
= NULL
;
2370 if (strequal(buf
, ".")) {
2371 if(newpswd
&& oldpswd
) {
2372 uchar old_nt_hash
[16];
2373 uchar old_lm_hash
[16];
2374 uchar new_nt_hash
[16];
2375 uchar new_lm_hash
[16];
2377 new_nt_pswd
= data_blob(NULL
, 516);
2378 old_nt_hash_enc
= data_blob(NULL
, 16);
2380 /* Calculate the MD4 hash (NT compatible) of the
2382 E_md4hash(oldpswd
, old_nt_hash
);
2383 E_md4hash(newpswd
, new_nt_hash
);
2385 /* E_deshash returns false for 'long'
2386 passwords (> 14 DOS chars).
2388 Therefore, don't send a buffer
2389 encrypted with the truncated hash
2390 (it could allow an even easier
2391 attack on the password)
2393 Likewise, obey the admin's restriction
2396 if (lp_client_lanman_auth() &&
2397 E_deshash(newpswd
, new_lm_hash
) &&
2398 E_deshash(oldpswd
, old_lm_hash
)) {
2399 new_lm_pswd
= data_blob(NULL
, 516);
2400 old_lm_hash_enc
= data_blob(NULL
, 16);
2401 encode_pw_buffer(new_lm_pswd
.data
, newpswd
,
2404 arcfour_crypt(new_lm_pswd
.data
, old_nt_hash
, 516);
2405 E_old_pw_hash(new_nt_hash
, old_lm_hash
,
2406 old_lm_hash_enc
.data
);
2408 new_lm_pswd
.data
= NULL
;
2409 new_lm_pswd
.length
= 0;
2410 old_lm_hash_enc
.data
= NULL
;
2411 old_lm_hash_enc
.length
= 0;
2414 encode_pw_buffer(new_nt_pswd
.data
, newpswd
,
2417 arcfour_crypt(new_nt_pswd
.data
, old_nt_hash
, 516);
2418 E_old_pw_hash(new_nt_hash
, old_nt_hash
,
2419 old_nt_hash_enc
.data
);
2422 if (!full_username
&& !username
) {
2423 x_fprintf(x_stdout
, "Error: No username supplied!\n");
2424 } else if ((!new_nt_pswd
.data
|| !old_nt_hash_enc
.data
) &&
2425 (!new_lm_pswd
.data
|| old_lm_hash_enc
.data
) ) {
2426 x_fprintf(x_stdout
, "Error: No NT or LM password "
2427 "blobs supplied!\n");
2429 char *error_string
= NULL
;
2431 if (full_username
&& !username
) {
2433 fstring fstr_domain
;
2435 if (!parse_ntlm_auth_domain_user(full_username
,
2438 /* username might be 'tainted', don't
2439 * print into our new-line
2440 * deleimianted stream */
2441 x_fprintf(x_stdout
, "Error: Could not "
2442 "parse into domain and "
2444 SAFE_FREE(username
);
2445 username
= smb_xstrdup(full_username
);
2447 SAFE_FREE(username
);
2449 username
= smb_xstrdup(fstr_user
);
2450 domain
= smb_xstrdup(fstr_domain
);
2455 if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
2462 x_fprintf(x_stdout
, "Password-Change: No\n");
2463 x_fprintf(x_stdout
, "Password-Change-Error: "
2464 "%s\n.\n", error_string
);
2466 x_fprintf(x_stdout
, "Password-Change: Yes\n");
2469 SAFE_FREE(error_string
);
2471 /* clear out the state */
2472 new_nt_pswd
= data_blob_null
;
2473 old_nt_hash_enc
= data_blob_null
;
2474 new_lm_pswd
= data_blob_null
;
2475 old_nt_hash_enc
= data_blob_null
;
2476 SAFE_FREE(full_username
);
2477 SAFE_FREE(username
);
2481 x_fprintf(x_stdout
, ".\n");
2488 /* Indicates a base64 encoded structure */
2489 parameter
= strstr_m(request
, ":: ");
2491 parameter
= strstr_m(request
, ": ");
2494 DEBUG(0, ("Parameter not found!\n"));
2495 x_fprintf(x_stdout
, "Error: Parameter not found!\n.\n");
2511 base64_decode_inplace(parameter
);
2514 if (strequal(request
, "new-nt-password-blob")) {
2515 new_nt_pswd
= strhex_to_data_blob(NULL
, parameter
);
2516 if (new_nt_pswd
.length
!= 516) {
2517 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2518 "(got %d bytes, expected 516)\n.\n",
2520 (int)new_nt_pswd
.length
);
2521 new_nt_pswd
= data_blob_null
;
2523 } else if (strequal(request
, "old-nt-hash-blob")) {
2524 old_nt_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2525 if (old_nt_hash_enc
.length
!= 16) {
2526 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2527 "(got %d bytes, expected 16)\n.\n",
2529 (int)old_nt_hash_enc
.length
);
2530 old_nt_hash_enc
= data_blob_null
;
2532 } else if (strequal(request
, "new-lm-password-blob")) {
2533 new_lm_pswd
= strhex_to_data_blob(NULL
, parameter
);
2534 if (new_lm_pswd
.length
!= 516) {
2535 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2536 "(got %d bytes, expected 516)\n.\n",
2538 (int)new_lm_pswd
.length
);
2539 new_lm_pswd
= data_blob_null
;
2542 else if (strequal(request
, "old-lm-hash-blob")) {
2543 old_lm_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2544 if (old_lm_hash_enc
.length
!= 16)
2546 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2547 "(got %d bytes, expected 16)\n.\n",
2549 (int)old_lm_hash_enc
.length
);
2550 old_lm_hash_enc
= data_blob_null
;
2552 } else if (strequal(request
, "nt-domain")) {
2553 domain
= smb_xstrdup(parameter
);
2554 } else if(strequal(request
, "username")) {
2555 username
= smb_xstrdup(parameter
);
2556 } else if(strequal(request
, "full-username")) {
2557 username
= smb_xstrdup(parameter
);
2558 } else if(strequal(request
, "new-password")) {
2559 newpswd
= smb_xstrdup(parameter
);
2560 } else if (strequal(request
, "old-password")) {
2561 oldpswd
= smb_xstrdup(parameter
);
2563 x_fprintf(x_stdout
, "Error: Unknown request %s\n.\n", request
);
2567 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode
,
2568 struct loadparm_context
*lp_ctx
,
2569 struct ntlm_auth_state
*state
,
2570 stdio_helper_function fn
, void **private2
)
2573 char tmp
[INITIAL_BUFFER_SIZE
+1];
2574 int length
, buf_size
= 0;
2577 buf
= talloc_strdup(state
->mem_ctx
, "");
2579 DEBUG(0, ("Failed to allocate input buffer.\n"));
2580 x_fprintf(x_stderr
, "ERR\n");
2586 /* this is not a typo - x_fgets doesn't work too well under
2588 if (fgets(tmp
, sizeof(tmp
)-1, stdin
) == NULL
) {
2589 if (ferror(stdin
)) {
2590 DEBUG(1, ("fgets() failed! dying..... errno=%d "
2591 "(%s)\n", ferror(stdin
),
2592 strerror(ferror(stdin
))));
2599 buf
= talloc_strdup_append_buffer(buf
, tmp
);
2600 buf_size
+= INITIAL_BUFFER_SIZE
;
2602 if (buf_size
> MAX_BUFFER_SIZE
) {
2603 DEBUG(2, ("Oversized message\n"));
2604 x_fprintf(x_stderr
, "ERR\n");
2609 c
= strchr(buf
, '\n');
2610 } while (c
== NULL
);
2615 DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf
,length
));
2617 if (buf
[0] == '\0') {
2618 DEBUG(2, ("Invalid Request\n"));
2619 x_fprintf(x_stderr
, "ERR\n");
2624 fn(stdio_helper_mode
, lp_ctx
, state
, buf
, length
, private2
);
2629 static void squid_stream(enum stdio_helper_mode stdio_mode
,
2630 struct loadparm_context
*lp_ctx
,
2631 stdio_helper_function fn
) {
2632 TALLOC_CTX
*mem_ctx
;
2633 struct ntlm_auth_state
*state
;
2635 /* initialize FDescs */
2636 x_setbuf(x_stdout
, NULL
);
2637 x_setbuf(x_stderr
, NULL
);
2639 mem_ctx
= talloc_init("ntlm_auth");
2641 DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
2642 x_fprintf(x_stderr
, "ERR\n");
2646 state
= talloc_zero(mem_ctx
, struct ntlm_auth_state
);
2648 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
2649 x_fprintf(x_stderr
, "ERR\n");
2653 state
->mem_ctx
= mem_ctx
;
2654 state
->helper_mode
= stdio_mode
;
2657 TALLOC_CTX
*frame
= talloc_stackframe();
2658 manage_squid_request(stdio_mode
, lp_ctx
, state
, fn
, NULL
);
2664 /* Authenticate a user with a challenge/response */
2666 static bool check_auth_crap(void)
2671 char user_session_key
[16];
2673 char *hex_user_session_key
;
2675 static uint8 zeros
[16];
2677 x_setbuf(x_stdout
, NULL
);
2680 flags
|= WBFLAG_PAM_LMKEY
;
2682 if (request_user_session_key
)
2683 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
2685 flags
|= WBFLAG_PAM_NT_STATUS_SQUASH
;
2687 nt_status
= contact_winbind_auth_crap(opt_username
, opt_domain
,
2693 (unsigned char *)lm_key
,
2694 (unsigned char *)user_session_key
,
2695 &error_string
, NULL
);
2697 if (!NT_STATUS_IS_OK(nt_status
)) {
2698 x_fprintf(x_stdout
, "%s (0x%x)\n",
2700 NT_STATUS_V(nt_status
));
2701 SAFE_FREE(error_string
);
2706 && (memcmp(zeros
, lm_key
,
2707 sizeof(lm_key
)) != 0)) {
2708 hex_lm_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)lm_key
,
2710 x_fprintf(x_stdout
, "LM_KEY: %s\n", hex_lm_key
);
2711 TALLOC_FREE(hex_lm_key
);
2713 if (request_user_session_key
2714 && (memcmp(zeros
, user_session_key
,
2715 sizeof(user_session_key
)) != 0)) {
2716 hex_user_session_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)user_session_key
,
2717 sizeof(user_session_key
));
2718 x_fprintf(x_stdout
, "NT_KEY: %s\n", hex_user_session_key
);
2719 TALLOC_FREE(hex_user_session_key
);
2728 OPT_USERNAME
= 1000,
2737 OPT_USER_SESSION_KEY
,
2739 OPT_REQUIRE_MEMBERSHIP
,
2740 OPT_USE_CACHED_CREDS
,
2741 OPT_PAM_WINBIND_CONF
,
2746 int main(int argc
, const char **argv
)
2748 TALLOC_CTX
*frame
= talloc_stackframe();
2750 static const char *helper_protocol
;
2751 static int diagnostics
;
2753 static const char *hex_challenge
;
2754 static const char *hex_lm_response
;
2755 static const char *hex_nt_response
;
2756 struct loadparm_context
*lp_ctx
;
2759 /* NOTE: DO NOT change this interface without considering the implications!
2760 This is an external interface, which other programs will use to interact
2764 /* We do not use single-letter command abbreviations, because they harm future
2765 interface stability. */
2767 struct poptOption long_options
[] = {
2769 { "helper-protocol", 0, POPT_ARG_STRING
, &helper_protocol
, OPT_DOMAIN
, "operate as a stdio-based helper", "helper protocol to use"},
2770 { "username", 0, POPT_ARG_STRING
, &opt_username
, OPT_USERNAME
, "username"},
2771 { "domain", 0, POPT_ARG_STRING
, &opt_domain
, OPT_DOMAIN
, "domain name"},
2772 { "workstation", 0, POPT_ARG_STRING
, &opt_workstation
, OPT_WORKSTATION
, "workstation"},
2773 { "challenge", 0, POPT_ARG_STRING
, &hex_challenge
, OPT_CHALLENGE
, "challenge (HEX encoded)"},
2774 { "lm-response", 0, POPT_ARG_STRING
, &hex_lm_response
, OPT_LM
, "LM Response to the challenge (HEX encoded)"},
2775 { "nt-response", 0, POPT_ARG_STRING
, &hex_nt_response
, OPT_NT
, "NT or NTLMv2 Response to the challenge (HEX encoded)"},
2776 { "password", 0, POPT_ARG_STRING
, &opt_password
, OPT_PASSWORD
, "User's plaintext password"},
2777 { "request-lm-key", 0, POPT_ARG_NONE
, &request_lm_key
, OPT_LM_KEY
, "Retrieve LM session key"},
2778 { "request-nt-key", 0, POPT_ARG_NONE
, &request_user_session_key
, OPT_USER_SESSION_KEY
, "Retrieve User (NT) session key"},
2779 { "use-cached-creds", 0, POPT_ARG_NONE
, &use_cached_creds
, OPT_USE_CACHED_CREDS
, "Use cached credentials if no password is given"},
2780 { "diagnostics", 0, POPT_ARG_NONE
, &diagnostics
,
2782 "Perform diagnostics on the authentication chain"},
2783 { "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" },
2784 { "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" },
2785 { "target-service", 0, POPT_ARG_STRING
, &opt_target_service
, OPT_TARGET_SERVICE
, "Target service (eg http)" },
2786 { "target-hostname", 0, POPT_ARG_STRING
, &opt_target_hostname
, OPT_TARGET_HOSTNAME
, "Target hostname" },
2787 POPT_COMMON_CONFIGFILE
2792 /* Samba client initialisation */
2795 setup_logging("ntlm_auth", DEBUG_STDERR
);
2799 pc
= poptGetContext("ntlm_auth", argc
, argv
, long_options
, 0);
2801 /* Parse command line options */
2804 poptPrintHelp(pc
, stderr
, 0);
2808 while((opt
= poptGetNextOpt(pc
)) != -1) {
2809 /* Get generic config options like --configfile */
2812 poptFreeContext(pc
);
2814 if (!lp_load_global(get_dyn_CONFIGFILE())) {
2815 d_fprintf(stderr
, "ntlm_auth: error opening config file %s. Error was %s\n",
2816 get_dyn_CONFIGFILE(), strerror(errno
));
2820 pc
= poptGetContext(NULL
, argc
, (const char **)argv
, long_options
,
2821 POPT_CONTEXT_KEEP_FIRST
);
2823 while((opt
= poptGetNextOpt(pc
)) != -1) {
2826 opt_challenge
= strhex_to_data_blob(NULL
, hex_challenge
);
2827 if (opt_challenge
.length
!= 8) {
2828 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2830 (int)opt_challenge
.length
);
2835 opt_lm_response
= strhex_to_data_blob(NULL
, hex_lm_response
);
2836 if (opt_lm_response
.length
!= 24) {
2837 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2839 (int)opt_lm_response
.length
);
2845 opt_nt_response
= strhex_to_data_blob(NULL
, hex_nt_response
);
2846 if (opt_nt_response
.length
< 24) {
2847 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2849 (int)opt_nt_response
.length
);
2854 case OPT_REQUIRE_MEMBERSHIP
:
2855 if (strncasecmp_m("S-", require_membership_of
, 2) == 0) {
2856 require_membership_of_sid
= require_membership_of
;
2863 char *domain
= SMB_STRDUP(opt_username
);
2864 char *p
= strchr_m(domain
, *lp_winbind_separator());
2868 if (opt_domain
&& !strequal(opt_domain
, domain
)) {
2869 x_fprintf(x_stderr
, "Domain specified in username (%s) "
2870 "doesn't match specified domain (%s)!\n\n",
2871 domain
, opt_domain
);
2872 poptPrintHelp(pc
, stderr
, 0);
2875 opt_domain
= domain
;
2881 /* Note: if opt_domain is "" then send no domain */
2882 if (opt_domain
== NULL
) {
2883 opt_domain
= get_winbind_domain();
2886 if (opt_workstation
== NULL
) {
2887 opt_workstation
= "";
2890 lp_ctx
= loadparm_init_s3(NULL
, loadparm_s3_helpers());
2891 if (lp_ctx
== NULL
) {
2892 x_fprintf(x_stderr
, "loadparm_init_s3() failed!\n");
2896 if (helper_protocol
) {
2898 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2899 if (strcmp(helper_protocol
, stdio_helper_protocols
[i
].name
) == 0) {
2900 squid_stream(stdio_helper_protocols
[i
].mode
, lp_ctx
, stdio_helper_protocols
[i
].fn
);
2904 x_fprintf(x_stderr
, "unknown helper protocol [%s]\n\nValid helper protools:\n\n", helper_protocol
);
2906 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2907 x_fprintf(x_stderr
, "%s\n", stdio_helper_protocols
[i
].name
);
2913 if (!opt_username
|| !*opt_username
) {
2914 x_fprintf(x_stderr
, "username must be specified!\n\n");
2915 poptPrintHelp(pc
, stderr
, 0);
2919 if (opt_challenge
.length
) {
2920 if (!check_auth_crap()) {
2926 if (!opt_password
) {
2927 opt_password
= getpass("password: ");
2931 if (!diagnose_ntlm_auth()) {
2937 fstr_sprintf(user
, "%s%c%s", opt_domain
, winbind_separator(), opt_username
);
2938 if (!check_plaintext_auth(user
, opt_password
, True
)) {
2945 poptFreeContext(pc
);