2 Unix SMB/CIFS implementation.
4 Winbind status program.
6 Copyright (C) Tim Potter 2000-2003
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003-2004
8 Copyright (C) Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it> 2000
9 Copyright (C) Robert O'Callahan 2006 (added cached credential code).
10 Copyright (C) Kai Blin <kai@samba.org> 2008
11 Copyright (C) Simo Sorce 2010
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 3 of the License, or
16 (at your option) any later version.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 #include "lib/param/param.h"
29 #include "popt_common.h"
30 #include "utils/ntlm_auth.h"
31 #include "../libcli/auth/libcli_auth.h"
32 #include "../libcli/auth/spnego.h"
33 #include "auth/ntlmssp/ntlmssp.h"
34 #include "auth/gensec/gensec.h"
35 #include "auth/credentials/credentials.h"
36 #include "librpc/crypto/gse.h"
38 #include <iniparser.h>
39 #include "../lib/crypto/arcfour.h"
40 #include "libads/kerberos_proto.h"
41 #include "nsswitch/winbind_client.h"
42 #include "librpc/gen_ndr/krb5pac.h"
43 #include "../lib/util/asn1.h"
44 #include "auth/common_auth.h"
45 #include "source3/include/auth.h"
46 #include "source3/auth/proto.h"
47 #include "nsswitch/libwbclient/wbclient.h"
49 #ifndef PAM_WINBIND_CONFIG_FILE
50 #define PAM_WINBIND_CONFIG_FILE "/etc/security/pam_winbind.conf"
53 #define WINBIND_KRB5_AUTH 0x00000080
56 #define DBGC_CLASS DBGC_WINBIND
58 #define INITIAL_BUFFER_SIZE 300
59 #define MAX_BUFFER_SIZE 630000
61 enum stdio_helper_mode
{
69 NTLM_CHANGE_PASSWORD_1
,
73 enum ntlm_auth_cli_state
{
80 struct ntlm_auth_state
{
82 enum stdio_helper_mode helper_mode
;
83 enum ntlm_auth_cli_state cli_state
;
84 struct ntlmssp_state
*ntlmssp_state
;
86 char *want_feature_list
;
87 bool have_session_key
;
88 DATA_BLOB session_key
;
89 DATA_BLOB initial_message
;
90 void *gensec_private_1
;
92 typedef void (*stdio_helper_function
)(enum stdio_helper_mode stdio_helper_mode
,
93 struct loadparm_context
*lp_ctx
,
94 struct ntlm_auth_state
*state
, char *buf
,
95 int length
, void **private2
);
97 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode
,
98 struct loadparm_context
*lp_ctx
,
99 struct ntlm_auth_state
*state
,
100 stdio_helper_function fn
, void **private2
);
102 static void manage_squid_basic_request (enum stdio_helper_mode stdio_helper_mode
,
103 struct loadparm_context
*lp_ctx
,
104 struct ntlm_auth_state
*state
,
105 char *buf
, int length
, void **private2
);
107 static void manage_squid_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode
,
108 struct loadparm_context
*lp_ctx
,
109 struct ntlm_auth_state
*state
,
110 char *buf
, int length
, void **private2
);
112 static void manage_client_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode
,
113 struct loadparm_context
*lp_ctx
,
114 struct ntlm_auth_state
*state
,
115 char *buf
, int length
, void **private2
);
117 static void manage_gss_spnego_request (enum stdio_helper_mode stdio_helper_mode
,
118 struct loadparm_context
*lp_ctx
,
119 struct ntlm_auth_state
*state
,
120 char *buf
, int length
, void **private2
);
122 static void manage_gss_spnego_client_request (enum stdio_helper_mode stdio_helper_mode
,
123 struct loadparm_context
*lp_ctx
,
124 struct ntlm_auth_state
*state
,
125 char *buf
, int length
, void **private2
);
127 static void manage_ntlm_server_1_request (enum stdio_helper_mode stdio_helper_mode
,
128 struct loadparm_context
*lp_ctx
,
129 struct ntlm_auth_state
*state
,
130 char *buf
, int length
, void **private2
);
132 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode
,
133 struct loadparm_context
*lp_ctx
,
134 struct ntlm_auth_state
*state
,
135 char *buf
, int length
, void **private2
);
137 static const struct {
138 enum stdio_helper_mode mode
;
140 stdio_helper_function fn
;
141 } stdio_helper_protocols
[] = {
142 { SQUID_2_4_BASIC
, "squid-2.4-basic", manage_squid_basic_request
},
143 { SQUID_2_5_BASIC
, "squid-2.5-basic", manage_squid_basic_request
},
144 { SQUID_2_5_NTLMSSP
, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request
},
145 { NTLMSSP_CLIENT_1
, "ntlmssp-client-1", manage_client_ntlmssp_request
},
146 { GSS_SPNEGO_SERVER
, "gss-spnego", manage_gss_spnego_request
},
147 { GSS_SPNEGO_CLIENT
, "gss-spnego-client", manage_gss_spnego_client_request
},
148 { NTLM_SERVER_1
, "ntlm-server-1", manage_ntlm_server_1_request
},
149 { NTLM_CHANGE_PASSWORD_1
, "ntlm-change-password-1", manage_ntlm_change_password_1_request
},
150 { NUM_HELPER_MODES
, NULL
, NULL
}
153 const char *opt_username
;
154 const char *opt_domain
;
155 const char *opt_workstation
;
156 const char *opt_password
;
157 static DATA_BLOB opt_challenge
;
158 static DATA_BLOB opt_lm_response
;
159 static DATA_BLOB opt_nt_response
;
160 static int request_lm_key
;
161 static int request_user_session_key
;
162 static int use_cached_creds
;
164 static const char *require_membership_of
;
165 static const char *require_membership_of_sid
;
166 static const char *opt_pam_winbind_conf
;
168 const char *opt_target_service
;
169 const char *opt_target_hostname
;
172 /* This is a bit hairy, but the basic idea is to do a password callback
173 to the calling application. The callback comes from within gensec */
175 static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mode
,
176 struct loadparm_context
*lp_ctx
,
177 struct ntlm_auth_state
*state
, char *buf
, int length
,
181 if (strlen(buf
) < 2) {
182 DEBUG(1, ("query [%s] invalid", buf
));
183 x_fprintf(x_stdout
, "BH Query invalid\n");
187 if (strlen(buf
) > 3) {
188 in
= base64_decode_data_blob(buf
+ 3);
190 in
= data_blob(NULL
, 0);
193 if (strncmp(buf
, "PW ", 3) == 0) {
195 *password
= talloc_strndup(NULL
,
196 (const char *)in
.data
, in
.length
);
198 if (*password
== NULL
) {
199 DEBUG(1, ("Out of memory\n"));
200 x_fprintf(x_stdout
, "BH Out of memory\n");
205 x_fprintf(x_stdout
, "OK\n");
209 DEBUG(1, ("Asked for (and expected) a password\n"));
210 x_fprintf(x_stdout
, "BH Expected a password\n");
215 * Callback for password credentials. This is not async, and when
216 * GENSEC and the credentials code is made async, it will look rather
220 static const char *get_password(struct cli_credentials
*credentials
)
222 char *password
= NULL
;
224 /* Ask for a password */
225 x_fprintf(x_stdout
, "PW\n");
226 credentials
->priv_data
= NULL
;
228 manage_squid_request(NUM_HELPER_MODES
/* bogus */, NULL
, NULL
, manage_gensec_get_pw_request
, (void **)&password
);
229 talloc_steal(credentials
, password
);
234 * A limited set of features are defined with text strings as needed
238 static void gensec_want_feature_list(struct gensec_security
*state
, char* feature_list
)
240 if (in_list("NTLMSSP_FEATURE_SESSION_KEY", feature_list
, true)) {
241 DEBUG(10, ("want GENSEC_FEATURE_SESSION_KEY\n"));
242 gensec_want_feature(state
, GENSEC_FEATURE_SESSION_KEY
);
244 if (in_list("NTLMSSP_FEATURE_SIGN", feature_list
, true)) {
245 DEBUG(10, ("want GENSEC_FEATURE_SIGN\n"));
246 gensec_want_feature(state
, GENSEC_FEATURE_SIGN
);
248 if (in_list("NTLMSSP_FEATURE_SEAL", feature_list
, true)) {
249 DEBUG(10, ("want GENSEC_FEATURE_SEAL\n"));
250 gensec_want_feature(state
, GENSEC_FEATURE_SEAL
);
254 static char winbind_separator(void)
256 struct winbindd_response response
;
263 ZERO_STRUCT(response
);
265 /* Send off request */
267 if (winbindd_request_response(WINBINDD_INFO
, NULL
, &response
) !=
268 NSS_STATUS_SUCCESS
) {
269 d_printf("could not obtain winbind separator!\n");
270 return *lp_winbind_separator();
273 sep
= response
.data
.info
.winbind_separator
;
277 d_printf("winbind separator was NULL!\n");
278 return *lp_winbind_separator();
284 const char *get_winbind_domain(void)
286 struct winbindd_response response
;
288 static fstring winbind_domain
;
289 if (*winbind_domain
) {
290 return winbind_domain
;
293 ZERO_STRUCT(response
);
295 /* Send off request */
297 if (winbindd_request_response(WINBINDD_DOMAIN_NAME
, NULL
, &response
) !=
298 NSS_STATUS_SUCCESS
) {
299 DEBUG(0, ("could not obtain winbind domain name!\n"));
300 return lp_workgroup();
303 fstrcpy(winbind_domain
, response
.data
.domain_name
);
305 return winbind_domain
;
309 const char *get_winbind_netbios_name(void)
311 struct winbindd_response response
;
313 static fstring winbind_netbios_name
;
315 if (*winbind_netbios_name
) {
316 return winbind_netbios_name
;
319 ZERO_STRUCT(response
);
321 /* Send off request */
323 if (winbindd_request_response(WINBINDD_NETBIOS_NAME
, NULL
, &response
) !=
324 NSS_STATUS_SUCCESS
) {
325 DEBUG(0, ("could not obtain winbind netbios name!\n"));
326 return lp_netbios_name();
329 fstrcpy(winbind_netbios_name
, response
.data
.netbios_name
);
331 return winbind_netbios_name
;
335 DATA_BLOB
get_challenge(void)
337 static DATA_BLOB chal
;
338 if (opt_challenge
.length
)
339 return opt_challenge
;
341 chal
= data_blob(NULL
, 8);
343 generate_random_buffer(chal
.data
, chal
.length
);
347 /* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
348 form DOMAIN/user into a domain and a user */
350 static bool parse_ntlm_auth_domain_user(const char *domuser
, fstring domain
,
354 char *p
= strchr(domuser
,winbind_separator());
361 fstrcpy(domain
, domuser
);
362 domain
[PTR_DIFF(p
, domuser
)] = 0;
368 static bool get_require_membership_sid(void) {
369 struct winbindd_request request
;
370 struct winbindd_response response
;
372 if (!require_membership_of
) {
376 if (require_membership_of_sid
) {
380 /* Otherwise, ask winbindd for the name->sid request */
382 ZERO_STRUCT(request
);
383 ZERO_STRUCT(response
);
385 if (!parse_ntlm_auth_domain_user(require_membership_of
,
386 request
.data
.name
.dom_name
,
387 request
.data
.name
.name
)) {
388 DEBUG(0, ("Could not parse %s into seperate domain/name parts!\n",
389 require_membership_of
));
393 if (winbindd_request_response(WINBINDD_LOOKUPNAME
, &request
, &response
) !=
394 NSS_STATUS_SUCCESS
) {
395 DEBUG(0, ("Winbindd lookupname failed to resolve %s into a SID!\n",
396 require_membership_of
));
400 require_membership_of_sid
= SMB_STRDUP(response
.data
.sid
.sid
);
402 if (require_membership_of_sid
)
409 * Get some configuration from pam_winbind.conf to see if we
410 * need to contact trusted domain
413 int get_pam_winbind_config()
416 dictionary
*d
= NULL
;
418 if (!opt_pam_winbind_conf
|| !*opt_pam_winbind_conf
) {
419 opt_pam_winbind_conf
= PAM_WINBIND_CONFIG_FILE
;
422 d
= iniparser_load(discard_const_p(char, opt_pam_winbind_conf
));
428 if (iniparser_getboolean(d
, discard_const_p(char, "global:krb5_auth"), false)) {
429 ctrl
|= WINBIND_KRB5_AUTH
;
432 iniparser_freedict(d
);
437 /* Authenticate a user with a plaintext password */
439 static bool check_plaintext_auth(const char *user
, const char *pass
,
440 bool stdout_diagnostics
)
442 struct winbindd_request request
;
443 struct winbindd_response response
;
446 if (!get_require_membership_sid()) {
450 /* Send off request */
452 ZERO_STRUCT(request
);
453 ZERO_STRUCT(response
);
455 fstrcpy(request
.data
.auth
.user
, user
);
456 fstrcpy(request
.data
.auth
.pass
, pass
);
457 if (require_membership_of_sid
) {
458 strlcpy(request
.data
.auth
.require_membership_of_sid
,
459 require_membership_of_sid
,
460 sizeof(request
.data
.auth
.require_membership_of_sid
));
463 result
= winbindd_request_response(WINBINDD_PAM_AUTH
, &request
, &response
);
465 /* Display response */
467 if (stdout_diagnostics
) {
468 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
469 d_printf("Reading winbind reply failed! (0x01)\n");
472 d_printf("%s: %s (0x%x)\n",
473 response
.data
.auth
.nt_status_string
,
474 response
.data
.auth
.error_string
,
475 response
.data
.auth
.nt_status
);
477 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
478 DEBUG(1, ("Reading winbind reply failed! (0x01)\n"));
481 DEBUG(3, ("%s: %s (0x%x)\n",
482 response
.data
.auth
.nt_status_string
,
483 response
.data
.auth
.error_string
,
484 response
.data
.auth
.nt_status
));
487 return (result
== NSS_STATUS_SUCCESS
);
490 /* authenticate a user with an encrypted username/password */
492 NTSTATUS
contact_winbind_auth_crap(const char *username
,
494 const char *workstation
,
495 const DATA_BLOB
*challenge
,
496 const DATA_BLOB
*lm_response
,
497 const DATA_BLOB
*nt_response
,
499 uint32 extra_logon_parameters
,
501 uint8 user_session_key
[16],
507 struct winbindd_request request
;
508 struct winbindd_response response
;
510 if (!get_require_membership_sid()) {
511 return NT_STATUS_INVALID_PARAMETER
;
514 ZERO_STRUCT(request
);
515 ZERO_STRUCT(response
);
517 request
.flags
= flags
;
519 request
.data
.auth_crap
.logon_parameters
= extra_logon_parameters
520 | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
| MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT
;
522 if (require_membership_of_sid
)
523 fstrcpy(request
.data
.auth_crap
.require_membership_of_sid
, require_membership_of_sid
);
525 fstrcpy(request
.data
.auth_crap
.user
, username
);
526 fstrcpy(request
.data
.auth_crap
.domain
, domain
);
528 fstrcpy(request
.data
.auth_crap
.workstation
,
531 memcpy(request
.data
.auth_crap
.chal
, challenge
->data
, MIN(challenge
->length
, 8));
533 if (lm_response
&& lm_response
->length
) {
534 memcpy(request
.data
.auth_crap
.lm_resp
,
536 MIN(lm_response
->length
, sizeof(request
.data
.auth_crap
.lm_resp
)));
537 request
.data
.auth_crap
.lm_resp_len
= lm_response
->length
;
540 if (nt_response
&& nt_response
->length
) {
541 if (nt_response
->length
> sizeof(request
.data
.auth_crap
.nt_resp
)) {
542 request
.flags
= request
.flags
| WBFLAG_BIG_NTLMV2_BLOB
;
543 request
.extra_len
= nt_response
->length
;
544 request
.extra_data
.data
= SMB_MALLOC_ARRAY(char, request
.extra_len
);
545 if (request
.extra_data
.data
== NULL
) {
546 return NT_STATUS_NO_MEMORY
;
548 memcpy(request
.extra_data
.data
, nt_response
->data
,
549 nt_response
->length
);
552 memcpy(request
.data
.auth_crap
.nt_resp
,
553 nt_response
->data
, nt_response
->length
);
555 request
.data
.auth_crap
.nt_resp_len
= nt_response
->length
;
558 result
= winbindd_request_response(WINBINDD_PAM_AUTH_CRAP
, &request
, &response
);
559 SAFE_FREE(request
.extra_data
.data
);
561 /* Display response */
563 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
564 nt_status
= NT_STATUS_UNSUCCESSFUL
;
566 *error_string
= smb_xstrdup("Reading winbind reply failed!");
567 winbindd_free_response(&response
);
571 nt_status
= (NT_STATUS(response
.data
.auth
.nt_status
));
572 if (!NT_STATUS_IS_OK(nt_status
)) {
574 *error_string
= smb_xstrdup(response
.data
.auth
.error_string
);
575 winbindd_free_response(&response
);
579 if ((flags
& WBFLAG_PAM_LMKEY
) && lm_key
) {
580 memcpy(lm_key
, response
.data
.auth
.first_8_lm_hash
,
581 sizeof(response
.data
.auth
.first_8_lm_hash
));
583 if ((flags
& WBFLAG_PAM_USER_SESSION_KEY
) && user_session_key
) {
584 memcpy(user_session_key
, response
.data
.auth
.user_session_key
,
585 sizeof(response
.data
.auth
.user_session_key
));
588 if (flags
& WBFLAG_PAM_UNIX_NAME
) {
589 *unix_name
= SMB_STRDUP(response
.data
.auth
.unix_username
);
591 winbindd_free_response(&response
);
592 return NT_STATUS_NO_MEMORY
;
596 winbindd_free_response(&response
);
600 /* contact server to change user password using auth crap */
601 static NTSTATUS
contact_winbind_change_pswd_auth_crap(const char *username
,
603 const DATA_BLOB new_nt_pswd
,
604 const DATA_BLOB old_nt_hash_enc
,
605 const DATA_BLOB new_lm_pswd
,
606 const DATA_BLOB old_lm_hash_enc
,
611 struct winbindd_request request
;
612 struct winbindd_response response
;
614 if (!get_require_membership_sid())
617 *error_string
= smb_xstrdup("Can't get membership sid.");
618 return NT_STATUS_INVALID_PARAMETER
;
621 ZERO_STRUCT(request
);
622 ZERO_STRUCT(response
);
625 fstrcpy(request
.data
.chng_pswd_auth_crap
.user
, username
);
627 fstrcpy(request
.data
.chng_pswd_auth_crap
.domain
,domain
);
629 if(new_nt_pswd
.length
)
631 memcpy(request
.data
.chng_pswd_auth_crap
.new_nt_pswd
, new_nt_pswd
.data
, sizeof(request
.data
.chng_pswd_auth_crap
.new_nt_pswd
));
632 request
.data
.chng_pswd_auth_crap
.new_nt_pswd_len
= new_nt_pswd
.length
;
635 if(old_nt_hash_enc
.length
)
637 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
));
638 request
.data
.chng_pswd_auth_crap
.old_nt_hash_enc_len
= old_nt_hash_enc
.length
;
641 if(new_lm_pswd
.length
)
643 memcpy(request
.data
.chng_pswd_auth_crap
.new_lm_pswd
, new_lm_pswd
.data
, sizeof(request
.data
.chng_pswd_auth_crap
.new_lm_pswd
));
644 request
.data
.chng_pswd_auth_crap
.new_lm_pswd_len
= new_lm_pswd
.length
;
647 if(old_lm_hash_enc
.length
)
649 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
));
650 request
.data
.chng_pswd_auth_crap
.old_lm_hash_enc_len
= old_lm_hash_enc
.length
;
653 result
= winbindd_request_response(WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP
, &request
, &response
);
655 /* Display response */
657 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0))
659 nt_status
= NT_STATUS_UNSUCCESSFUL
;
661 *error_string
= smb_xstrdup("Reading winbind reply failed!");
662 winbindd_free_response(&response
);
666 nt_status
= (NT_STATUS(response
.data
.auth
.nt_status
));
667 if (!NT_STATUS_IS_OK(nt_status
))
670 *error_string
= smb_xstrdup(response
.data
.auth
.error_string
);
671 winbindd_free_response(&response
);
675 winbindd_free_response(&response
);
680 static NTSTATUS
ntlm_auth_generate_session_info(struct auth4_context
*auth_context
,
682 void *server_returned_info
,
683 const char *original_user_name
,
684 uint32_t session_info_flags
,
685 struct auth_session_info
**session_info_out
)
687 char *unix_username
= (char *)server_returned_info
;
688 struct auth_session_info
*session_info
= talloc_zero(mem_ctx
, struct auth_session_info
);
690 return NT_STATUS_NO_MEMORY
;
693 session_info
->unix_info
= talloc_zero(session_info
, struct auth_user_info_unix
);
694 if (!session_info
->unix_info
) {
695 TALLOC_FREE(session_info
);
696 return NT_STATUS_NO_MEMORY
;
698 session_info
->unix_info
->unix_name
= talloc_steal(session_info
->unix_info
, unix_username
);
700 *session_info_out
= session_info
;
705 static NTSTATUS
ntlm_auth_generate_session_info_pac(struct auth4_context
*auth_ctx
,
707 struct smb_krb5_context
*smb_krb5_context
,
709 const char *princ_name
,
710 const struct tsocket_address
*remote_address
,
711 uint32_t session_info_flags
,
712 struct auth_session_info
**session_info
)
715 struct PAC_DATA
*pac_data
= NULL
;
716 struct PAC_LOGON_INFO
*logon_info
= NULL
;
725 tmp_ctx
= talloc_new(mem_ctx
);
727 return NT_STATUS_NO_MEMORY
;
732 status
= kerberos_decode_pac(tmp_ctx
,
734 NULL
, NULL
, NULL
, NULL
, 0, &pac_data
);
736 status
= NT_STATUS_ACCESS_DENIED
;
738 if (!NT_STATUS_IS_OK(status
)) {
742 /* get logon name and logon info */
743 for (i
= 0; i
< pac_data
->num_buffers
; i
++) {
744 struct PAC_BUFFER
*data_buf
= &pac_data
->buffers
[i
];
746 switch (data_buf
->type
) {
747 case PAC_TYPE_LOGON_INFO
:
748 if (!data_buf
->info
) {
751 logon_info
= data_buf
->info
->logon_info
.info
;
758 DEBUG(1, ("Invalid PAC data, missing logon info!\n"));
759 status
= NT_STATUS_NOT_FOUND
;
764 DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name
));
766 p
= strchr_m(princ_name
, '@');
768 DEBUG(3, ("[%s] Doesn't look like a valid principal\n",
770 return NT_STATUS_LOGON_FAILURE
;
773 user
= talloc_strndup(mem_ctx
, princ_name
, p
- princ_name
);
775 return NT_STATUS_NO_MEMORY
;
778 realm
= talloc_strdup(talloc_tos(), p
+ 1);
780 return NT_STATUS_NO_MEMORY
;
783 if (!strequal(realm
, lp_realm())) {
784 DEBUG(3, ("Ticket for foreign realm %s@%s\n", user
, realm
));
785 if (!lp_allow_trusted_domains()) {
786 return NT_STATUS_LOGON_FAILURE
;
790 if (logon_info
&& logon_info
->info3
.base
.logon_domain
.string
) {
791 domain
= talloc_strdup(mem_ctx
,
792 logon_info
->info3
.base
.logon_domain
.string
);
794 return NT_STATUS_NO_MEMORY
;
796 DEBUG(10, ("Domain is [%s] (using PAC)\n", domain
));
799 /* If we have winbind running, we can (and must) shorten the
800 username by using the short netbios name. Otherwise we will
801 have inconsistent user names. With Kerberos, we get the
802 fully qualified realm, with ntlmssp we get the short
803 name. And even w2k3 does use ntlmssp if you for example
804 connect to an ip address. */
807 struct wbcDomainInfo
*info
= NULL
;
809 DEBUG(10, ("Mapping [%s] to short name using winbindd\n",
812 wbc_status
= wbcDomainInfo(realm
, &info
);
814 if (WBC_ERROR_IS_OK(wbc_status
)) {
815 domain
= talloc_strdup(mem_ctx
,
819 DEBUG(3, ("Could not find short name: %s\n",
820 wbcErrorString(wbc_status
)));
821 domain
= talloc_strdup(mem_ctx
, realm
);
824 return NT_STATUS_NO_MEMORY
;
826 DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain
));
829 unixuser
= talloc_asprintf(tmp_ctx
, "%s%c%s", domain
, winbind_separator(), user
);
831 status
= NT_STATUS_NO_MEMORY
;
835 status
= ntlm_auth_generate_session_info(auth_ctx
, mem_ctx
, unixuser
, NULL
, session_info_flags
, session_info
);
838 TALLOC_FREE(tmp_ctx
);
845 * Return the challenge as determined by the authentication subsystem
846 * @return an 8 byte random challenge
849 static NTSTATUS
ntlm_auth_get_challenge(struct auth4_context
*auth_ctx
,
852 if (auth_ctx
->challenge
.data
.length
== 8) {
853 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
854 auth_ctx
->challenge
.set_by
));
855 memcpy(chal
, auth_ctx
->challenge
.data
.data
, 8);
859 if (!auth_ctx
->challenge
.set_by
) {
860 generate_random_buffer(chal
, 8);
862 auth_ctx
->challenge
.data
= data_blob_talloc(auth_ctx
, chal
, 8);
863 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.data
.data
);
864 auth_ctx
->challenge
.set_by
= "random";
866 auth_ctx
->challenge
.may_be_modified
= true;
869 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
870 auth_ctx
->challenge
.set_by
));
876 * Some authentication methods 'fix' the challenge, so we may not be able to set it
878 * @return If the effective challenge used by the auth subsystem may be modified
880 static bool ntlm_auth_may_set_challenge(struct auth4_context
*auth_ctx
)
882 return auth_ctx
->challenge
.may_be_modified
;
886 * NTLM2 authentication modifies the effective challenge,
887 * @param challenge The new challenge value
889 static NTSTATUS
ntlm_auth_set_challenge(struct auth4_context
*auth_ctx
, const uint8_t chal
[8], const char *set_by
)
891 auth_ctx
->challenge
.set_by
= talloc_strdup(auth_ctx
, set_by
);
892 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.set_by
);
894 auth_ctx
->challenge
.data
= data_blob_talloc(auth_ctx
, chal
, 8);
895 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.data
.data
);
901 * Check the password on an NTLMSSP login.
903 * Return the session keys used on the connection.
906 static NTSTATUS
winbind_pw_check(struct auth4_context
*auth4_context
,
908 const struct auth_usersupplied_info
*user_info
,
909 void **server_returned_info
,
910 DATA_BLOB
*session_key
, DATA_BLOB
*lm_session_key
)
912 static const char zeros
[16] = { 0, };
914 char *error_string
= NULL
;
916 uint8 user_sess_key
[16];
917 char *unix_name
= NULL
;
919 nt_status
= contact_winbind_auth_crap(user_info
->client
.account_name
, user_info
->client
.domain_name
,
920 user_info
->workstation_name
,
921 &auth4_context
->challenge
.data
,
922 &user_info
->password
.response
.lanman
,
923 &user_info
->password
.response
.nt
,
924 WBFLAG_PAM_LMKEY
| WBFLAG_PAM_USER_SESSION_KEY
| WBFLAG_PAM_UNIX_NAME
,
926 lm_key
, user_sess_key
,
927 &error_string
, &unix_name
);
929 if (NT_STATUS_IS_OK(nt_status
)) {
930 if (memcmp(lm_key
, zeros
, 8) != 0) {
931 *lm_session_key
= data_blob_talloc(mem_ctx
, NULL
, 16);
932 memcpy(lm_session_key
->data
, lm_key
, 8);
933 memset(lm_session_key
->data
+8, '\0', 8);
936 if (memcmp(user_sess_key
, zeros
, 16) != 0) {
937 *session_key
= data_blob_talloc(mem_ctx
, user_sess_key
, 16);
939 *server_returned_info
= talloc_strdup(mem_ctx
,
942 DEBUG(NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCESS_DENIED
) ? 0 : 3,
943 ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
944 user_info
->client
.domain_name
, user_info
->client
.account_name
,
945 user_info
->workstation_name
,
946 error_string
? error_string
: "unknown error (NULL)"));
949 SAFE_FREE(error_string
);
950 SAFE_FREE(unix_name
);
954 static NTSTATUS
local_pw_check(struct auth4_context
*auth4_context
,
956 const struct auth_usersupplied_info
*user_info
,
957 void **server_returned_info
,
958 DATA_BLOB
*session_key
, DATA_BLOB
*lm_session_key
)
961 struct samr_Password lm_pw
, nt_pw
;
963 nt_lm_owf_gen (opt_password
, nt_pw
.hash
, lm_pw
.hash
);
965 nt_status
= ntlm_password_check(mem_ctx
,
967 &auth4_context
->challenge
.data
,
968 &user_info
->password
.response
.lanman
,
969 &user_info
->password
.response
.nt
,
970 user_info
->client
.account_name
,
971 user_info
->client
.account_name
,
972 user_info
->client
.domain_name
,
973 &lm_pw
, &nt_pw
, session_key
, lm_session_key
);
975 if (NT_STATUS_IS_OK(nt_status
)) {
976 *server_returned_info
= talloc_asprintf(mem_ctx
,
977 "%s%c%s", user_info
->client
.domain_name
,
978 *lp_winbind_separator(),
979 user_info
->client
.account_name
);
981 DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
982 user_info
->client
.domain_name
, user_info
->client
.account_name
,
983 user_info
->workstation_name
,
984 nt_errstr(nt_status
)));
989 static NTSTATUS
ntlm_auth_start_ntlmssp_client(struct ntlmssp_state
**client_ntlmssp_state
)
992 if ( (opt_username
== NULL
) || (opt_domain
== NULL
) ) {
993 status
= NT_STATUS_UNSUCCESSFUL
;
994 DEBUG(1, ("Need username and domain for NTLMSSP\n"));
995 return NT_STATUS_INVALID_PARAMETER
;
998 status
= ntlmssp_client_start(NULL
,
1001 lp_client_ntlmv2_auth(),
1002 client_ntlmssp_state
);
1004 if (!NT_STATUS_IS_OK(status
)) {
1005 DEBUG(1, ("Could not start NTLMSSP client: %s\n",
1006 nt_errstr(status
)));
1007 TALLOC_FREE(*client_ntlmssp_state
);
1011 status
= ntlmssp_set_username(*client_ntlmssp_state
, opt_username
);
1013 if (!NT_STATUS_IS_OK(status
)) {
1014 DEBUG(1, ("Could not set username: %s\n",
1015 nt_errstr(status
)));
1016 TALLOC_FREE(*client_ntlmssp_state
);
1020 status
= ntlmssp_set_domain(*client_ntlmssp_state
, opt_domain
);
1022 if (!NT_STATUS_IS_OK(status
)) {
1023 DEBUG(1, ("Could not set domain: %s\n",
1024 nt_errstr(status
)));
1025 TALLOC_FREE(*client_ntlmssp_state
);
1030 status
= ntlmssp_set_password(*client_ntlmssp_state
, opt_password
);
1032 if (!NT_STATUS_IS_OK(status
)) {
1033 DEBUG(1, ("Could not set password: %s\n",
1034 nt_errstr(status
)));
1035 TALLOC_FREE(*client_ntlmssp_state
);
1040 return NT_STATUS_OK
;
1043 static struct auth4_context
*make_auth4_context_ntlm_auth(TALLOC_CTX
*mem_ctx
, bool local_pw
)
1045 struct auth4_context
*auth4_context
= talloc_zero(mem_ctx
, struct auth4_context
);
1046 if (auth4_context
== NULL
) {
1047 DEBUG(10, ("failed to allocate auth4_context failed\n"));
1050 auth4_context
->generate_session_info
= ntlm_auth_generate_session_info
;
1051 auth4_context
->generate_session_info_pac
= ntlm_auth_generate_session_info_pac
;
1052 auth4_context
->get_ntlm_challenge
= ntlm_auth_get_challenge
;
1053 auth4_context
->set_ntlm_challenge
= ntlm_auth_set_challenge
;
1054 auth4_context
->challenge_may_be_modified
= ntlm_auth_may_set_challenge
;
1056 auth4_context
->check_ntlm_password
= local_pw_check
;
1058 auth4_context
->check_ntlm_password
= winbind_pw_check
;
1060 auth4_context
->private_data
= NULL
;
1061 return auth4_context
;
1064 static NTSTATUS
ntlm_auth_start_ntlmssp_server(TALLOC_CTX
*mem_ctx
,
1065 struct loadparm_context
*lp_ctx
,
1066 struct gensec_security
**gensec_security_out
)
1068 struct gensec_security
*gensec_security
;
1071 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
1072 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx
);
1074 struct gensec_settings
*gensec_settings
;
1076 struct cli_credentials
*server_credentials
;
1078 struct auth4_context
*auth4_context
= make_auth4_context_ntlm_auth(tmp_ctx
, opt_password
);
1079 if (auth4_context
== NULL
) {
1080 TALLOC_FREE(tmp_ctx
);
1081 return NT_STATUS_NO_MEMORY
;
1084 gensec_settings
= lpcfg_gensec_settings(tmp_ctx
, lp_ctx
);
1085 if (lp_ctx
== NULL
) {
1086 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1087 TALLOC_FREE(tmp_ctx
);
1088 return NT_STATUS_NO_MEMORY
;
1092 * This should be a 'netbios domain -> DNS domain'
1093 * mapping, and can currently validly return NULL on
1094 * poorly configured systems.
1096 * This is used for the NTLMSSP server
1100 gensec_settings
->server_netbios_name
= lp_netbios_name();
1101 gensec_settings
->server_netbios_domain
= lp_workgroup();
1103 gensec_settings
->server_netbios_name
= get_winbind_netbios_name();
1104 gensec_settings
->server_netbios_domain
= get_winbind_domain();
1107 gensec_settings
->server_dns_domain
= strlower_talloc(gensec_settings
,
1108 get_mydnsdomname(talloc_tos()));
1109 gensec_settings
->server_dns_name
= strlower_talloc(gensec_settings
,
1110 get_mydnsfullname());
1112 gensec_settings
->backends
= talloc_zero_array(gensec_settings
,
1113 struct gensec_security_ops
*, 4);
1115 if (gensec_settings
->backends
== NULL
) {
1116 TALLOC_FREE(tmp_ctx
);
1117 return NT_STATUS_NO_MEMORY
;
1122 /* These need to be in priority order, krb5 before NTLMSSP */
1123 #if defined(HAVE_KRB5)
1124 gensec_settings
->backends
[idx
++] = &gensec_gse_krb5_security_ops
;
1127 gensec_settings
->backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_NTLMSSP
);
1129 gensec_settings
->backends
[idx
++] = gensec_security_by_oid(NULL
,
1133 * This is anonymous for now, because we just use it
1134 * to set the kerberos state at the moment
1136 server_credentials
= cli_credentials_init_anon(tmp_ctx
);
1137 if (!server_credentials
) {
1138 DEBUG(0, ("auth_generic_prepare: Failed to init server credentials\n"));
1139 return NT_STATUS_NO_MEMORY
;
1142 cli_credentials_set_conf(server_credentials
, lp_ctx
);
1144 if (lp_security() == SEC_ADS
|| USE_KERBEROS_KEYTAB
) {
1145 cli_credentials_set_kerberos_state(server_credentials
, CRED_AUTO_USE_KERBEROS
);
1147 cli_credentials_set_kerberos_state(server_credentials
, CRED_DONT_USE_KERBEROS
);
1150 nt_status
= gensec_server_start(tmp_ctx
, gensec_settings
,
1151 auth4_context
, &gensec_security
);
1153 if (!NT_STATUS_IS_OK(nt_status
)) {
1154 TALLOC_FREE(tmp_ctx
);
1158 gensec_set_credentials(gensec_security
, server_credentials
);
1160 gensec_want_feature(gensec_security
, GENSEC_FEATURE_SIGN
);
1161 gensec_want_feature(gensec_security
, GENSEC_FEATURE_SEAL
);
1163 talloc_unlink(tmp_ctx
, lp_ctx
);
1164 talloc_unlink(tmp_ctx
, server_credentials
);
1165 talloc_unlink(tmp_ctx
, gensec_settings
);
1166 talloc_unlink(tmp_ctx
, auth4_context
);
1168 nt_status
= gensec_start_mech_by_oid(gensec_security
, GENSEC_OID_NTLMSSP
);
1169 if (!NT_STATUS_IS_OK(nt_status
)) {
1170 TALLOC_FREE(tmp_ctx
);
1174 *gensec_security_out
= talloc_steal(mem_ctx
, gensec_security
);
1175 TALLOC_FREE(tmp_ctx
);
1176 return NT_STATUS_OK
;
1179 /*******************************************************************
1180 Used by firefox to drive NTLM auth to IIS servers.
1181 *******************************************************************/
1183 static NTSTATUS
do_ccache_ntlm_auth(DATA_BLOB initial_msg
, DATA_BLOB challenge_msg
,
1186 struct winbindd_request wb_request
;
1187 struct winbindd_response wb_response
;
1191 /* get winbindd to do the ntlmssp step on our behalf */
1192 ZERO_STRUCT(wb_request
);
1193 ZERO_STRUCT(wb_response
);
1196 * This is tricky here. If we set krb5_auth in pam_winbind.conf
1197 * creds for users in trusted domain will be stored the winbindd
1198 * child of the trusted domain. If we ask the primary domain for
1199 * ntlm_ccache_auth, it will fail. So, we have to ask the trusted
1200 * domain's child for ccache_ntlm_auth. that is to say, we have to
1201 * set WBFLAG_PAM_CONTACT_TRUSTDOM in request.flags.
1203 ctrl
= get_pam_winbind_config();
1205 if (ctrl
& WINBIND_KRB5_AUTH
) {
1206 wb_request
.flags
|= WBFLAG_PAM_CONTACT_TRUSTDOM
;
1209 fstr_sprintf(wb_request
.data
.ccache_ntlm_auth
.user
,
1210 "%s%c%s", opt_domain
, winbind_separator(), opt_username
);
1211 wb_request
.data
.ccache_ntlm_auth
.uid
= geteuid();
1212 wb_request
.data
.ccache_ntlm_auth
.initial_blob_len
= initial_msg
.length
;
1213 wb_request
.data
.ccache_ntlm_auth
.challenge_blob_len
= challenge_msg
.length
;
1214 wb_request
.extra_len
= initial_msg
.length
+ challenge_msg
.length
;
1216 if (wb_request
.extra_len
> 0) {
1217 wb_request
.extra_data
.data
= SMB_MALLOC_ARRAY(char, wb_request
.extra_len
);
1218 if (wb_request
.extra_data
.data
== NULL
) {
1219 return NT_STATUS_NO_MEMORY
;
1222 memcpy(wb_request
.extra_data
.data
, initial_msg
.data
, initial_msg
.length
);
1223 memcpy(wb_request
.extra_data
.data
+ initial_msg
.length
,
1224 challenge_msg
.data
, challenge_msg
.length
);
1227 result
= winbindd_request_response(WINBINDD_CCACHE_NTLMAUTH
, &wb_request
, &wb_response
);
1228 SAFE_FREE(wb_request
.extra_data
.data
);
1230 if (result
!= NSS_STATUS_SUCCESS
) {
1231 winbindd_free_response(&wb_response
);
1232 return NT_STATUS_UNSUCCESSFUL
;
1236 *reply
= data_blob(wb_response
.extra_data
.data
,
1237 wb_response
.data
.ccache_ntlm_auth
.auth_blob_len
);
1238 if (wb_response
.data
.ccache_ntlm_auth
.auth_blob_len
> 0 &&
1239 reply
->data
== NULL
) {
1240 winbindd_free_response(&wb_response
);
1241 return NT_STATUS_NO_MEMORY
;
1245 winbindd_free_response(&wb_response
);
1246 return NT_STATUS_MORE_PROCESSING_REQUIRED
;
1249 static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode
,
1250 struct loadparm_context
*lp_ctx
,
1251 struct ntlm_auth_state
*state
,
1252 char *buf
, int length
, void **private2
)
1254 DATA_BLOB request
, reply
;
1257 if (!opt_username
|| !*opt_username
) {
1258 x_fprintf(x_stderr
, "username must be specified!\n\n");
1262 if (strlen(buf
) < 2) {
1263 DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf
));
1264 x_fprintf(x_stdout
, "BH NTLMSSP query invalid\n");
1268 if (strlen(buf
) > 3) {
1269 if(strncmp(buf
, "SF ", 3) == 0) {
1270 DEBUG(10, ("Looking for flags to negotiate\n"));
1271 talloc_free(state
->want_feature_list
);
1272 state
->want_feature_list
= talloc_strdup(state
->mem_ctx
,
1274 x_fprintf(x_stdout
, "OK\n");
1277 request
= base64_decode_data_blob(buf
+ 3);
1279 request
= data_blob_null
;
1282 if (strncmp(buf
, "PW ", 3) == 0) {
1283 /* We asked for a password and obviously got it :-) */
1285 opt_password
= SMB_STRNDUP((const char *)request
.data
,
1288 if (opt_password
== NULL
) {
1289 DEBUG(1, ("Out of memory\n"));
1290 x_fprintf(x_stdout
, "BH Out of memory\n");
1291 data_blob_free(&request
);
1295 x_fprintf(x_stdout
, "OK\n");
1296 data_blob_free(&request
);
1300 if (!state
->ntlmssp_state
&& use_cached_creds
) {
1301 /* check whether cached credentials are usable. */
1302 DATA_BLOB empty_blob
= data_blob_null
;
1304 nt_status
= do_ccache_ntlm_auth(empty_blob
, empty_blob
, NULL
);
1305 if (!NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1306 /* failed to use cached creds */
1307 use_cached_creds
= False
;
1311 if (opt_password
== NULL
&& !use_cached_creds
) {
1312 /* Request a password from the calling process. After
1313 sending it, the calling process should retry asking for the
1316 DEBUG(10, ("Requesting password\n"));
1317 x_fprintf(x_stdout
, "PW\n");
1321 if (strncmp(buf
, "YR", 2) == 0) {
1322 TALLOC_FREE(state
->ntlmssp_state
);
1323 state
->cli_state
= CLIENT_INITIAL
;
1324 } else if (strncmp(buf
, "TT", 2) == 0) {
1325 /* No special preprocessing required */
1326 } else if (strncmp(buf
, "GF", 2) == 0) {
1327 DEBUG(10, ("Requested negotiated NTLMSSP flags\n"));
1329 if(state
->cli_state
== CLIENT_FINISHED
) {
1330 x_fprintf(x_stdout
, "GF 0x%08x\n", state
->neg_flags
);
1333 x_fprintf(x_stdout
, "BH\n");
1336 data_blob_free(&request
);
1338 } else if (strncmp(buf
, "GK", 2) == 0 ) {
1339 DEBUG(10, ("Requested session key\n"));
1341 if(state
->cli_state
== CLIENT_FINISHED
) {
1342 char *key64
= base64_encode_data_blob(state
->mem_ctx
,
1343 state
->session_key
);
1344 x_fprintf(x_stdout
, "GK %s\n", key64
?key64
:"<NULL>");
1348 x_fprintf(x_stdout
, "BH\n");
1351 data_blob_free(&request
);
1354 DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf
));
1355 x_fprintf(x_stdout
, "BH NTLMSSP query invalid\n");
1359 if (!state
->ntlmssp_state
) {
1360 nt_status
= ntlm_auth_start_ntlmssp_client(
1361 &state
->ntlmssp_state
);
1362 if (!NT_STATUS_IS_OK(nt_status
)) {
1363 x_fprintf(x_stdout
, "BH %s\n", nt_errstr(nt_status
));
1366 ntlmssp_want_feature_list(state
->ntlmssp_state
,
1367 state
->want_feature_list
);
1368 state
->initial_message
= data_blob_null
;
1371 DEBUG(10, ("got NTLMSSP packet:\n"));
1372 dump_data(10, request
.data
, request
.length
);
1374 if (use_cached_creds
&& !opt_password
&&
1375 (state
->cli_state
== CLIENT_RESPONSE
)) {
1376 nt_status
= do_ccache_ntlm_auth(state
->initial_message
, request
,
1379 nt_status
= ntlmssp_update(state
->ntlmssp_state
, request
,
1383 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1384 char *reply_base64
= base64_encode_data_blob(state
->mem_ctx
,
1386 if (state
->cli_state
== CLIENT_INITIAL
) {
1387 x_fprintf(x_stdout
, "YR %s\n", reply_base64
);
1388 state
->initial_message
= reply
;
1389 state
->cli_state
= CLIENT_RESPONSE
;
1391 x_fprintf(x_stdout
, "KK %s\n", reply_base64
);
1392 data_blob_free(&reply
);
1394 TALLOC_FREE(reply_base64
);
1395 DEBUG(10, ("NTLMSSP challenge\n"));
1396 } else if (NT_STATUS_IS_OK(nt_status
)) {
1397 char *reply_base64
= base64_encode_data_blob(talloc_tos(),
1399 x_fprintf(x_stdout
, "AF %s\n", reply_base64
);
1400 TALLOC_FREE(reply_base64
);
1402 if(state
->have_session_key
)
1403 data_blob_free(&state
->session_key
);
1405 state
->session_key
= data_blob(
1406 state
->ntlmssp_state
->session_key
.data
,
1407 state
->ntlmssp_state
->session_key
.length
);
1408 state
->neg_flags
= state
->ntlmssp_state
->neg_flags
;
1409 state
->have_session_key
= true;
1411 DEBUG(10, ("NTLMSSP OK!\n"));
1412 state
->cli_state
= CLIENT_FINISHED
;
1413 TALLOC_FREE(state
->ntlmssp_state
);
1415 x_fprintf(x_stdout
, "BH %s\n", nt_errstr(nt_status
));
1416 DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status
)));
1417 state
->cli_state
= CLIENT_ERROR
;
1418 TALLOC_FREE(state
->ntlmssp_state
);
1421 data_blob_free(&request
);
1424 static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode
,
1425 struct loadparm_context
*lp_ctx
,
1426 struct ntlm_auth_state
*state
,
1427 char *buf
, int length
, void **private2
)
1432 pass
=(char *)memchr(buf
,' ',length
);
1434 DEBUG(2, ("Password not found. Denying access\n"));
1435 x_fprintf(x_stdout
, "ERR\n");
1441 if (state
->helper_mode
== SQUID_2_5_BASIC
) {
1442 rfc1738_unescape(user
);
1443 rfc1738_unescape(pass
);
1446 if (check_plaintext_auth(user
, pass
, False
)) {
1447 x_fprintf(x_stdout
, "OK\n");
1449 x_fprintf(x_stdout
, "ERR\n");
1453 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode
,
1454 struct loadparm_context
*lp_ctx
,
1455 char *buf
, int length
, void **private1
)
1458 DATA_BLOB out
= data_blob(NULL
, 0);
1459 char *out_base64
= NULL
;
1460 const char *reply_arg
= NULL
;
1461 struct gensec_ntlm_state
{
1462 struct gensec_security
*gensec_state
;
1463 const char *set_password
;
1465 struct gensec_ntlm_state
*state
;
1469 const char *reply_code
;
1470 struct cli_credentials
*creds
;
1472 static char *want_feature_list
= NULL
;
1473 static DATA_BLOB session_key
;
1475 TALLOC_CTX
*mem_ctx
;
1478 state
= (struct gensec_ntlm_state
*)*private1
;
1480 state
= talloc_zero(NULL
, struct gensec_ntlm_state
);
1482 x_fprintf(x_stdout
, "BH No Memory\n");
1487 state
->set_password
= opt_password
;
1491 if (strlen(buf
) < 2) {
1492 DEBUG(1, ("query [%s] invalid", buf
));
1493 x_fprintf(x_stdout
, "BH Query invalid\n");
1497 if (strlen(buf
) > 3) {
1498 if(strncmp(buf
, "SF ", 3) == 0) {
1499 DEBUG(10, ("Setting flags to negotiate\n"));
1500 talloc_free(want_feature_list
);
1501 want_feature_list
= talloc_strndup(state
, buf
+3, strlen(buf
)-3);
1502 x_fprintf(x_stdout
, "OK\n");
1505 in
= base64_decode_data_blob(buf
+ 3);
1507 in
= data_blob(NULL
, 0);
1510 if (strncmp(buf
, "YR", 2) == 0) {
1511 if (state
->gensec_state
) {
1512 talloc_free(state
->gensec_state
);
1513 state
->gensec_state
= NULL
;
1515 } else if ( (strncmp(buf
, "OK", 2) == 0)) {
1516 /* Just return BH, like ntlm_auth from Samba 3 does. */
1517 x_fprintf(x_stdout
, "BH Command expected\n");
1518 data_blob_free(&in
);
1520 } else if ( (strncmp(buf
, "TT ", 3) != 0) &&
1521 (strncmp(buf
, "KK ", 3) != 0) &&
1522 (strncmp(buf
, "AF ", 3) != 0) &&
1523 (strncmp(buf
, "NA ", 3) != 0) &&
1524 (strncmp(buf
, "UG", 2) != 0) &&
1525 (strncmp(buf
, "PW ", 3) != 0) &&
1526 (strncmp(buf
, "GK", 2) != 0) &&
1527 (strncmp(buf
, "GF", 2) != 0)) {
1528 DEBUG(1, ("SPNEGO request [%s] invalid prefix\n", buf
));
1529 x_fprintf(x_stdout
, "BH SPNEGO request invalid prefix\n");
1530 data_blob_free(&in
);
1534 mem_ctx
= talloc_named(NULL
, 0, "manage_gensec_request internal mem_ctx");
1537 if (!(state
->gensec_state
)) {
1538 switch (stdio_helper_mode
) {
1539 case GSS_SPNEGO_CLIENT
:
1540 case NTLMSSP_CLIENT_1
:
1541 /* setup the client side */
1543 nt_status
= gensec_client_start(NULL
, &state
->gensec_state
,
1544 lpcfg_gensec_settings(NULL
, lp_ctx
));
1545 if (!NT_STATUS_IS_OK(nt_status
)) {
1546 x_fprintf(x_stdout
, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status
));
1547 talloc_free(mem_ctx
);
1551 creds
= cli_credentials_init(state
->gensec_state
);
1552 cli_credentials_set_conf(creds
, lp_ctx
);
1554 cli_credentials_set_username(creds
, opt_username
, CRED_SPECIFIED
);
1557 cli_credentials_set_domain(creds
, opt_domain
, CRED_SPECIFIED
);
1559 if (state
->set_password
) {
1560 cli_credentials_set_password(creds
, state
->set_password
, CRED_SPECIFIED
);
1562 cli_credentials_set_password_callback(creds
, get_password
);
1564 if (opt_workstation
) {
1565 cli_credentials_set_workstation(creds
, opt_workstation
, CRED_SPECIFIED
);
1568 gensec_set_credentials(state
->gensec_state
, creds
);
1571 case GSS_SPNEGO_SERVER
:
1572 case SQUID_2_5_NTLMSSP
:
1574 nt_status
= ntlm_auth_start_ntlmssp_server(state
, lp_ctx
,
1575 &state
->gensec_state
);
1576 if (!NT_STATUS_IS_OK(nt_status
)) {
1577 x_fprintf(x_stdout
, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status
));
1578 talloc_free(mem_ctx
);
1584 talloc_free(mem_ctx
);
1588 gensec_want_feature_list(state
->gensec_state
, want_feature_list
);
1590 switch (stdio_helper_mode
) {
1591 case GSS_SPNEGO_CLIENT
:
1592 case GSS_SPNEGO_SERVER
:
1593 nt_status
= gensec_start_mech_by_oid(state
->gensec_state
, GENSEC_OID_SPNEGO
);
1598 case NTLMSSP_CLIENT_1
:
1603 case SQUID_2_5_NTLMSSP
:
1604 nt_status
= gensec_start_mech_by_oid(state
->gensec_state
, GENSEC_OID_NTLMSSP
);
1607 talloc_free(mem_ctx
);
1611 if (!NT_STATUS_IS_OK(nt_status
)) {
1612 DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status
)));
1613 x_fprintf(x_stdout
, "BH GENSEC mech failed to start\n");
1614 talloc_free(mem_ctx
);
1622 if (strncmp(buf
, "PW ", 3) == 0) {
1623 state
->set_password
= talloc_strndup(state
,
1624 (const char *)in
.data
,
1627 cli_credentials_set_password(gensec_get_credentials(state
->gensec_state
),
1628 state
->set_password
,
1630 x_fprintf(x_stdout
, "OK\n");
1631 data_blob_free(&in
);
1632 talloc_free(mem_ctx
);
1636 if (strncmp(buf
, "GK", 2) == 0) {
1638 DEBUG(10, ("Requested session key\n"));
1639 nt_status
= gensec_session_key(state
->gensec_state
, mem_ctx
, &session_key
);
1640 if(!NT_STATUS_IS_OK(nt_status
)) {
1641 DEBUG(1, ("gensec_session_key failed: %s\n", nt_errstr(nt_status
)));
1642 x_fprintf(x_stdout
, "BH No session key\n");
1643 talloc_free(mem_ctx
);
1646 base64_key
= base64_encode_data_blob(state
, session_key
);
1647 x_fprintf(x_stdout
, "GK %s\n", base64_key
);
1648 talloc_free(base64_key
);
1650 talloc_free(mem_ctx
);
1654 if (stdio_helper_mode
== SQUID_2_5_NTLMSSP
&& strncmp(buf
, "GF", 2) == 0) {
1657 neg_flags
= gensec_ntlmssp_neg_flags(state
->gensec_state
);
1659 DEBUG(10, ("Requested negotiated feature flags\n"));
1660 x_fprintf(x_stdout
, "GF 0x%08x\n", neg_flags
);
1664 nt_status
= gensec_update(state
->gensec_state
, mem_ctx
, NULL
, in
, &out
);
1666 /* don't leak 'bad password'/'no such user' info to the network client */
1667 nt_status
= nt_status_squash(nt_status
);
1670 out_base64
= base64_encode_data_blob(mem_ctx
, out
);
1675 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1677 if (first
&& state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1679 } else if (state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1681 } else if (state
->gensec_state
->gensec_role
== GENSEC_SERVER
) {
1688 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCESS_DENIED
)) {
1689 reply_code
= "BH NT_STATUS_ACCESS_DENIED";
1690 reply_arg
= nt_errstr(nt_status
);
1691 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1692 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_UNSUCCESSFUL
)) {
1693 reply_code
= "BH NT_STATUS_UNSUCCESSFUL";
1694 reply_arg
= nt_errstr(nt_status
);
1695 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1696 } else if (!NT_STATUS_IS_OK(nt_status
)) {
1698 reply_arg
= nt_errstr(nt_status
);
1699 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1700 } else if /* OK */ (state
->gensec_state
->gensec_role
== GENSEC_SERVER
) {
1701 struct auth_session_info
*session_info
;
1703 nt_status
= gensec_session_info(state
->gensec_state
, mem_ctx
, &session_info
);
1704 if (!NT_STATUS_IS_OK(nt_status
)) {
1705 reply_code
= "BH Failed to retrive session info";
1706 reply_arg
= nt_errstr(nt_status
);
1707 DEBUG(1, ("GENSEC failed to retrieve the session info: %s\n", nt_errstr(nt_status
)));
1711 reply_arg
= session_info
->unix_info
->unix_name
;
1712 talloc_free(session_info
);
1714 } else if (state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1716 reply_arg
= out_base64
;
1721 switch (stdio_helper_mode
) {
1722 case GSS_SPNEGO_SERVER
:
1723 x_fprintf(x_stdout
, "%s %s %s\n", reply_code
,
1724 out_base64
? out_base64
: "*",
1725 reply_arg
? reply_arg
: "*");
1729 x_fprintf(x_stdout
, "%s %s\n", reply_code
, out_base64
);
1730 } else if (reply_arg
) {
1731 x_fprintf(x_stdout
, "%s %s\n", reply_code
, reply_arg
);
1733 x_fprintf(x_stdout
, "%s\n", reply_code
);
1737 talloc_free(mem_ctx
);
1741 static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode
,
1742 struct loadparm_context
*lp_ctx
,
1743 struct ntlm_auth_state
*state
,
1744 char *buf
, int length
, void **private2
)
1746 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1750 static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode
,
1751 struct loadparm_context
*lp_ctx
,
1752 struct ntlm_auth_state
*state
,
1753 char *buf
, int length
, void **private2
)
1755 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1759 static struct ntlmssp_state
*client_ntlmssp_state
= NULL
;
1761 static bool manage_client_ntlmssp_init(struct spnego_data spnego
)
1764 DATA_BLOB null_blob
= data_blob_null
;
1765 DATA_BLOB to_server
;
1766 char *to_server_base64
;
1767 const char *my_mechs
[] = {OID_NTLMSSP
, NULL
};
1768 TALLOC_CTX
*ctx
= talloc_tos();
1770 DEBUG(10, ("Got spnego negTokenInit with NTLMSSP\n"));
1772 if (client_ntlmssp_state
!= NULL
) {
1773 DEBUG(1, ("Request for initial SPNEGO request where "
1774 "we already have a state\n"));
1778 if (!client_ntlmssp_state
) {
1779 if (!NT_STATUS_IS_OK(status
= ntlm_auth_start_ntlmssp_client(&client_ntlmssp_state
))) {
1780 x_fprintf(x_stdout
, "BH %s\n", nt_errstr(status
));
1786 if (opt_password
== NULL
) {
1788 /* Request a password from the calling process. After
1789 sending it, the calling process should retry with
1790 the negTokenInit. */
1792 DEBUG(10, ("Requesting password\n"));
1793 x_fprintf(x_stdout
, "PW\n");
1797 spnego
.type
= SPNEGO_NEG_TOKEN_INIT
;
1798 spnego
.negTokenInit
.mechTypes
= my_mechs
;
1799 spnego
.negTokenInit
.reqFlags
= data_blob_null
;
1800 spnego
.negTokenInit
.reqFlagsPadding
= 0;
1801 spnego
.negTokenInit
.mechListMIC
= null_blob
;
1803 status
= ntlmssp_update(client_ntlmssp_state
, null_blob
,
1804 &spnego
.negTokenInit
.mechToken
);
1806 if ( !(NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
) ||
1807 NT_STATUS_IS_OK(status
)) ) {
1808 DEBUG(1, ("Expected OK or MORE_PROCESSING_REQUIRED, got: %s\n",
1809 nt_errstr(status
)));
1810 TALLOC_FREE(client_ntlmssp_state
);
1814 spnego_write_data(ctx
, &to_server
, &spnego
);
1815 data_blob_free(&spnego
.negTokenInit
.mechToken
);
1817 to_server_base64
= base64_encode_data_blob(talloc_tos(), to_server
);
1818 data_blob_free(&to_server
);
1819 x_fprintf(x_stdout
, "KK %s\n", to_server_base64
);
1820 TALLOC_FREE(to_server_base64
);
1824 static void manage_client_ntlmssp_targ(struct spnego_data spnego
)
1827 DATA_BLOB null_blob
= data_blob_null
;
1829 DATA_BLOB to_server
;
1830 char *to_server_base64
;
1831 TALLOC_CTX
*ctx
= talloc_tos();
1833 DEBUG(10, ("Got spnego negTokenTarg with NTLMSSP\n"));
1835 if (client_ntlmssp_state
== NULL
) {
1836 DEBUG(1, ("Got NTLMSSP tArg without a client state\n"));
1837 x_fprintf(x_stdout
, "BH Got NTLMSSP tArg without a client state\n");
1841 if (spnego
.negTokenTarg
.negResult
== SPNEGO_REJECT
) {
1842 x_fprintf(x_stdout
, "NA\n");
1843 TALLOC_FREE(client_ntlmssp_state
);
1847 if (spnego
.negTokenTarg
.negResult
== SPNEGO_ACCEPT_COMPLETED
) {
1848 x_fprintf(x_stdout
, "AF\n");
1849 TALLOC_FREE(client_ntlmssp_state
);
1853 status
= ntlmssp_update(client_ntlmssp_state
,
1854 spnego
.negTokenTarg
.responseToken
,
1857 if (!NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
) && !NT_STATUS_IS_OK(status
)) {
1858 DEBUG(1, ("Expected MORE_PROCESSING_REQUIRED or OK from "
1859 "ntlmssp_client_update, got: %s\n",
1860 nt_errstr(status
)));
1861 x_fprintf(x_stdout
, "BH Expected MORE_PROCESSING_REQUIRED from "
1862 "ntlmssp_client_update\n");
1863 data_blob_free(&request
);
1864 TALLOC_FREE(client_ntlmssp_state
);
1868 spnego
.type
= SPNEGO_NEG_TOKEN_TARG
;
1869 spnego
.negTokenTarg
.negResult
= SPNEGO_ACCEPT_INCOMPLETE
;
1870 spnego
.negTokenTarg
.supportedMech
= (const char *)OID_NTLMSSP
;
1871 spnego
.negTokenTarg
.responseToken
= request
;
1872 spnego
.negTokenTarg
.mechListMIC
= null_blob
;
1874 spnego_write_data(ctx
, &to_server
, &spnego
);
1875 data_blob_free(&request
);
1877 to_server_base64
= base64_encode_data_blob(talloc_tos(), to_server
);
1878 data_blob_free(&to_server
);
1879 x_fprintf(x_stdout
, "KK %s\n", to_server_base64
);
1880 TALLOC_FREE(to_server_base64
);
1886 static bool manage_client_krb5_init(struct spnego_data spnego
)
1889 DATA_BLOB tkt
, tkt_wrapped
, to_server
;
1890 DATA_BLOB session_key_krb5
= data_blob_null
;
1891 struct spnego_data reply
;
1895 const char *my_mechs
[] = {OID_KERBEROS5_OLD
, NULL
};
1897 TALLOC_CTX
*ctx
= talloc_tos();
1899 principal
= spnego
.negTokenInit
.targetPrincipal
;
1901 /* We may not be allowed to use the server-supplied SPNEGO principal, or it may not have been supplied to us
1903 if (!lp_client_use_spnego_principal() || strequal(principal
, ADS_IGNORE_PRINCIPAL
)) {
1907 if (principal
== NULL
&&
1908 opt_target_service
&& opt_target_hostname
&& !is_ipaddress(opt_target_hostname
)) {
1909 DEBUG(3,("manage_client_krb5_init: using target "
1910 "hostname not SPNEGO principal\n"));
1912 principal
= kerberos_get_principal_from_service_hostname(talloc_tos(),
1914 opt_target_hostname
);
1920 DEBUG(3,("manage_client_krb5_init: guessed "
1921 "server principal=%s\n",
1922 principal
? principal
: "<null>"));
1925 if (principal
== NULL
) {
1926 DEBUG(3,("manage_client_krb5_init: could not guess server principal\n"));
1930 retval
= cli_krb5_get_ticket(ctx
, principal
, 0,
1931 &tkt
, &session_key_krb5
,
1932 0, NULL
, NULL
, NULL
);
1936 /* Let's try to first get the TGT, for that we need a
1939 if (opt_password
== NULL
) {
1940 DEBUG(10, ("Requesting password\n"));
1941 x_fprintf(x_stdout
, "PW\n");
1945 user
= talloc_asprintf(talloc_tos(), "%s@%s", opt_username
, opt_domain
);
1950 if ((retval
= kerberos_kinit_password(user
, opt_password
, 0, NULL
))) {
1951 DEBUG(10, ("Requesting TGT failed: %s\n", error_message(retval
)));
1955 retval
= cli_krb5_get_ticket(ctx
, principal
, 0,
1956 &tkt
, &session_key_krb5
,
1957 0, NULL
, NULL
, NULL
);
1959 DEBUG(10, ("Kinit suceeded, but getting a ticket failed: %s\n", error_message(retval
)));
1965 /* wrap that up in a nice GSS-API wrapping */
1966 tkt_wrapped
= spnego_gen_krb5_wrap(ctx
, tkt
, TOK_ID_KRB_AP_REQ
);
1968 data_blob_free(&session_key_krb5
);
1972 reply
.type
= SPNEGO_NEG_TOKEN_INIT
;
1973 reply
.negTokenInit
.mechTypes
= my_mechs
;
1974 reply
.negTokenInit
.reqFlags
= data_blob_null
;
1975 reply
.negTokenInit
.reqFlagsPadding
= 0;
1976 reply
.negTokenInit
.mechToken
= tkt_wrapped
;
1977 reply
.negTokenInit
.mechListMIC
= data_blob_null
;
1979 len
= spnego_write_data(ctx
, &to_server
, &reply
);
1980 data_blob_free(&tkt
);
1983 DEBUG(1, ("Could not write SPNEGO data blob\n"));
1987 reply_base64
= base64_encode_data_blob(talloc_tos(), to_server
);
1988 x_fprintf(x_stdout
, "KK %s *\n", reply_base64
);
1990 TALLOC_FREE(reply_base64
);
1991 data_blob_free(&to_server
);
1992 DEBUG(10, ("sent GSS-SPNEGO KERBEROS5 negTokenInit\n"));
1996 static void manage_client_krb5_targ(struct spnego_data spnego
)
1998 switch (spnego
.negTokenTarg
.negResult
) {
1999 case SPNEGO_ACCEPT_INCOMPLETE
:
2000 DEBUG(1, ("Got a Kerberos negTokenTarg with ACCEPT_INCOMPLETE\n"));
2001 x_fprintf(x_stdout
, "BH Got a Kerberos negTokenTarg with "
2002 "ACCEPT_INCOMPLETE\n");
2004 case SPNEGO_ACCEPT_COMPLETED
:
2005 DEBUG(10, ("Accept completed\n"));
2006 x_fprintf(x_stdout
, "AF\n");
2009 DEBUG(10, ("Rejected\n"));
2010 x_fprintf(x_stdout
, "NA\n");
2013 DEBUG(1, ("Got an invalid negTokenTarg\n"));
2014 x_fprintf(x_stdout
, "AF\n");
2020 static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode
,
2021 struct loadparm_context
*lp_ctx
,
2022 struct ntlm_auth_state
*state
,
2023 char *buf
, int length
, void **private2
)
2026 struct spnego_data spnego
;
2028 TALLOC_CTX
*ctx
= talloc_tos();
2030 if (!opt_username
|| !*opt_username
) {
2031 x_fprintf(x_stderr
, "username must be specified!\n\n");
2035 if (strlen(buf
) <= 3) {
2036 DEBUG(1, ("SPNEGO query [%s] too short\n", buf
));
2037 x_fprintf(x_stdout
, "BH SPNEGO query too short\n");
2041 request
= base64_decode_data_blob(buf
+3);
2043 if (strncmp(buf
, "PW ", 3) == 0) {
2045 /* We asked for a password and obviously got it :-) */
2047 opt_password
= SMB_STRNDUP((const char *)request
.data
, request
.length
);
2049 if (opt_password
== NULL
) {
2050 DEBUG(1, ("Out of memory\n"));
2051 x_fprintf(x_stdout
, "BH Out of memory\n");
2052 data_blob_free(&request
);
2056 x_fprintf(x_stdout
, "OK\n");
2057 data_blob_free(&request
);
2061 if ( (strncmp(buf
, "TT ", 3) != 0) &&
2062 (strncmp(buf
, "AF ", 3) != 0) &&
2063 (strncmp(buf
, "NA ", 3) != 0) ) {
2064 DEBUG(1, ("SPNEGO request [%s] invalid\n", buf
));
2065 x_fprintf(x_stdout
, "BH SPNEGO request invalid\n");
2066 data_blob_free(&request
);
2070 /* So we got a server challenge to generate a SPNEGO
2071 client-to-server request... */
2073 len
= spnego_read_data(ctx
, request
, &spnego
);
2074 data_blob_free(&request
);
2077 DEBUG(1, ("Could not read SPNEGO data for [%s]\n", buf
));
2078 x_fprintf(x_stdout
, "BH Could not read SPNEGO data\n");
2082 if (spnego
.type
== SPNEGO_NEG_TOKEN_INIT
) {
2084 /* The server offers a list of mechanisms */
2086 const char **mechType
= (const char **)spnego
.negTokenInit
.mechTypes
;
2088 while (*mechType
!= NULL
) {
2091 if ( (strcmp(*mechType
, OID_KERBEROS5_OLD
) == 0) ||
2092 (strcmp(*mechType
, OID_KERBEROS5
) == 0) ) {
2093 if (manage_client_krb5_init(spnego
))
2098 if (strcmp(*mechType
, OID_NTLMSSP
) == 0) {
2099 if (manage_client_ntlmssp_init(spnego
))
2106 DEBUG(1, ("Server offered no compatible mechanism\n"));
2107 x_fprintf(x_stdout
, "BH Server offered no compatible mechanism\n");
2111 if (spnego
.type
== SPNEGO_NEG_TOKEN_TARG
) {
2113 if (spnego
.negTokenTarg
.supportedMech
== NULL
) {
2114 /* On accept/reject Windows does not send the
2115 mechanism anymore. Handle that here and
2116 shut down the mechanisms. */
2118 switch (spnego
.negTokenTarg
.negResult
) {
2119 case SPNEGO_ACCEPT_COMPLETED
:
2120 x_fprintf(x_stdout
, "AF\n");
2123 x_fprintf(x_stdout
, "NA\n");
2126 DEBUG(1, ("Got a negTokenTarg with no mech and an "
2127 "unknown negResult: %d\n",
2128 spnego
.negTokenTarg
.negResult
));
2129 x_fprintf(x_stdout
, "BH Got a negTokenTarg with"
2130 " no mech and an unknown "
2134 TALLOC_FREE(client_ntlmssp_state
);
2138 if (strcmp(spnego
.negTokenTarg
.supportedMech
,
2139 OID_NTLMSSP
) == 0) {
2140 manage_client_ntlmssp_targ(spnego
);
2145 if (strcmp(spnego
.negTokenTarg
.supportedMech
,
2146 OID_KERBEROS5_OLD
) == 0) {
2147 manage_client_krb5_targ(spnego
);
2154 DEBUG(1, ("Got an SPNEGO token I could not handle [%s]!\n", buf
));
2155 x_fprintf(x_stdout
, "BH Got an SPNEGO token I could not handle\n");
2159 spnego_free_data(&spnego
);
2163 static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode
,
2164 struct loadparm_context
*lp_ctx
,
2165 struct ntlm_auth_state
*state
,
2166 char *buf
, int length
, void **private2
)
2168 char *request
, *parameter
;
2169 static DATA_BLOB challenge
;
2170 static DATA_BLOB lm_response
;
2171 static DATA_BLOB nt_response
;
2172 static char *full_username
;
2173 static char *username
;
2174 static char *domain
;
2175 static char *plaintext_password
;
2176 static bool ntlm_server_1_user_session_key
;
2177 static bool ntlm_server_1_lm_session_key
;
2179 if (strequal(buf
, ".")) {
2180 if (!full_username
&& !username
) {
2181 x_fprintf(x_stdout
, "Error: No username supplied!\n");
2182 } else if (plaintext_password
) {
2183 /* handle this request as plaintext */
2184 if (!full_username
) {
2185 if (asprintf(&full_username
, "%s%c%s", domain
, winbind_separator(), username
) == -1) {
2186 x_fprintf(x_stdout
, "Error: Out of memory in asprintf!\n.\n");
2190 if (check_plaintext_auth(full_username
, plaintext_password
, False
)) {
2191 x_fprintf(x_stdout
, "Authenticated: Yes\n");
2193 x_fprintf(x_stdout
, "Authenticated: No\n");
2195 } else if (!lm_response
.data
&& !nt_response
.data
) {
2196 x_fprintf(x_stdout
, "Error: No password supplied!\n");
2197 } else if (!challenge
.data
) {
2198 x_fprintf(x_stdout
, "Error: No lanman-challenge supplied!\n");
2200 char *error_string
= NULL
;
2202 uchar user_session_key
[16];
2205 if (full_username
&& !username
) {
2207 fstring fstr_domain
;
2209 if (!parse_ntlm_auth_domain_user(full_username
, fstr_user
, fstr_domain
)) {
2210 /* username might be 'tainted', don't print into our new-line deleimianted stream */
2211 x_fprintf(x_stdout
, "Error: Could not parse into domain and username\n");
2213 SAFE_FREE(username
);
2215 username
= smb_xstrdup(fstr_user
);
2216 domain
= smb_xstrdup(fstr_domain
);
2220 domain
= smb_xstrdup(get_winbind_domain());
2223 if (ntlm_server_1_lm_session_key
)
2224 flags
|= WBFLAG_PAM_LMKEY
;
2226 if (ntlm_server_1_user_session_key
)
2227 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
2229 if (!NT_STATUS_IS_OK(
2230 contact_winbind_auth_crap(username
,
2242 x_fprintf(x_stdout
, "Authenticated: No\n");
2243 x_fprintf(x_stdout
, "Authentication-Error: %s\n.\n", error_string
);
2245 static char zeros
[16];
2247 char *hex_user_session_key
;
2249 x_fprintf(x_stdout
, "Authenticated: Yes\n");
2251 if (ntlm_server_1_lm_session_key
2252 && (memcmp(zeros
, lm_key
,
2253 sizeof(lm_key
)) != 0)) {
2254 hex_lm_key
= hex_encode_talloc(NULL
,
2255 (const unsigned char *)lm_key
,
2257 x_fprintf(x_stdout
, "LANMAN-Session-Key: %s\n", hex_lm_key
);
2258 TALLOC_FREE(hex_lm_key
);
2261 if (ntlm_server_1_user_session_key
2262 && (memcmp(zeros
, user_session_key
,
2263 sizeof(user_session_key
)) != 0)) {
2264 hex_user_session_key
= hex_encode_talloc(NULL
,
2265 (const unsigned char *)user_session_key
,
2266 sizeof(user_session_key
));
2267 x_fprintf(x_stdout
, "User-Session-Key: %s\n", hex_user_session_key
);
2268 TALLOC_FREE(hex_user_session_key
);
2271 SAFE_FREE(error_string
);
2273 /* clear out the state */
2274 challenge
= data_blob_null
;
2275 nt_response
= data_blob_null
;
2276 lm_response
= data_blob_null
;
2277 SAFE_FREE(full_username
);
2278 SAFE_FREE(username
);
2280 SAFE_FREE(plaintext_password
);
2281 ntlm_server_1_user_session_key
= False
;
2282 ntlm_server_1_lm_session_key
= False
;
2283 x_fprintf(x_stdout
, ".\n");
2290 /* Indicates a base64 encoded structure */
2291 parameter
= strstr_m(request
, ":: ");
2293 parameter
= strstr_m(request
, ": ");
2296 DEBUG(0, ("Parameter not found!\n"));
2297 x_fprintf(x_stdout
, "Error: Parameter not found!\n.\n");
2314 base64_decode_inplace(parameter
);
2317 if (strequal(request
, "LANMAN-Challenge")) {
2318 challenge
= strhex_to_data_blob(NULL
, parameter
);
2319 if (challenge
.length
!= 8) {
2320 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (got %d bytes, expected 8)\n.\n",
2322 (int)challenge
.length
);
2323 challenge
= data_blob_null
;
2325 } else if (strequal(request
, "NT-Response")) {
2326 nt_response
= strhex_to_data_blob(NULL
, parameter
);
2327 if (nt_response
.length
< 24) {
2328 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (only got %d bytes, needed at least 24)\n.\n",
2330 (int)nt_response
.length
);
2331 nt_response
= data_blob_null
;
2333 } else if (strequal(request
, "LANMAN-Response")) {
2334 lm_response
= strhex_to_data_blob(NULL
, parameter
);
2335 if (lm_response
.length
!= 24) {
2336 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (got %d bytes, expected 24)\n.\n",
2338 (int)lm_response
.length
);
2339 lm_response
= data_blob_null
;
2341 } else if (strequal(request
, "Password")) {
2342 plaintext_password
= smb_xstrdup(parameter
);
2343 } else if (strequal(request
, "NT-Domain")) {
2344 domain
= smb_xstrdup(parameter
);
2345 } else if (strequal(request
, "Username")) {
2346 username
= smb_xstrdup(parameter
);
2347 } else if (strequal(request
, "Full-Username")) {
2348 full_username
= smb_xstrdup(parameter
);
2349 } else if (strequal(request
, "Request-User-Session-Key")) {
2350 ntlm_server_1_user_session_key
= strequal(parameter
, "Yes");
2351 } else if (strequal(request
, "Request-LanMan-Session-Key")) {
2352 ntlm_server_1_lm_session_key
= strequal(parameter
, "Yes");
2354 x_fprintf(x_stdout
, "Error: Unknown request %s\n.\n", request
);
2358 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode
,
2359 struct loadparm_context
*lp_ctx
,
2360 struct ntlm_auth_state
*state
,
2361 char *buf
, int length
, void **private2
)
2363 char *request
, *parameter
;
2364 static DATA_BLOB new_nt_pswd
;
2365 static DATA_BLOB old_nt_hash_enc
;
2366 static DATA_BLOB new_lm_pswd
;
2367 static DATA_BLOB old_lm_hash_enc
;
2368 static char *full_username
= NULL
;
2369 static char *username
= NULL
;
2370 static char *domain
= NULL
;
2371 static char *newpswd
= NULL
;
2372 static char *oldpswd
= NULL
;
2374 if (strequal(buf
, ".")) {
2375 if(newpswd
&& oldpswd
) {
2376 uchar old_nt_hash
[16];
2377 uchar old_lm_hash
[16];
2378 uchar new_nt_hash
[16];
2379 uchar new_lm_hash
[16];
2381 new_nt_pswd
= data_blob(NULL
, 516);
2382 old_nt_hash_enc
= data_blob(NULL
, 16);
2384 /* Calculate the MD4 hash (NT compatible) of the
2386 E_md4hash(oldpswd
, old_nt_hash
);
2387 E_md4hash(newpswd
, new_nt_hash
);
2389 /* E_deshash returns false for 'long'
2390 passwords (> 14 DOS chars).
2392 Therefore, don't send a buffer
2393 encrypted with the truncated hash
2394 (it could allow an even easier
2395 attack on the password)
2397 Likewise, obey the admin's restriction
2400 if (lp_client_lanman_auth() &&
2401 E_deshash(newpswd
, new_lm_hash
) &&
2402 E_deshash(oldpswd
, old_lm_hash
)) {
2403 new_lm_pswd
= data_blob(NULL
, 516);
2404 old_lm_hash_enc
= data_blob(NULL
, 16);
2405 encode_pw_buffer(new_lm_pswd
.data
, newpswd
,
2408 arcfour_crypt(new_lm_pswd
.data
, old_nt_hash
, 516);
2409 E_old_pw_hash(new_nt_hash
, old_lm_hash
,
2410 old_lm_hash_enc
.data
);
2412 new_lm_pswd
.data
= NULL
;
2413 new_lm_pswd
.length
= 0;
2414 old_lm_hash_enc
.data
= NULL
;
2415 old_lm_hash_enc
.length
= 0;
2418 encode_pw_buffer(new_nt_pswd
.data
, newpswd
,
2421 arcfour_crypt(new_nt_pswd
.data
, old_nt_hash
, 516);
2422 E_old_pw_hash(new_nt_hash
, old_nt_hash
,
2423 old_nt_hash_enc
.data
);
2426 if (!full_username
&& !username
) {
2427 x_fprintf(x_stdout
, "Error: No username supplied!\n");
2428 } else if ((!new_nt_pswd
.data
|| !old_nt_hash_enc
.data
) &&
2429 (!new_lm_pswd
.data
|| old_lm_hash_enc
.data
) ) {
2430 x_fprintf(x_stdout
, "Error: No NT or LM password "
2431 "blobs supplied!\n");
2433 char *error_string
= NULL
;
2435 if (full_username
&& !username
) {
2437 fstring fstr_domain
;
2439 if (!parse_ntlm_auth_domain_user(full_username
,
2442 /* username might be 'tainted', don't
2443 * print into our new-line
2444 * deleimianted stream */
2445 x_fprintf(x_stdout
, "Error: Could not "
2446 "parse into domain and "
2448 SAFE_FREE(username
);
2449 username
= smb_xstrdup(full_username
);
2451 SAFE_FREE(username
);
2453 username
= smb_xstrdup(fstr_user
);
2454 domain
= smb_xstrdup(fstr_domain
);
2459 if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
2466 x_fprintf(x_stdout
, "Password-Change: No\n");
2467 x_fprintf(x_stdout
, "Password-Change-Error: "
2468 "%s\n.\n", error_string
);
2470 x_fprintf(x_stdout
, "Password-Change: Yes\n");
2473 SAFE_FREE(error_string
);
2475 /* clear out the state */
2476 new_nt_pswd
= data_blob_null
;
2477 old_nt_hash_enc
= data_blob_null
;
2478 new_lm_pswd
= data_blob_null
;
2479 old_nt_hash_enc
= data_blob_null
;
2480 SAFE_FREE(full_username
);
2481 SAFE_FREE(username
);
2485 x_fprintf(x_stdout
, ".\n");
2492 /* Indicates a base64 encoded structure */
2493 parameter
= strstr_m(request
, ":: ");
2495 parameter
= strstr_m(request
, ": ");
2498 DEBUG(0, ("Parameter not found!\n"));
2499 x_fprintf(x_stdout
, "Error: Parameter not found!\n.\n");
2515 base64_decode_inplace(parameter
);
2518 if (strequal(request
, "new-nt-password-blob")) {
2519 new_nt_pswd
= strhex_to_data_blob(NULL
, parameter
);
2520 if (new_nt_pswd
.length
!= 516) {
2521 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2522 "(got %d bytes, expected 516)\n.\n",
2524 (int)new_nt_pswd
.length
);
2525 new_nt_pswd
= data_blob_null
;
2527 } else if (strequal(request
, "old-nt-hash-blob")) {
2528 old_nt_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2529 if (old_nt_hash_enc
.length
!= 16) {
2530 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2531 "(got %d bytes, expected 16)\n.\n",
2533 (int)old_nt_hash_enc
.length
);
2534 old_nt_hash_enc
= data_blob_null
;
2536 } else if (strequal(request
, "new-lm-password-blob")) {
2537 new_lm_pswd
= strhex_to_data_blob(NULL
, parameter
);
2538 if (new_lm_pswd
.length
!= 516) {
2539 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2540 "(got %d bytes, expected 516)\n.\n",
2542 (int)new_lm_pswd
.length
);
2543 new_lm_pswd
= data_blob_null
;
2546 else if (strequal(request
, "old-lm-hash-blob")) {
2547 old_lm_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2548 if (old_lm_hash_enc
.length
!= 16)
2550 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2551 "(got %d bytes, expected 16)\n.\n",
2553 (int)old_lm_hash_enc
.length
);
2554 old_lm_hash_enc
= data_blob_null
;
2556 } else if (strequal(request
, "nt-domain")) {
2557 domain
= smb_xstrdup(parameter
);
2558 } else if(strequal(request
, "username")) {
2559 username
= smb_xstrdup(parameter
);
2560 } else if(strequal(request
, "full-username")) {
2561 username
= smb_xstrdup(parameter
);
2562 } else if(strequal(request
, "new-password")) {
2563 newpswd
= smb_xstrdup(parameter
);
2564 } else if (strequal(request
, "old-password")) {
2565 oldpswd
= smb_xstrdup(parameter
);
2567 x_fprintf(x_stdout
, "Error: Unknown request %s\n.\n", request
);
2571 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode
,
2572 struct loadparm_context
*lp_ctx
,
2573 struct ntlm_auth_state
*state
,
2574 stdio_helper_function fn
, void **private2
)
2577 char tmp
[INITIAL_BUFFER_SIZE
+1];
2578 int length
, buf_size
= 0;
2581 buf
= talloc_strdup(state
->mem_ctx
, "");
2583 DEBUG(0, ("Failed to allocate input buffer.\n"));
2584 x_fprintf(x_stderr
, "ERR\n");
2590 /* this is not a typo - x_fgets doesn't work too well under
2592 if (fgets(tmp
, sizeof(tmp
)-1, stdin
) == NULL
) {
2593 if (ferror(stdin
)) {
2594 DEBUG(1, ("fgets() failed! dying..... errno=%d "
2595 "(%s)\n", ferror(stdin
),
2596 strerror(ferror(stdin
))));
2603 buf
= talloc_strdup_append_buffer(buf
, tmp
);
2604 buf_size
+= INITIAL_BUFFER_SIZE
;
2606 if (buf_size
> MAX_BUFFER_SIZE
) {
2607 DEBUG(2, ("Oversized message\n"));
2608 x_fprintf(x_stderr
, "ERR\n");
2613 c
= strchr(buf
, '\n');
2614 } while (c
== NULL
);
2619 DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf
,length
));
2621 if (buf
[0] == '\0') {
2622 DEBUG(2, ("Invalid Request\n"));
2623 x_fprintf(x_stderr
, "ERR\n");
2628 fn(stdio_helper_mode
, lp_ctx
, state
, buf
, length
, private2
);
2633 static void squid_stream(enum stdio_helper_mode stdio_mode
,
2634 struct loadparm_context
*lp_ctx
,
2635 stdio_helper_function fn
) {
2636 TALLOC_CTX
*mem_ctx
;
2637 struct ntlm_auth_state
*state
;
2639 /* initialize FDescs */
2640 x_setbuf(x_stdout
, NULL
);
2641 x_setbuf(x_stderr
, NULL
);
2643 mem_ctx
= talloc_init("ntlm_auth");
2645 DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
2646 x_fprintf(x_stderr
, "ERR\n");
2650 state
= talloc_zero(mem_ctx
, struct ntlm_auth_state
);
2652 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
2653 x_fprintf(x_stderr
, "ERR\n");
2657 state
->mem_ctx
= mem_ctx
;
2658 state
->helper_mode
= stdio_mode
;
2661 TALLOC_CTX
*frame
= talloc_stackframe();
2662 manage_squid_request(stdio_mode
, lp_ctx
, state
, fn
, NULL
);
2668 /* Authenticate a user with a challenge/response */
2670 static bool check_auth_crap(void)
2675 char user_session_key
[16];
2677 char *hex_user_session_key
;
2679 static uint8 zeros
[16];
2681 x_setbuf(x_stdout
, NULL
);
2684 flags
|= WBFLAG_PAM_LMKEY
;
2686 if (request_user_session_key
)
2687 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
2689 flags
|= WBFLAG_PAM_NT_STATUS_SQUASH
;
2691 nt_status
= contact_winbind_auth_crap(opt_username
, opt_domain
,
2697 (unsigned char *)lm_key
,
2698 (unsigned char *)user_session_key
,
2699 &error_string
, NULL
);
2701 if (!NT_STATUS_IS_OK(nt_status
)) {
2702 x_fprintf(x_stdout
, "%s (0x%x)\n",
2704 NT_STATUS_V(nt_status
));
2705 SAFE_FREE(error_string
);
2710 && (memcmp(zeros
, lm_key
,
2711 sizeof(lm_key
)) != 0)) {
2712 hex_lm_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)lm_key
,
2714 x_fprintf(x_stdout
, "LM_KEY: %s\n", hex_lm_key
);
2715 TALLOC_FREE(hex_lm_key
);
2717 if (request_user_session_key
2718 && (memcmp(zeros
, user_session_key
,
2719 sizeof(user_session_key
)) != 0)) {
2720 hex_user_session_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)user_session_key
,
2721 sizeof(user_session_key
));
2722 x_fprintf(x_stdout
, "NT_KEY: %s\n", hex_user_session_key
);
2723 TALLOC_FREE(hex_user_session_key
);
2732 OPT_USERNAME
= 1000,
2741 OPT_USER_SESSION_KEY
,
2743 OPT_REQUIRE_MEMBERSHIP
,
2744 OPT_USE_CACHED_CREDS
,
2745 OPT_PAM_WINBIND_CONF
,
2750 int main(int argc
, const char **argv
)
2752 TALLOC_CTX
*frame
= talloc_stackframe();
2754 static const char *helper_protocol
;
2755 static int diagnostics
;
2757 static const char *hex_challenge
;
2758 static const char *hex_lm_response
;
2759 static const char *hex_nt_response
;
2760 struct loadparm_context
*lp_ctx
;
2763 /* NOTE: DO NOT change this interface without considering the implications!
2764 This is an external interface, which other programs will use to interact
2768 /* We do not use single-letter command abbreviations, because they harm future
2769 interface stability. */
2771 struct poptOption long_options
[] = {
2773 { "helper-protocol", 0, POPT_ARG_STRING
, &helper_protocol
, OPT_DOMAIN
, "operate as a stdio-based helper", "helper protocol to use"},
2774 { "username", 0, POPT_ARG_STRING
, &opt_username
, OPT_USERNAME
, "username"},
2775 { "domain", 0, POPT_ARG_STRING
, &opt_domain
, OPT_DOMAIN
, "domain name"},
2776 { "workstation", 0, POPT_ARG_STRING
, &opt_workstation
, OPT_WORKSTATION
, "workstation"},
2777 { "challenge", 0, POPT_ARG_STRING
, &hex_challenge
, OPT_CHALLENGE
, "challenge (HEX encoded)"},
2778 { "lm-response", 0, POPT_ARG_STRING
, &hex_lm_response
, OPT_LM
, "LM Response to the challenge (HEX encoded)"},
2779 { "nt-response", 0, POPT_ARG_STRING
, &hex_nt_response
, OPT_NT
, "NT or NTLMv2 Response to the challenge (HEX encoded)"},
2780 { "password", 0, POPT_ARG_STRING
, &opt_password
, OPT_PASSWORD
, "User's plaintext password"},
2781 { "request-lm-key", 0, POPT_ARG_NONE
, &request_lm_key
, OPT_LM_KEY
, "Retrieve LM session key"},
2782 { "request-nt-key", 0, POPT_ARG_NONE
, &request_user_session_key
, OPT_USER_SESSION_KEY
, "Retrieve User (NT) session key"},
2783 { "use-cached-creds", 0, POPT_ARG_NONE
, &use_cached_creds
, OPT_USE_CACHED_CREDS
, "Use cached credentials if no password is given"},
2784 { "diagnostics", 0, POPT_ARG_NONE
, &diagnostics
,
2786 "Perform diagnostics on the authentication chain"},
2787 { "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" },
2788 { "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" },
2789 { "target-service", 0, POPT_ARG_STRING
, &opt_target_service
, OPT_TARGET_SERVICE
, "Target service (eg http)" },
2790 { "target-hostname", 0, POPT_ARG_STRING
, &opt_target_hostname
, OPT_TARGET_HOSTNAME
, "Target hostname" },
2791 POPT_COMMON_CONFIGFILE
2796 /* Samba client initialisation */
2799 setup_logging("ntlm_auth", DEBUG_STDERR
);
2803 pc
= poptGetContext("ntlm_auth", argc
, argv
, long_options
, 0);
2805 /* Parse command line options */
2808 poptPrintHelp(pc
, stderr
, 0);
2812 while((opt
= poptGetNextOpt(pc
)) != -1) {
2813 /* Get generic config options like --configfile */
2816 poptFreeContext(pc
);
2818 if (!lp_load_global(get_dyn_CONFIGFILE())) {
2819 d_fprintf(stderr
, "ntlm_auth: error opening config file %s. Error was %s\n",
2820 get_dyn_CONFIGFILE(), strerror(errno
));
2824 pc
= poptGetContext(NULL
, argc
, (const char **)argv
, long_options
,
2825 POPT_CONTEXT_KEEP_FIRST
);
2827 while((opt
= poptGetNextOpt(pc
)) != -1) {
2830 opt_challenge
= strhex_to_data_blob(NULL
, hex_challenge
);
2831 if (opt_challenge
.length
!= 8) {
2832 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2834 (int)opt_challenge
.length
);
2839 opt_lm_response
= strhex_to_data_blob(NULL
, hex_lm_response
);
2840 if (opt_lm_response
.length
!= 24) {
2841 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2843 (int)opt_lm_response
.length
);
2849 opt_nt_response
= strhex_to_data_blob(NULL
, hex_nt_response
);
2850 if (opt_nt_response
.length
< 24) {
2851 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2853 (int)opt_nt_response
.length
);
2858 case OPT_REQUIRE_MEMBERSHIP
:
2859 if (strncasecmp_m("S-", require_membership_of
, 2) == 0) {
2860 require_membership_of_sid
= require_membership_of
;
2867 char *domain
= SMB_STRDUP(opt_username
);
2868 char *p
= strchr_m(domain
, *lp_winbind_separator());
2872 if (opt_domain
&& !strequal(opt_domain
, domain
)) {
2873 x_fprintf(x_stderr
, "Domain specified in username (%s) "
2874 "doesn't match specified domain (%s)!\n\n",
2875 domain
, opt_domain
);
2876 poptPrintHelp(pc
, stderr
, 0);
2879 opt_domain
= domain
;
2885 /* Note: if opt_domain is "" then send no domain */
2886 if (opt_domain
== NULL
) {
2887 opt_domain
= get_winbind_domain();
2890 if (opt_workstation
== NULL
) {
2891 opt_workstation
= "";
2894 lp_ctx
= loadparm_init_s3(NULL
, loadparm_s3_context());
2895 if (lp_ctx
== NULL
) {
2896 x_fprintf(x_stderr
, "loadparm_init_s3() failed!\n");
2900 if (helper_protocol
) {
2902 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2903 if (strcmp(helper_protocol
, stdio_helper_protocols
[i
].name
) == 0) {
2904 squid_stream(stdio_helper_protocols
[i
].mode
, lp_ctx
, stdio_helper_protocols
[i
].fn
);
2908 x_fprintf(x_stderr
, "unknown helper protocol [%s]\n\nValid helper protools:\n\n", helper_protocol
);
2910 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2911 x_fprintf(x_stderr
, "%s\n", stdio_helper_protocols
[i
].name
);
2917 if (!opt_username
|| !*opt_username
) {
2918 x_fprintf(x_stderr
, "username must be specified!\n\n");
2919 poptPrintHelp(pc
, stderr
, 0);
2923 if (opt_challenge
.length
) {
2924 if (!check_auth_crap()) {
2930 if (!opt_password
) {
2931 opt_password
= getpass("password: ");
2935 if (!diagnose_ntlm_auth()) {
2941 fstr_sprintf(user
, "%s%c%s", opt_domain
, winbind_separator(), opt_username
);
2942 if (!check_plaintext_auth(user
, opt_password
, True
)) {
2949 poptFreeContext(pc
);