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/gensec/gensec_internal.h"
36 #include "auth/credentials/credentials.h"
37 #include "librpc/crypto/gse.h"
39 #include "lib/util/tiniparser.h"
40 #include "../lib/crypto/arcfour.h"
41 #include "libads/kerberos_proto.h"
42 #include "nsswitch/winbind_client.h"
43 #include "librpc/gen_ndr/krb5pac.h"
44 #include "../lib/util/asn1.h"
45 #include "auth/common_auth.h"
46 #include "source3/include/auth.h"
47 #include "source3/auth/proto.h"
48 #include "nsswitch/libwbclient/wbclient.h"
49 #include "lib/param/loadparm.h"
52 #include "auth/kerberos/pac_utils.h"
55 #ifndef PAM_WINBIND_CONFIG_FILE
56 #define PAM_WINBIND_CONFIG_FILE "/etc/security/pam_winbind.conf"
59 #define WINBIND_KRB5_AUTH 0x00000080
62 #define DBGC_CLASS DBGC_WINBIND
64 #define INITIAL_BUFFER_SIZE 300
65 #define MAX_BUFFER_SIZE 630000
67 enum stdio_helper_mode
{
75 NTLM_CHANGE_PASSWORD_1
,
79 enum ntlm_auth_cli_state
{
86 struct ntlm_auth_state
{
88 enum stdio_helper_mode helper_mode
;
89 enum ntlm_auth_cli_state cli_state
;
90 struct ntlmssp_state
*ntlmssp_state
;
92 char *want_feature_list
;
93 bool have_session_key
;
94 DATA_BLOB session_key
;
95 DATA_BLOB initial_message
;
96 void *gensec_private_1
;
98 typedef void (*stdio_helper_function
)(enum stdio_helper_mode stdio_helper_mode
,
99 struct loadparm_context
*lp_ctx
,
100 struct ntlm_auth_state
*state
, char *buf
,
101 int length
, void **private2
);
103 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode
,
104 struct loadparm_context
*lp_ctx
,
105 struct ntlm_auth_state
*state
,
106 stdio_helper_function fn
, void **private2
);
108 static void manage_squid_basic_request (enum stdio_helper_mode stdio_helper_mode
,
109 struct loadparm_context
*lp_ctx
,
110 struct ntlm_auth_state
*state
,
111 char *buf
, int length
, void **private2
);
113 static void manage_squid_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode
,
114 struct loadparm_context
*lp_ctx
,
115 struct ntlm_auth_state
*state
,
116 char *buf
, int length
, void **private2
);
118 static void manage_client_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode
,
119 struct loadparm_context
*lp_ctx
,
120 struct ntlm_auth_state
*state
,
121 char *buf
, int length
, void **private2
);
123 static void manage_gss_spnego_request (enum stdio_helper_mode stdio_helper_mode
,
124 struct loadparm_context
*lp_ctx
,
125 struct ntlm_auth_state
*state
,
126 char *buf
, int length
, void **private2
);
128 static void manage_gss_spnego_client_request (enum stdio_helper_mode stdio_helper_mode
,
129 struct loadparm_context
*lp_ctx
,
130 struct ntlm_auth_state
*state
,
131 char *buf
, int length
, void **private2
);
133 static void manage_ntlm_server_1_request (enum stdio_helper_mode stdio_helper_mode
,
134 struct loadparm_context
*lp_ctx
,
135 struct ntlm_auth_state
*state
,
136 char *buf
, int length
, void **private2
);
138 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode
,
139 struct loadparm_context
*lp_ctx
,
140 struct ntlm_auth_state
*state
,
141 char *buf
, int length
, void **private2
);
143 static const struct {
144 enum stdio_helper_mode mode
;
146 stdio_helper_function fn
;
147 } stdio_helper_protocols
[] = {
148 { SQUID_2_4_BASIC
, "squid-2.4-basic", manage_squid_basic_request
},
149 { SQUID_2_5_BASIC
, "squid-2.5-basic", manage_squid_basic_request
},
150 { SQUID_2_5_NTLMSSP
, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request
},
151 { NTLMSSP_CLIENT_1
, "ntlmssp-client-1", manage_client_ntlmssp_request
},
152 { GSS_SPNEGO_SERVER
, "gss-spnego", manage_gss_spnego_request
},
153 { GSS_SPNEGO_CLIENT
, "gss-spnego-client", manage_gss_spnego_client_request
},
154 { NTLM_SERVER_1
, "ntlm-server-1", manage_ntlm_server_1_request
},
155 { NTLM_CHANGE_PASSWORD_1
, "ntlm-change-password-1", manage_ntlm_change_password_1_request
},
156 { NUM_HELPER_MODES
, NULL
, NULL
}
159 const char *opt_username
;
160 const char *opt_domain
;
161 const char *opt_workstation
;
162 const char *opt_password
;
163 static DATA_BLOB opt_challenge
;
164 static DATA_BLOB opt_lm_response
;
165 static DATA_BLOB opt_nt_response
;
166 static int request_lm_key
;
167 static int request_user_session_key
;
168 static int use_cached_creds
;
170 static const char *require_membership_of
;
171 static const char *require_membership_of_sid
;
172 static const char *opt_pam_winbind_conf
;
174 const char *opt_target_service
;
175 const char *opt_target_hostname
;
178 /* This is a bit hairy, but the basic idea is to do a password callback
179 to the calling application. The callback comes from within gensec */
181 static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mode
,
182 struct loadparm_context
*lp_ctx
,
183 struct ntlm_auth_state
*state
, char *buf
, int length
,
187 if (strlen(buf
) < 2) {
188 DEBUG(1, ("query [%s] invalid", buf
));
189 x_fprintf(x_stdout
, "BH Query invalid\n");
193 if (strlen(buf
) > 3) {
194 in
= base64_decode_data_blob(buf
+ 3);
196 in
= data_blob(NULL
, 0);
199 if (strncmp(buf
, "PW ", 3) == 0) {
201 *password
= talloc_strndup(NULL
,
202 (const char *)in
.data
, in
.length
);
204 if (*password
== NULL
) {
205 DEBUG(1, ("Out of memory\n"));
206 x_fprintf(x_stdout
, "BH Out of memory\n");
211 x_fprintf(x_stdout
, "OK\n");
215 DEBUG(1, ("Asked for (and expected) a password\n"));
216 x_fprintf(x_stdout
, "BH Expected a password\n");
221 * Callback for password credentials. This is not async, and when
222 * GENSEC and the credentials code is made async, it will look rather
226 static const char *get_password(struct cli_credentials
*credentials
)
228 char *password
= NULL
;
230 /* Ask for a password */
231 x_fprintf(x_stdout
, "PW\n");
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(NULL
, 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(NULL
, 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(NULL
, 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 separate domain/name parts!\n",
392 require_membership_of
));
396 if (winbindd_request_response(NULL
, 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 struct tiniparser_dictionary
*d
= NULL
;
421 if (!opt_pam_winbind_conf
|| !*opt_pam_winbind_conf
) {
422 opt_pam_winbind_conf
= PAM_WINBIND_CONFIG_FILE
;
425 d
= tiniparser_load(opt_pam_winbind_conf
);
431 if (tiniparser_getboolean(d
, "global:krb5_auth", false)) {
432 ctrl
|= WINBIND_KRB5_AUTH
;
435 tiniparser_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(NULL
, 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_t extra_logon_parameters
,
504 uint8_t 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(NULL
, 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(NULL
, 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_t 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_prepare_gensec_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
;
1038 const struct gensec_security_ops
**backends
;
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 backends
= talloc_zero_array(gensec_settings
,
1083 const struct gensec_security_ops
*, 4);
1085 if (backends
== NULL
) {
1086 TALLOC_FREE(tmp_ctx
);
1087 return NT_STATUS_NO_MEMORY
;
1089 gensec_settings
->backends
= backends
;
1093 /* These need to be in priority order, krb5 before NTLMSSP */
1094 #if defined(HAVE_KRB5)
1095 backends
[idx
++] = &gensec_gse_krb5_security_ops
;
1098 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_NTLMSSP
);
1100 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_SPNEGO
);
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_server_role() == ROLE_ACTIVE_DIRECTORY_DC
|| 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 *gensec_security_out
= talloc_steal(mem_ctx
, gensec_security
);
1139 TALLOC_FREE(tmp_ctx
);
1140 return NT_STATUS_OK
;
1143 /*******************************************************************
1144 Used by firefox to drive NTLM auth to IIS servers.
1145 *******************************************************************/
1147 static NTSTATUS
do_ccache_ntlm_auth(DATA_BLOB initial_msg
, DATA_BLOB challenge_msg
,
1150 struct winbindd_request wb_request
;
1151 struct winbindd_response wb_response
;
1155 /* get winbindd to do the ntlmssp step on our behalf */
1156 ZERO_STRUCT(wb_request
);
1157 ZERO_STRUCT(wb_response
);
1160 * This is tricky here. If we set krb5_auth in pam_winbind.conf
1161 * creds for users in trusted domain will be stored the winbindd
1162 * child of the trusted domain. If we ask the primary domain for
1163 * ntlm_ccache_auth, it will fail. So, we have to ask the trusted
1164 * domain's child for ccache_ntlm_auth. that is to say, we have to
1165 * set WBFLAG_PAM_CONTACT_TRUSTDOM in request.flags.
1167 ctrl
= get_pam_winbind_config();
1169 if (ctrl
& WINBIND_KRB5_AUTH
) {
1170 wb_request
.flags
|= WBFLAG_PAM_CONTACT_TRUSTDOM
;
1173 fstr_sprintf(wb_request
.data
.ccache_ntlm_auth
.user
,
1174 "%s%c%s", opt_domain
, winbind_separator(), opt_username
);
1175 wb_request
.data
.ccache_ntlm_auth
.uid
= geteuid();
1176 wb_request
.data
.ccache_ntlm_auth
.initial_blob_len
= initial_msg
.length
;
1177 wb_request
.data
.ccache_ntlm_auth
.challenge_blob_len
= challenge_msg
.length
;
1178 wb_request
.extra_len
= initial_msg
.length
+ challenge_msg
.length
;
1180 if (wb_request
.extra_len
> 0) {
1181 wb_request
.extra_data
.data
= SMB_MALLOC_ARRAY(char, wb_request
.extra_len
);
1182 if (wb_request
.extra_data
.data
== NULL
) {
1183 return NT_STATUS_NO_MEMORY
;
1186 memcpy(wb_request
.extra_data
.data
, initial_msg
.data
, initial_msg
.length
);
1187 memcpy(wb_request
.extra_data
.data
+ initial_msg
.length
,
1188 challenge_msg
.data
, challenge_msg
.length
);
1191 result
= winbindd_request_response(NULL
, WINBINDD_CCACHE_NTLMAUTH
, &wb_request
, &wb_response
);
1192 SAFE_FREE(wb_request
.extra_data
.data
);
1194 if (result
!= NSS_STATUS_SUCCESS
) {
1195 winbindd_free_response(&wb_response
);
1196 return NT_STATUS_UNSUCCESSFUL
;
1200 *reply
= data_blob(wb_response
.extra_data
.data
,
1201 wb_response
.data
.ccache_ntlm_auth
.auth_blob_len
);
1202 if (wb_response
.data
.ccache_ntlm_auth
.auth_blob_len
> 0 &&
1203 reply
->data
== NULL
) {
1204 winbindd_free_response(&wb_response
);
1205 return NT_STATUS_NO_MEMORY
;
1209 winbindd_free_response(&wb_response
);
1210 return NT_STATUS_MORE_PROCESSING_REQUIRED
;
1213 static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode
,
1214 struct loadparm_context
*lp_ctx
,
1215 struct ntlm_auth_state
*state
,
1216 char *buf
, int length
, void **private2
)
1218 DATA_BLOB request
, reply
;
1221 if (!opt_username
|| !*opt_username
) {
1222 x_fprintf(x_stderr
, "username must be specified!\n\n");
1226 if (strlen(buf
) < 2) {
1227 DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf
));
1228 x_fprintf(x_stdout
, "BH NTLMSSP query invalid\n");
1232 if (strlen(buf
) > 3) {
1233 if(strncmp(buf
, "SF ", 3) == 0) {
1234 DEBUG(10, ("Looking for flags to negotiate\n"));
1235 talloc_free(state
->want_feature_list
);
1236 state
->want_feature_list
= talloc_strdup(state
->mem_ctx
,
1238 x_fprintf(x_stdout
, "OK\n");
1241 request
= base64_decode_data_blob(buf
+ 3);
1243 request
= data_blob_null
;
1246 if (strncmp(buf
, "PW ", 3) == 0) {
1247 /* We asked for a password and obviously got it :-) */
1249 opt_password
= SMB_STRNDUP((const char *)request
.data
,
1252 if (opt_password
== NULL
) {
1253 DEBUG(1, ("Out of memory\n"));
1254 x_fprintf(x_stdout
, "BH Out of memory\n");
1255 data_blob_free(&request
);
1259 x_fprintf(x_stdout
, "OK\n");
1260 data_blob_free(&request
);
1264 if (!state
->ntlmssp_state
&& use_cached_creds
) {
1265 /* check whether cached credentials are usable. */
1266 DATA_BLOB empty_blob
= data_blob_null
;
1268 nt_status
= do_ccache_ntlm_auth(empty_blob
, empty_blob
, NULL
);
1269 if (!NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1270 /* failed to use cached creds */
1271 use_cached_creds
= False
;
1275 if (opt_password
== NULL
&& !use_cached_creds
) {
1276 /* Request a password from the calling process. After
1277 sending it, the calling process should retry asking for the
1280 DEBUG(10, ("Requesting password\n"));
1281 x_fprintf(x_stdout
, "PW\n");
1285 if (strncmp(buf
, "YR", 2) == 0) {
1286 TALLOC_FREE(state
->ntlmssp_state
);
1287 state
->cli_state
= CLIENT_INITIAL
;
1288 } else if (strncmp(buf
, "TT", 2) == 0) {
1289 /* No special preprocessing required */
1290 } else if (strncmp(buf
, "GF", 2) == 0) {
1291 DEBUG(10, ("Requested negotiated NTLMSSP flags\n"));
1293 if(state
->cli_state
== CLIENT_FINISHED
) {
1294 x_fprintf(x_stdout
, "GF 0x%08x\n", state
->neg_flags
);
1297 x_fprintf(x_stdout
, "BH\n");
1300 data_blob_free(&request
);
1302 } else if (strncmp(buf
, "GK", 2) == 0 ) {
1303 DEBUG(10, ("Requested session key\n"));
1305 if(state
->cli_state
== CLIENT_FINISHED
) {
1306 char *key64
= base64_encode_data_blob(state
->mem_ctx
,
1307 state
->session_key
);
1308 x_fprintf(x_stdout
, "GK %s\n", key64
?key64
:"<NULL>");
1312 x_fprintf(x_stdout
, "BH\n");
1315 data_blob_free(&request
);
1318 DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf
));
1319 x_fprintf(x_stdout
, "BH NTLMSSP query invalid\n");
1323 if (!state
->ntlmssp_state
) {
1324 nt_status
= ntlm_auth_start_ntlmssp_client(
1325 &state
->ntlmssp_state
);
1326 if (!NT_STATUS_IS_OK(nt_status
)) {
1327 x_fprintf(x_stdout
, "BH %s\n", nt_errstr(nt_status
));
1330 ntlmssp_want_feature_list(state
->ntlmssp_state
,
1331 state
->want_feature_list
);
1332 state
->initial_message
= data_blob_null
;
1335 DEBUG(10, ("got NTLMSSP packet:\n"));
1336 dump_data(10, request
.data
, request
.length
);
1338 if (use_cached_creds
&& !opt_password
&&
1339 (state
->cli_state
== CLIENT_RESPONSE
)) {
1340 nt_status
= do_ccache_ntlm_auth(state
->initial_message
, request
,
1343 nt_status
= ntlmssp_update(state
->ntlmssp_state
, request
,
1347 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1348 char *reply_base64
= base64_encode_data_blob(state
->mem_ctx
,
1350 if (state
->cli_state
== CLIENT_INITIAL
) {
1351 x_fprintf(x_stdout
, "YR %s\n", reply_base64
);
1352 state
->initial_message
= reply
;
1353 state
->cli_state
= CLIENT_RESPONSE
;
1355 x_fprintf(x_stdout
, "KK %s\n", reply_base64
);
1356 data_blob_free(&reply
);
1358 TALLOC_FREE(reply_base64
);
1359 DEBUG(10, ("NTLMSSP challenge\n"));
1360 } else if (NT_STATUS_IS_OK(nt_status
)) {
1361 char *reply_base64
= base64_encode_data_blob(talloc_tos(),
1363 x_fprintf(x_stdout
, "AF %s\n", reply_base64
);
1364 TALLOC_FREE(reply_base64
);
1366 if(state
->have_session_key
)
1367 data_blob_free(&state
->session_key
);
1369 state
->session_key
= data_blob(
1370 state
->ntlmssp_state
->session_key
.data
,
1371 state
->ntlmssp_state
->session_key
.length
);
1372 state
->neg_flags
= state
->ntlmssp_state
->neg_flags
;
1373 state
->have_session_key
= true;
1375 DEBUG(10, ("NTLMSSP OK!\n"));
1376 state
->cli_state
= CLIENT_FINISHED
;
1377 TALLOC_FREE(state
->ntlmssp_state
);
1379 x_fprintf(x_stdout
, "BH %s\n", nt_errstr(nt_status
));
1380 DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status
)));
1381 state
->cli_state
= CLIENT_ERROR
;
1382 TALLOC_FREE(state
->ntlmssp_state
);
1385 data_blob_free(&request
);
1388 static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode
,
1389 struct loadparm_context
*lp_ctx
,
1390 struct ntlm_auth_state
*state
,
1391 char *buf
, int length
, void **private2
)
1396 pass
=(char *)memchr(buf
,' ',length
);
1398 DEBUG(2, ("Password not found. Denying access\n"));
1399 x_fprintf(x_stdout
, "ERR\n");
1405 if (state
->helper_mode
== SQUID_2_5_BASIC
) {
1406 rfc1738_unescape(user
);
1407 rfc1738_unescape(pass
);
1410 if (check_plaintext_auth(user
, pass
, False
)) {
1411 x_fprintf(x_stdout
, "OK\n");
1413 x_fprintf(x_stdout
, "ERR\n");
1417 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode
,
1418 struct loadparm_context
*lp_ctx
,
1419 char *buf
, int length
, void **private1
)
1422 DATA_BLOB out
= data_blob(NULL
, 0);
1423 char *out_base64
= NULL
;
1424 const char *reply_arg
= NULL
;
1425 struct gensec_ntlm_state
{
1426 struct gensec_security
*gensec_state
;
1427 const char *set_password
;
1429 struct gensec_ntlm_state
*state
;
1433 const char *reply_code
;
1434 struct cli_credentials
*creds
;
1436 static char *want_feature_list
= NULL
;
1437 static DATA_BLOB session_key
;
1439 TALLOC_CTX
*mem_ctx
;
1442 state
= (struct gensec_ntlm_state
*)*private1
;
1444 state
= talloc_zero(NULL
, struct gensec_ntlm_state
);
1446 x_fprintf(x_stdout
, "BH No Memory\n");
1451 state
->set_password
= opt_password
;
1455 if (strlen(buf
) < 2) {
1456 DEBUG(1, ("query [%s] invalid", buf
));
1457 x_fprintf(x_stdout
, "BH Query invalid\n");
1461 if (strlen(buf
) > 3) {
1462 if(strncmp(buf
, "SF ", 3) == 0) {
1463 DEBUG(10, ("Setting flags to negotiate\n"));
1464 talloc_free(want_feature_list
);
1465 want_feature_list
= talloc_strndup(state
, buf
+3, strlen(buf
)-3);
1466 x_fprintf(x_stdout
, "OK\n");
1469 in
= base64_decode_data_blob(buf
+ 3);
1471 in
= data_blob(NULL
, 0);
1474 if (strncmp(buf
, "YR", 2) == 0) {
1475 if (state
->gensec_state
) {
1476 talloc_free(state
->gensec_state
);
1477 state
->gensec_state
= NULL
;
1479 } else if ( (strncmp(buf
, "OK", 2) == 0)) {
1480 /* Just return BH, like ntlm_auth from Samba 3 does. */
1481 x_fprintf(x_stdout
, "BH Command expected\n");
1482 data_blob_free(&in
);
1484 } else if ( (strncmp(buf
, "TT ", 3) != 0) &&
1485 (strncmp(buf
, "KK ", 3) != 0) &&
1486 (strncmp(buf
, "AF ", 3) != 0) &&
1487 (strncmp(buf
, "NA ", 3) != 0) &&
1488 (strncmp(buf
, "UG", 2) != 0) &&
1489 (strncmp(buf
, "PW ", 3) != 0) &&
1490 (strncmp(buf
, "GK", 2) != 0) &&
1491 (strncmp(buf
, "GF", 2) != 0)) {
1492 DEBUG(1, ("SPNEGO request [%s] invalid prefix\n", buf
));
1493 x_fprintf(x_stdout
, "BH SPNEGO request invalid prefix\n");
1494 data_blob_free(&in
);
1498 mem_ctx
= talloc_named(NULL
, 0, "manage_gensec_request internal mem_ctx");
1501 if (!(state
->gensec_state
)) {
1502 switch (stdio_helper_mode
) {
1503 case GSS_SPNEGO_CLIENT
:
1504 case NTLMSSP_CLIENT_1
:
1505 /* setup the client side */
1507 nt_status
= gensec_client_start(NULL
, &state
->gensec_state
,
1508 lpcfg_gensec_settings(NULL
, lp_ctx
));
1509 if (!NT_STATUS_IS_OK(nt_status
)) {
1510 x_fprintf(x_stdout
, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status
));
1511 talloc_free(mem_ctx
);
1515 creds
= cli_credentials_init(state
->gensec_state
);
1516 cli_credentials_set_conf(creds
, lp_ctx
);
1518 cli_credentials_set_username(creds
, opt_username
, CRED_SPECIFIED
);
1521 cli_credentials_set_domain(creds
, opt_domain
, CRED_SPECIFIED
);
1523 if (state
->set_password
) {
1524 cli_credentials_set_password(creds
, state
->set_password
, CRED_SPECIFIED
);
1526 cli_credentials_set_password_callback(creds
, get_password
);
1528 if (opt_workstation
) {
1529 cli_credentials_set_workstation(creds
, opt_workstation
, CRED_SPECIFIED
);
1532 gensec_set_credentials(state
->gensec_state
, creds
);
1535 case GSS_SPNEGO_SERVER
:
1536 case SQUID_2_5_NTLMSSP
:
1538 nt_status
= ntlm_auth_prepare_gensec_server(state
, lp_ctx
,
1539 &state
->gensec_state
);
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
);
1548 talloc_free(mem_ctx
);
1552 gensec_want_feature_list(state
->gensec_state
, want_feature_list
);
1554 switch (stdio_helper_mode
) {
1555 case GSS_SPNEGO_CLIENT
:
1556 case GSS_SPNEGO_SERVER
:
1557 nt_status
= gensec_start_mech_by_oid(state
->gensec_state
, GENSEC_OID_SPNEGO
);
1562 case NTLMSSP_CLIENT_1
:
1567 case SQUID_2_5_NTLMSSP
:
1568 nt_status
= gensec_start_mech_by_oid(state
->gensec_state
, GENSEC_OID_NTLMSSP
);
1571 talloc_free(mem_ctx
);
1575 if (!NT_STATUS_IS_OK(nt_status
)) {
1576 DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status
)));
1577 x_fprintf(x_stdout
, "BH GENSEC mech failed to start\n");
1578 talloc_free(mem_ctx
);
1586 if (strncmp(buf
, "PW ", 3) == 0) {
1587 state
->set_password
= talloc_strndup(state
,
1588 (const char *)in
.data
,
1591 cli_credentials_set_password(gensec_get_credentials(state
->gensec_state
),
1592 state
->set_password
,
1594 x_fprintf(x_stdout
, "OK\n");
1595 data_blob_free(&in
);
1596 talloc_free(mem_ctx
);
1600 if (strncmp(buf
, "GK", 2) == 0) {
1602 DEBUG(10, ("Requested session key\n"));
1603 nt_status
= gensec_session_key(state
->gensec_state
, mem_ctx
, &session_key
);
1604 if(!NT_STATUS_IS_OK(nt_status
)) {
1605 DEBUG(1, ("gensec_session_key failed: %s\n", nt_errstr(nt_status
)));
1606 x_fprintf(x_stdout
, "BH No session key\n");
1607 talloc_free(mem_ctx
);
1610 base64_key
= base64_encode_data_blob(state
, session_key
);
1611 x_fprintf(x_stdout
, "GK %s\n", base64_key
);
1612 talloc_free(base64_key
);
1614 talloc_free(mem_ctx
);
1618 if (stdio_helper_mode
== SQUID_2_5_NTLMSSP
&& strncmp(buf
, "GF", 2) == 0) {
1621 neg_flags
= gensec_ntlmssp_neg_flags(state
->gensec_state
);
1623 DEBUG(10, ("Requested negotiated feature flags\n"));
1624 x_fprintf(x_stdout
, "GF 0x%08x\n", neg_flags
);
1628 nt_status
= gensec_update(state
->gensec_state
, mem_ctx
, in
, &out
);
1630 /* don't leak 'bad password'/'no such user' info to the network client */
1631 nt_status
= nt_status_squash(nt_status
);
1634 out_base64
= base64_encode_data_blob(mem_ctx
, out
);
1639 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1641 if (first
&& state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1643 } else if (state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1645 } else if (state
->gensec_state
->gensec_role
== GENSEC_SERVER
) {
1652 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCESS_DENIED
)) {
1653 reply_code
= "BH NT_STATUS_ACCESS_DENIED";
1654 reply_arg
= nt_errstr(nt_status
);
1655 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1656 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_UNSUCCESSFUL
)) {
1657 reply_code
= "BH NT_STATUS_UNSUCCESSFUL";
1658 reply_arg
= nt_errstr(nt_status
);
1659 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1660 } else if (!NT_STATUS_IS_OK(nt_status
)) {
1662 reply_arg
= nt_errstr(nt_status
);
1663 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1664 } else if /* OK */ (state
->gensec_state
->gensec_role
== GENSEC_SERVER
) {
1665 struct auth_session_info
*session_info
;
1667 nt_status
= gensec_session_info(state
->gensec_state
, mem_ctx
, &session_info
);
1668 if (!NT_STATUS_IS_OK(nt_status
)) {
1669 reply_code
= "BH Failed to retrive session info";
1670 reply_arg
= nt_errstr(nt_status
);
1671 DEBUG(1, ("GENSEC failed to retrieve the session info: %s\n", nt_errstr(nt_status
)));
1675 reply_arg
= talloc_strdup(state
->gensec_state
, session_info
->unix_info
->unix_name
);
1676 if (reply_arg
== NULL
) {
1677 reply_code
= "BH out of memory";
1678 reply_arg
= nt_errstr(NT_STATUS_NO_MEMORY
);
1680 talloc_free(session_info
);
1682 } else if (state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1684 reply_arg
= out_base64
;
1689 switch (stdio_helper_mode
) {
1690 case GSS_SPNEGO_SERVER
:
1691 x_fprintf(x_stdout
, "%s %s %s\n", reply_code
,
1692 out_base64
? out_base64
: "*",
1693 reply_arg
? reply_arg
: "*");
1697 x_fprintf(x_stdout
, "%s %s\n", reply_code
, out_base64
);
1698 } else if (reply_arg
) {
1699 x_fprintf(x_stdout
, "%s %s\n", reply_code
, reply_arg
);
1701 x_fprintf(x_stdout
, "%s\n", reply_code
);
1705 talloc_free(mem_ctx
);
1709 static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode
,
1710 struct loadparm_context
*lp_ctx
,
1711 struct ntlm_auth_state
*state
,
1712 char *buf
, int length
, void **private2
)
1714 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1718 static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode
,
1719 struct loadparm_context
*lp_ctx
,
1720 struct ntlm_auth_state
*state
,
1721 char *buf
, int length
, void **private2
)
1723 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1727 static struct ntlmssp_state
*client_ntlmssp_state
= NULL
;
1729 static bool manage_client_ntlmssp_init(struct spnego_data spnego
)
1732 DATA_BLOB null_blob
= data_blob_null
;
1733 DATA_BLOB to_server
;
1734 char *to_server_base64
;
1735 const char *my_mechs
[] = {OID_NTLMSSP
, NULL
};
1736 TALLOC_CTX
*ctx
= talloc_tos();
1738 DEBUG(10, ("Got spnego negTokenInit with NTLMSSP\n"));
1740 if (client_ntlmssp_state
!= NULL
) {
1741 DEBUG(1, ("Request for initial SPNEGO request where "
1742 "we already have a state\n"));
1746 if (!client_ntlmssp_state
) {
1747 if (!NT_STATUS_IS_OK(status
= ntlm_auth_start_ntlmssp_client(&client_ntlmssp_state
))) {
1748 x_fprintf(x_stdout
, "BH %s\n", nt_errstr(status
));
1754 if (opt_password
== NULL
) {
1756 /* Request a password from the calling process. After
1757 sending it, the calling process should retry with
1758 the negTokenInit. */
1760 DEBUG(10, ("Requesting password\n"));
1761 x_fprintf(x_stdout
, "PW\n");
1765 spnego
.type
= SPNEGO_NEG_TOKEN_INIT
;
1766 spnego
.negTokenInit
.mechTypes
= my_mechs
;
1767 spnego
.negTokenInit
.reqFlags
= data_blob_null
;
1768 spnego
.negTokenInit
.reqFlagsPadding
= 0;
1769 spnego
.negTokenInit
.mechListMIC
= null_blob
;
1771 status
= ntlmssp_update(client_ntlmssp_state
, null_blob
,
1772 &spnego
.negTokenInit
.mechToken
);
1774 if ( !(NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
) ||
1775 NT_STATUS_IS_OK(status
)) ) {
1776 DEBUG(1, ("Expected OK or MORE_PROCESSING_REQUIRED, got: %s\n",
1777 nt_errstr(status
)));
1778 TALLOC_FREE(client_ntlmssp_state
);
1782 spnego_write_data(ctx
, &to_server
, &spnego
);
1783 data_blob_free(&spnego
.negTokenInit
.mechToken
);
1785 to_server_base64
= base64_encode_data_blob(talloc_tos(), to_server
);
1786 data_blob_free(&to_server
);
1787 x_fprintf(x_stdout
, "KK %s\n", to_server_base64
);
1788 TALLOC_FREE(to_server_base64
);
1792 static void manage_client_ntlmssp_targ(struct spnego_data spnego
)
1795 DATA_BLOB null_blob
= data_blob_null
;
1797 DATA_BLOB to_server
;
1798 char *to_server_base64
;
1799 TALLOC_CTX
*ctx
= talloc_tos();
1801 DEBUG(10, ("Got spnego negTokenTarg with NTLMSSP\n"));
1803 if (client_ntlmssp_state
== NULL
) {
1804 DEBUG(1, ("Got NTLMSSP tArg without a client state\n"));
1805 x_fprintf(x_stdout
, "BH Got NTLMSSP tArg without a client state\n");
1809 if (spnego
.negTokenTarg
.negResult
== SPNEGO_REJECT
) {
1810 x_fprintf(x_stdout
, "NA\n");
1811 TALLOC_FREE(client_ntlmssp_state
);
1815 if (spnego
.negTokenTarg
.negResult
== SPNEGO_ACCEPT_COMPLETED
) {
1816 x_fprintf(x_stdout
, "AF\n");
1817 TALLOC_FREE(client_ntlmssp_state
);
1821 status
= ntlmssp_update(client_ntlmssp_state
,
1822 spnego
.negTokenTarg
.responseToken
,
1825 if (!NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
) && !NT_STATUS_IS_OK(status
)) {
1826 DEBUG(1, ("Expected MORE_PROCESSING_REQUIRED or OK from "
1827 "ntlmssp_client_update, got: %s\n",
1828 nt_errstr(status
)));
1829 x_fprintf(x_stdout
, "BH Expected MORE_PROCESSING_REQUIRED from "
1830 "ntlmssp_client_update\n");
1831 data_blob_free(&request
);
1832 TALLOC_FREE(client_ntlmssp_state
);
1836 spnego
.type
= SPNEGO_NEG_TOKEN_TARG
;
1837 spnego
.negTokenTarg
.negResult
= SPNEGO_ACCEPT_INCOMPLETE
;
1838 spnego
.negTokenTarg
.supportedMech
= (const char *)OID_NTLMSSP
;
1839 spnego
.negTokenTarg
.responseToken
= request
;
1840 spnego
.negTokenTarg
.mechListMIC
= null_blob
;
1842 spnego_write_data(ctx
, &to_server
, &spnego
);
1843 data_blob_free(&request
);
1845 to_server_base64
= base64_encode_data_blob(talloc_tos(), to_server
);
1846 data_blob_free(&to_server
);
1847 x_fprintf(x_stdout
, "KK %s\n", to_server_base64
);
1848 TALLOC_FREE(to_server_base64
);
1854 static bool manage_client_krb5_init(struct spnego_data spnego
)
1857 DATA_BLOB tkt
, tkt_wrapped
, to_server
;
1858 DATA_BLOB session_key_krb5
= data_blob_null
;
1859 struct spnego_data reply
;
1863 const char *my_mechs
[] = {OID_KERBEROS5_OLD
, NULL
};
1865 TALLOC_CTX
*ctx
= talloc_tos();
1867 principal
= spnego
.negTokenInit
.targetPrincipal
;
1869 /* We may not be allowed to use the server-supplied SPNEGO principal, or it may not have been supplied to us
1871 if (!lp_client_use_spnego_principal() || strequal(principal
, ADS_IGNORE_PRINCIPAL
)) {
1875 if (principal
== NULL
&&
1876 opt_target_service
&& opt_target_hostname
&& !is_ipaddress(opt_target_hostname
)) {
1877 DEBUG(3,("manage_client_krb5_init: using target "
1878 "hostname not SPNEGO principal\n"));
1880 principal
= kerberos_get_principal_from_service_hostname(talloc_tos(),
1882 opt_target_hostname
,
1889 DEBUG(3,("manage_client_krb5_init: guessed "
1890 "server principal=%s\n",
1891 principal
? principal
: "<null>"));
1894 if (principal
== NULL
) {
1895 DEBUG(3,("manage_client_krb5_init: could not guess server principal\n"));
1899 retval
= cli_krb5_get_ticket(ctx
, principal
, 0,
1900 &tkt
, &session_key_krb5
,
1901 0, NULL
, NULL
, NULL
);
1905 /* Let's try to first get the TGT, for that we need a
1908 if (opt_password
== NULL
) {
1909 DEBUG(10, ("Requesting password\n"));
1910 x_fprintf(x_stdout
, "PW\n");
1914 user
= talloc_asprintf(talloc_tos(), "%s@%s", opt_username
, opt_domain
);
1919 if ((retval
= kerberos_kinit_password(user
, opt_password
, 0, NULL
))) {
1920 DEBUG(10, ("Requesting TGT failed: %s\n", error_message(retval
)));
1924 retval
= cli_krb5_get_ticket(ctx
, principal
, 0,
1925 &tkt
, &session_key_krb5
,
1926 0, NULL
, NULL
, NULL
);
1928 DEBUG(10, ("Kinit suceeded, but getting a ticket failed: %s\n", error_message(retval
)));
1934 /* wrap that up in a nice GSS-API wrapping */
1935 tkt_wrapped
= spnego_gen_krb5_wrap(ctx
, tkt
, TOK_ID_KRB_AP_REQ
);
1937 data_blob_free(&session_key_krb5
);
1941 reply
.type
= SPNEGO_NEG_TOKEN_INIT
;
1942 reply
.negTokenInit
.mechTypes
= my_mechs
;
1943 reply
.negTokenInit
.reqFlags
= data_blob_null
;
1944 reply
.negTokenInit
.reqFlagsPadding
= 0;
1945 reply
.negTokenInit
.mechToken
= tkt_wrapped
;
1946 reply
.negTokenInit
.mechListMIC
= data_blob_null
;
1948 len
= spnego_write_data(ctx
, &to_server
, &reply
);
1949 data_blob_free(&tkt
);
1952 DEBUG(1, ("Could not write SPNEGO data blob\n"));
1956 reply_base64
= base64_encode_data_blob(talloc_tos(), to_server
);
1957 x_fprintf(x_stdout
, "KK %s *\n", reply_base64
);
1959 TALLOC_FREE(reply_base64
);
1960 data_blob_free(&to_server
);
1961 DEBUG(10, ("sent GSS-SPNEGO KERBEROS5 negTokenInit\n"));
1965 static void manage_client_krb5_targ(struct spnego_data spnego
)
1967 switch (spnego
.negTokenTarg
.negResult
) {
1968 case SPNEGO_ACCEPT_INCOMPLETE
:
1969 DEBUG(1, ("Got a Kerberos negTokenTarg with ACCEPT_INCOMPLETE\n"));
1970 x_fprintf(x_stdout
, "BH Got a Kerberos negTokenTarg with "
1971 "ACCEPT_INCOMPLETE\n");
1973 case SPNEGO_ACCEPT_COMPLETED
:
1974 DEBUG(10, ("Accept completed\n"));
1975 x_fprintf(x_stdout
, "AF\n");
1978 DEBUG(10, ("Rejected\n"));
1979 x_fprintf(x_stdout
, "NA\n");
1982 DEBUG(1, ("Got an invalid negTokenTarg\n"));
1983 x_fprintf(x_stdout
, "AF\n");
1989 static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode
,
1990 struct loadparm_context
*lp_ctx
,
1991 struct ntlm_auth_state
*state
,
1992 char *buf
, int length
, void **private2
)
1995 struct spnego_data spnego
;
1997 TALLOC_CTX
*ctx
= talloc_tos();
1999 if (!opt_username
|| !*opt_username
) {
2000 x_fprintf(x_stderr
, "username must be specified!\n\n");
2004 if (strlen(buf
) <= 3) {
2005 DEBUG(1, ("SPNEGO query [%s] too short\n", buf
));
2006 x_fprintf(x_stdout
, "BH SPNEGO query too short\n");
2010 request
= base64_decode_data_blob(buf
+3);
2012 if (strncmp(buf
, "PW ", 3) == 0) {
2014 /* We asked for a password and obviously got it :-) */
2016 opt_password
= SMB_STRNDUP((const char *)request
.data
, request
.length
);
2018 if (opt_password
== NULL
) {
2019 DEBUG(1, ("Out of memory\n"));
2020 x_fprintf(x_stdout
, "BH Out of memory\n");
2021 data_blob_free(&request
);
2025 x_fprintf(x_stdout
, "OK\n");
2026 data_blob_free(&request
);
2030 if ( (strncmp(buf
, "TT ", 3) != 0) &&
2031 (strncmp(buf
, "AF ", 3) != 0) &&
2032 (strncmp(buf
, "NA ", 3) != 0) ) {
2033 DEBUG(1, ("SPNEGO request [%s] invalid\n", buf
));
2034 x_fprintf(x_stdout
, "BH SPNEGO request invalid\n");
2035 data_blob_free(&request
);
2039 /* So we got a server challenge to generate a SPNEGO
2040 client-to-server request... */
2042 len
= spnego_read_data(ctx
, request
, &spnego
);
2043 data_blob_free(&request
);
2046 DEBUG(1, ("Could not read SPNEGO data for [%s]\n", buf
));
2047 x_fprintf(x_stdout
, "BH Could not read SPNEGO data\n");
2051 if (spnego
.type
== SPNEGO_NEG_TOKEN_INIT
) {
2053 /* The server offers a list of mechanisms */
2055 const char *const *mechType
= spnego
.negTokenInit
.mechTypes
;
2057 while (*mechType
!= NULL
) {
2060 if ( (strcmp(*mechType
, OID_KERBEROS5_OLD
) == 0) ||
2061 (strcmp(*mechType
, OID_KERBEROS5
) == 0) ) {
2062 if (manage_client_krb5_init(spnego
))
2067 if (strcmp(*mechType
, OID_NTLMSSP
) == 0) {
2068 if (manage_client_ntlmssp_init(spnego
))
2075 DEBUG(1, ("Server offered no compatible mechanism\n"));
2076 x_fprintf(x_stdout
, "BH Server offered no compatible mechanism\n");
2080 if (spnego
.type
== SPNEGO_NEG_TOKEN_TARG
) {
2082 if (spnego
.negTokenTarg
.supportedMech
== NULL
) {
2083 /* On accept/reject Windows does not send the
2084 mechanism anymore. Handle that here and
2085 shut down the mechanisms. */
2087 switch (spnego
.negTokenTarg
.negResult
) {
2088 case SPNEGO_ACCEPT_COMPLETED
:
2089 x_fprintf(x_stdout
, "AF\n");
2092 x_fprintf(x_stdout
, "NA\n");
2095 DEBUG(1, ("Got a negTokenTarg with no mech and an "
2096 "unknown negResult: %d\n",
2097 spnego
.negTokenTarg
.negResult
));
2098 x_fprintf(x_stdout
, "BH Got a negTokenTarg with"
2099 " no mech and an unknown "
2103 TALLOC_FREE(client_ntlmssp_state
);
2107 if (strcmp(spnego
.negTokenTarg
.supportedMech
,
2108 OID_NTLMSSP
) == 0) {
2109 manage_client_ntlmssp_targ(spnego
);
2114 if (strcmp(spnego
.negTokenTarg
.supportedMech
,
2115 OID_KERBEROS5_OLD
) == 0) {
2116 manage_client_krb5_targ(spnego
);
2123 DEBUG(1, ("Got an SPNEGO token I could not handle [%s]!\n", buf
));
2124 x_fprintf(x_stdout
, "BH Got an SPNEGO token I could not handle\n");
2128 spnego_free_data(&spnego
);
2132 static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode
,
2133 struct loadparm_context
*lp_ctx
,
2134 struct ntlm_auth_state
*state
,
2135 char *buf
, int length
, void **private2
)
2137 char *request
, *parameter
;
2138 static DATA_BLOB challenge
;
2139 static DATA_BLOB lm_response
;
2140 static DATA_BLOB nt_response
;
2141 static char *full_username
;
2142 static char *username
;
2143 static char *domain
;
2144 static char *plaintext_password
;
2145 static bool ntlm_server_1_user_session_key
;
2146 static bool ntlm_server_1_lm_session_key
;
2148 if (strequal(buf
, ".")) {
2149 if (!full_username
&& !username
) {
2150 x_fprintf(x_stdout
, "Error: No username supplied!\n");
2151 } else if (plaintext_password
) {
2152 /* handle this request as plaintext */
2153 if (!full_username
) {
2154 if (asprintf(&full_username
, "%s%c%s", domain
, winbind_separator(), username
) == -1) {
2155 x_fprintf(x_stdout
, "Error: Out of memory in asprintf!\n.\n");
2159 if (check_plaintext_auth(full_username
, plaintext_password
, False
)) {
2160 x_fprintf(x_stdout
, "Authenticated: Yes\n");
2162 x_fprintf(x_stdout
, "Authenticated: No\n");
2164 } else if (!lm_response
.data
&& !nt_response
.data
) {
2165 x_fprintf(x_stdout
, "Error: No password supplied!\n");
2166 } else if (!challenge
.data
) {
2167 x_fprintf(x_stdout
, "Error: No lanman-challenge supplied!\n");
2169 char *error_string
= NULL
;
2171 uchar user_session_key
[16];
2174 if (full_username
&& !username
) {
2176 fstring fstr_domain
;
2178 if (!parse_ntlm_auth_domain_user(full_username
, fstr_user
, fstr_domain
)) {
2179 /* username might be 'tainted', don't print into our new-line deleimianted stream */
2180 x_fprintf(x_stdout
, "Error: Could not parse into domain and username\n");
2182 SAFE_FREE(username
);
2184 username
= smb_xstrdup(fstr_user
);
2185 domain
= smb_xstrdup(fstr_domain
);
2189 domain
= smb_xstrdup(get_winbind_domain());
2192 if (ntlm_server_1_lm_session_key
)
2193 flags
|= WBFLAG_PAM_LMKEY
;
2195 if (ntlm_server_1_user_session_key
)
2196 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
2198 if (!NT_STATUS_IS_OK(
2199 contact_winbind_auth_crap(username
,
2211 x_fprintf(x_stdout
, "Authenticated: No\n");
2212 x_fprintf(x_stdout
, "Authentication-Error: %s\n.\n", error_string
);
2214 static char zeros
[16];
2216 char *hex_user_session_key
;
2218 x_fprintf(x_stdout
, "Authenticated: Yes\n");
2220 if (ntlm_server_1_lm_session_key
2221 && (memcmp(zeros
, lm_key
,
2222 sizeof(lm_key
)) != 0)) {
2223 hex_lm_key
= hex_encode_talloc(NULL
,
2224 (const unsigned char *)lm_key
,
2226 x_fprintf(x_stdout
, "LANMAN-Session-Key: %s\n", hex_lm_key
);
2227 TALLOC_FREE(hex_lm_key
);
2230 if (ntlm_server_1_user_session_key
2231 && (memcmp(zeros
, user_session_key
,
2232 sizeof(user_session_key
)) != 0)) {
2233 hex_user_session_key
= hex_encode_talloc(NULL
,
2234 (const unsigned char *)user_session_key
,
2235 sizeof(user_session_key
));
2236 x_fprintf(x_stdout
, "User-Session-Key: %s\n", hex_user_session_key
);
2237 TALLOC_FREE(hex_user_session_key
);
2240 SAFE_FREE(error_string
);
2242 /* clear out the state */
2243 challenge
= data_blob_null
;
2244 nt_response
= data_blob_null
;
2245 lm_response
= data_blob_null
;
2246 SAFE_FREE(full_username
);
2247 SAFE_FREE(username
);
2249 SAFE_FREE(plaintext_password
);
2250 ntlm_server_1_user_session_key
= False
;
2251 ntlm_server_1_lm_session_key
= False
;
2252 x_fprintf(x_stdout
, ".\n");
2259 /* Indicates a base64 encoded structure */
2260 parameter
= strstr_m(request
, ":: ");
2262 parameter
= strstr_m(request
, ": ");
2265 DEBUG(0, ("Parameter not found!\n"));
2266 x_fprintf(x_stdout
, "Error: Parameter not found!\n.\n");
2283 base64_decode_inplace(parameter
);
2286 if (strequal(request
, "LANMAN-Challenge")) {
2287 challenge
= strhex_to_data_blob(NULL
, parameter
);
2288 if (challenge
.length
!= 8) {
2289 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (got %d bytes, expected 8)\n.\n",
2291 (int)challenge
.length
);
2292 challenge
= data_blob_null
;
2294 } else if (strequal(request
, "NT-Response")) {
2295 nt_response
= strhex_to_data_blob(NULL
, parameter
);
2296 if (nt_response
.length
< 24) {
2297 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (only got %d bytes, needed at least 24)\n.\n",
2299 (int)nt_response
.length
);
2300 nt_response
= data_blob_null
;
2302 } else if (strequal(request
, "LANMAN-Response")) {
2303 lm_response
= strhex_to_data_blob(NULL
, parameter
);
2304 if (lm_response
.length
!= 24) {
2305 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (got %d bytes, expected 24)\n.\n",
2307 (int)lm_response
.length
);
2308 lm_response
= data_blob_null
;
2310 } else if (strequal(request
, "Password")) {
2311 plaintext_password
= smb_xstrdup(parameter
);
2312 } else if (strequal(request
, "NT-Domain")) {
2313 domain
= smb_xstrdup(parameter
);
2314 } else if (strequal(request
, "Username")) {
2315 username
= smb_xstrdup(parameter
);
2316 } else if (strequal(request
, "Full-Username")) {
2317 full_username
= smb_xstrdup(parameter
);
2318 } else if (strequal(request
, "Request-User-Session-Key")) {
2319 ntlm_server_1_user_session_key
= strequal(parameter
, "Yes");
2320 } else if (strequal(request
, "Request-LanMan-Session-Key")) {
2321 ntlm_server_1_lm_session_key
= strequal(parameter
, "Yes");
2323 x_fprintf(x_stdout
, "Error: Unknown request %s\n.\n", request
);
2327 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode
,
2328 struct loadparm_context
*lp_ctx
,
2329 struct ntlm_auth_state
*state
,
2330 char *buf
, int length
, void **private2
)
2332 char *request
, *parameter
;
2333 static DATA_BLOB new_nt_pswd
;
2334 static DATA_BLOB old_nt_hash_enc
;
2335 static DATA_BLOB new_lm_pswd
;
2336 static DATA_BLOB old_lm_hash_enc
;
2337 static char *full_username
= NULL
;
2338 static char *username
= NULL
;
2339 static char *domain
= NULL
;
2340 static char *newpswd
= NULL
;
2341 static char *oldpswd
= NULL
;
2343 if (strequal(buf
, ".")) {
2344 if(newpswd
&& oldpswd
) {
2345 uchar old_nt_hash
[16];
2346 uchar old_lm_hash
[16];
2347 uchar new_nt_hash
[16];
2348 uchar new_lm_hash
[16];
2350 new_nt_pswd
= data_blob(NULL
, 516);
2351 old_nt_hash_enc
= data_blob(NULL
, 16);
2353 /* Calculate the MD4 hash (NT compatible) of the
2355 E_md4hash(oldpswd
, old_nt_hash
);
2356 E_md4hash(newpswd
, new_nt_hash
);
2358 /* E_deshash returns false for 'long'
2359 passwords (> 14 DOS chars).
2361 Therefore, don't send a buffer
2362 encrypted with the truncated hash
2363 (it could allow an even easier
2364 attack on the password)
2366 Likewise, obey the admin's restriction
2369 if (lp_client_lanman_auth() &&
2370 E_deshash(newpswd
, new_lm_hash
) &&
2371 E_deshash(oldpswd
, old_lm_hash
)) {
2372 new_lm_pswd
= data_blob(NULL
, 516);
2373 old_lm_hash_enc
= data_blob(NULL
, 16);
2374 encode_pw_buffer(new_lm_pswd
.data
, newpswd
,
2377 arcfour_crypt(new_lm_pswd
.data
, old_nt_hash
, 516);
2378 E_old_pw_hash(new_nt_hash
, old_lm_hash
,
2379 old_lm_hash_enc
.data
);
2381 new_lm_pswd
.data
= NULL
;
2382 new_lm_pswd
.length
= 0;
2383 old_lm_hash_enc
.data
= NULL
;
2384 old_lm_hash_enc
.length
= 0;
2387 encode_pw_buffer(new_nt_pswd
.data
, newpswd
,
2390 arcfour_crypt(new_nt_pswd
.data
, old_nt_hash
, 516);
2391 E_old_pw_hash(new_nt_hash
, old_nt_hash
,
2392 old_nt_hash_enc
.data
);
2395 if (!full_username
&& !username
) {
2396 x_fprintf(x_stdout
, "Error: No username supplied!\n");
2397 } else if ((!new_nt_pswd
.data
|| !old_nt_hash_enc
.data
) &&
2398 (!new_lm_pswd
.data
|| old_lm_hash_enc
.data
) ) {
2399 x_fprintf(x_stdout
, "Error: No NT or LM password "
2400 "blobs supplied!\n");
2402 char *error_string
= NULL
;
2404 if (full_username
&& !username
) {
2406 fstring fstr_domain
;
2408 if (!parse_ntlm_auth_domain_user(full_username
,
2411 /* username might be 'tainted', don't
2412 * print into our new-line
2413 * deleimianted stream */
2414 x_fprintf(x_stdout
, "Error: Could not "
2415 "parse into domain and "
2417 SAFE_FREE(username
);
2418 username
= smb_xstrdup(full_username
);
2420 SAFE_FREE(username
);
2422 username
= smb_xstrdup(fstr_user
);
2423 domain
= smb_xstrdup(fstr_domain
);
2428 if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
2435 x_fprintf(x_stdout
, "Password-Change: No\n");
2436 x_fprintf(x_stdout
, "Password-Change-Error: "
2437 "%s\n.\n", error_string
);
2439 x_fprintf(x_stdout
, "Password-Change: Yes\n");
2442 SAFE_FREE(error_string
);
2444 /* clear out the state */
2445 new_nt_pswd
= data_blob_null
;
2446 old_nt_hash_enc
= data_blob_null
;
2447 new_lm_pswd
= data_blob_null
;
2448 old_nt_hash_enc
= data_blob_null
;
2449 SAFE_FREE(full_username
);
2450 SAFE_FREE(username
);
2454 x_fprintf(x_stdout
, ".\n");
2461 /* Indicates a base64 encoded structure */
2462 parameter
= strstr_m(request
, ":: ");
2464 parameter
= strstr_m(request
, ": ");
2467 DEBUG(0, ("Parameter not found!\n"));
2468 x_fprintf(x_stdout
, "Error: Parameter not found!\n.\n");
2484 base64_decode_inplace(parameter
);
2487 if (strequal(request
, "new-nt-password-blob")) {
2488 new_nt_pswd
= strhex_to_data_blob(NULL
, parameter
);
2489 if (new_nt_pswd
.length
!= 516) {
2490 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2491 "(got %d bytes, expected 516)\n.\n",
2493 (int)new_nt_pswd
.length
);
2494 new_nt_pswd
= data_blob_null
;
2496 } else if (strequal(request
, "old-nt-hash-blob")) {
2497 old_nt_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2498 if (old_nt_hash_enc
.length
!= 16) {
2499 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2500 "(got %d bytes, expected 16)\n.\n",
2502 (int)old_nt_hash_enc
.length
);
2503 old_nt_hash_enc
= data_blob_null
;
2505 } else if (strequal(request
, "new-lm-password-blob")) {
2506 new_lm_pswd
= strhex_to_data_blob(NULL
, parameter
);
2507 if (new_lm_pswd
.length
!= 516) {
2508 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2509 "(got %d bytes, expected 516)\n.\n",
2511 (int)new_lm_pswd
.length
);
2512 new_lm_pswd
= data_blob_null
;
2515 else if (strequal(request
, "old-lm-hash-blob")) {
2516 old_lm_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2517 if (old_lm_hash_enc
.length
!= 16)
2519 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2520 "(got %d bytes, expected 16)\n.\n",
2522 (int)old_lm_hash_enc
.length
);
2523 old_lm_hash_enc
= data_blob_null
;
2525 } else if (strequal(request
, "nt-domain")) {
2526 domain
= smb_xstrdup(parameter
);
2527 } else if(strequal(request
, "username")) {
2528 username
= smb_xstrdup(parameter
);
2529 } else if(strequal(request
, "full-username")) {
2530 username
= smb_xstrdup(parameter
);
2531 } else if(strequal(request
, "new-password")) {
2532 newpswd
= smb_xstrdup(parameter
);
2533 } else if (strequal(request
, "old-password")) {
2534 oldpswd
= smb_xstrdup(parameter
);
2536 x_fprintf(x_stdout
, "Error: Unknown request %s\n.\n", request
);
2540 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode
,
2541 struct loadparm_context
*lp_ctx
,
2542 struct ntlm_auth_state
*state
,
2543 stdio_helper_function fn
, void **private2
)
2546 char tmp
[INITIAL_BUFFER_SIZE
+1];
2547 int length
, buf_size
= 0;
2550 buf
= talloc_strdup(state
->mem_ctx
, "");
2552 DEBUG(0, ("Failed to allocate input buffer.\n"));
2553 x_fprintf(x_stderr
, "ERR\n");
2559 /* this is not a typo - x_fgets doesn't work too well under
2561 if (fgets(tmp
, sizeof(tmp
)-1, stdin
) == NULL
) {
2562 if (ferror(stdin
)) {
2563 DEBUG(1, ("fgets() failed! dying..... errno=%d "
2564 "(%s)\n", ferror(stdin
),
2565 strerror(ferror(stdin
))));
2572 buf
= talloc_strdup_append_buffer(buf
, tmp
);
2573 buf_size
+= INITIAL_BUFFER_SIZE
;
2575 if (buf_size
> MAX_BUFFER_SIZE
) {
2576 DEBUG(2, ("Oversized message\n"));
2577 x_fprintf(x_stderr
, "ERR\n");
2582 c
= strchr(buf
, '\n');
2583 } while (c
== NULL
);
2588 DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf
,length
));
2590 if (buf
[0] == '\0') {
2591 DEBUG(2, ("Invalid Request\n"));
2592 x_fprintf(x_stderr
, "ERR\n");
2597 fn(stdio_helper_mode
, lp_ctx
, state
, buf
, length
, private2
);
2602 static void squid_stream(enum stdio_helper_mode stdio_mode
,
2603 struct loadparm_context
*lp_ctx
,
2604 stdio_helper_function fn
) {
2605 TALLOC_CTX
*mem_ctx
;
2606 struct ntlm_auth_state
*state
;
2608 /* initialize FDescs */
2609 x_setbuf(x_stdout
, NULL
);
2610 x_setbuf(x_stderr
, NULL
);
2612 mem_ctx
= talloc_init("ntlm_auth");
2614 DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
2615 x_fprintf(x_stderr
, "ERR\n");
2619 state
= talloc_zero(mem_ctx
, struct ntlm_auth_state
);
2621 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
2622 x_fprintf(x_stderr
, "ERR\n");
2626 state
->mem_ctx
= mem_ctx
;
2627 state
->helper_mode
= stdio_mode
;
2630 TALLOC_CTX
*frame
= talloc_stackframe();
2631 manage_squid_request(stdio_mode
, lp_ctx
, state
, fn
, NULL
);
2637 /* Authenticate a user with a challenge/response */
2639 static bool check_auth_crap(void)
2644 char user_session_key
[16];
2646 char *hex_user_session_key
;
2648 static uint8_t zeros
[16];
2650 x_setbuf(x_stdout
, NULL
);
2653 flags
|= WBFLAG_PAM_LMKEY
;
2655 if (request_user_session_key
)
2656 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
2658 flags
|= WBFLAG_PAM_NT_STATUS_SQUASH
;
2660 nt_status
= contact_winbind_auth_crap(opt_username
, opt_domain
,
2666 (unsigned char *)lm_key
,
2667 (unsigned char *)user_session_key
,
2668 &error_string
, NULL
);
2670 if (!NT_STATUS_IS_OK(nt_status
)) {
2671 x_fprintf(x_stdout
, "%s (0x%x)\n",
2673 NT_STATUS_V(nt_status
));
2674 SAFE_FREE(error_string
);
2679 && (memcmp(zeros
, lm_key
,
2680 sizeof(lm_key
)) != 0)) {
2681 hex_lm_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)lm_key
,
2683 x_fprintf(x_stdout
, "LM_KEY: %s\n", hex_lm_key
);
2684 TALLOC_FREE(hex_lm_key
);
2686 if (request_user_session_key
2687 && (memcmp(zeros
, user_session_key
,
2688 sizeof(user_session_key
)) != 0)) {
2689 hex_user_session_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)user_session_key
,
2690 sizeof(user_session_key
));
2691 x_fprintf(x_stdout
, "NT_KEY: %s\n", hex_user_session_key
);
2692 TALLOC_FREE(hex_user_session_key
);
2701 OPT_USERNAME
= 1000,
2710 OPT_USER_SESSION_KEY
,
2712 OPT_REQUIRE_MEMBERSHIP
,
2713 OPT_USE_CACHED_CREDS
,
2714 OPT_PAM_WINBIND_CONF
,
2719 int main(int argc
, const char **argv
)
2721 TALLOC_CTX
*frame
= talloc_stackframe();
2723 static const char *helper_protocol
;
2724 static int diagnostics
;
2726 static const char *hex_challenge
;
2727 static const char *hex_lm_response
;
2728 static const char *hex_nt_response
;
2729 struct loadparm_context
*lp_ctx
;
2732 /* NOTE: DO NOT change this interface without considering the implications!
2733 This is an external interface, which other programs will use to interact
2737 /* We do not use single-letter command abbreviations, because they harm future
2738 interface stability. */
2740 struct poptOption long_options
[] = {
2742 { "helper-protocol", 0, POPT_ARG_STRING
, &helper_protocol
, OPT_DOMAIN
, "operate as a stdio-based helper", "helper protocol to use"},
2743 { "username", 0, POPT_ARG_STRING
, &opt_username
, OPT_USERNAME
, "username"},
2744 { "domain", 0, POPT_ARG_STRING
, &opt_domain
, OPT_DOMAIN
, "domain name"},
2745 { "workstation", 0, POPT_ARG_STRING
, &opt_workstation
, OPT_WORKSTATION
, "workstation"},
2746 { "challenge", 0, POPT_ARG_STRING
, &hex_challenge
, OPT_CHALLENGE
, "challenge (HEX encoded)"},
2747 { "lm-response", 0, POPT_ARG_STRING
, &hex_lm_response
, OPT_LM
, "LM Response to the challenge (HEX encoded)"},
2748 { "nt-response", 0, POPT_ARG_STRING
, &hex_nt_response
, OPT_NT
, "NT or NTLMv2 Response to the challenge (HEX encoded)"},
2749 { "password", 0, POPT_ARG_STRING
, &opt_password
, OPT_PASSWORD
, "User's plaintext password"},
2750 { "request-lm-key", 0, POPT_ARG_NONE
, &request_lm_key
, OPT_LM_KEY
, "Retrieve LM session key"},
2751 { "request-nt-key", 0, POPT_ARG_NONE
, &request_user_session_key
, OPT_USER_SESSION_KEY
, "Retrieve User (NT) session key"},
2752 { "use-cached-creds", 0, POPT_ARG_NONE
, &use_cached_creds
, OPT_USE_CACHED_CREDS
, "Use cached credentials if no password is given"},
2753 { "diagnostics", 0, POPT_ARG_NONE
, &diagnostics
,
2755 "Perform diagnostics on the authentication chain"},
2756 { "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" },
2757 { "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" },
2758 { "target-service", 0, POPT_ARG_STRING
, &opt_target_service
, OPT_TARGET_SERVICE
, "Target service (eg http)" },
2759 { "target-hostname", 0, POPT_ARG_STRING
, &opt_target_hostname
, OPT_TARGET_HOSTNAME
, "Target hostname" },
2760 POPT_COMMON_CONFIGFILE
2766 /* Samba client initialisation */
2769 setup_logging("ntlm_auth", DEBUG_STDERR
);
2773 pc
= poptGetContext("ntlm_auth", argc
, argv
, long_options
, 0);
2775 /* Parse command line options */
2778 poptPrintHelp(pc
, stderr
, 0);
2782 while((opt
= poptGetNextOpt(pc
)) != -1) {
2783 /* Get generic config options like --configfile */
2786 poptFreeContext(pc
);
2788 if (!lp_load_global(get_dyn_CONFIGFILE())) {
2789 d_fprintf(stderr
, "ntlm_auth: error opening config file %s. Error was %s\n",
2790 get_dyn_CONFIGFILE(), strerror(errno
));
2794 pc
= poptGetContext(NULL
, argc
, (const char **)argv
, long_options
,
2795 POPT_CONTEXT_KEEP_FIRST
);
2797 while((opt
= poptGetNextOpt(pc
)) != -1) {
2800 opt_challenge
= strhex_to_data_blob(NULL
, hex_challenge
);
2801 if (opt_challenge
.length
!= 8) {
2802 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2804 (int)opt_challenge
.length
);
2809 opt_lm_response
= strhex_to_data_blob(NULL
, hex_lm_response
);
2810 if (opt_lm_response
.length
!= 24) {
2811 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2813 (int)opt_lm_response
.length
);
2819 opt_nt_response
= strhex_to_data_blob(NULL
, hex_nt_response
);
2820 if (opt_nt_response
.length
< 24) {
2821 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2823 (int)opt_nt_response
.length
);
2828 case OPT_REQUIRE_MEMBERSHIP
:
2829 if (strncasecmp_m("S-", require_membership_of
, 2) == 0) {
2830 require_membership_of_sid
= require_membership_of
;
2837 char *domain
= SMB_STRDUP(opt_username
);
2838 char *p
= strchr_m(domain
, *lp_winbind_separator());
2842 if (opt_domain
&& !strequal(opt_domain
, domain
)) {
2843 x_fprintf(x_stderr
, "Domain specified in username (%s) "
2844 "doesn't match specified domain (%s)!\n\n",
2845 domain
, opt_domain
);
2846 poptPrintHelp(pc
, stderr
, 0);
2849 opt_domain
= domain
;
2855 /* Note: if opt_domain is "" then send no domain */
2856 if (opt_domain
== NULL
) {
2857 opt_domain
= get_winbind_domain();
2860 if (opt_workstation
== NULL
) {
2861 opt_workstation
= "";
2864 lp_ctx
= loadparm_init_s3(NULL
, loadparm_s3_helpers());
2865 if (lp_ctx
== NULL
) {
2866 x_fprintf(x_stderr
, "loadparm_init_s3() failed!\n");
2870 if (helper_protocol
) {
2872 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2873 if (strcmp(helper_protocol
, stdio_helper_protocols
[i
].name
) == 0) {
2874 squid_stream(stdio_helper_protocols
[i
].mode
, lp_ctx
, stdio_helper_protocols
[i
].fn
);
2878 x_fprintf(x_stderr
, "unknown helper protocol [%s]\n\nValid helper protools:\n\n", helper_protocol
);
2880 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2881 x_fprintf(x_stderr
, "%s\n", stdio_helper_protocols
[i
].name
);
2887 if (!opt_username
|| !*opt_username
) {
2888 x_fprintf(x_stderr
, "username must be specified!\n\n");
2889 poptPrintHelp(pc
, stderr
, 0);
2893 if (opt_challenge
.length
) {
2894 if (!check_auth_crap()) {
2900 if (!opt_password
) {
2901 char pwd
[256] = {0};
2904 rc
= samba_getpass("Password: ", pwd
, sizeof(pwd
), false, false);
2906 opt_password
= SMB_STRDUP(pwd
);
2911 if (!diagnose_ntlm_auth()) {
2917 fstr_sprintf(user
, "%s%c%s", opt_domain
, winbind_separator(), opt_username
);
2918 if (!check_plaintext_auth(user
, opt_password
, True
)) {
2925 poptFreeContext(pc
);