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 "libcli/security/security.h"
31 #include "utils/ntlm_auth.h"
32 #include "../libcli/auth/libcli_auth.h"
33 #include "auth/ntlmssp/ntlmssp.h"
34 #include "auth/gensec/gensec.h"
35 #include "auth/gensec/gensec_internal.h"
36 #include "auth/credentials/credentials.h"
37 #include "librpc/crypto/gse.h"
39 #include "lib/util/tiniparser.h"
40 #include "../lib/crypto/arcfour.h"
41 #include "nsswitch/winbind_client.h"
42 #include "librpc/gen_ndr/krb5pac.h"
43 #include "../lib/util/asn1.h"
44 #include "auth/common_auth.h"
45 #include "source3/include/auth.h"
46 #include "source3/auth/proto.h"
47 #include "nsswitch/libwbclient/wbclient.h"
48 #include "lib/param/loadparm.h"
49 #include "lib/util/base64.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_gensec_request(enum stdio_helper_mode stdio_helper_mode
,
104 struct loadparm_context
*lp_ctx
,
105 char *buf
, int length
, void **private1
);
107 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode
,
108 struct loadparm_context
*lp_ctx
,
109 struct ntlm_auth_state
*state
,
110 stdio_helper_function fn
, void **private2
);
112 static void manage_squid_basic_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_squid_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode
,
118 struct loadparm_context
*lp_ctx
,
119 struct ntlm_auth_state
*state
,
120 char *buf
, int length
, void **private2
);
122 static void manage_client_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode
,
123 struct loadparm_context
*lp_ctx
,
124 struct ntlm_auth_state
*state
,
125 char *buf
, int length
, void **private2
);
127 static void manage_gss_spnego_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_gss_spnego_client_request (enum stdio_helper_mode stdio_helper_mode
,
133 struct loadparm_context
*lp_ctx
,
134 struct ntlm_auth_state
*state
,
135 char *buf
, int length
, void **private2
);
137 static void manage_ntlm_server_1_request (enum stdio_helper_mode stdio_helper_mode
,
138 struct loadparm_context
*lp_ctx
,
139 struct ntlm_auth_state
*state
,
140 char *buf
, int length
, void **private2
);
142 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode
,
143 struct loadparm_context
*lp_ctx
,
144 struct ntlm_auth_state
*state
,
145 char *buf
, int length
, void **private2
);
147 static const struct {
148 enum stdio_helper_mode mode
;
150 stdio_helper_function fn
;
151 } stdio_helper_protocols
[] = {
152 { SQUID_2_4_BASIC
, "squid-2.4-basic", manage_squid_basic_request
},
153 { SQUID_2_5_BASIC
, "squid-2.5-basic", manage_squid_basic_request
},
154 { SQUID_2_5_NTLMSSP
, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request
},
155 { NTLMSSP_CLIENT_1
, "ntlmssp-client-1", manage_client_ntlmssp_request
},
156 { GSS_SPNEGO_SERVER
, "gss-spnego", manage_gss_spnego_request
},
157 { GSS_SPNEGO_CLIENT
, "gss-spnego-client", manage_gss_spnego_client_request
},
158 { NTLM_SERVER_1
, "ntlm-server-1", manage_ntlm_server_1_request
},
159 { NTLM_CHANGE_PASSWORD_1
, "ntlm-change-password-1", manage_ntlm_change_password_1_request
},
160 { NUM_HELPER_MODES
, NULL
, NULL
}
163 const char *opt_username
;
164 const char *opt_domain
;
165 const char *opt_workstation
;
166 const char *opt_password
;
167 static DATA_BLOB opt_challenge
;
168 static DATA_BLOB opt_lm_response
;
169 static DATA_BLOB opt_nt_response
;
170 static int request_lm_key
;
171 static int request_user_session_key
;
172 static int use_cached_creds
;
173 static int offline_logon
;
174 static int opt_allow_mschapv2
;
176 static const char *require_membership_of
;
177 static const char *require_membership_of_sid
;
178 static const char *opt_pam_winbind_conf
;
180 const char *opt_target_service
;
181 const char *opt_target_hostname
;
184 /* This is a bit hairy, but the basic idea is to do a password callback
185 to the calling application. The callback comes from within gensec */
187 static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mode
,
188 struct loadparm_context
*lp_ctx
,
189 struct ntlm_auth_state
*state
, char *buf
, int length
,
193 if (strlen(buf
) < 2) {
194 DEBUG(1, ("query [%s] invalid", buf
));
195 printf("BH Query invalid\n");
199 if (strlen(buf
) > 3) {
200 in
= base64_decode_data_blob(buf
+ 3);
202 in
= data_blob(NULL
, 0);
205 if (strncmp(buf
, "PW ", 3) == 0) {
207 *password
= talloc_strndup(NULL
,
208 (const char *)in
.data
, in
.length
);
210 if (*password
== NULL
) {
211 DEBUG(1, ("Out of memory\n"));
212 printf("BH Out of memory\n");
221 DEBUG(1, ("Asked for (and expected) a password\n"));
222 printf("BH Expected a password\n");
227 * Callback for password credentials. This is not async, and when
228 * GENSEC and the credentials code is made async, it will look rather
232 static const char *get_password(struct cli_credentials
*credentials
)
234 TALLOC_CTX
*frame
= talloc_stackframe();
235 char *password
= NULL
;
236 struct ntlm_auth_state
*state
;
238 state
= talloc_zero(frame
, struct ntlm_auth_state
);
240 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
241 fprintf(stderr
, "ERR\n");
245 state
->mem_ctx
= state
;
247 /* Ask for a password */
250 manage_squid_request(NUM_HELPER_MODES
/* bogus */, NULL
, state
, manage_gensec_get_pw_request
, (void **)&password
);
251 talloc_steal(credentials
, password
);
257 * A limited set of features are defined with text strings as needed
261 static void gensec_want_feature_list(struct gensec_security
*state
, char* feature_list
)
263 if (in_list("NTLMSSP_FEATURE_SESSION_KEY", feature_list
, true)) {
264 DEBUG(10, ("want GENSEC_FEATURE_SESSION_KEY\n"));
265 gensec_want_feature(state
, GENSEC_FEATURE_SESSION_KEY
);
267 if (in_list("NTLMSSP_FEATURE_SIGN", feature_list
, true)) {
268 DEBUG(10, ("want GENSEC_FEATURE_SIGN\n"));
269 gensec_want_feature(state
, GENSEC_FEATURE_SIGN
);
271 if (in_list("NTLMSSP_FEATURE_SEAL", feature_list
, true)) {
272 DEBUG(10, ("want GENSEC_FEATURE_SEAL\n"));
273 gensec_want_feature(state
, GENSEC_FEATURE_SEAL
);
275 if (in_list("NTLMSSP_FEATURE_CCACHE", feature_list
, true)) {
276 DEBUG(10, ("want GENSEC_FEATURE_NTLM_CCACHE\n"));
277 gensec_want_feature(state
, GENSEC_FEATURE_NTLM_CCACHE
);
281 static char winbind_separator(void)
283 struct wbcInterfaceDetails
*details
;
291 ret
= wbcInterfaceDetails(&details
);
292 if (!WBC_ERROR_IS_OK(ret
)) {
293 d_fprintf(stderr
, "could not obtain winbind separator!\n");
294 return *lp_winbind_separator();
297 sep
= details
->winbind_separator
;
299 wbcFreeMemory(details
);
304 d_fprintf(stderr
, "winbind separator was NULL!\n");
305 return *lp_winbind_separator();
311 const char *get_winbind_domain(void)
313 struct wbcInterfaceDetails
*details
;
316 static fstring winbind_domain
;
317 if (*winbind_domain
) {
318 return winbind_domain
;
321 /* Send off request */
323 ret
= wbcInterfaceDetails(&details
);
324 if (!WBC_ERROR_IS_OK(ret
)) {
325 DEBUG(1, ("could not obtain winbind domain name!\n"));
326 return lp_workgroup();
329 fstrcpy(winbind_domain
, details
->netbios_domain
);
331 wbcFreeMemory(details
);
333 return winbind_domain
;
337 const char *get_winbind_netbios_name(void)
339 struct wbcInterfaceDetails
*details
;
342 static fstring winbind_netbios_name
;
344 if (*winbind_netbios_name
) {
345 return winbind_netbios_name
;
348 /* Send off request */
350 ret
= wbcInterfaceDetails(&details
);
351 if (!WBC_ERROR_IS_OK(ret
)) {
352 DEBUG(1, ("could not obtain winbind netbios name!\n"));
353 return lp_netbios_name();
356 fstrcpy(winbind_netbios_name
, details
->netbios_name
);
358 wbcFreeMemory(details
);
360 return winbind_netbios_name
;
364 DATA_BLOB
get_challenge(void)
366 static DATA_BLOB chal
;
367 if (opt_challenge
.length
)
368 return opt_challenge
;
370 chal
= data_blob(NULL
, 8);
372 generate_random_buffer(chal
.data
, chal
.length
);
376 /* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
377 form DOMAIN/user into a domain and a user */
379 static bool parse_ntlm_auth_domain_user(const char *domuser
, fstring domain
,
383 char *p
= strchr(domuser
,winbind_separator());
390 fstrcpy(domain
, domuser
);
391 domain
[PTR_DIFF(p
, domuser
)] = 0;
392 return strupper_m(domain
);
395 static bool get_require_membership_sid(void) {
396 fstring domain
, name
, sidbuf
;
397 struct wbcDomainSid sid
;
398 enum wbcSidType type
;
401 if (!require_membership_of
) {
405 if (require_membership_of_sid
) {
409 /* Otherwise, ask winbindd for the name->sid request */
411 if (!parse_ntlm_auth_domain_user(require_membership_of
,
413 DEBUG(0, ("Could not parse %s into separate domain/name parts!\n",
414 require_membership_of
));
418 ret
= wbcLookupName(domain
, name
, &sid
, &type
);
419 if (!WBC_ERROR_IS_OK(ret
)) {
420 DEBUG(0, ("Winbindd lookupname failed to resolve %s into a SID!\n",
421 require_membership_of
));
425 wbcSidToStringBuf(&sid
, sidbuf
, sizeof(sidbuf
));
427 require_membership_of_sid
= SMB_STRDUP(sidbuf
);
429 if (require_membership_of_sid
)
436 * Get some configuration from pam_winbind.conf to see if we
437 * need to contact trusted domain
440 int get_pam_winbind_config()
443 struct tiniparser_dictionary
*d
= NULL
;
445 if (!opt_pam_winbind_conf
|| !*opt_pam_winbind_conf
) {
446 opt_pam_winbind_conf
= PAM_WINBIND_CONFIG_FILE
;
449 d
= tiniparser_load(opt_pam_winbind_conf
);
455 if (tiniparser_getboolean(d
, "global:krb5_auth", false)) {
456 ctrl
|= WINBIND_KRB5_AUTH
;
459 tiniparser_freedict(d
);
464 /* Authenticate a user with a plaintext password */
466 static bool check_plaintext_auth(const char *user
, const char *pass
,
467 bool stdout_diagnostics
)
469 struct winbindd_request request
;
470 struct winbindd_response response
;
473 if (!get_require_membership_sid()) {
477 /* Send off request */
479 ZERO_STRUCT(request
);
480 ZERO_STRUCT(response
);
482 fstrcpy(request
.data
.auth
.user
, user
);
483 fstrcpy(request
.data
.auth
.pass
, pass
);
484 if (require_membership_of_sid
) {
485 strlcpy(request
.data
.auth
.require_membership_of_sid
,
486 require_membership_of_sid
,
487 sizeof(request
.data
.auth
.require_membership_of_sid
));
491 request
.flags
|= WBFLAG_PAM_CACHED_LOGIN
;
494 result
= winbindd_request_response(NULL
, WINBINDD_PAM_AUTH
, &request
, &response
);
496 /* Display response */
498 if (stdout_diagnostics
) {
499 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
500 d_fprintf(stderr
, "Reading winbind reply failed! (0x01)\n");
503 d_printf("%s: %s (0x%x)\n",
504 response
.data
.auth
.nt_status_string
,
505 response
.data
.auth
.error_string
,
506 response
.data
.auth
.nt_status
);
508 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
509 DEBUG(1, ("Reading winbind reply failed! (0x01)\n"));
512 DEBUG(3, ("%s: %s (0x%x)\n",
513 response
.data
.auth
.nt_status_string
,
514 response
.data
.auth
.error_string
,
515 response
.data
.auth
.nt_status
));
518 return (result
== NSS_STATUS_SUCCESS
);
521 /* authenticate a user with an encrypted username/password */
523 NTSTATUS
contact_winbind_auth_crap(const char *username
,
525 const char *workstation
,
526 const DATA_BLOB
*challenge
,
527 const DATA_BLOB
*lm_response
,
528 const DATA_BLOB
*nt_response
,
530 uint32_t extra_logon_parameters
,
532 uint8_t user_session_key
[16],
533 uint8_t *pauthoritative
,
539 struct winbindd_request request
;
540 struct winbindd_response response
;
544 if (!get_require_membership_sid()) {
545 return NT_STATUS_INVALID_PARAMETER
;
548 ZERO_STRUCT(request
);
549 ZERO_STRUCT(response
);
551 request
.flags
= flags
;
553 request
.data
.auth_crap
.logon_parameters
= extra_logon_parameters
554 | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
| MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT
;
556 if (opt_allow_mschapv2
) {
557 request
.data
.auth_crap
.logon_parameters
|= MSV1_0_ALLOW_MSVCHAPV2
;
560 if (require_membership_of_sid
)
561 fstrcpy(request
.data
.auth_crap
.require_membership_of_sid
, require_membership_of_sid
);
563 fstrcpy(request
.data
.auth_crap
.user
, username
);
564 fstrcpy(request
.data
.auth_crap
.domain
, domain
);
566 fstrcpy(request
.data
.auth_crap
.workstation
,
569 memcpy(request
.data
.auth_crap
.chal
, challenge
->data
, MIN(challenge
->length
, 8));
571 if (lm_response
&& lm_response
->length
) {
572 memcpy(request
.data
.auth_crap
.lm_resp
,
574 MIN(lm_response
->length
, sizeof(request
.data
.auth_crap
.lm_resp
)));
575 request
.data
.auth_crap
.lm_resp_len
= lm_response
->length
;
578 if (nt_response
&& nt_response
->length
) {
579 if (nt_response
->length
> sizeof(request
.data
.auth_crap
.nt_resp
)) {
580 request
.flags
= request
.flags
| WBFLAG_BIG_NTLMV2_BLOB
;
581 request
.extra_len
= nt_response
->length
;
582 request
.extra_data
.data
= SMB_MALLOC_ARRAY(char, request
.extra_len
);
583 if (request
.extra_data
.data
== NULL
) {
584 return NT_STATUS_NO_MEMORY
;
586 memcpy(request
.extra_data
.data
, nt_response
->data
,
587 nt_response
->length
);
590 memcpy(request
.data
.auth_crap
.nt_resp
,
591 nt_response
->data
, nt_response
->length
);
593 request
.data
.auth_crap
.nt_resp_len
= nt_response
->length
;
596 result
= winbindd_request_response(NULL
, WINBINDD_PAM_AUTH_CRAP
, &request
, &response
);
597 SAFE_FREE(request
.extra_data
.data
);
599 /* Display response */
601 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
602 nt_status
= NT_STATUS_UNSUCCESSFUL
;
604 *error_string
= smb_xstrdup("Reading winbind reply failed!");
605 winbindd_free_response(&response
);
609 nt_status
= (NT_STATUS(response
.data
.auth
.nt_status
));
610 if (!NT_STATUS_IS_OK(nt_status
)) {
612 *error_string
= smb_xstrdup(response
.data
.auth
.error_string
);
613 *pauthoritative
= response
.data
.auth
.authoritative
;
614 winbindd_free_response(&response
);
618 if ((flags
& WBFLAG_PAM_LMKEY
) && lm_key
) {
619 memcpy(lm_key
, response
.data
.auth
.first_8_lm_hash
,
620 sizeof(response
.data
.auth
.first_8_lm_hash
));
622 if ((flags
& WBFLAG_PAM_USER_SESSION_KEY
) && user_session_key
) {
623 memcpy(user_session_key
, response
.data
.auth
.user_session_key
,
624 sizeof(response
.data
.auth
.user_session_key
));
627 if (flags
& WBFLAG_PAM_UNIX_NAME
) {
628 *unix_name
= SMB_STRDUP(response
.data
.auth
.unix_username
);
630 winbindd_free_response(&response
);
631 return NT_STATUS_NO_MEMORY
;
635 winbindd_free_response(&response
);
639 /* contact server to change user password using auth crap */
640 static NTSTATUS
contact_winbind_change_pswd_auth_crap(const char *username
,
642 const DATA_BLOB new_nt_pswd
,
643 const DATA_BLOB old_nt_hash_enc
,
644 const DATA_BLOB new_lm_pswd
,
645 const DATA_BLOB old_lm_hash_enc
,
650 struct winbindd_request request
;
651 struct winbindd_response response
;
653 if (!get_require_membership_sid())
656 *error_string
= smb_xstrdup("Can't get membership sid.");
657 return NT_STATUS_INVALID_PARAMETER
;
660 ZERO_STRUCT(request
);
661 ZERO_STRUCT(response
);
664 fstrcpy(request
.data
.chng_pswd_auth_crap
.user
, username
);
666 fstrcpy(request
.data
.chng_pswd_auth_crap
.domain
,domain
);
668 if(new_nt_pswd
.length
)
670 memcpy(request
.data
.chng_pswd_auth_crap
.new_nt_pswd
, new_nt_pswd
.data
, sizeof(request
.data
.chng_pswd_auth_crap
.new_nt_pswd
));
671 request
.data
.chng_pswd_auth_crap
.new_nt_pswd_len
= new_nt_pswd
.length
;
674 if(old_nt_hash_enc
.length
)
676 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
));
677 request
.data
.chng_pswd_auth_crap
.old_nt_hash_enc_len
= old_nt_hash_enc
.length
;
680 if(new_lm_pswd
.length
)
682 memcpy(request
.data
.chng_pswd_auth_crap
.new_lm_pswd
, new_lm_pswd
.data
, sizeof(request
.data
.chng_pswd_auth_crap
.new_lm_pswd
));
683 request
.data
.chng_pswd_auth_crap
.new_lm_pswd_len
= new_lm_pswd
.length
;
686 if(old_lm_hash_enc
.length
)
688 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
));
689 request
.data
.chng_pswd_auth_crap
.old_lm_hash_enc_len
= old_lm_hash_enc
.length
;
692 result
= winbindd_request_response(NULL
, WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP
, &request
, &response
);
694 /* Display response */
696 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0))
698 nt_status
= NT_STATUS_UNSUCCESSFUL
;
700 *error_string
= smb_xstrdup("Reading winbind reply failed!");
701 winbindd_free_response(&response
);
705 nt_status
= (NT_STATUS(response
.data
.auth
.nt_status
));
706 if (!NT_STATUS_IS_OK(nt_status
))
709 *error_string
= smb_xstrdup(response
.data
.auth
.error_string
);
710 winbindd_free_response(&response
);
714 winbindd_free_response(&response
);
719 static NTSTATUS
ntlm_auth_generate_session_info(struct auth4_context
*auth_context
,
721 void *server_returned_info
,
722 const char *original_user_name
,
723 uint32_t session_info_flags
,
724 struct auth_session_info
**session_info_out
)
726 const char *unix_username
= (const char *)server_returned_info
;
728 struct dom_sid
*sids
= NULL
;
729 struct auth_session_info
*session_info
= NULL
;
731 session_info
= talloc_zero(mem_ctx
, struct auth_session_info
);
732 if (session_info
== NULL
) {
733 return NT_STATUS_NO_MEMORY
;
736 session_info
->unix_info
= talloc_zero(session_info
, struct auth_user_info_unix
);
737 if (session_info
->unix_info
== NULL
) {
738 TALLOC_FREE(session_info
);
739 return NT_STATUS_NO_MEMORY
;
741 session_info
->unix_info
->unix_name
= talloc_strdup(session_info
->unix_info
,
743 if (session_info
->unix_info
->unix_name
== NULL
) {
744 TALLOC_FREE(session_info
);
745 return NT_STATUS_NO_MEMORY
;
748 session_info
->security_token
= talloc_zero(session_info
, struct security_token
);
749 if (session_info
->security_token
== NULL
) {
750 TALLOC_FREE(session_info
);
751 return NT_STATUS_NO_MEMORY
;
754 sids
= talloc_zero_array(session_info
->security_token
,
757 TALLOC_FREE(session_info
);
758 return NT_STATUS_NO_MEMORY
;
760 ok
= dom_sid_parse(SID_WORLD
, &sids
[0]);
762 TALLOC_FREE(session_info
);
763 return NT_STATUS_INTERNAL_ERROR
;
765 ok
= dom_sid_parse(SID_NT_NETWORK
, &sids
[1]);
767 TALLOC_FREE(session_info
);
768 return NT_STATUS_INTERNAL_ERROR
;
770 ok
= dom_sid_parse(SID_NT_AUTHENTICATED_USERS
, &sids
[2]);
772 TALLOC_FREE(session_info
);
773 return NT_STATUS_INTERNAL_ERROR
;
776 session_info
->security_token
->num_sids
= talloc_array_length(sids
);
777 session_info
->security_token
->sids
= sids
;
779 *session_info_out
= session_info
;
784 static NTSTATUS
ntlm_auth_generate_session_info_pac(struct auth4_context
*auth_ctx
,
786 struct smb_krb5_context
*smb_krb5_context
,
788 const char *princ_name
,
789 const struct tsocket_address
*remote_address
,
790 uint32_t session_info_flags
,
791 struct auth_session_info
**session_info
)
794 struct PAC_LOGON_INFO
*logon_info
= NULL
;
802 tmp_ctx
= talloc_new(mem_ctx
);
804 return NT_STATUS_NO_MEMORY
;
809 status
= kerberos_pac_logon_info(tmp_ctx
, *pac_blob
, NULL
, NULL
,
810 NULL
, NULL
, 0, &logon_info
);
812 status
= NT_STATUS_ACCESS_DENIED
;
814 if (!NT_STATUS_IS_OK(status
)) {
819 DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name
));
821 p
= strchr_m(princ_name
, '@');
823 DEBUG(3, ("[%s] Doesn't look like a valid principal\n",
825 return NT_STATUS_LOGON_FAILURE
;
828 user
= talloc_strndup(mem_ctx
, princ_name
, p
- princ_name
);
830 return NT_STATUS_NO_MEMORY
;
833 realm
= talloc_strdup(talloc_tos(), p
+ 1);
835 return NT_STATUS_NO_MEMORY
;
838 if (!strequal(realm
, lp_realm())) {
839 DEBUG(3, ("Ticket for foreign realm %s@%s\n", user
, realm
));
840 if (!lp_allow_trusted_domains()) {
841 return NT_STATUS_LOGON_FAILURE
;
845 if (logon_info
&& logon_info
->info3
.base
.logon_domain
.string
) {
846 domain
= talloc_strdup(mem_ctx
,
847 logon_info
->info3
.base
.logon_domain
.string
);
849 return NT_STATUS_NO_MEMORY
;
851 DEBUG(10, ("Domain is [%s] (using PAC)\n", domain
));
854 /* If we have winbind running, we can (and must) shorten the
855 username by using the short netbios name. Otherwise we will
856 have inconsistent user names. With Kerberos, we get the
857 fully qualified realm, with ntlmssp we get the short
858 name. And even w2k3 does use ntlmssp if you for example
859 connect to an ip address. */
862 struct wbcDomainInfo
*info
= NULL
;
864 DEBUG(10, ("Mapping [%s] to short name using winbindd\n",
867 wbc_status
= wbcDomainInfo(realm
, &info
);
869 if (WBC_ERROR_IS_OK(wbc_status
)) {
870 domain
= talloc_strdup(mem_ctx
,
874 DEBUG(3, ("Could not find short name: %s\n",
875 wbcErrorString(wbc_status
)));
876 domain
= talloc_strdup(mem_ctx
, realm
);
879 return NT_STATUS_NO_MEMORY
;
881 DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain
));
884 unixuser
= talloc_asprintf(tmp_ctx
, "%s%c%s", domain
, winbind_separator(), user
);
886 status
= NT_STATUS_NO_MEMORY
;
890 status
= ntlm_auth_generate_session_info(auth_ctx
, mem_ctx
, unixuser
, NULL
, session_info_flags
, session_info
);
893 TALLOC_FREE(tmp_ctx
);
900 * Return the challenge as determined by the authentication subsystem
901 * @return an 8 byte random challenge
904 static NTSTATUS
ntlm_auth_get_challenge(struct auth4_context
*auth_ctx
,
907 if (auth_ctx
->challenge
.data
.length
== 8) {
908 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
909 auth_ctx
->challenge
.set_by
));
910 memcpy(chal
, auth_ctx
->challenge
.data
.data
, 8);
914 if (!auth_ctx
->challenge
.set_by
) {
915 generate_random_buffer(chal
, 8);
917 auth_ctx
->challenge
.data
= data_blob_talloc(auth_ctx
, chal
, 8);
918 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.data
.data
);
919 auth_ctx
->challenge
.set_by
= "random";
922 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
923 auth_ctx
->challenge
.set_by
));
929 * NTLM2 authentication modifies the effective challenge,
930 * @param challenge The new challenge value
932 static NTSTATUS
ntlm_auth_set_challenge(struct auth4_context
*auth_ctx
, const uint8_t chal
[8], const char *set_by
)
934 auth_ctx
->challenge
.set_by
= talloc_strdup(auth_ctx
, set_by
);
935 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.set_by
);
937 auth_ctx
->challenge
.data
= data_blob_talloc(auth_ctx
, chal
, 8);
938 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.data
.data
);
944 * Check the password on an NTLMSSP login.
946 * Return the session keys used on the connection.
949 static NTSTATUS
winbind_pw_check(struct auth4_context
*auth4_context
,
951 const struct auth_usersupplied_info
*user_info
,
952 uint8_t *pauthoritative
,
953 void **server_returned_info
,
954 DATA_BLOB
*session_key
, DATA_BLOB
*lm_session_key
)
957 char *error_string
= NULL
;
959 uint8_t user_sess_key
[16];
960 char *unix_name
= NULL
;
962 nt_status
= contact_winbind_auth_crap(user_info
->client
.account_name
, user_info
->client
.domain_name
,
963 user_info
->workstation_name
,
964 &auth4_context
->challenge
.data
,
965 &user_info
->password
.response
.lanman
,
966 &user_info
->password
.response
.nt
,
967 WBFLAG_PAM_LMKEY
| WBFLAG_PAM_USER_SESSION_KEY
| WBFLAG_PAM_UNIX_NAME
,
969 lm_key
, user_sess_key
,
971 &error_string
, &unix_name
);
973 if (NT_STATUS_IS_OK(nt_status
)) {
974 if (!all_zero(lm_key
, 8)) {
975 *lm_session_key
= data_blob_talloc(mem_ctx
, NULL
, 16);
976 memcpy(lm_session_key
->data
, lm_key
, 8);
977 memset(lm_session_key
->data
+8, '\0', 8);
980 if (!all_zero(user_sess_key
, 16)) {
981 *session_key
= data_blob_talloc(mem_ctx
, user_sess_key
, 16);
983 *server_returned_info
= talloc_strdup(mem_ctx
,
986 DEBUG(NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCESS_DENIED
) ? 0 : 3,
987 ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
988 user_info
->client
.domain_name
, user_info
->client
.account_name
,
989 user_info
->workstation_name
,
990 error_string
? error_string
: "unknown error (NULL)"));
993 SAFE_FREE(error_string
);
994 SAFE_FREE(unix_name
);
998 static NTSTATUS
local_pw_check(struct auth4_context
*auth4_context
,
1000 const struct auth_usersupplied_info
*user_info
,
1001 uint8_t *pauthoritative
,
1002 void **server_returned_info
,
1003 DATA_BLOB
*session_key
, DATA_BLOB
*lm_session_key
)
1006 struct samr_Password lm_pw
, nt_pw
;
1008 nt_lm_owf_gen (opt_password
, nt_pw
.hash
, lm_pw
.hash
);
1010 *pauthoritative
= 1;
1012 nt_status
= ntlm_password_check(mem_ctx
,
1014 &auth4_context
->challenge
.data
,
1015 &user_info
->password
.response
.lanman
,
1016 &user_info
->password
.response
.nt
,
1017 user_info
->client
.account_name
,
1018 user_info
->client
.account_name
,
1019 user_info
->client
.domain_name
,
1020 &lm_pw
, &nt_pw
, session_key
, lm_session_key
);
1022 if (NT_STATUS_IS_OK(nt_status
)) {
1023 *server_returned_info
= talloc_asprintf(mem_ctx
,
1024 "%s%c%s", user_info
->client
.domain_name
,
1025 *lp_winbind_separator(),
1026 user_info
->client
.account_name
);
1028 DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
1029 user_info
->client
.domain_name
, user_info
->client
.account_name
,
1030 user_info
->workstation_name
,
1031 nt_errstr(nt_status
)));
1036 static NTSTATUS
ntlm_auth_prepare_gensec_client(TALLOC_CTX
*mem_ctx
,
1037 struct loadparm_context
*lp_ctx
,
1038 struct gensec_security
**gensec_security_out
)
1040 struct gensec_security
*gensec_security
= NULL
;
1042 TALLOC_CTX
*tmp_ctx
;
1043 const struct gensec_security_ops
**backends
= NULL
;
1044 struct gensec_settings
*gensec_settings
= NULL
;
1047 tmp_ctx
= talloc_new(mem_ctx
);
1048 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx
);
1050 gensec_settings
= lpcfg_gensec_settings(tmp_ctx
, lp_ctx
);
1051 if (gensec_settings
== NULL
) {
1052 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1053 TALLOC_FREE(tmp_ctx
);
1054 return NT_STATUS_NO_MEMORY
;
1057 backends
= talloc_zero_array(gensec_settings
,
1058 const struct gensec_security_ops
*, 4);
1059 if (backends
== NULL
) {
1060 TALLOC_FREE(tmp_ctx
);
1061 return NT_STATUS_NO_MEMORY
;
1063 gensec_settings
->backends
= backends
;
1067 /* These need to be in priority order, krb5 before NTLMSSP */
1068 #if defined(HAVE_KRB5)
1069 backends
[idx
++] = &gensec_gse_krb5_security_ops
;
1072 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_NTLMSSP
);
1074 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_SPNEGO
);
1076 nt_status
= gensec_client_start(NULL
, &gensec_security
,
1078 if (!NT_STATUS_IS_OK(nt_status
)) {
1079 TALLOC_FREE(tmp_ctx
);
1083 talloc_unlink(tmp_ctx
, gensec_settings
);
1085 if (opt_target_service
!= NULL
) {
1086 nt_status
= gensec_set_target_service(gensec_security
,
1087 opt_target_service
);
1088 if (!NT_STATUS_IS_OK(nt_status
)) {
1089 TALLOC_FREE(tmp_ctx
);
1094 if (opt_target_hostname
!= NULL
) {
1095 nt_status
= gensec_set_target_hostname(gensec_security
,
1096 opt_target_hostname
);
1097 if (!NT_STATUS_IS_OK(nt_status
)) {
1098 TALLOC_FREE(tmp_ctx
);
1103 *gensec_security_out
= talloc_steal(mem_ctx
, gensec_security
);
1104 TALLOC_FREE(tmp_ctx
);
1105 return NT_STATUS_OK
;
1108 static struct auth4_context
*make_auth4_context_ntlm_auth(TALLOC_CTX
*mem_ctx
, bool local_pw
)
1110 struct auth4_context
*auth4_context
= talloc_zero(mem_ctx
, struct auth4_context
);
1111 if (auth4_context
== NULL
) {
1112 DEBUG(10, ("failed to allocate auth4_context failed\n"));
1115 auth4_context
->generate_session_info
= ntlm_auth_generate_session_info
;
1116 auth4_context
->generate_session_info_pac
= ntlm_auth_generate_session_info_pac
;
1117 auth4_context
->get_ntlm_challenge
= ntlm_auth_get_challenge
;
1118 auth4_context
->set_ntlm_challenge
= ntlm_auth_set_challenge
;
1120 auth4_context
->check_ntlm_password
= local_pw_check
;
1122 auth4_context
->check_ntlm_password
= winbind_pw_check
;
1124 auth4_context
->private_data
= NULL
;
1125 return auth4_context
;
1128 static NTSTATUS
ntlm_auth_prepare_gensec_server(TALLOC_CTX
*mem_ctx
,
1129 struct loadparm_context
*lp_ctx
,
1130 struct gensec_security
**gensec_security_out
)
1132 struct gensec_security
*gensec_security
;
1135 TALLOC_CTX
*tmp_ctx
;
1136 const struct gensec_security_ops
**backends
;
1137 struct gensec_settings
*gensec_settings
;
1139 struct cli_credentials
*server_credentials
;
1141 struct auth4_context
*auth4_context
;
1143 tmp_ctx
= talloc_new(mem_ctx
);
1144 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx
);
1146 auth4_context
= make_auth4_context_ntlm_auth(tmp_ctx
, opt_password
);
1147 if (auth4_context
== NULL
) {
1148 TALLOC_FREE(tmp_ctx
);
1149 return NT_STATUS_NO_MEMORY
;
1152 gensec_settings
= lpcfg_gensec_settings(tmp_ctx
, lp_ctx
);
1153 if (lp_ctx
== NULL
) {
1154 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1155 TALLOC_FREE(tmp_ctx
);
1156 return NT_STATUS_NO_MEMORY
;
1160 * This should be a 'netbios domain -> DNS domain'
1161 * mapping, and can currently validly return NULL on
1162 * poorly configured systems.
1164 * This is used for the NTLMSSP server
1168 gensec_settings
->server_netbios_name
= lp_netbios_name();
1169 gensec_settings
->server_netbios_domain
= lp_workgroup();
1171 gensec_settings
->server_netbios_name
= get_winbind_netbios_name();
1172 gensec_settings
->server_netbios_domain
= get_winbind_domain();
1175 gensec_settings
->server_dns_domain
= strlower_talloc(gensec_settings
,
1176 get_mydnsdomname(talloc_tos()));
1177 gensec_settings
->server_dns_name
= strlower_talloc(gensec_settings
,
1178 get_mydnsfullname());
1180 backends
= talloc_zero_array(gensec_settings
,
1181 const struct gensec_security_ops
*, 4);
1183 if (backends
== NULL
) {
1184 TALLOC_FREE(tmp_ctx
);
1185 return NT_STATUS_NO_MEMORY
;
1187 gensec_settings
->backends
= backends
;
1191 /* These need to be in priority order, krb5 before NTLMSSP */
1192 #if defined(HAVE_KRB5)
1193 backends
[idx
++] = &gensec_gse_krb5_security_ops
;
1196 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_NTLMSSP
);
1198 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_SPNEGO
);
1201 * This is anonymous for now, because we just use it
1202 * to set the kerberos state at the moment
1204 server_credentials
= cli_credentials_init_anon(tmp_ctx
);
1205 if (!server_credentials
) {
1206 DEBUG(0, ("auth_generic_prepare: Failed to init server credentials\n"));
1207 return NT_STATUS_NO_MEMORY
;
1210 cli_credentials_set_conf(server_credentials
, lp_ctx
);
1212 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC
|| lp_security() == SEC_ADS
|| USE_KERBEROS_KEYTAB
) {
1213 cli_credentials_set_kerberos_state(server_credentials
, CRED_AUTO_USE_KERBEROS
);
1215 cli_credentials_set_kerberos_state(server_credentials
, CRED_DONT_USE_KERBEROS
);
1218 nt_status
= gensec_server_start(tmp_ctx
, gensec_settings
,
1219 auth4_context
, &gensec_security
);
1221 if (!NT_STATUS_IS_OK(nt_status
)) {
1222 TALLOC_FREE(tmp_ctx
);
1226 gensec_set_credentials(gensec_security
, server_credentials
);
1229 * TODO: Allow the caller to pass their own description here
1230 * via a command-line option
1232 nt_status
= gensec_set_target_service_description(gensec_security
,
1234 if (!NT_STATUS_IS_OK(nt_status
)) {
1235 TALLOC_FREE(tmp_ctx
);
1239 talloc_unlink(tmp_ctx
, lp_ctx
);
1240 talloc_unlink(tmp_ctx
, server_credentials
);
1241 talloc_unlink(tmp_ctx
, gensec_settings
);
1242 talloc_unlink(tmp_ctx
, auth4_context
);
1244 *gensec_security_out
= talloc_steal(mem_ctx
, gensec_security
);
1245 TALLOC_FREE(tmp_ctx
);
1246 return NT_STATUS_OK
;
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 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1258 static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode
,
1259 struct loadparm_context
*lp_ctx
,
1260 struct ntlm_auth_state
*state
,
1261 char *buf
, int length
, void **private2
)
1266 pass
=(char *)memchr(buf
,' ',length
);
1268 DEBUG(2, ("Password not found. Denying access\n"));
1275 if (state
->helper_mode
== SQUID_2_5_BASIC
) {
1276 char *end
= rfc1738_unescape(user
);
1277 if (end
== NULL
|| (end
- user
) != strlen(user
)) {
1278 DEBUG(2, ("Badly rfc1738 encoded username: %s; "
1279 "denying access\n", user
));
1283 end
= rfc1738_unescape(pass
);
1284 if (end
== NULL
|| (end
- pass
) != strlen(pass
)) {
1285 DEBUG(2, ("Badly encoded password for %s; "
1286 "denying access\n", user
));
1292 if (check_plaintext_auth(user
, pass
, False
)) {
1299 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode
,
1300 struct loadparm_context
*lp_ctx
,
1301 char *buf
, int length
, void **private1
)
1304 DATA_BLOB out
= data_blob(NULL
, 0);
1305 char *out_base64
= NULL
;
1306 const char *reply_arg
= NULL
;
1307 struct gensec_ntlm_state
{
1308 struct gensec_security
*gensec_state
;
1309 const char *set_password
;
1311 struct gensec_ntlm_state
*state
;
1315 const char *reply_code
;
1316 struct cli_credentials
*creds
;
1318 static char *want_feature_list
= NULL
;
1319 static DATA_BLOB session_key
;
1321 TALLOC_CTX
*mem_ctx
;
1323 mem_ctx
= talloc_named(NULL
, 0, "manage_gensec_request internal mem_ctx");
1326 state
= (struct gensec_ntlm_state
*)*private1
;
1328 state
= talloc_zero(NULL
, struct gensec_ntlm_state
);
1330 printf("BH No Memory\n");
1335 state
->set_password
= opt_password
;
1339 if (strlen(buf
) < 2) {
1340 DEBUG(1, ("query [%s] invalid", buf
));
1341 printf("BH Query invalid\n");
1342 talloc_free(mem_ctx
);
1346 if (strlen(buf
) > 3) {
1347 if(strncmp(buf
, "SF ", 3) == 0) {
1348 DEBUG(10, ("Setting flags to negotiate\n"));
1349 talloc_free(want_feature_list
);
1350 want_feature_list
= talloc_strndup(state
, buf
+3, strlen(buf
)-3);
1352 talloc_free(mem_ctx
);
1355 in
= base64_decode_data_blob_talloc(mem_ctx
, buf
+ 3);
1357 in
= data_blob(NULL
, 0);
1360 if (strncmp(buf
, "YR", 2) == 0) {
1361 if (state
->gensec_state
) {
1362 talloc_free(state
->gensec_state
);
1363 state
->gensec_state
= NULL
;
1365 } else if ( (strncmp(buf
, "OK", 2) == 0)) {
1366 /* Just return BH, like ntlm_auth from Samba 3 does. */
1367 printf("BH Command expected\n");
1368 talloc_free(mem_ctx
);
1370 } else if ( (strncmp(buf
, "TT ", 3) != 0) &&
1371 (strncmp(buf
, "KK ", 3) != 0) &&
1372 (strncmp(buf
, "AF ", 3) != 0) &&
1373 (strncmp(buf
, "NA ", 3) != 0) &&
1374 (strncmp(buf
, "UG", 2) != 0) &&
1375 (strncmp(buf
, "PW ", 3) != 0) &&
1376 (strncmp(buf
, "GK", 2) != 0) &&
1377 (strncmp(buf
, "GF", 2) != 0)) {
1378 DEBUG(1, ("SPNEGO request [%s] invalid prefix\n", buf
));
1379 printf("BH SPNEGO request invalid prefix\n");
1380 talloc_free(mem_ctx
);
1385 if (!(state
->gensec_state
)) {
1386 switch (stdio_helper_mode
) {
1387 case GSS_SPNEGO_CLIENT
:
1389 * cached credentials are only supported by
1390 * NTLMSSP_CLIENT_1 for now.
1392 use_cached_creds
= false;
1394 case NTLMSSP_CLIENT_1
:
1395 /* setup the client side */
1397 if (state
->set_password
!= NULL
) {
1398 use_cached_creds
= false;
1401 if (use_cached_creds
) {
1402 struct wbcCredentialCacheParams params
;
1403 struct wbcCredentialCacheInfo
*info
= NULL
;
1404 struct wbcAuthErrorInfo
*error
= NULL
;
1407 params
.account_name
= opt_username
;
1408 params
.domain_name
= opt_domain
;
1409 params
.level
= WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP
;
1410 params
.num_blobs
= 0;
1411 params
.blobs
= NULL
;
1413 wbc_status
= wbcCredentialCache(¶ms
, &info
,
1415 wbcFreeMemory(error
);
1416 if (!WBC_ERROR_IS_OK(wbc_status
)) {
1417 use_cached_creds
= false;
1419 wbcFreeMemory(info
);
1422 nt_status
= ntlm_auth_prepare_gensec_client(state
, lp_ctx
,
1423 &state
->gensec_state
);
1424 if (!NT_STATUS_IS_OK(nt_status
)) {
1425 printf("BH GENSEC mech failed to start: %s\n",
1426 nt_errstr(nt_status
));
1427 talloc_free(mem_ctx
);
1431 creds
= cli_credentials_init(state
->gensec_state
);
1432 cli_credentials_set_conf(creds
, lp_ctx
);
1434 cli_credentials_set_username(creds
, opt_username
, CRED_SPECIFIED
);
1437 cli_credentials_set_domain(creds
, opt_domain
, CRED_SPECIFIED
);
1439 if (use_cached_creds
) {
1440 gensec_want_feature(state
->gensec_state
,
1441 GENSEC_FEATURE_NTLM_CCACHE
);
1442 } else if (state
->set_password
) {
1443 cli_credentials_set_password(creds
, state
->set_password
, CRED_SPECIFIED
);
1445 cli_credentials_set_password_callback(creds
, get_password
);
1447 if (opt_workstation
) {
1448 cli_credentials_set_workstation(creds
, opt_workstation
, CRED_SPECIFIED
);
1451 gensec_set_credentials(state
->gensec_state
, creds
);
1454 case GSS_SPNEGO_SERVER
:
1455 case SQUID_2_5_NTLMSSP
:
1457 nt_status
= ntlm_auth_prepare_gensec_server(state
, lp_ctx
,
1458 &state
->gensec_state
);
1459 if (!NT_STATUS_IS_OK(nt_status
)) {
1460 printf("BH GENSEC mech failed to start: %s\n",
1461 nt_errstr(nt_status
));
1462 talloc_free(mem_ctx
);
1468 talloc_free(mem_ctx
);
1472 gensec_want_feature_list(state
->gensec_state
, want_feature_list
);
1474 /* Session info is not complete, do not pass to auth log */
1475 gensec_want_feature(state
->gensec_state
, GENSEC_FEATURE_NO_AUTHZ_LOG
);
1477 switch (stdio_helper_mode
) {
1478 case GSS_SPNEGO_CLIENT
:
1479 case GSS_SPNEGO_SERVER
:
1480 nt_status
= gensec_start_mech_by_oid(state
->gensec_state
, GENSEC_OID_SPNEGO
);
1485 case NTLMSSP_CLIENT_1
:
1490 case SQUID_2_5_NTLMSSP
:
1491 nt_status
= gensec_start_mech_by_oid(state
->gensec_state
, GENSEC_OID_NTLMSSP
);
1494 talloc_free(mem_ctx
);
1498 if (!NT_STATUS_IS_OK(nt_status
)) {
1499 DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status
)));
1500 printf("BH GENSEC mech failed to start\n");
1501 talloc_free(mem_ctx
);
1509 if (strncmp(buf
, "PW ", 3) == 0) {
1510 state
->set_password
= talloc_strndup(state
,
1511 (const char *)in
.data
,
1514 cli_credentials_set_password(gensec_get_credentials(state
->gensec_state
),
1515 state
->set_password
,
1518 talloc_free(mem_ctx
);
1522 if (strncmp(buf
, "GK", 2) == 0) {
1524 DEBUG(10, ("Requested session key\n"));
1525 nt_status
= gensec_session_key(state
->gensec_state
, mem_ctx
, &session_key
);
1526 if(!NT_STATUS_IS_OK(nt_status
)) {
1527 DEBUG(1, ("gensec_session_key failed: %s\n", nt_errstr(nt_status
)));
1528 printf("BH No session key\n");
1529 talloc_free(mem_ctx
);
1532 base64_key
= base64_encode_data_blob(state
, session_key
);
1533 SMB_ASSERT(base64_key
!= NULL
);
1534 printf("GK %s\n", base64_key
);
1535 talloc_free(base64_key
);
1537 talloc_free(mem_ctx
);
1541 if (strncmp(buf
, "GF", 2) == 0) {
1544 DEBUG(10, ("Requested negotiated NTLMSSP feature flags\n"));
1546 neg_flags
= gensec_ntlmssp_neg_flags(state
->gensec_state
);
1547 if (neg_flags
== 0) {
1549 talloc_free(mem_ctx
);
1553 printf("GF 0x%08x\n", neg_flags
);
1554 talloc_free(mem_ctx
);
1558 nt_status
= gensec_update(state
->gensec_state
, mem_ctx
, in
, &out
);
1560 /* don't leak 'bad password'/'no such user' info to the network client */
1561 nt_status
= nt_status_squash(nt_status
);
1564 out_base64
= base64_encode_data_blob(mem_ctx
, out
);
1565 SMB_ASSERT(out_base64
!= NULL
);
1570 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1572 if (first
&& state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1574 } else if (state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1576 } else if (state
->gensec_state
->gensec_role
== GENSEC_SERVER
) {
1583 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCESS_DENIED
)) {
1584 reply_code
= "BH NT_STATUS_ACCESS_DENIED";
1585 reply_arg
= nt_errstr(nt_status
);
1586 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1587 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_UNSUCCESSFUL
)) {
1588 reply_code
= "BH NT_STATUS_UNSUCCESSFUL";
1589 reply_arg
= nt_errstr(nt_status
);
1590 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1591 } else if (!NT_STATUS_IS_OK(nt_status
)) {
1593 reply_arg
= nt_errstr(nt_status
);
1594 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1595 } else if /* OK */ (state
->gensec_state
->gensec_role
== GENSEC_SERVER
) {
1596 struct auth_session_info
*session_info
;
1598 nt_status
= gensec_session_info(state
->gensec_state
, mem_ctx
, &session_info
);
1599 if (!NT_STATUS_IS_OK(nt_status
)) {
1600 reply_code
= "BH Failed to retrive session info";
1601 reply_arg
= nt_errstr(nt_status
);
1602 DEBUG(1, ("GENSEC failed to retrieve the session info: %s\n", nt_errstr(nt_status
)));
1606 reply_arg
= talloc_strdup(state
->gensec_state
, session_info
->unix_info
->unix_name
);
1607 if (reply_arg
== NULL
) {
1608 reply_code
= "BH out of memory";
1609 reply_arg
= nt_errstr(NT_STATUS_NO_MEMORY
);
1611 talloc_free(session_info
);
1613 } else if (state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1615 reply_arg
= out_base64
;
1620 switch (stdio_helper_mode
) {
1621 case GSS_SPNEGO_SERVER
:
1622 printf("%s %s %s\n", reply_code
,
1623 out_base64
? out_base64
: "*",
1624 reply_arg
? reply_arg
: "*");
1628 printf("%s %s\n", reply_code
, out_base64
);
1629 } else if (reply_arg
) {
1630 printf("%s %s\n", reply_code
, reply_arg
);
1632 printf("%s\n", reply_code
);
1636 talloc_free(mem_ctx
);
1640 static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode
,
1641 struct loadparm_context
*lp_ctx
,
1642 struct ntlm_auth_state
*state
,
1643 char *buf
, int length
, void **private2
)
1645 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1649 static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode
,
1650 struct loadparm_context
*lp_ctx
,
1651 struct ntlm_auth_state
*state
,
1652 char *buf
, int length
, void **private2
)
1654 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1658 static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode
,
1659 struct loadparm_context
*lp_ctx
,
1660 struct ntlm_auth_state
*state
,
1661 char *buf
, int length
, void **private2
)
1663 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1667 static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode
,
1668 struct loadparm_context
*lp_ctx
,
1669 struct ntlm_auth_state
*state
,
1670 char *buf
, int length
, void **private2
)
1672 char *request
, *parameter
;
1673 static DATA_BLOB challenge
;
1674 static DATA_BLOB lm_response
;
1675 static DATA_BLOB nt_response
;
1676 static char *full_username
;
1677 static char *username
;
1678 static char *domain
;
1679 static char *plaintext_password
;
1680 static bool ntlm_server_1_user_session_key
;
1681 static bool ntlm_server_1_lm_session_key
;
1683 if (strequal(buf
, ".")) {
1684 if (!full_username
&& !username
) {
1685 printf("Error: No username supplied!\n");
1686 } else if (plaintext_password
) {
1687 /* handle this request as plaintext */
1688 if (!full_username
) {
1689 if (asprintf(&full_username
, "%s%c%s", domain
, winbind_separator(), username
) == -1) {
1690 printf("Error: Out of memory in "
1695 if (check_plaintext_auth(full_username
, plaintext_password
, False
)) {
1696 printf("Authenticated: Yes\n");
1698 printf("Authenticated: No\n");
1700 } else if (!lm_response
.data
&& !nt_response
.data
) {
1701 printf("Error: No password supplied!\n");
1702 } else if (!challenge
.data
) {
1703 printf("Error: No lanman-challenge supplied!\n");
1705 char *error_string
= NULL
;
1707 uchar user_session_key
[16];
1710 if (full_username
&& !username
) {
1712 fstring fstr_domain
;
1714 if (!parse_ntlm_auth_domain_user(full_username
, fstr_user
, fstr_domain
)) {
1715 /* username might be 'tainted', don't print into our new-line deleimianted stream */
1716 printf("Error: Could not parse into "
1717 "domain and username\n");
1719 SAFE_FREE(username
);
1721 username
= smb_xstrdup(fstr_user
);
1722 domain
= smb_xstrdup(fstr_domain
);
1726 DATA_BLOB nt_session_key
, lm_session_key
;
1727 struct samr_Password lm_pw
, nt_pw
;
1728 TALLOC_CTX
*mem_ctx
= talloc_new(NULL
);
1729 ZERO_STRUCT(user_session_key
);
1730 ZERO_STRUCT(lm_key
);
1732 nt_lm_owf_gen (opt_password
, nt_pw
.hash
, lm_pw
.hash
);
1733 nt_status
= ntlm_password_check(mem_ctx
,
1744 error_string
= smb_xstrdup(get_friendly_nt_error_msg(nt_status
));
1745 if (ntlm_server_1_user_session_key
) {
1746 if (nt_session_key
.length
== sizeof(user_session_key
)) {
1747 memcpy(user_session_key
,
1748 nt_session_key
.data
,
1749 sizeof(user_session_key
));
1752 if (ntlm_server_1_lm_session_key
) {
1753 if (lm_session_key
.length
== sizeof(lm_key
)) {
1755 lm_session_key
.data
,
1759 TALLOC_FREE(mem_ctx
);
1762 uint8_t authoritative
= 0;
1765 domain
= smb_xstrdup(get_winbind_domain());
1768 if (ntlm_server_1_lm_session_key
)
1769 flags
|= WBFLAG_PAM_LMKEY
;
1771 if (ntlm_server_1_user_session_key
)
1772 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
1774 nt_status
= contact_winbind_auth_crap(username
,
1788 if (!NT_STATUS_IS_OK(nt_status
)) {
1789 printf("Authenticated: No\n");
1790 printf("Authentication-Error: %s\n.\n",
1794 char *hex_user_session_key
;
1796 printf("Authenticated: Yes\n");
1798 if (ntlm_server_1_lm_session_key
1799 && (!all_zero(lm_key
,
1801 hex_lm_key
= hex_encode_talloc(NULL
,
1802 (const unsigned char *)lm_key
,
1804 printf("LANMAN-Session-Key: %s\n",
1806 TALLOC_FREE(hex_lm_key
);
1809 if (ntlm_server_1_user_session_key
1810 && (!all_zero(user_session_key
,
1811 sizeof(user_session_key
)))) {
1812 hex_user_session_key
= hex_encode_talloc(NULL
,
1813 (const unsigned char *)user_session_key
,
1814 sizeof(user_session_key
));
1815 printf("User-Session-Key: %s\n",
1816 hex_user_session_key
);
1817 TALLOC_FREE(hex_user_session_key
);
1820 SAFE_FREE(error_string
);
1822 /* clear out the state */
1823 challenge
= data_blob_null
;
1824 nt_response
= data_blob_null
;
1825 lm_response
= data_blob_null
;
1826 SAFE_FREE(full_username
);
1827 SAFE_FREE(username
);
1829 SAFE_FREE(plaintext_password
);
1830 ntlm_server_1_user_session_key
= False
;
1831 ntlm_server_1_lm_session_key
= False
;
1839 /* Indicates a base64 encoded structure */
1840 parameter
= strstr_m(request
, ":: ");
1842 parameter
= strstr_m(request
, ": ");
1845 DEBUG(0, ("Parameter not found!\n"));
1846 printf("Error: Parameter not found!\n.\n");
1863 base64_decode_inplace(parameter
);
1866 if (strequal(request
, "LANMAN-Challenge")) {
1867 challenge
= strhex_to_data_blob(NULL
, parameter
);
1868 if (challenge
.length
!= 8) {
1869 printf("Error: hex decode of %s failed! "
1870 "(got %d bytes, expected 8)\n.\n",
1872 (int)challenge
.length
);
1873 challenge
= data_blob_null
;
1875 } else if (strequal(request
, "NT-Response")) {
1876 nt_response
= strhex_to_data_blob(NULL
, parameter
);
1877 if (nt_response
.length
< 24) {
1878 printf("Error: hex decode of %s failed! "
1879 "(only got %d bytes, needed at least 24)\n.\n",
1881 (int)nt_response
.length
);
1882 nt_response
= data_blob_null
;
1884 } else if (strequal(request
, "LANMAN-Response")) {
1885 lm_response
= strhex_to_data_blob(NULL
, parameter
);
1886 if (lm_response
.length
!= 24) {
1887 printf("Error: hex decode of %s failed! "
1888 "(got %d bytes, expected 24)\n.\n",
1890 (int)lm_response
.length
);
1891 lm_response
= data_blob_null
;
1893 } else if (strequal(request
, "Password")) {
1894 plaintext_password
= smb_xstrdup(parameter
);
1895 } else if (strequal(request
, "NT-Domain")) {
1896 domain
= smb_xstrdup(parameter
);
1897 } else if (strequal(request
, "Username")) {
1898 username
= smb_xstrdup(parameter
);
1899 } else if (strequal(request
, "Full-Username")) {
1900 full_username
= smb_xstrdup(parameter
);
1901 } else if (strequal(request
, "Request-User-Session-Key")) {
1902 ntlm_server_1_user_session_key
= strequal(parameter
, "Yes");
1903 } else if (strequal(request
, "Request-LanMan-Session-Key")) {
1904 ntlm_server_1_lm_session_key
= strequal(parameter
, "Yes");
1906 printf("Error: Unknown request %s\n.\n", request
);
1910 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode
,
1911 struct loadparm_context
*lp_ctx
,
1912 struct ntlm_auth_state
*state
,
1913 char *buf
, int length
, void **private2
)
1915 char *request
, *parameter
;
1916 static DATA_BLOB new_nt_pswd
;
1917 static DATA_BLOB old_nt_hash_enc
;
1918 static DATA_BLOB new_lm_pswd
;
1919 static DATA_BLOB old_lm_hash_enc
;
1920 static char *full_username
= NULL
;
1921 static char *username
= NULL
;
1922 static char *domain
= NULL
;
1923 static char *newpswd
= NULL
;
1924 static char *oldpswd
= NULL
;
1926 if (strequal(buf
, ".")) {
1927 if(newpswd
&& oldpswd
) {
1928 uchar old_nt_hash
[16];
1929 uchar old_lm_hash
[16];
1930 uchar new_nt_hash
[16];
1931 uchar new_lm_hash
[16];
1933 new_nt_pswd
= data_blob(NULL
, 516);
1934 old_nt_hash_enc
= data_blob(NULL
, 16);
1936 /* Calculate the MD4 hash (NT compatible) of the
1938 E_md4hash(oldpswd
, old_nt_hash
);
1939 E_md4hash(newpswd
, new_nt_hash
);
1941 /* E_deshash returns false for 'long'
1942 passwords (> 14 DOS chars).
1944 Therefore, don't send a buffer
1945 encrypted with the truncated hash
1946 (it could allow an even easier
1947 attack on the password)
1949 Likewise, obey the admin's restriction
1952 if (lp_client_lanman_auth() &&
1953 E_deshash(newpswd
, new_lm_hash
) &&
1954 E_deshash(oldpswd
, old_lm_hash
)) {
1955 new_lm_pswd
= data_blob(NULL
, 516);
1956 old_lm_hash_enc
= data_blob(NULL
, 16);
1957 encode_pw_buffer(new_lm_pswd
.data
, newpswd
,
1960 arcfour_crypt(new_lm_pswd
.data
, old_nt_hash
, 516);
1961 E_old_pw_hash(new_nt_hash
, old_lm_hash
,
1962 old_lm_hash_enc
.data
);
1964 new_lm_pswd
.data
= NULL
;
1965 new_lm_pswd
.length
= 0;
1966 old_lm_hash_enc
.data
= NULL
;
1967 old_lm_hash_enc
.length
= 0;
1970 encode_pw_buffer(new_nt_pswd
.data
, newpswd
,
1973 arcfour_crypt(new_nt_pswd
.data
, old_nt_hash
, 516);
1974 E_old_pw_hash(new_nt_hash
, old_nt_hash
,
1975 old_nt_hash_enc
.data
);
1978 if (!full_username
&& !username
) {
1979 printf("Error: No username supplied!\n");
1980 } else if ((!new_nt_pswd
.data
|| !old_nt_hash_enc
.data
) &&
1981 (!new_lm_pswd
.data
|| old_lm_hash_enc
.data
) ) {
1982 printf("Error: No NT or LM password "
1983 "blobs supplied!\n");
1985 char *error_string
= NULL
;
1987 if (full_username
&& !username
) {
1989 fstring fstr_domain
;
1991 if (!parse_ntlm_auth_domain_user(full_username
,
1994 /* username might be 'tainted', don't
1995 * print into our new-line
1996 * deleimianted stream */
1997 printf("Error: Could not "
1998 "parse into domain and "
2000 SAFE_FREE(username
);
2001 username
= smb_xstrdup(full_username
);
2003 SAFE_FREE(username
);
2005 username
= smb_xstrdup(fstr_user
);
2006 domain
= smb_xstrdup(fstr_domain
);
2011 if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
2018 printf("Password-Change: No\n");
2019 printf("Password-Change-Error: %s\n.\n",
2022 printf("Password-Change: Yes\n");
2025 SAFE_FREE(error_string
);
2027 /* clear out the state */
2028 new_nt_pswd
= data_blob_null
;
2029 old_nt_hash_enc
= data_blob_null
;
2030 new_lm_pswd
= data_blob_null
;
2031 old_nt_hash_enc
= data_blob_null
;
2032 SAFE_FREE(full_username
);
2033 SAFE_FREE(username
);
2044 /* Indicates a base64 encoded structure */
2045 parameter
= strstr_m(request
, ":: ");
2047 parameter
= strstr_m(request
, ": ");
2050 DEBUG(0, ("Parameter not found!\n"));
2051 printf("Error: Parameter not found!\n.\n");
2067 base64_decode_inplace(parameter
);
2070 if (strequal(request
, "new-nt-password-blob")) {
2071 new_nt_pswd
= strhex_to_data_blob(NULL
, parameter
);
2072 if (new_nt_pswd
.length
!= 516) {
2073 printf("Error: hex decode of %s failed! "
2074 "(got %d bytes, expected 516)\n.\n",
2076 (int)new_nt_pswd
.length
);
2077 new_nt_pswd
= data_blob_null
;
2079 } else if (strequal(request
, "old-nt-hash-blob")) {
2080 old_nt_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2081 if (old_nt_hash_enc
.length
!= 16) {
2082 printf("Error: hex decode of %s failed! "
2083 "(got %d bytes, expected 16)\n.\n",
2085 (int)old_nt_hash_enc
.length
);
2086 old_nt_hash_enc
= data_blob_null
;
2088 } else if (strequal(request
, "new-lm-password-blob")) {
2089 new_lm_pswd
= strhex_to_data_blob(NULL
, parameter
);
2090 if (new_lm_pswd
.length
!= 516) {
2091 printf("Error: hex decode of %s failed! "
2092 "(got %d bytes, expected 516)\n.\n",
2094 (int)new_lm_pswd
.length
);
2095 new_lm_pswd
= data_blob_null
;
2098 else if (strequal(request
, "old-lm-hash-blob")) {
2099 old_lm_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2100 if (old_lm_hash_enc
.length
!= 16)
2102 printf("Error: hex decode of %s failed! "
2103 "(got %d bytes, expected 16)\n.\n",
2105 (int)old_lm_hash_enc
.length
);
2106 old_lm_hash_enc
= data_blob_null
;
2108 } else if (strequal(request
, "nt-domain")) {
2109 domain
= smb_xstrdup(parameter
);
2110 } else if(strequal(request
, "username")) {
2111 username
= smb_xstrdup(parameter
);
2112 } else if(strequal(request
, "full-username")) {
2113 username
= smb_xstrdup(parameter
);
2114 } else if(strequal(request
, "new-password")) {
2115 newpswd
= smb_xstrdup(parameter
);
2116 } else if (strequal(request
, "old-password")) {
2117 oldpswd
= smb_xstrdup(parameter
);
2119 printf("Error: Unknown request %s\n.\n", request
);
2123 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode
,
2124 struct loadparm_context
*lp_ctx
,
2125 struct ntlm_auth_state
*state
,
2126 stdio_helper_function fn
, void **private2
)
2129 char tmp
[INITIAL_BUFFER_SIZE
+1];
2130 int length
, buf_size
= 0;
2133 buf
= talloc_strdup(state
->mem_ctx
, "");
2135 DEBUG(0, ("Failed to allocate input buffer.\n"));
2136 fprintf(stderr
, "ERR\n");
2142 /* this is not a typo - x_fgets doesn't work too well under
2144 if (fgets(tmp
, sizeof(tmp
)-1, stdin
) == NULL
) {
2145 if (ferror(stdin
)) {
2146 DEBUG(1, ("fgets() failed! dying..... errno=%d "
2147 "(%s)\n", ferror(stdin
),
2148 strerror(ferror(stdin
))));
2155 buf
= talloc_strdup_append_buffer(buf
, tmp
);
2156 buf_size
+= INITIAL_BUFFER_SIZE
;
2158 if (buf_size
> MAX_BUFFER_SIZE
) {
2159 DEBUG(2, ("Oversized message\n"));
2160 fprintf(stderr
, "ERR\n");
2165 c
= strchr(buf
, '\n');
2166 } while (c
== NULL
);
2171 DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf
,length
));
2173 if (buf
[0] == '\0') {
2174 DEBUG(2, ("Invalid Request\n"));
2175 fprintf(stderr
, "ERR\n");
2180 fn(stdio_helper_mode
, lp_ctx
, state
, buf
, length
, private2
);
2185 static void squid_stream(enum stdio_helper_mode stdio_mode
,
2186 struct loadparm_context
*lp_ctx
,
2187 stdio_helper_function fn
) {
2188 TALLOC_CTX
*mem_ctx
;
2189 struct ntlm_auth_state
*state
;
2191 /* initialize FDescs */
2192 setbuf(stdout
, NULL
);
2193 setbuf(stderr
, NULL
);
2195 mem_ctx
= talloc_init("ntlm_auth");
2197 DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
2198 fprintf(stderr
, "ERR\n");
2202 state
= talloc_zero(mem_ctx
, struct ntlm_auth_state
);
2204 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
2205 fprintf(stderr
, "ERR\n");
2209 state
->mem_ctx
= mem_ctx
;
2210 state
->helper_mode
= stdio_mode
;
2213 TALLOC_CTX
*frame
= talloc_stackframe();
2214 manage_squid_request(stdio_mode
, lp_ctx
, state
, fn
, NULL
);
2220 /* Authenticate a user with a challenge/response */
2222 static bool check_auth_crap(void)
2227 char user_session_key
[16];
2229 char *hex_user_session_key
;
2231 uint8_t authoritative
= 0;
2233 setbuf(stdout
, NULL
);
2236 flags
|= WBFLAG_PAM_LMKEY
;
2238 if (request_user_session_key
)
2239 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
2241 flags
|= WBFLAG_PAM_NT_STATUS_SQUASH
;
2243 nt_status
= contact_winbind_auth_crap(opt_username
, opt_domain
,
2249 (unsigned char *)lm_key
,
2250 (unsigned char *)user_session_key
,
2252 &error_string
, NULL
);
2254 if (!NT_STATUS_IS_OK(nt_status
)) {
2255 printf("%s (0x%x)\n", error_string
,
2256 NT_STATUS_V(nt_status
));
2257 SAFE_FREE(error_string
);
2262 && (!all_zero((uint8_t *)lm_key
, sizeof(lm_key
)))) {
2263 hex_lm_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)lm_key
,
2265 printf("LM_KEY: %s\n", hex_lm_key
);
2266 TALLOC_FREE(hex_lm_key
);
2268 if (request_user_session_key
2269 && (!all_zero((uint8_t *)user_session_key
,
2270 sizeof(user_session_key
)))) {
2271 hex_user_session_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)user_session_key
,
2272 sizeof(user_session_key
));
2273 printf("NT_KEY: %s\n", hex_user_session_key
);
2274 TALLOC_FREE(hex_user_session_key
);
2283 OPT_USERNAME
= 1000,
2292 OPT_USER_SESSION_KEY
,
2294 OPT_REQUIRE_MEMBERSHIP
,
2295 OPT_USE_CACHED_CREDS
,
2297 OPT_PAM_WINBIND_CONF
,
2299 OPT_TARGET_HOSTNAME
,
2303 int main(int argc
, const char **argv
)
2305 TALLOC_CTX
*frame
= talloc_stackframe();
2307 const char *helper_protocol
= NULL
;
2308 int diagnostics
= 0;
2310 const char *hex_challenge
= NULL
;
2311 const char *hex_lm_response
= NULL
;
2312 const char *hex_nt_response
= NULL
;
2313 struct loadparm_context
*lp_ctx
;
2316 /* NOTE: DO NOT change this interface without considering the implications!
2317 This is an external interface, which other programs will use to interact
2321 /* We do not use single-letter command abbreviations, because they harm future
2322 interface stability. */
2324 struct poptOption long_options
[] = {
2326 { "helper-protocol", 0, POPT_ARG_STRING
, &helper_protocol
, OPT_DOMAIN
, "operate as a stdio-based helper", "helper protocol to use"},
2327 { "username", 0, POPT_ARG_STRING
, &opt_username
, OPT_USERNAME
, "username"},
2328 { "domain", 0, POPT_ARG_STRING
, &opt_domain
, OPT_DOMAIN
, "domain name"},
2329 { "workstation", 0, POPT_ARG_STRING
, &opt_workstation
, OPT_WORKSTATION
, "workstation"},
2330 { "challenge", 0, POPT_ARG_STRING
, &hex_challenge
, OPT_CHALLENGE
, "challenge (HEX encoded)"},
2331 { "lm-response", 0, POPT_ARG_STRING
, &hex_lm_response
, OPT_LM
, "LM Response to the challenge (HEX encoded)"},
2332 { "nt-response", 0, POPT_ARG_STRING
, &hex_nt_response
, OPT_NT
, "NT or NTLMv2 Response to the challenge (HEX encoded)"},
2333 { "password", 0, POPT_ARG_STRING
, &opt_password
, OPT_PASSWORD
, "User's plaintext password"},
2334 { "request-lm-key", 0, POPT_ARG_NONE
, &request_lm_key
, OPT_LM_KEY
, "Retrieve LM session key"},
2335 { "request-nt-key", 0, POPT_ARG_NONE
, &request_user_session_key
, OPT_USER_SESSION_KEY
, "Retrieve User (NT) session key"},
2336 { "use-cached-creds", 0, POPT_ARG_NONE
, &use_cached_creds
, OPT_USE_CACHED_CREDS
, "Use cached credentials if no password is given"},
2337 { "allow-mschapv2", 0, POPT_ARG_NONE
, &opt_allow_mschapv2
, OPT_ALLOW_MSCHAPV2
, "Explicitly allow MSCHAPv2" },
2338 { "offline-logon", 0, POPT_ARG_NONE
, &offline_logon
,
2340 "Use cached passwords when DC is offline"},
2341 { "diagnostics", 0, POPT_ARG_NONE
, &diagnostics
,
2343 "Perform diagnostics on the authentication chain"},
2344 { "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" },
2345 { "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" },
2346 { "target-service", 0, POPT_ARG_STRING
, &opt_target_service
, OPT_TARGET_SERVICE
, "Target service (eg http)" },
2347 { "target-hostname", 0, POPT_ARG_STRING
, &opt_target_hostname
, OPT_TARGET_HOSTNAME
, "Target hostname" },
2348 POPT_COMMON_CONFIGFILE
2354 /* Samba client initialisation */
2357 setup_logging("ntlm_auth", DEBUG_STDERR
);
2362 pc
= poptGetContext("ntlm_auth", argc
, argv
, long_options
, 0);
2364 /* Parse command line options */
2367 poptPrintHelp(pc
, stderr
, 0);
2371 while((opt
= poptGetNextOpt(pc
)) != -1) {
2372 /* Get generic config options like --configfile */
2375 poptFreeContext(pc
);
2377 if (!lp_load_global(get_dyn_CONFIGFILE())) {
2378 d_fprintf(stderr
, "ntlm_auth: error opening config file %s. Error was %s\n",
2379 get_dyn_CONFIGFILE(), strerror(errno
));
2383 pc
= poptGetContext(NULL
, argc
, (const char **)argv
, long_options
,
2384 POPT_CONTEXT_KEEP_FIRST
);
2386 while((opt
= poptGetNextOpt(pc
)) != -1) {
2389 opt_challenge
= strhex_to_data_blob(NULL
, hex_challenge
);
2390 if (opt_challenge
.length
!= 8) {
2391 fprintf(stderr
, "hex decode of %s failed! "
2392 "(only got %d bytes)\n",
2394 (int)opt_challenge
.length
);
2399 opt_lm_response
= strhex_to_data_blob(NULL
, hex_lm_response
);
2400 if (opt_lm_response
.length
!= 24) {
2401 fprintf(stderr
, "hex decode of %s failed! "
2402 "(only got %d bytes)\n",
2404 (int)opt_lm_response
.length
);
2410 opt_nt_response
= strhex_to_data_blob(NULL
, hex_nt_response
);
2411 if (opt_nt_response
.length
< 24) {
2412 fprintf(stderr
, "hex decode of %s failed! "
2413 "(only got %d bytes)\n",
2415 (int)opt_nt_response
.length
);
2420 case OPT_REQUIRE_MEMBERSHIP
:
2421 if (strncasecmp_m("S-", require_membership_of
, 2) == 0) {
2422 require_membership_of_sid
= require_membership_of
;
2429 char *domain
= SMB_STRDUP(opt_username
);
2430 char *p
= strchr_m(domain
, *lp_winbind_separator());
2434 if (opt_domain
&& !strequal(opt_domain
, domain
)) {
2435 fprintf(stderr
, "Domain specified in username (%s) "
2436 "doesn't match specified domain (%s)!\n\n",
2437 domain
, opt_domain
);
2438 poptPrintHelp(pc
, stderr
, 0);
2441 opt_domain
= domain
;
2447 /* Note: if opt_domain is "" then send no domain */
2448 if (opt_domain
== NULL
) {
2449 opt_domain
= get_winbind_domain();
2452 if (opt_workstation
== NULL
) {
2453 opt_workstation
= "";
2456 lp_ctx
= loadparm_init_s3(NULL
, loadparm_s3_helpers());
2457 if (lp_ctx
== NULL
) {
2458 fprintf(stderr
, "loadparm_init_s3() failed!\n");
2462 if (helper_protocol
) {
2464 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2465 if (strcmp(helper_protocol
, stdio_helper_protocols
[i
].name
) == 0) {
2466 squid_stream(stdio_helper_protocols
[i
].mode
, lp_ctx
, stdio_helper_protocols
[i
].fn
);
2470 fprintf(stderr
, "unknown helper protocol [%s]\n\n"
2471 "Valid helper protools:\n\n", helper_protocol
);
2473 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2474 fprintf(stderr
, "%s\n",
2475 stdio_helper_protocols
[i
].name
);
2481 if (!opt_username
|| !*opt_username
) {
2482 fprintf(stderr
, "username must be specified!\n\n");
2483 poptPrintHelp(pc
, stderr
, 0);
2487 if (opt_challenge
.length
) {
2488 if (!check_auth_crap()) {
2494 if (!opt_password
) {
2495 char pwd
[256] = {0};
2498 rc
= samba_getpass("Password: ", pwd
, sizeof(pwd
), false, false);
2500 opt_password
= SMB_STRDUP(pwd
);
2505 if (!diagnose_ntlm_auth()) {
2511 fstr_sprintf(user
, "%s%c%s", opt_domain
, winbind_separator(), opt_username
);
2512 if (!check_plaintext_auth(user
, opt_password
, True
)) {
2519 poptFreeContext(pc
);