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 <iniparser.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(WINBINDD_INFO
, NULL
, &response
) !=
273 NSS_STATUS_SUCCESS
) {
274 d_printf("could not obtain winbind separator!\n");
275 return *lp_winbind_separator();
278 sep
= response
.data
.info
.winbind_separator
;
282 d_printf("winbind separator was NULL!\n");
283 return *lp_winbind_separator();
289 const char *get_winbind_domain(void)
291 struct winbindd_response response
;
293 static fstring winbind_domain
;
294 if (*winbind_domain
) {
295 return winbind_domain
;
298 ZERO_STRUCT(response
);
300 /* Send off request */
302 if (winbindd_request_response(WINBINDD_DOMAIN_NAME
, NULL
, &response
) !=
303 NSS_STATUS_SUCCESS
) {
304 DEBUG(1, ("could not obtain winbind domain name!\n"));
305 return lp_workgroup();
308 fstrcpy(winbind_domain
, response
.data
.domain_name
);
310 return winbind_domain
;
314 const char *get_winbind_netbios_name(void)
316 struct winbindd_response response
;
318 static fstring winbind_netbios_name
;
320 if (*winbind_netbios_name
) {
321 return winbind_netbios_name
;
324 ZERO_STRUCT(response
);
326 /* Send off request */
328 if (winbindd_request_response(WINBINDD_NETBIOS_NAME
, NULL
, &response
) !=
329 NSS_STATUS_SUCCESS
) {
330 DEBUG(1, ("could not obtain winbind netbios name!\n"));
331 return lp_netbios_name();
334 fstrcpy(winbind_netbios_name
, response
.data
.netbios_name
);
336 return winbind_netbios_name
;
340 DATA_BLOB
get_challenge(void)
342 static DATA_BLOB chal
;
343 if (opt_challenge
.length
)
344 return opt_challenge
;
346 chal
= data_blob(NULL
, 8);
348 generate_random_buffer(chal
.data
, chal
.length
);
352 /* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
353 form DOMAIN/user into a domain and a user */
355 static bool parse_ntlm_auth_domain_user(const char *domuser
, fstring domain
,
359 char *p
= strchr(domuser
,winbind_separator());
366 fstrcpy(domain
, domuser
);
367 domain
[PTR_DIFF(p
, domuser
)] = 0;
368 return strupper_m(domain
);
371 static bool get_require_membership_sid(void) {
372 struct winbindd_request request
;
373 struct winbindd_response response
;
375 if (!require_membership_of
) {
379 if (require_membership_of_sid
) {
383 /* Otherwise, ask winbindd for the name->sid request */
385 ZERO_STRUCT(request
);
386 ZERO_STRUCT(response
);
388 if (!parse_ntlm_auth_domain_user(require_membership_of
,
389 request
.data
.name
.dom_name
,
390 request
.data
.name
.name
)) {
391 DEBUG(0, ("Could not parse %s into separate domain/name parts!\n",
392 require_membership_of
));
396 if (winbindd_request_response(WINBINDD_LOOKUPNAME
, &request
, &response
) !=
397 NSS_STATUS_SUCCESS
) {
398 DEBUG(0, ("Winbindd lookupname failed to resolve %s into a SID!\n",
399 require_membership_of
));
403 require_membership_of_sid
= SMB_STRDUP(response
.data
.sid
.sid
);
405 if (require_membership_of_sid
)
412 * Get some configuration from pam_winbind.conf to see if we
413 * need to contact trusted domain
416 int get_pam_winbind_config()
419 dictionary
*d
= NULL
;
421 if (!opt_pam_winbind_conf
|| !*opt_pam_winbind_conf
) {
422 opt_pam_winbind_conf
= PAM_WINBIND_CONFIG_FILE
;
425 d
= iniparser_load(discard_const_p(char, opt_pam_winbind_conf
));
431 if (iniparser_getboolean(d
, discard_const_p(char, "global:krb5_auth"), false)) {
432 ctrl
|= WINBIND_KRB5_AUTH
;
435 iniparser_freedict(d
);
440 /* Authenticate a user with a plaintext password */
442 static bool check_plaintext_auth(const char *user
, const char *pass
,
443 bool stdout_diagnostics
)
445 struct winbindd_request request
;
446 struct winbindd_response response
;
449 if (!get_require_membership_sid()) {
453 /* Send off request */
455 ZERO_STRUCT(request
);
456 ZERO_STRUCT(response
);
458 fstrcpy(request
.data
.auth
.user
, user
);
459 fstrcpy(request
.data
.auth
.pass
, pass
);
460 if (require_membership_of_sid
) {
461 strlcpy(request
.data
.auth
.require_membership_of_sid
,
462 require_membership_of_sid
,
463 sizeof(request
.data
.auth
.require_membership_of_sid
));
466 result
= winbindd_request_response(WINBINDD_PAM_AUTH
, &request
, &response
);
468 /* Display response */
470 if (stdout_diagnostics
) {
471 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
472 d_printf("Reading winbind reply failed! (0x01)\n");
475 d_printf("%s: %s (0x%x)\n",
476 response
.data
.auth
.nt_status_string
,
477 response
.data
.auth
.error_string
,
478 response
.data
.auth
.nt_status
);
480 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
481 DEBUG(1, ("Reading winbind reply failed! (0x01)\n"));
484 DEBUG(3, ("%s: %s (0x%x)\n",
485 response
.data
.auth
.nt_status_string
,
486 response
.data
.auth
.error_string
,
487 response
.data
.auth
.nt_status
));
490 return (result
== NSS_STATUS_SUCCESS
);
493 /* authenticate a user with an encrypted username/password */
495 NTSTATUS
contact_winbind_auth_crap(const char *username
,
497 const char *workstation
,
498 const DATA_BLOB
*challenge
,
499 const DATA_BLOB
*lm_response
,
500 const DATA_BLOB
*nt_response
,
502 uint32 extra_logon_parameters
,
504 uint8 user_session_key
[16],
510 struct winbindd_request request
;
511 struct winbindd_response response
;
513 if (!get_require_membership_sid()) {
514 return NT_STATUS_INVALID_PARAMETER
;
517 ZERO_STRUCT(request
);
518 ZERO_STRUCT(response
);
520 request
.flags
= flags
;
522 request
.data
.auth_crap
.logon_parameters
= extra_logon_parameters
523 | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
| MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT
;
525 if (require_membership_of_sid
)
526 fstrcpy(request
.data
.auth_crap
.require_membership_of_sid
, require_membership_of_sid
);
528 fstrcpy(request
.data
.auth_crap
.user
, username
);
529 fstrcpy(request
.data
.auth_crap
.domain
, domain
);
531 fstrcpy(request
.data
.auth_crap
.workstation
,
534 memcpy(request
.data
.auth_crap
.chal
, challenge
->data
, MIN(challenge
->length
, 8));
536 if (lm_response
&& lm_response
->length
) {
537 memcpy(request
.data
.auth_crap
.lm_resp
,
539 MIN(lm_response
->length
, sizeof(request
.data
.auth_crap
.lm_resp
)));
540 request
.data
.auth_crap
.lm_resp_len
= lm_response
->length
;
543 if (nt_response
&& nt_response
->length
) {
544 if (nt_response
->length
> sizeof(request
.data
.auth_crap
.nt_resp
)) {
545 request
.flags
= request
.flags
| WBFLAG_BIG_NTLMV2_BLOB
;
546 request
.extra_len
= nt_response
->length
;
547 request
.extra_data
.data
= SMB_MALLOC_ARRAY(char, request
.extra_len
);
548 if (request
.extra_data
.data
== NULL
) {
549 return NT_STATUS_NO_MEMORY
;
551 memcpy(request
.extra_data
.data
, nt_response
->data
,
552 nt_response
->length
);
555 memcpy(request
.data
.auth_crap
.nt_resp
,
556 nt_response
->data
, nt_response
->length
);
558 request
.data
.auth_crap
.nt_resp_len
= nt_response
->length
;
561 result
= winbindd_request_response(WINBINDD_PAM_AUTH_CRAP
, &request
, &response
);
562 SAFE_FREE(request
.extra_data
.data
);
564 /* Display response */
566 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
567 nt_status
= NT_STATUS_UNSUCCESSFUL
;
569 *error_string
= smb_xstrdup("Reading winbind reply failed!");
570 winbindd_free_response(&response
);
574 nt_status
= (NT_STATUS(response
.data
.auth
.nt_status
));
575 if (!NT_STATUS_IS_OK(nt_status
)) {
577 *error_string
= smb_xstrdup(response
.data
.auth
.error_string
);
578 winbindd_free_response(&response
);
582 if ((flags
& WBFLAG_PAM_LMKEY
) && lm_key
) {
583 memcpy(lm_key
, response
.data
.auth
.first_8_lm_hash
,
584 sizeof(response
.data
.auth
.first_8_lm_hash
));
586 if ((flags
& WBFLAG_PAM_USER_SESSION_KEY
) && user_session_key
) {
587 memcpy(user_session_key
, response
.data
.auth
.user_session_key
,
588 sizeof(response
.data
.auth
.user_session_key
));
591 if (flags
& WBFLAG_PAM_UNIX_NAME
) {
592 *unix_name
= SMB_STRDUP(response
.data
.auth
.unix_username
);
594 winbindd_free_response(&response
);
595 return NT_STATUS_NO_MEMORY
;
599 winbindd_free_response(&response
);
603 /* contact server to change user password using auth crap */
604 static NTSTATUS
contact_winbind_change_pswd_auth_crap(const char *username
,
606 const DATA_BLOB new_nt_pswd
,
607 const DATA_BLOB old_nt_hash_enc
,
608 const DATA_BLOB new_lm_pswd
,
609 const DATA_BLOB old_lm_hash_enc
,
614 struct winbindd_request request
;
615 struct winbindd_response response
;
617 if (!get_require_membership_sid())
620 *error_string
= smb_xstrdup("Can't get membership sid.");
621 return NT_STATUS_INVALID_PARAMETER
;
624 ZERO_STRUCT(request
);
625 ZERO_STRUCT(response
);
628 fstrcpy(request
.data
.chng_pswd_auth_crap
.user
, username
);
630 fstrcpy(request
.data
.chng_pswd_auth_crap
.domain
,domain
);
632 if(new_nt_pswd
.length
)
634 memcpy(request
.data
.chng_pswd_auth_crap
.new_nt_pswd
, new_nt_pswd
.data
, sizeof(request
.data
.chng_pswd_auth_crap
.new_nt_pswd
));
635 request
.data
.chng_pswd_auth_crap
.new_nt_pswd_len
= new_nt_pswd
.length
;
638 if(old_nt_hash_enc
.length
)
640 memcpy(request
.data
.chng_pswd_auth_crap
.old_nt_hash_enc
, old_nt_hash_enc
.data
, sizeof(request
.data
.chng_pswd_auth_crap
.old_nt_hash_enc
));
641 request
.data
.chng_pswd_auth_crap
.old_nt_hash_enc_len
= old_nt_hash_enc
.length
;
644 if(new_lm_pswd
.length
)
646 memcpy(request
.data
.chng_pswd_auth_crap
.new_lm_pswd
, new_lm_pswd
.data
, sizeof(request
.data
.chng_pswd_auth_crap
.new_lm_pswd
));
647 request
.data
.chng_pswd_auth_crap
.new_lm_pswd_len
= new_lm_pswd
.length
;
650 if(old_lm_hash_enc
.length
)
652 memcpy(request
.data
.chng_pswd_auth_crap
.old_lm_hash_enc
, old_lm_hash_enc
.data
, sizeof(request
.data
.chng_pswd_auth_crap
.old_lm_hash_enc
));
653 request
.data
.chng_pswd_auth_crap
.old_lm_hash_enc_len
= old_lm_hash_enc
.length
;
656 result
= winbindd_request_response(WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP
, &request
, &response
);
658 /* Display response */
660 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0))
662 nt_status
= NT_STATUS_UNSUCCESSFUL
;
664 *error_string
= smb_xstrdup("Reading winbind reply failed!");
665 winbindd_free_response(&response
);
669 nt_status
= (NT_STATUS(response
.data
.auth
.nt_status
));
670 if (!NT_STATUS_IS_OK(nt_status
))
673 *error_string
= smb_xstrdup(response
.data
.auth
.error_string
);
674 winbindd_free_response(&response
);
678 winbindd_free_response(&response
);
683 static NTSTATUS
ntlm_auth_generate_session_info(struct auth4_context
*auth_context
,
685 void *server_returned_info
,
686 const char *original_user_name
,
687 uint32_t session_info_flags
,
688 struct auth_session_info
**session_info_out
)
690 char *unix_username
= (char *)server_returned_info
;
691 struct auth_session_info
*session_info
= talloc_zero(mem_ctx
, struct auth_session_info
);
693 return NT_STATUS_NO_MEMORY
;
696 session_info
->unix_info
= talloc_zero(session_info
, struct auth_user_info_unix
);
697 if (!session_info
->unix_info
) {
698 TALLOC_FREE(session_info
);
699 return NT_STATUS_NO_MEMORY
;
701 session_info
->unix_info
->unix_name
= talloc_steal(session_info
->unix_info
, unix_username
);
703 *session_info_out
= session_info
;
708 static NTSTATUS
ntlm_auth_generate_session_info_pac(struct auth4_context
*auth_ctx
,
710 struct smb_krb5_context
*smb_krb5_context
,
712 const char *princ_name
,
713 const struct tsocket_address
*remote_address
,
714 uint32_t session_info_flags
,
715 struct auth_session_info
**session_info
)
718 struct PAC_LOGON_INFO
*logon_info
= NULL
;
726 tmp_ctx
= talloc_new(mem_ctx
);
728 return NT_STATUS_NO_MEMORY
;
733 status
= kerberos_pac_logon_info(tmp_ctx
, *pac_blob
, NULL
, NULL
,
734 NULL
, NULL
, 0, &logon_info
);
736 status
= NT_STATUS_ACCESS_DENIED
;
738 if (!NT_STATUS_IS_OK(status
)) {
743 DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name
));
745 p
= strchr_m(princ_name
, '@');
747 DEBUG(3, ("[%s] Doesn't look like a valid principal\n",
749 return NT_STATUS_LOGON_FAILURE
;
752 user
= talloc_strndup(mem_ctx
, princ_name
, p
- princ_name
);
754 return NT_STATUS_NO_MEMORY
;
757 realm
= talloc_strdup(talloc_tos(), p
+ 1);
759 return NT_STATUS_NO_MEMORY
;
762 if (!strequal(realm
, lp_realm())) {
763 DEBUG(3, ("Ticket for foreign realm %s@%s\n", user
, realm
));
764 if (!lp_allow_trusted_domains()) {
765 return NT_STATUS_LOGON_FAILURE
;
769 if (logon_info
&& logon_info
->info3
.base
.logon_domain
.string
) {
770 domain
= talloc_strdup(mem_ctx
,
771 logon_info
->info3
.base
.logon_domain
.string
);
773 return NT_STATUS_NO_MEMORY
;
775 DEBUG(10, ("Domain is [%s] (using PAC)\n", domain
));
778 /* If we have winbind running, we can (and must) shorten the
779 username by using the short netbios name. Otherwise we will
780 have inconsistent user names. With Kerberos, we get the
781 fully qualified realm, with ntlmssp we get the short
782 name. And even w2k3 does use ntlmssp if you for example
783 connect to an ip address. */
786 struct wbcDomainInfo
*info
= NULL
;
788 DEBUG(10, ("Mapping [%s] to short name using winbindd\n",
791 wbc_status
= wbcDomainInfo(realm
, &info
);
793 if (WBC_ERROR_IS_OK(wbc_status
)) {
794 domain
= talloc_strdup(mem_ctx
,
798 DEBUG(3, ("Could not find short name: %s\n",
799 wbcErrorString(wbc_status
)));
800 domain
= talloc_strdup(mem_ctx
, realm
);
803 return NT_STATUS_NO_MEMORY
;
805 DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain
));
808 unixuser
= talloc_asprintf(tmp_ctx
, "%s%c%s", domain
, winbind_separator(), user
);
810 status
= NT_STATUS_NO_MEMORY
;
814 status
= ntlm_auth_generate_session_info(auth_ctx
, mem_ctx
, unixuser
, NULL
, session_info_flags
, session_info
);
817 TALLOC_FREE(tmp_ctx
);
824 * Return the challenge as determined by the authentication subsystem
825 * @return an 8 byte random challenge
828 static NTSTATUS
ntlm_auth_get_challenge(struct auth4_context
*auth_ctx
,
831 if (auth_ctx
->challenge
.data
.length
== 8) {
832 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
833 auth_ctx
->challenge
.set_by
));
834 memcpy(chal
, auth_ctx
->challenge
.data
.data
, 8);
838 if (!auth_ctx
->challenge
.set_by
) {
839 generate_random_buffer(chal
, 8);
841 auth_ctx
->challenge
.data
= data_blob_talloc(auth_ctx
, chal
, 8);
842 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.data
.data
);
843 auth_ctx
->challenge
.set_by
= "random";
846 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
847 auth_ctx
->challenge
.set_by
));
853 * NTLM2 authentication modifies the effective challenge,
854 * @param challenge The new challenge value
856 static NTSTATUS
ntlm_auth_set_challenge(struct auth4_context
*auth_ctx
, const uint8_t chal
[8], const char *set_by
)
858 auth_ctx
->challenge
.set_by
= talloc_strdup(auth_ctx
, set_by
);
859 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.set_by
);
861 auth_ctx
->challenge
.data
= data_blob_talloc(auth_ctx
, chal
, 8);
862 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.data
.data
);
868 * Check the password on an NTLMSSP login.
870 * Return the session keys used on the connection.
873 static NTSTATUS
winbind_pw_check(struct auth4_context
*auth4_context
,
875 const struct auth_usersupplied_info
*user_info
,
876 void **server_returned_info
,
877 DATA_BLOB
*session_key
, DATA_BLOB
*lm_session_key
)
879 static const char zeros
[16] = { 0, };
881 char *error_string
= NULL
;
883 uint8 user_sess_key
[16];
884 char *unix_name
= NULL
;
886 nt_status
= contact_winbind_auth_crap(user_info
->client
.account_name
, user_info
->client
.domain_name
,
887 user_info
->workstation_name
,
888 &auth4_context
->challenge
.data
,
889 &user_info
->password
.response
.lanman
,
890 &user_info
->password
.response
.nt
,
891 WBFLAG_PAM_LMKEY
| WBFLAG_PAM_USER_SESSION_KEY
| WBFLAG_PAM_UNIX_NAME
,
893 lm_key
, user_sess_key
,
894 &error_string
, &unix_name
);
896 if (NT_STATUS_IS_OK(nt_status
)) {
897 if (memcmp(lm_key
, zeros
, 8) != 0) {
898 *lm_session_key
= data_blob_talloc(mem_ctx
, NULL
, 16);
899 memcpy(lm_session_key
->data
, lm_key
, 8);
900 memset(lm_session_key
->data
+8, '\0', 8);
903 if (memcmp(user_sess_key
, zeros
, 16) != 0) {
904 *session_key
= data_blob_talloc(mem_ctx
, user_sess_key
, 16);
906 *server_returned_info
= talloc_strdup(mem_ctx
,
909 DEBUG(NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCESS_DENIED
) ? 0 : 3,
910 ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
911 user_info
->client
.domain_name
, user_info
->client
.account_name
,
912 user_info
->workstation_name
,
913 error_string
? error_string
: "unknown error (NULL)"));
916 SAFE_FREE(error_string
);
917 SAFE_FREE(unix_name
);
921 static NTSTATUS
local_pw_check(struct auth4_context
*auth4_context
,
923 const struct auth_usersupplied_info
*user_info
,
924 void **server_returned_info
,
925 DATA_BLOB
*session_key
, DATA_BLOB
*lm_session_key
)
928 struct samr_Password lm_pw
, nt_pw
;
930 nt_lm_owf_gen (opt_password
, nt_pw
.hash
, lm_pw
.hash
);
932 nt_status
= ntlm_password_check(mem_ctx
,
934 &auth4_context
->challenge
.data
,
935 &user_info
->password
.response
.lanman
,
936 &user_info
->password
.response
.nt
,
937 user_info
->client
.account_name
,
938 user_info
->client
.account_name
,
939 user_info
->client
.domain_name
,
940 &lm_pw
, &nt_pw
, session_key
, lm_session_key
);
942 if (NT_STATUS_IS_OK(nt_status
)) {
943 *server_returned_info
= talloc_asprintf(mem_ctx
,
944 "%s%c%s", user_info
->client
.domain_name
,
945 *lp_winbind_separator(),
946 user_info
->client
.account_name
);
948 DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
949 user_info
->client
.domain_name
, user_info
->client
.account_name
,
950 user_info
->workstation_name
,
951 nt_errstr(nt_status
)));
956 static NTSTATUS
ntlm_auth_start_ntlmssp_client(struct ntlmssp_state
**client_ntlmssp_state
)
959 if ( (opt_username
== NULL
) || (opt_domain
== NULL
) ) {
960 status
= NT_STATUS_UNSUCCESSFUL
;
961 DEBUG(1, ("Need username and domain for NTLMSSP\n"));
962 return NT_STATUS_INVALID_PARAMETER
;
965 status
= ntlmssp_client_start(NULL
,
968 lp_client_ntlmv2_auth(),
969 client_ntlmssp_state
);
971 if (!NT_STATUS_IS_OK(status
)) {
972 DEBUG(1, ("Could not start NTLMSSP client: %s\n",
974 TALLOC_FREE(*client_ntlmssp_state
);
978 status
= ntlmssp_set_username(*client_ntlmssp_state
, opt_username
);
980 if (!NT_STATUS_IS_OK(status
)) {
981 DEBUG(1, ("Could not set username: %s\n",
983 TALLOC_FREE(*client_ntlmssp_state
);
987 status
= ntlmssp_set_domain(*client_ntlmssp_state
, opt_domain
);
989 if (!NT_STATUS_IS_OK(status
)) {
990 DEBUG(1, ("Could not set domain: %s\n",
992 TALLOC_FREE(*client_ntlmssp_state
);
997 status
= ntlmssp_set_password(*client_ntlmssp_state
, opt_password
);
999 if (!NT_STATUS_IS_OK(status
)) {
1000 DEBUG(1, ("Could not set password: %s\n",
1001 nt_errstr(status
)));
1002 TALLOC_FREE(*client_ntlmssp_state
);
1007 return NT_STATUS_OK
;
1010 static struct auth4_context
*make_auth4_context_ntlm_auth(TALLOC_CTX
*mem_ctx
, bool local_pw
)
1012 struct auth4_context
*auth4_context
= talloc_zero(mem_ctx
, struct auth4_context
);
1013 if (auth4_context
== NULL
) {
1014 DEBUG(10, ("failed to allocate auth4_context failed\n"));
1017 auth4_context
->generate_session_info
= ntlm_auth_generate_session_info
;
1018 auth4_context
->generate_session_info_pac
= ntlm_auth_generate_session_info_pac
;
1019 auth4_context
->get_ntlm_challenge
= ntlm_auth_get_challenge
;
1020 auth4_context
->set_ntlm_challenge
= ntlm_auth_set_challenge
;
1022 auth4_context
->check_ntlm_password
= local_pw_check
;
1024 auth4_context
->check_ntlm_password
= winbind_pw_check
;
1026 auth4_context
->private_data
= NULL
;
1027 return auth4_context
;
1030 static NTSTATUS
ntlm_auth_start_ntlmssp_server(TALLOC_CTX
*mem_ctx
,
1031 struct loadparm_context
*lp_ctx
,
1032 struct gensec_security
**gensec_security_out
)
1034 struct gensec_security
*gensec_security
;
1037 TALLOC_CTX
*tmp_ctx
;
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_security() == SEC_ADS
|| USE_KERBEROS_KEYTAB
) {
1115 cli_credentials_set_kerberos_state(server_credentials
, CRED_AUTO_USE_KERBEROS
);
1117 cli_credentials_set_kerberos_state(server_credentials
, CRED_DONT_USE_KERBEROS
);
1120 nt_status
= gensec_server_start(tmp_ctx
, gensec_settings
,
1121 auth4_context
, &gensec_security
);
1123 if (!NT_STATUS_IS_OK(nt_status
)) {
1124 TALLOC_FREE(tmp_ctx
);
1128 gensec_set_credentials(gensec_security
, server_credentials
);
1130 gensec_want_feature(gensec_security
, GENSEC_FEATURE_SIGN
);
1131 gensec_want_feature(gensec_security
, GENSEC_FEATURE_SEAL
);
1133 talloc_unlink(tmp_ctx
, lp_ctx
);
1134 talloc_unlink(tmp_ctx
, server_credentials
);
1135 talloc_unlink(tmp_ctx
, gensec_settings
);
1136 talloc_unlink(tmp_ctx
, auth4_context
);
1138 nt_status
= gensec_start_mech_by_oid(gensec_security
, GENSEC_OID_NTLMSSP
);
1139 if (!NT_STATUS_IS_OK(nt_status
)) {
1140 TALLOC_FREE(tmp_ctx
);
1144 *gensec_security_out
= talloc_steal(mem_ctx
, gensec_security
);
1145 TALLOC_FREE(tmp_ctx
);
1146 return NT_STATUS_OK
;
1149 /*******************************************************************
1150 Used by firefox to drive NTLM auth to IIS servers.
1151 *******************************************************************/
1153 static NTSTATUS
do_ccache_ntlm_auth(DATA_BLOB initial_msg
, DATA_BLOB challenge_msg
,
1156 struct winbindd_request wb_request
;
1157 struct winbindd_response wb_response
;
1161 /* get winbindd to do the ntlmssp step on our behalf */
1162 ZERO_STRUCT(wb_request
);
1163 ZERO_STRUCT(wb_response
);
1166 * This is tricky here. If we set krb5_auth in pam_winbind.conf
1167 * creds for users in trusted domain will be stored the winbindd
1168 * child of the trusted domain. If we ask the primary domain for
1169 * ntlm_ccache_auth, it will fail. So, we have to ask the trusted
1170 * domain's child for ccache_ntlm_auth. that is to say, we have to
1171 * set WBFLAG_PAM_CONTACT_TRUSTDOM in request.flags.
1173 ctrl
= get_pam_winbind_config();
1175 if (ctrl
& WINBIND_KRB5_AUTH
) {
1176 wb_request
.flags
|= WBFLAG_PAM_CONTACT_TRUSTDOM
;
1179 fstr_sprintf(wb_request
.data
.ccache_ntlm_auth
.user
,
1180 "%s%c%s", opt_domain
, winbind_separator(), opt_username
);
1181 wb_request
.data
.ccache_ntlm_auth
.uid
= geteuid();
1182 wb_request
.data
.ccache_ntlm_auth
.initial_blob_len
= initial_msg
.length
;
1183 wb_request
.data
.ccache_ntlm_auth
.challenge_blob_len
= challenge_msg
.length
;
1184 wb_request
.extra_len
= initial_msg
.length
+ challenge_msg
.length
;
1186 if (wb_request
.extra_len
> 0) {
1187 wb_request
.extra_data
.data
= SMB_MALLOC_ARRAY(char, wb_request
.extra_len
);
1188 if (wb_request
.extra_data
.data
== NULL
) {
1189 return NT_STATUS_NO_MEMORY
;
1192 memcpy(wb_request
.extra_data
.data
, initial_msg
.data
, initial_msg
.length
);
1193 memcpy(wb_request
.extra_data
.data
+ initial_msg
.length
,
1194 challenge_msg
.data
, challenge_msg
.length
);
1197 result
= winbindd_request_response(WINBINDD_CCACHE_NTLMAUTH
, &wb_request
, &wb_response
);
1198 SAFE_FREE(wb_request
.extra_data
.data
);
1200 if (result
!= NSS_STATUS_SUCCESS
) {
1201 winbindd_free_response(&wb_response
);
1202 return NT_STATUS_UNSUCCESSFUL
;
1206 *reply
= data_blob(wb_response
.extra_data
.data
,
1207 wb_response
.data
.ccache_ntlm_auth
.auth_blob_len
);
1208 if (wb_response
.data
.ccache_ntlm_auth
.auth_blob_len
> 0 &&
1209 reply
->data
== NULL
) {
1210 winbindd_free_response(&wb_response
);
1211 return NT_STATUS_NO_MEMORY
;
1215 winbindd_free_response(&wb_response
);
1216 return NT_STATUS_MORE_PROCESSING_REQUIRED
;
1219 static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode
,
1220 struct loadparm_context
*lp_ctx
,
1221 struct ntlm_auth_state
*state
,
1222 char *buf
, int length
, void **private2
)
1224 DATA_BLOB request
, reply
;
1227 if (!opt_username
|| !*opt_username
) {
1228 x_fprintf(x_stderr
, "username must be specified!\n\n");
1232 if (strlen(buf
) < 2) {
1233 DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf
));
1234 x_fprintf(x_stdout
, "BH NTLMSSP query invalid\n");
1238 if (strlen(buf
) > 3) {
1239 if(strncmp(buf
, "SF ", 3) == 0) {
1240 DEBUG(10, ("Looking for flags to negotiate\n"));
1241 talloc_free(state
->want_feature_list
);
1242 state
->want_feature_list
= talloc_strdup(state
->mem_ctx
,
1244 x_fprintf(x_stdout
, "OK\n");
1247 request
= base64_decode_data_blob(buf
+ 3);
1249 request
= data_blob_null
;
1252 if (strncmp(buf
, "PW ", 3) == 0) {
1253 /* We asked for a password and obviously got it :-) */
1255 opt_password
= SMB_STRNDUP((const char *)request
.data
,
1258 if (opt_password
== NULL
) {
1259 DEBUG(1, ("Out of memory\n"));
1260 x_fprintf(x_stdout
, "BH Out of memory\n");
1261 data_blob_free(&request
);
1265 x_fprintf(x_stdout
, "OK\n");
1266 data_blob_free(&request
);
1270 if (!state
->ntlmssp_state
&& use_cached_creds
) {
1271 /* check whether cached credentials are usable. */
1272 DATA_BLOB empty_blob
= data_blob_null
;
1274 nt_status
= do_ccache_ntlm_auth(empty_blob
, empty_blob
, NULL
);
1275 if (!NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1276 /* failed to use cached creds */
1277 use_cached_creds
= False
;
1281 if (opt_password
== NULL
&& !use_cached_creds
) {
1282 /* Request a password from the calling process. After
1283 sending it, the calling process should retry asking for the
1286 DEBUG(10, ("Requesting password\n"));
1287 x_fprintf(x_stdout
, "PW\n");
1291 if (strncmp(buf
, "YR", 2) == 0) {
1292 TALLOC_FREE(state
->ntlmssp_state
);
1293 state
->cli_state
= CLIENT_INITIAL
;
1294 } else if (strncmp(buf
, "TT", 2) == 0) {
1295 /* No special preprocessing required */
1296 } else if (strncmp(buf
, "GF", 2) == 0) {
1297 DEBUG(10, ("Requested negotiated NTLMSSP flags\n"));
1299 if(state
->cli_state
== CLIENT_FINISHED
) {
1300 x_fprintf(x_stdout
, "GF 0x%08x\n", state
->neg_flags
);
1303 x_fprintf(x_stdout
, "BH\n");
1306 data_blob_free(&request
);
1308 } else if (strncmp(buf
, "GK", 2) == 0 ) {
1309 DEBUG(10, ("Requested session key\n"));
1311 if(state
->cli_state
== CLIENT_FINISHED
) {
1312 char *key64
= base64_encode_data_blob(state
->mem_ctx
,
1313 state
->session_key
);
1314 x_fprintf(x_stdout
, "GK %s\n", key64
?key64
:"<NULL>");
1318 x_fprintf(x_stdout
, "BH\n");
1321 data_blob_free(&request
);
1324 DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf
));
1325 x_fprintf(x_stdout
, "BH NTLMSSP query invalid\n");
1329 if (!state
->ntlmssp_state
) {
1330 nt_status
= ntlm_auth_start_ntlmssp_client(
1331 &state
->ntlmssp_state
);
1332 if (!NT_STATUS_IS_OK(nt_status
)) {
1333 x_fprintf(x_stdout
, "BH %s\n", nt_errstr(nt_status
));
1336 ntlmssp_want_feature_list(state
->ntlmssp_state
,
1337 state
->want_feature_list
);
1338 state
->initial_message
= data_blob_null
;
1341 DEBUG(10, ("got NTLMSSP packet:\n"));
1342 dump_data(10, request
.data
, request
.length
);
1344 if (use_cached_creds
&& !opt_password
&&
1345 (state
->cli_state
== CLIENT_RESPONSE
)) {
1346 nt_status
= do_ccache_ntlm_auth(state
->initial_message
, request
,
1349 nt_status
= ntlmssp_update(state
->ntlmssp_state
, request
,
1353 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1354 char *reply_base64
= base64_encode_data_blob(state
->mem_ctx
,
1356 if (state
->cli_state
== CLIENT_INITIAL
) {
1357 x_fprintf(x_stdout
, "YR %s\n", reply_base64
);
1358 state
->initial_message
= reply
;
1359 state
->cli_state
= CLIENT_RESPONSE
;
1361 x_fprintf(x_stdout
, "KK %s\n", reply_base64
);
1362 data_blob_free(&reply
);
1364 TALLOC_FREE(reply_base64
);
1365 DEBUG(10, ("NTLMSSP challenge\n"));
1366 } else if (NT_STATUS_IS_OK(nt_status
)) {
1367 char *reply_base64
= base64_encode_data_blob(talloc_tos(),
1369 x_fprintf(x_stdout
, "AF %s\n", reply_base64
);
1370 TALLOC_FREE(reply_base64
);
1372 if(state
->have_session_key
)
1373 data_blob_free(&state
->session_key
);
1375 state
->session_key
= data_blob(
1376 state
->ntlmssp_state
->session_key
.data
,
1377 state
->ntlmssp_state
->session_key
.length
);
1378 state
->neg_flags
= state
->ntlmssp_state
->neg_flags
;
1379 state
->have_session_key
= true;
1381 DEBUG(10, ("NTLMSSP OK!\n"));
1382 state
->cli_state
= CLIENT_FINISHED
;
1383 TALLOC_FREE(state
->ntlmssp_state
);
1385 x_fprintf(x_stdout
, "BH %s\n", nt_errstr(nt_status
));
1386 DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status
)));
1387 state
->cli_state
= CLIENT_ERROR
;
1388 TALLOC_FREE(state
->ntlmssp_state
);
1391 data_blob_free(&request
);
1394 static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode
,
1395 struct loadparm_context
*lp_ctx
,
1396 struct ntlm_auth_state
*state
,
1397 char *buf
, int length
, void **private2
)
1402 pass
=(char *)memchr(buf
,' ',length
);
1404 DEBUG(2, ("Password not found. Denying access\n"));
1405 x_fprintf(x_stdout
, "ERR\n");
1411 if (state
->helper_mode
== SQUID_2_5_BASIC
) {
1412 rfc1738_unescape(user
);
1413 rfc1738_unescape(pass
);
1416 if (check_plaintext_auth(user
, pass
, False
)) {
1417 x_fprintf(x_stdout
, "OK\n");
1419 x_fprintf(x_stdout
, "ERR\n");
1423 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode
,
1424 struct loadparm_context
*lp_ctx
,
1425 char *buf
, int length
, void **private1
)
1428 DATA_BLOB out
= data_blob(NULL
, 0);
1429 char *out_base64
= NULL
;
1430 const char *reply_arg
= NULL
;
1431 struct gensec_ntlm_state
{
1432 struct gensec_security
*gensec_state
;
1433 const char *set_password
;
1435 struct gensec_ntlm_state
*state
;
1439 const char *reply_code
;
1440 struct cli_credentials
*creds
;
1442 static char *want_feature_list
= NULL
;
1443 static DATA_BLOB session_key
;
1445 TALLOC_CTX
*mem_ctx
;
1448 state
= (struct gensec_ntlm_state
*)*private1
;
1450 state
= talloc_zero(NULL
, struct gensec_ntlm_state
);
1452 x_fprintf(x_stdout
, "BH No Memory\n");
1457 state
->set_password
= opt_password
;
1461 if (strlen(buf
) < 2) {
1462 DEBUG(1, ("query [%s] invalid", buf
));
1463 x_fprintf(x_stdout
, "BH Query invalid\n");
1467 if (strlen(buf
) > 3) {
1468 if(strncmp(buf
, "SF ", 3) == 0) {
1469 DEBUG(10, ("Setting flags to negotiate\n"));
1470 talloc_free(want_feature_list
);
1471 want_feature_list
= talloc_strndup(state
, buf
+3, strlen(buf
)-3);
1472 x_fprintf(x_stdout
, "OK\n");
1475 in
= base64_decode_data_blob(buf
+ 3);
1477 in
= data_blob(NULL
, 0);
1480 if (strncmp(buf
, "YR", 2) == 0) {
1481 if (state
->gensec_state
) {
1482 talloc_free(state
->gensec_state
);
1483 state
->gensec_state
= NULL
;
1485 } else if ( (strncmp(buf
, "OK", 2) == 0)) {
1486 /* Just return BH, like ntlm_auth from Samba 3 does. */
1487 x_fprintf(x_stdout
, "BH Command expected\n");
1488 data_blob_free(&in
);
1490 } else if ( (strncmp(buf
, "TT ", 3) != 0) &&
1491 (strncmp(buf
, "KK ", 3) != 0) &&
1492 (strncmp(buf
, "AF ", 3) != 0) &&
1493 (strncmp(buf
, "NA ", 3) != 0) &&
1494 (strncmp(buf
, "UG", 2) != 0) &&
1495 (strncmp(buf
, "PW ", 3) != 0) &&
1496 (strncmp(buf
, "GK", 2) != 0) &&
1497 (strncmp(buf
, "GF", 2) != 0)) {
1498 DEBUG(1, ("SPNEGO request [%s] invalid prefix\n", buf
));
1499 x_fprintf(x_stdout
, "BH SPNEGO request invalid prefix\n");
1500 data_blob_free(&in
);
1504 mem_ctx
= talloc_named(NULL
, 0, "manage_gensec_request internal mem_ctx");
1507 if (!(state
->gensec_state
)) {
1508 switch (stdio_helper_mode
) {
1509 case GSS_SPNEGO_CLIENT
:
1510 case NTLMSSP_CLIENT_1
:
1511 /* setup the client side */
1513 nt_status
= gensec_client_start(NULL
, &state
->gensec_state
,
1514 lpcfg_gensec_settings(NULL
, lp_ctx
));
1515 if (!NT_STATUS_IS_OK(nt_status
)) {
1516 x_fprintf(x_stdout
, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status
));
1517 talloc_free(mem_ctx
);
1521 creds
= cli_credentials_init(state
->gensec_state
);
1522 cli_credentials_set_conf(creds
, lp_ctx
);
1524 cli_credentials_set_username(creds
, opt_username
, CRED_SPECIFIED
);
1527 cli_credentials_set_domain(creds
, opt_domain
, CRED_SPECIFIED
);
1529 if (state
->set_password
) {
1530 cli_credentials_set_password(creds
, state
->set_password
, CRED_SPECIFIED
);
1532 cli_credentials_set_password_callback(creds
, get_password
);
1534 if (opt_workstation
) {
1535 cli_credentials_set_workstation(creds
, opt_workstation
, CRED_SPECIFIED
);
1538 gensec_set_credentials(state
->gensec_state
, creds
);
1541 case GSS_SPNEGO_SERVER
:
1542 case SQUID_2_5_NTLMSSP
:
1544 nt_status
= ntlm_auth_start_ntlmssp_server(state
, lp_ctx
,
1545 &state
->gensec_state
);
1546 if (!NT_STATUS_IS_OK(nt_status
)) {
1547 x_fprintf(x_stdout
, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status
));
1548 talloc_free(mem_ctx
);
1554 talloc_free(mem_ctx
);
1558 gensec_want_feature_list(state
->gensec_state
, want_feature_list
);
1560 switch (stdio_helper_mode
) {
1561 case GSS_SPNEGO_CLIENT
:
1562 case GSS_SPNEGO_SERVER
:
1563 nt_status
= gensec_start_mech_by_oid(state
->gensec_state
, GENSEC_OID_SPNEGO
);
1568 case NTLMSSP_CLIENT_1
:
1573 case SQUID_2_5_NTLMSSP
:
1574 nt_status
= gensec_start_mech_by_oid(state
->gensec_state
, GENSEC_OID_NTLMSSP
);
1577 talloc_free(mem_ctx
);
1581 if (!NT_STATUS_IS_OK(nt_status
)) {
1582 DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status
)));
1583 x_fprintf(x_stdout
, "BH GENSEC mech failed to start\n");
1584 talloc_free(mem_ctx
);
1592 if (strncmp(buf
, "PW ", 3) == 0) {
1593 state
->set_password
= talloc_strndup(state
,
1594 (const char *)in
.data
,
1597 cli_credentials_set_password(gensec_get_credentials(state
->gensec_state
),
1598 state
->set_password
,
1600 x_fprintf(x_stdout
, "OK\n");
1601 data_blob_free(&in
);
1602 talloc_free(mem_ctx
);
1606 if (strncmp(buf
, "GK", 2) == 0) {
1608 DEBUG(10, ("Requested session key\n"));
1609 nt_status
= gensec_session_key(state
->gensec_state
, mem_ctx
, &session_key
);
1610 if(!NT_STATUS_IS_OK(nt_status
)) {
1611 DEBUG(1, ("gensec_session_key failed: %s\n", nt_errstr(nt_status
)));
1612 x_fprintf(x_stdout
, "BH No session key\n");
1613 talloc_free(mem_ctx
);
1616 base64_key
= base64_encode_data_blob(state
, session_key
);
1617 x_fprintf(x_stdout
, "GK %s\n", base64_key
);
1618 talloc_free(base64_key
);
1620 talloc_free(mem_ctx
);
1624 if (stdio_helper_mode
== SQUID_2_5_NTLMSSP
&& strncmp(buf
, "GF", 2) == 0) {
1627 neg_flags
= gensec_ntlmssp_neg_flags(state
->gensec_state
);
1629 DEBUG(10, ("Requested negotiated feature flags\n"));
1630 x_fprintf(x_stdout
, "GF 0x%08x\n", neg_flags
);
1634 nt_status
= gensec_update(state
->gensec_state
, mem_ctx
, NULL
, in
, &out
);
1636 /* don't leak 'bad password'/'no such user' info to the network client */
1637 nt_status
= nt_status_squash(nt_status
);
1640 out_base64
= base64_encode_data_blob(mem_ctx
, out
);
1645 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1647 if (first
&& state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1649 } else if (state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1651 } else if (state
->gensec_state
->gensec_role
== GENSEC_SERVER
) {
1658 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCESS_DENIED
)) {
1659 reply_code
= "BH NT_STATUS_ACCESS_DENIED";
1660 reply_arg
= nt_errstr(nt_status
);
1661 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1662 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_UNSUCCESSFUL
)) {
1663 reply_code
= "BH NT_STATUS_UNSUCCESSFUL";
1664 reply_arg
= nt_errstr(nt_status
);
1665 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1666 } else if (!NT_STATUS_IS_OK(nt_status
)) {
1668 reply_arg
= nt_errstr(nt_status
);
1669 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1670 } else if /* OK */ (state
->gensec_state
->gensec_role
== GENSEC_SERVER
) {
1671 struct auth_session_info
*session_info
;
1673 nt_status
= gensec_session_info(state
->gensec_state
, mem_ctx
, &session_info
);
1674 if (!NT_STATUS_IS_OK(nt_status
)) {
1675 reply_code
= "BH Failed to retrive session info";
1676 reply_arg
= nt_errstr(nt_status
);
1677 DEBUG(1, ("GENSEC failed to retrieve the session info: %s\n", nt_errstr(nt_status
)));
1681 reply_arg
= talloc_strdup(state
->gensec_state
, session_info
->unix_info
->unix_name
);
1682 if (reply_arg
== NULL
) {
1683 reply_code
= "BH out of memory";
1684 reply_arg
= nt_errstr(NT_STATUS_NO_MEMORY
);
1686 talloc_free(session_info
);
1688 } else if (state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1690 reply_arg
= out_base64
;
1695 switch (stdio_helper_mode
) {
1696 case GSS_SPNEGO_SERVER
:
1697 x_fprintf(x_stdout
, "%s %s %s\n", reply_code
,
1698 out_base64
? out_base64
: "*",
1699 reply_arg
? reply_arg
: "*");
1703 x_fprintf(x_stdout
, "%s %s\n", reply_code
, out_base64
);
1704 } else if (reply_arg
) {
1705 x_fprintf(x_stdout
, "%s %s\n", reply_code
, reply_arg
);
1707 x_fprintf(x_stdout
, "%s\n", reply_code
);
1711 talloc_free(mem_ctx
);
1715 static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode
,
1716 struct loadparm_context
*lp_ctx
,
1717 struct ntlm_auth_state
*state
,
1718 char *buf
, int length
, void **private2
)
1720 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1724 static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode
,
1725 struct loadparm_context
*lp_ctx
,
1726 struct ntlm_auth_state
*state
,
1727 char *buf
, int length
, void **private2
)
1729 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1733 static struct ntlmssp_state
*client_ntlmssp_state
= NULL
;
1735 static bool manage_client_ntlmssp_init(struct spnego_data spnego
)
1738 DATA_BLOB null_blob
= data_blob_null
;
1739 DATA_BLOB to_server
;
1740 char *to_server_base64
;
1741 const char *my_mechs
[] = {OID_NTLMSSP
, NULL
};
1742 TALLOC_CTX
*ctx
= talloc_tos();
1744 DEBUG(10, ("Got spnego negTokenInit with NTLMSSP\n"));
1746 if (client_ntlmssp_state
!= NULL
) {
1747 DEBUG(1, ("Request for initial SPNEGO request where "
1748 "we already have a state\n"));
1752 if (!client_ntlmssp_state
) {
1753 if (!NT_STATUS_IS_OK(status
= ntlm_auth_start_ntlmssp_client(&client_ntlmssp_state
))) {
1754 x_fprintf(x_stdout
, "BH %s\n", nt_errstr(status
));
1760 if (opt_password
== NULL
) {
1762 /* Request a password from the calling process. After
1763 sending it, the calling process should retry with
1764 the negTokenInit. */
1766 DEBUG(10, ("Requesting password\n"));
1767 x_fprintf(x_stdout
, "PW\n");
1771 spnego
.type
= SPNEGO_NEG_TOKEN_INIT
;
1772 spnego
.negTokenInit
.mechTypes
= my_mechs
;
1773 spnego
.negTokenInit
.reqFlags
= data_blob_null
;
1774 spnego
.negTokenInit
.reqFlagsPadding
= 0;
1775 spnego
.negTokenInit
.mechListMIC
= null_blob
;
1777 status
= ntlmssp_update(client_ntlmssp_state
, null_blob
,
1778 &spnego
.negTokenInit
.mechToken
);
1780 if ( !(NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
) ||
1781 NT_STATUS_IS_OK(status
)) ) {
1782 DEBUG(1, ("Expected OK or MORE_PROCESSING_REQUIRED, got: %s\n",
1783 nt_errstr(status
)));
1784 TALLOC_FREE(client_ntlmssp_state
);
1788 spnego_write_data(ctx
, &to_server
, &spnego
);
1789 data_blob_free(&spnego
.negTokenInit
.mechToken
);
1791 to_server_base64
= base64_encode_data_blob(talloc_tos(), to_server
);
1792 data_blob_free(&to_server
);
1793 x_fprintf(x_stdout
, "KK %s\n", to_server_base64
);
1794 TALLOC_FREE(to_server_base64
);
1798 static void manage_client_ntlmssp_targ(struct spnego_data spnego
)
1801 DATA_BLOB null_blob
= data_blob_null
;
1803 DATA_BLOB to_server
;
1804 char *to_server_base64
;
1805 TALLOC_CTX
*ctx
= talloc_tos();
1807 DEBUG(10, ("Got spnego negTokenTarg with NTLMSSP\n"));
1809 if (client_ntlmssp_state
== NULL
) {
1810 DEBUG(1, ("Got NTLMSSP tArg without a client state\n"));
1811 x_fprintf(x_stdout
, "BH Got NTLMSSP tArg without a client state\n");
1815 if (spnego
.negTokenTarg
.negResult
== SPNEGO_REJECT
) {
1816 x_fprintf(x_stdout
, "NA\n");
1817 TALLOC_FREE(client_ntlmssp_state
);
1821 if (spnego
.negTokenTarg
.negResult
== SPNEGO_ACCEPT_COMPLETED
) {
1822 x_fprintf(x_stdout
, "AF\n");
1823 TALLOC_FREE(client_ntlmssp_state
);
1827 status
= ntlmssp_update(client_ntlmssp_state
,
1828 spnego
.negTokenTarg
.responseToken
,
1831 if (!NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
) && !NT_STATUS_IS_OK(status
)) {
1832 DEBUG(1, ("Expected MORE_PROCESSING_REQUIRED or OK from "
1833 "ntlmssp_client_update, got: %s\n",
1834 nt_errstr(status
)));
1835 x_fprintf(x_stdout
, "BH Expected MORE_PROCESSING_REQUIRED from "
1836 "ntlmssp_client_update\n");
1837 data_blob_free(&request
);
1838 TALLOC_FREE(client_ntlmssp_state
);
1842 spnego
.type
= SPNEGO_NEG_TOKEN_TARG
;
1843 spnego
.negTokenTarg
.negResult
= SPNEGO_ACCEPT_INCOMPLETE
;
1844 spnego
.negTokenTarg
.supportedMech
= (const char *)OID_NTLMSSP
;
1845 spnego
.negTokenTarg
.responseToken
= request
;
1846 spnego
.negTokenTarg
.mechListMIC
= null_blob
;
1848 spnego_write_data(ctx
, &to_server
, &spnego
);
1849 data_blob_free(&request
);
1851 to_server_base64
= base64_encode_data_blob(talloc_tos(), to_server
);
1852 data_blob_free(&to_server
);
1853 x_fprintf(x_stdout
, "KK %s\n", to_server_base64
);
1854 TALLOC_FREE(to_server_base64
);
1860 static bool manage_client_krb5_init(struct spnego_data spnego
)
1863 DATA_BLOB tkt
, tkt_wrapped
, to_server
;
1864 DATA_BLOB session_key_krb5
= data_blob_null
;
1865 struct spnego_data reply
;
1869 const char *my_mechs
[] = {OID_KERBEROS5_OLD
, NULL
};
1871 TALLOC_CTX
*ctx
= talloc_tos();
1873 principal
= spnego
.negTokenInit
.targetPrincipal
;
1875 /* We may not be allowed to use the server-supplied SPNEGO principal, or it may not have been supplied to us
1877 if (!lp_client_use_spnego_principal() || strequal(principal
, ADS_IGNORE_PRINCIPAL
)) {
1881 if (principal
== NULL
&&
1882 opt_target_service
&& opt_target_hostname
&& !is_ipaddress(opt_target_hostname
)) {
1883 DEBUG(3,("manage_client_krb5_init: using target "
1884 "hostname not SPNEGO principal\n"));
1886 principal
= kerberos_get_principal_from_service_hostname(talloc_tos(),
1888 opt_target_hostname
,
1895 DEBUG(3,("manage_client_krb5_init: guessed "
1896 "server principal=%s\n",
1897 principal
? principal
: "<null>"));
1900 if (principal
== NULL
) {
1901 DEBUG(3,("manage_client_krb5_init: could not guess server principal\n"));
1905 retval
= cli_krb5_get_ticket(ctx
, principal
, 0,
1906 &tkt
, &session_key_krb5
,
1907 0, NULL
, NULL
, NULL
);
1911 /* Let's try to first get the TGT, for that we need a
1914 if (opt_password
== NULL
) {
1915 DEBUG(10, ("Requesting password\n"));
1916 x_fprintf(x_stdout
, "PW\n");
1920 user
= talloc_asprintf(talloc_tos(), "%s@%s", opt_username
, opt_domain
);
1925 if ((retval
= kerberos_kinit_password(user
, opt_password
, 0, NULL
))) {
1926 DEBUG(10, ("Requesting TGT failed: %s\n", error_message(retval
)));
1930 retval
= cli_krb5_get_ticket(ctx
, principal
, 0,
1931 &tkt
, &session_key_krb5
,
1932 0, NULL
, NULL
, NULL
);
1934 DEBUG(10, ("Kinit suceeded, but getting a ticket failed: %s\n", error_message(retval
)));
1940 /* wrap that up in a nice GSS-API wrapping */
1941 tkt_wrapped
= spnego_gen_krb5_wrap(ctx
, tkt
, TOK_ID_KRB_AP_REQ
);
1943 data_blob_free(&session_key_krb5
);
1947 reply
.type
= SPNEGO_NEG_TOKEN_INIT
;
1948 reply
.negTokenInit
.mechTypes
= my_mechs
;
1949 reply
.negTokenInit
.reqFlags
= data_blob_null
;
1950 reply
.negTokenInit
.reqFlagsPadding
= 0;
1951 reply
.negTokenInit
.mechToken
= tkt_wrapped
;
1952 reply
.negTokenInit
.mechListMIC
= data_blob_null
;
1954 len
= spnego_write_data(ctx
, &to_server
, &reply
);
1955 data_blob_free(&tkt
);
1958 DEBUG(1, ("Could not write SPNEGO data blob\n"));
1962 reply_base64
= base64_encode_data_blob(talloc_tos(), to_server
);
1963 x_fprintf(x_stdout
, "KK %s *\n", reply_base64
);
1965 TALLOC_FREE(reply_base64
);
1966 data_blob_free(&to_server
);
1967 DEBUG(10, ("sent GSS-SPNEGO KERBEROS5 negTokenInit\n"));
1971 static void manage_client_krb5_targ(struct spnego_data spnego
)
1973 switch (spnego
.negTokenTarg
.negResult
) {
1974 case SPNEGO_ACCEPT_INCOMPLETE
:
1975 DEBUG(1, ("Got a Kerberos negTokenTarg with ACCEPT_INCOMPLETE\n"));
1976 x_fprintf(x_stdout
, "BH Got a Kerberos negTokenTarg with "
1977 "ACCEPT_INCOMPLETE\n");
1979 case SPNEGO_ACCEPT_COMPLETED
:
1980 DEBUG(10, ("Accept completed\n"));
1981 x_fprintf(x_stdout
, "AF\n");
1984 DEBUG(10, ("Rejected\n"));
1985 x_fprintf(x_stdout
, "NA\n");
1988 DEBUG(1, ("Got an invalid negTokenTarg\n"));
1989 x_fprintf(x_stdout
, "AF\n");
1995 static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode
,
1996 struct loadparm_context
*lp_ctx
,
1997 struct ntlm_auth_state
*state
,
1998 char *buf
, int length
, void **private2
)
2001 struct spnego_data spnego
;
2003 TALLOC_CTX
*ctx
= talloc_tos();
2005 if (!opt_username
|| !*opt_username
) {
2006 x_fprintf(x_stderr
, "username must be specified!\n\n");
2010 if (strlen(buf
) <= 3) {
2011 DEBUG(1, ("SPNEGO query [%s] too short\n", buf
));
2012 x_fprintf(x_stdout
, "BH SPNEGO query too short\n");
2016 request
= base64_decode_data_blob(buf
+3);
2018 if (strncmp(buf
, "PW ", 3) == 0) {
2020 /* We asked for a password and obviously got it :-) */
2022 opt_password
= SMB_STRNDUP((const char *)request
.data
, request
.length
);
2024 if (opt_password
== NULL
) {
2025 DEBUG(1, ("Out of memory\n"));
2026 x_fprintf(x_stdout
, "BH Out of memory\n");
2027 data_blob_free(&request
);
2031 x_fprintf(x_stdout
, "OK\n");
2032 data_blob_free(&request
);
2036 if ( (strncmp(buf
, "TT ", 3) != 0) &&
2037 (strncmp(buf
, "AF ", 3) != 0) &&
2038 (strncmp(buf
, "NA ", 3) != 0) ) {
2039 DEBUG(1, ("SPNEGO request [%s] invalid\n", buf
));
2040 x_fprintf(x_stdout
, "BH SPNEGO request invalid\n");
2041 data_blob_free(&request
);
2045 /* So we got a server challenge to generate a SPNEGO
2046 client-to-server request... */
2048 len
= spnego_read_data(ctx
, request
, &spnego
);
2049 data_blob_free(&request
);
2052 DEBUG(1, ("Could not read SPNEGO data for [%s]\n", buf
));
2053 x_fprintf(x_stdout
, "BH Could not read SPNEGO data\n");
2057 if (spnego
.type
== SPNEGO_NEG_TOKEN_INIT
) {
2059 /* The server offers a list of mechanisms */
2061 const char *const *mechType
= spnego
.negTokenInit
.mechTypes
;
2063 while (*mechType
!= NULL
) {
2066 if ( (strcmp(*mechType
, OID_KERBEROS5_OLD
) == 0) ||
2067 (strcmp(*mechType
, OID_KERBEROS5
) == 0) ) {
2068 if (manage_client_krb5_init(spnego
))
2073 if (strcmp(*mechType
, OID_NTLMSSP
) == 0) {
2074 if (manage_client_ntlmssp_init(spnego
))
2081 DEBUG(1, ("Server offered no compatible mechanism\n"));
2082 x_fprintf(x_stdout
, "BH Server offered no compatible mechanism\n");
2086 if (spnego
.type
== SPNEGO_NEG_TOKEN_TARG
) {
2088 if (spnego
.negTokenTarg
.supportedMech
== NULL
) {
2089 /* On accept/reject Windows does not send the
2090 mechanism anymore. Handle that here and
2091 shut down the mechanisms. */
2093 switch (spnego
.negTokenTarg
.negResult
) {
2094 case SPNEGO_ACCEPT_COMPLETED
:
2095 x_fprintf(x_stdout
, "AF\n");
2098 x_fprintf(x_stdout
, "NA\n");
2101 DEBUG(1, ("Got a negTokenTarg with no mech and an "
2102 "unknown negResult: %d\n",
2103 spnego
.negTokenTarg
.negResult
));
2104 x_fprintf(x_stdout
, "BH Got a negTokenTarg with"
2105 " no mech and an unknown "
2109 TALLOC_FREE(client_ntlmssp_state
);
2113 if (strcmp(spnego
.negTokenTarg
.supportedMech
,
2114 OID_NTLMSSP
) == 0) {
2115 manage_client_ntlmssp_targ(spnego
);
2120 if (strcmp(spnego
.negTokenTarg
.supportedMech
,
2121 OID_KERBEROS5_OLD
) == 0) {
2122 manage_client_krb5_targ(spnego
);
2129 DEBUG(1, ("Got an SPNEGO token I could not handle [%s]!\n", buf
));
2130 x_fprintf(x_stdout
, "BH Got an SPNEGO token I could not handle\n");
2134 spnego_free_data(&spnego
);
2138 static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode
,
2139 struct loadparm_context
*lp_ctx
,
2140 struct ntlm_auth_state
*state
,
2141 char *buf
, int length
, void **private2
)
2143 char *request
, *parameter
;
2144 static DATA_BLOB challenge
;
2145 static DATA_BLOB lm_response
;
2146 static DATA_BLOB nt_response
;
2147 static char *full_username
;
2148 static char *username
;
2149 static char *domain
;
2150 static char *plaintext_password
;
2151 static bool ntlm_server_1_user_session_key
;
2152 static bool ntlm_server_1_lm_session_key
;
2154 if (strequal(buf
, ".")) {
2155 if (!full_username
&& !username
) {
2156 x_fprintf(x_stdout
, "Error: No username supplied!\n");
2157 } else if (plaintext_password
) {
2158 /* handle this request as plaintext */
2159 if (!full_username
) {
2160 if (asprintf(&full_username
, "%s%c%s", domain
, winbind_separator(), username
) == -1) {
2161 x_fprintf(x_stdout
, "Error: Out of memory in asprintf!\n.\n");
2165 if (check_plaintext_auth(full_username
, plaintext_password
, False
)) {
2166 x_fprintf(x_stdout
, "Authenticated: Yes\n");
2168 x_fprintf(x_stdout
, "Authenticated: No\n");
2170 } else if (!lm_response
.data
&& !nt_response
.data
) {
2171 x_fprintf(x_stdout
, "Error: No password supplied!\n");
2172 } else if (!challenge
.data
) {
2173 x_fprintf(x_stdout
, "Error: No lanman-challenge supplied!\n");
2175 char *error_string
= NULL
;
2177 uchar user_session_key
[16];
2180 if (full_username
&& !username
) {
2182 fstring fstr_domain
;
2184 if (!parse_ntlm_auth_domain_user(full_username
, fstr_user
, fstr_domain
)) {
2185 /* username might be 'tainted', don't print into our new-line deleimianted stream */
2186 x_fprintf(x_stdout
, "Error: Could not parse into domain and username\n");
2188 SAFE_FREE(username
);
2190 username
= smb_xstrdup(fstr_user
);
2191 domain
= smb_xstrdup(fstr_domain
);
2195 domain
= smb_xstrdup(get_winbind_domain());
2198 if (ntlm_server_1_lm_session_key
)
2199 flags
|= WBFLAG_PAM_LMKEY
;
2201 if (ntlm_server_1_user_session_key
)
2202 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
2204 if (!NT_STATUS_IS_OK(
2205 contact_winbind_auth_crap(username
,
2217 x_fprintf(x_stdout
, "Authenticated: No\n");
2218 x_fprintf(x_stdout
, "Authentication-Error: %s\n.\n", error_string
);
2220 static char zeros
[16];
2222 char *hex_user_session_key
;
2224 x_fprintf(x_stdout
, "Authenticated: Yes\n");
2226 if (ntlm_server_1_lm_session_key
2227 && (memcmp(zeros
, lm_key
,
2228 sizeof(lm_key
)) != 0)) {
2229 hex_lm_key
= hex_encode_talloc(NULL
,
2230 (const unsigned char *)lm_key
,
2232 x_fprintf(x_stdout
, "LANMAN-Session-Key: %s\n", hex_lm_key
);
2233 TALLOC_FREE(hex_lm_key
);
2236 if (ntlm_server_1_user_session_key
2237 && (memcmp(zeros
, user_session_key
,
2238 sizeof(user_session_key
)) != 0)) {
2239 hex_user_session_key
= hex_encode_talloc(NULL
,
2240 (const unsigned char *)user_session_key
,
2241 sizeof(user_session_key
));
2242 x_fprintf(x_stdout
, "User-Session-Key: %s\n", hex_user_session_key
);
2243 TALLOC_FREE(hex_user_session_key
);
2246 SAFE_FREE(error_string
);
2248 /* clear out the state */
2249 challenge
= data_blob_null
;
2250 nt_response
= data_blob_null
;
2251 lm_response
= data_blob_null
;
2252 SAFE_FREE(full_username
);
2253 SAFE_FREE(username
);
2255 SAFE_FREE(plaintext_password
);
2256 ntlm_server_1_user_session_key
= False
;
2257 ntlm_server_1_lm_session_key
= False
;
2258 x_fprintf(x_stdout
, ".\n");
2265 /* Indicates a base64 encoded structure */
2266 parameter
= strstr_m(request
, ":: ");
2268 parameter
= strstr_m(request
, ": ");
2271 DEBUG(0, ("Parameter not found!\n"));
2272 x_fprintf(x_stdout
, "Error: Parameter not found!\n.\n");
2289 base64_decode_inplace(parameter
);
2292 if (strequal(request
, "LANMAN-Challenge")) {
2293 challenge
= strhex_to_data_blob(NULL
, parameter
);
2294 if (challenge
.length
!= 8) {
2295 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (got %d bytes, expected 8)\n.\n",
2297 (int)challenge
.length
);
2298 challenge
= data_blob_null
;
2300 } else if (strequal(request
, "NT-Response")) {
2301 nt_response
= strhex_to_data_blob(NULL
, parameter
);
2302 if (nt_response
.length
< 24) {
2303 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (only got %d bytes, needed at least 24)\n.\n",
2305 (int)nt_response
.length
);
2306 nt_response
= data_blob_null
;
2308 } else if (strequal(request
, "LANMAN-Response")) {
2309 lm_response
= strhex_to_data_blob(NULL
, parameter
);
2310 if (lm_response
.length
!= 24) {
2311 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (got %d bytes, expected 24)\n.\n",
2313 (int)lm_response
.length
);
2314 lm_response
= data_blob_null
;
2316 } else if (strequal(request
, "Password")) {
2317 plaintext_password
= smb_xstrdup(parameter
);
2318 } else if (strequal(request
, "NT-Domain")) {
2319 domain
= smb_xstrdup(parameter
);
2320 } else if (strequal(request
, "Username")) {
2321 username
= smb_xstrdup(parameter
);
2322 } else if (strequal(request
, "Full-Username")) {
2323 full_username
= smb_xstrdup(parameter
);
2324 } else if (strequal(request
, "Request-User-Session-Key")) {
2325 ntlm_server_1_user_session_key
= strequal(parameter
, "Yes");
2326 } else if (strequal(request
, "Request-LanMan-Session-Key")) {
2327 ntlm_server_1_lm_session_key
= strequal(parameter
, "Yes");
2329 x_fprintf(x_stdout
, "Error: Unknown request %s\n.\n", request
);
2333 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode
,
2334 struct loadparm_context
*lp_ctx
,
2335 struct ntlm_auth_state
*state
,
2336 char *buf
, int length
, void **private2
)
2338 char *request
, *parameter
;
2339 static DATA_BLOB new_nt_pswd
;
2340 static DATA_BLOB old_nt_hash_enc
;
2341 static DATA_BLOB new_lm_pswd
;
2342 static DATA_BLOB old_lm_hash_enc
;
2343 static char *full_username
= NULL
;
2344 static char *username
= NULL
;
2345 static char *domain
= NULL
;
2346 static char *newpswd
= NULL
;
2347 static char *oldpswd
= NULL
;
2349 if (strequal(buf
, ".")) {
2350 if(newpswd
&& oldpswd
) {
2351 uchar old_nt_hash
[16];
2352 uchar old_lm_hash
[16];
2353 uchar new_nt_hash
[16];
2354 uchar new_lm_hash
[16];
2356 new_nt_pswd
= data_blob(NULL
, 516);
2357 old_nt_hash_enc
= data_blob(NULL
, 16);
2359 /* Calculate the MD4 hash (NT compatible) of the
2361 E_md4hash(oldpswd
, old_nt_hash
);
2362 E_md4hash(newpswd
, new_nt_hash
);
2364 /* E_deshash returns false for 'long'
2365 passwords (> 14 DOS chars).
2367 Therefore, don't send a buffer
2368 encrypted with the truncated hash
2369 (it could allow an even easier
2370 attack on the password)
2372 Likewise, obey the admin's restriction
2375 if (lp_client_lanman_auth() &&
2376 E_deshash(newpswd
, new_lm_hash
) &&
2377 E_deshash(oldpswd
, old_lm_hash
)) {
2378 new_lm_pswd
= data_blob(NULL
, 516);
2379 old_lm_hash_enc
= data_blob(NULL
, 16);
2380 encode_pw_buffer(new_lm_pswd
.data
, newpswd
,
2383 arcfour_crypt(new_lm_pswd
.data
, old_nt_hash
, 516);
2384 E_old_pw_hash(new_nt_hash
, old_lm_hash
,
2385 old_lm_hash_enc
.data
);
2387 new_lm_pswd
.data
= NULL
;
2388 new_lm_pswd
.length
= 0;
2389 old_lm_hash_enc
.data
= NULL
;
2390 old_lm_hash_enc
.length
= 0;
2393 encode_pw_buffer(new_nt_pswd
.data
, newpswd
,
2396 arcfour_crypt(new_nt_pswd
.data
, old_nt_hash
, 516);
2397 E_old_pw_hash(new_nt_hash
, old_nt_hash
,
2398 old_nt_hash_enc
.data
);
2401 if (!full_username
&& !username
) {
2402 x_fprintf(x_stdout
, "Error: No username supplied!\n");
2403 } else if ((!new_nt_pswd
.data
|| !old_nt_hash_enc
.data
) &&
2404 (!new_lm_pswd
.data
|| old_lm_hash_enc
.data
) ) {
2405 x_fprintf(x_stdout
, "Error: No NT or LM password "
2406 "blobs supplied!\n");
2408 char *error_string
= NULL
;
2410 if (full_username
&& !username
) {
2412 fstring fstr_domain
;
2414 if (!parse_ntlm_auth_domain_user(full_username
,
2417 /* username might be 'tainted', don't
2418 * print into our new-line
2419 * deleimianted stream */
2420 x_fprintf(x_stdout
, "Error: Could not "
2421 "parse into domain and "
2423 SAFE_FREE(username
);
2424 username
= smb_xstrdup(full_username
);
2426 SAFE_FREE(username
);
2428 username
= smb_xstrdup(fstr_user
);
2429 domain
= smb_xstrdup(fstr_domain
);
2434 if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
2441 x_fprintf(x_stdout
, "Password-Change: No\n");
2442 x_fprintf(x_stdout
, "Password-Change-Error: "
2443 "%s\n.\n", error_string
);
2445 x_fprintf(x_stdout
, "Password-Change: Yes\n");
2448 SAFE_FREE(error_string
);
2450 /* clear out the state */
2451 new_nt_pswd
= data_blob_null
;
2452 old_nt_hash_enc
= data_blob_null
;
2453 new_lm_pswd
= data_blob_null
;
2454 old_nt_hash_enc
= data_blob_null
;
2455 SAFE_FREE(full_username
);
2456 SAFE_FREE(username
);
2460 x_fprintf(x_stdout
, ".\n");
2467 /* Indicates a base64 encoded structure */
2468 parameter
= strstr_m(request
, ":: ");
2470 parameter
= strstr_m(request
, ": ");
2473 DEBUG(0, ("Parameter not found!\n"));
2474 x_fprintf(x_stdout
, "Error: Parameter not found!\n.\n");
2490 base64_decode_inplace(parameter
);
2493 if (strequal(request
, "new-nt-password-blob")) {
2494 new_nt_pswd
= strhex_to_data_blob(NULL
, parameter
);
2495 if (new_nt_pswd
.length
!= 516) {
2496 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2497 "(got %d bytes, expected 516)\n.\n",
2499 (int)new_nt_pswd
.length
);
2500 new_nt_pswd
= data_blob_null
;
2502 } else if (strequal(request
, "old-nt-hash-blob")) {
2503 old_nt_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2504 if (old_nt_hash_enc
.length
!= 16) {
2505 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2506 "(got %d bytes, expected 16)\n.\n",
2508 (int)old_nt_hash_enc
.length
);
2509 old_nt_hash_enc
= data_blob_null
;
2511 } else if (strequal(request
, "new-lm-password-blob")) {
2512 new_lm_pswd
= strhex_to_data_blob(NULL
, parameter
);
2513 if (new_lm_pswd
.length
!= 516) {
2514 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2515 "(got %d bytes, expected 516)\n.\n",
2517 (int)new_lm_pswd
.length
);
2518 new_lm_pswd
= data_blob_null
;
2521 else if (strequal(request
, "old-lm-hash-blob")) {
2522 old_lm_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2523 if (old_lm_hash_enc
.length
!= 16)
2525 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2526 "(got %d bytes, expected 16)\n.\n",
2528 (int)old_lm_hash_enc
.length
);
2529 old_lm_hash_enc
= data_blob_null
;
2531 } else if (strequal(request
, "nt-domain")) {
2532 domain
= smb_xstrdup(parameter
);
2533 } else if(strequal(request
, "username")) {
2534 username
= smb_xstrdup(parameter
);
2535 } else if(strequal(request
, "full-username")) {
2536 username
= smb_xstrdup(parameter
);
2537 } else if(strequal(request
, "new-password")) {
2538 newpswd
= smb_xstrdup(parameter
);
2539 } else if (strequal(request
, "old-password")) {
2540 oldpswd
= smb_xstrdup(parameter
);
2542 x_fprintf(x_stdout
, "Error: Unknown request %s\n.\n", request
);
2546 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode
,
2547 struct loadparm_context
*lp_ctx
,
2548 struct ntlm_auth_state
*state
,
2549 stdio_helper_function fn
, void **private2
)
2552 char tmp
[INITIAL_BUFFER_SIZE
+1];
2553 int length
, buf_size
= 0;
2556 buf
= talloc_strdup(state
->mem_ctx
, "");
2558 DEBUG(0, ("Failed to allocate input buffer.\n"));
2559 x_fprintf(x_stderr
, "ERR\n");
2565 /* this is not a typo - x_fgets doesn't work too well under
2567 if (fgets(tmp
, sizeof(tmp
)-1, stdin
) == NULL
) {
2568 if (ferror(stdin
)) {
2569 DEBUG(1, ("fgets() failed! dying..... errno=%d "
2570 "(%s)\n", ferror(stdin
),
2571 strerror(ferror(stdin
))));
2578 buf
= talloc_strdup_append_buffer(buf
, tmp
);
2579 buf_size
+= INITIAL_BUFFER_SIZE
;
2581 if (buf_size
> MAX_BUFFER_SIZE
) {
2582 DEBUG(2, ("Oversized message\n"));
2583 x_fprintf(x_stderr
, "ERR\n");
2588 c
= strchr(buf
, '\n');
2589 } while (c
== NULL
);
2594 DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf
,length
));
2596 if (buf
[0] == '\0') {
2597 DEBUG(2, ("Invalid Request\n"));
2598 x_fprintf(x_stderr
, "ERR\n");
2603 fn(stdio_helper_mode
, lp_ctx
, state
, buf
, length
, private2
);
2608 static void squid_stream(enum stdio_helper_mode stdio_mode
,
2609 struct loadparm_context
*lp_ctx
,
2610 stdio_helper_function fn
) {
2611 TALLOC_CTX
*mem_ctx
;
2612 struct ntlm_auth_state
*state
;
2614 /* initialize FDescs */
2615 x_setbuf(x_stdout
, NULL
);
2616 x_setbuf(x_stderr
, NULL
);
2618 mem_ctx
= talloc_init("ntlm_auth");
2620 DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
2621 x_fprintf(x_stderr
, "ERR\n");
2625 state
= talloc_zero(mem_ctx
, struct ntlm_auth_state
);
2627 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
2628 x_fprintf(x_stderr
, "ERR\n");
2632 state
->mem_ctx
= mem_ctx
;
2633 state
->helper_mode
= stdio_mode
;
2636 TALLOC_CTX
*frame
= talloc_stackframe();
2637 manage_squid_request(stdio_mode
, lp_ctx
, state
, fn
, NULL
);
2643 /* Authenticate a user with a challenge/response */
2645 static bool check_auth_crap(void)
2650 char user_session_key
[16];
2652 char *hex_user_session_key
;
2654 static uint8 zeros
[16];
2656 x_setbuf(x_stdout
, NULL
);
2659 flags
|= WBFLAG_PAM_LMKEY
;
2661 if (request_user_session_key
)
2662 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
2664 flags
|= WBFLAG_PAM_NT_STATUS_SQUASH
;
2666 nt_status
= contact_winbind_auth_crap(opt_username
, opt_domain
,
2672 (unsigned char *)lm_key
,
2673 (unsigned char *)user_session_key
,
2674 &error_string
, NULL
);
2676 if (!NT_STATUS_IS_OK(nt_status
)) {
2677 x_fprintf(x_stdout
, "%s (0x%x)\n",
2679 NT_STATUS_V(nt_status
));
2680 SAFE_FREE(error_string
);
2685 && (memcmp(zeros
, lm_key
,
2686 sizeof(lm_key
)) != 0)) {
2687 hex_lm_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)lm_key
,
2689 x_fprintf(x_stdout
, "LM_KEY: %s\n", hex_lm_key
);
2690 TALLOC_FREE(hex_lm_key
);
2692 if (request_user_session_key
2693 && (memcmp(zeros
, user_session_key
,
2694 sizeof(user_session_key
)) != 0)) {
2695 hex_user_session_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)user_session_key
,
2696 sizeof(user_session_key
));
2697 x_fprintf(x_stdout
, "NT_KEY: %s\n", hex_user_session_key
);
2698 TALLOC_FREE(hex_user_session_key
);
2707 OPT_USERNAME
= 1000,
2716 OPT_USER_SESSION_KEY
,
2718 OPT_REQUIRE_MEMBERSHIP
,
2719 OPT_USE_CACHED_CREDS
,
2720 OPT_PAM_WINBIND_CONF
,
2725 int main(int argc
, const char **argv
)
2727 TALLOC_CTX
*frame
= talloc_stackframe();
2729 static const char *helper_protocol
;
2730 static int diagnostics
;
2732 static const char *hex_challenge
;
2733 static const char *hex_lm_response
;
2734 static const char *hex_nt_response
;
2735 struct loadparm_context
*lp_ctx
;
2738 /* NOTE: DO NOT change this interface without considering the implications!
2739 This is an external interface, which other programs will use to interact
2743 /* We do not use single-letter command abbreviations, because they harm future
2744 interface stability. */
2746 struct poptOption long_options
[] = {
2748 { "helper-protocol", 0, POPT_ARG_STRING
, &helper_protocol
, OPT_DOMAIN
, "operate as a stdio-based helper", "helper protocol to use"},
2749 { "username", 0, POPT_ARG_STRING
, &opt_username
, OPT_USERNAME
, "username"},
2750 { "domain", 0, POPT_ARG_STRING
, &opt_domain
, OPT_DOMAIN
, "domain name"},
2751 { "workstation", 0, POPT_ARG_STRING
, &opt_workstation
, OPT_WORKSTATION
, "workstation"},
2752 { "challenge", 0, POPT_ARG_STRING
, &hex_challenge
, OPT_CHALLENGE
, "challenge (HEX encoded)"},
2753 { "lm-response", 0, POPT_ARG_STRING
, &hex_lm_response
, OPT_LM
, "LM Response to the challenge (HEX encoded)"},
2754 { "nt-response", 0, POPT_ARG_STRING
, &hex_nt_response
, OPT_NT
, "NT or NTLMv2 Response to the challenge (HEX encoded)"},
2755 { "password", 0, POPT_ARG_STRING
, &opt_password
, OPT_PASSWORD
, "User's plaintext password"},
2756 { "request-lm-key", 0, POPT_ARG_NONE
, &request_lm_key
, OPT_LM_KEY
, "Retrieve LM session key"},
2757 { "request-nt-key", 0, POPT_ARG_NONE
, &request_user_session_key
, OPT_USER_SESSION_KEY
, "Retrieve User (NT) session key"},
2758 { "use-cached-creds", 0, POPT_ARG_NONE
, &use_cached_creds
, OPT_USE_CACHED_CREDS
, "Use cached credentials if no password is given"},
2759 { "diagnostics", 0, POPT_ARG_NONE
, &diagnostics
,
2761 "Perform diagnostics on the authentication chain"},
2762 { "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" },
2763 { "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" },
2764 { "target-service", 0, POPT_ARG_STRING
, &opt_target_service
, OPT_TARGET_SERVICE
, "Target service (eg http)" },
2765 { "target-hostname", 0, POPT_ARG_STRING
, &opt_target_hostname
, OPT_TARGET_HOSTNAME
, "Target hostname" },
2766 POPT_COMMON_CONFIGFILE
2771 /* Samba client initialisation */
2774 setup_logging("ntlm_auth", DEBUG_STDERR
);
2778 pc
= poptGetContext("ntlm_auth", argc
, argv
, long_options
, 0);
2780 /* Parse command line options */
2783 poptPrintHelp(pc
, stderr
, 0);
2787 while((opt
= poptGetNextOpt(pc
)) != -1) {
2788 /* Get generic config options like --configfile */
2791 poptFreeContext(pc
);
2793 if (!lp_load_global(get_dyn_CONFIGFILE())) {
2794 d_fprintf(stderr
, "ntlm_auth: error opening config file %s. Error was %s\n",
2795 get_dyn_CONFIGFILE(), strerror(errno
));
2799 pc
= poptGetContext(NULL
, argc
, (const char **)argv
, long_options
,
2800 POPT_CONTEXT_KEEP_FIRST
);
2802 while((opt
= poptGetNextOpt(pc
)) != -1) {
2805 opt_challenge
= strhex_to_data_blob(NULL
, hex_challenge
);
2806 if (opt_challenge
.length
!= 8) {
2807 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2809 (int)opt_challenge
.length
);
2814 opt_lm_response
= strhex_to_data_blob(NULL
, hex_lm_response
);
2815 if (opt_lm_response
.length
!= 24) {
2816 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2818 (int)opt_lm_response
.length
);
2824 opt_nt_response
= strhex_to_data_blob(NULL
, hex_nt_response
);
2825 if (opt_nt_response
.length
< 24) {
2826 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2828 (int)opt_nt_response
.length
);
2833 case OPT_REQUIRE_MEMBERSHIP
:
2834 if (strncasecmp_m("S-", require_membership_of
, 2) == 0) {
2835 require_membership_of_sid
= require_membership_of
;
2842 char *domain
= SMB_STRDUP(opt_username
);
2843 char *p
= strchr_m(domain
, *lp_winbind_separator());
2847 if (opt_domain
&& !strequal(opt_domain
, domain
)) {
2848 x_fprintf(x_stderr
, "Domain specified in username (%s) "
2849 "doesn't match specified domain (%s)!\n\n",
2850 domain
, opt_domain
);
2851 poptPrintHelp(pc
, stderr
, 0);
2854 opt_domain
= domain
;
2860 /* Note: if opt_domain is "" then send no domain */
2861 if (opt_domain
== NULL
) {
2862 opt_domain
= get_winbind_domain();
2865 if (opt_workstation
== NULL
) {
2866 opt_workstation
= "";
2869 lp_ctx
= loadparm_init_s3(NULL
, loadparm_s3_helpers());
2870 if (lp_ctx
== NULL
) {
2871 x_fprintf(x_stderr
, "loadparm_init_s3() failed!\n");
2875 if (helper_protocol
) {
2877 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2878 if (strcmp(helper_protocol
, stdio_helper_protocols
[i
].name
) == 0) {
2879 squid_stream(stdio_helper_protocols
[i
].mode
, lp_ctx
, stdio_helper_protocols
[i
].fn
);
2883 x_fprintf(x_stderr
, "unknown helper protocol [%s]\n\nValid helper protools:\n\n", helper_protocol
);
2885 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2886 x_fprintf(x_stderr
, "%s\n", stdio_helper_protocols
[i
].name
);
2892 if (!opt_username
|| !*opt_username
) {
2893 x_fprintf(x_stderr
, "username must be specified!\n\n");
2894 poptPrintHelp(pc
, stderr
, 0);
2898 if (opt_challenge
.length
) {
2899 if (!check_auth_crap()) {
2905 if (!opt_password
) {
2906 char pwd
[256] = {0};
2909 rc
= samba_getpass("Password: ", pwd
, sizeof(pwd
), false, false);
2911 opt_password
= SMB_STRDUP(pwd
);
2916 if (!diagnose_ntlm_auth()) {
2922 fstr_sprintf(user
, "%s%c%s", opt_domain
, winbind_separator(), opt_username
);
2923 if (!check_plaintext_auth(user
, opt_password
, True
)) {
2930 poptFreeContext(pc
);