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 "lib/cmdline/cmdline.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 "librpc/gen_ndr/krb5pac.h"
41 #include "auth/common_auth.h"
42 #include "source3/include/auth.h"
43 #include "source3/auth/proto.h"
44 #include "nsswitch/libwbclient/wbclient.h"
45 #include "nsswitch/winbind_struct_protocol.h"
46 #include "nsswitch/libwbclient/wbclient_internal.h"
47 #include "lib/param/loadparm.h"
48 #include "lib/util/base64.h"
49 #include "cmdline_contexts.h"
50 #include "lib/util/tevent_ntstatus.h"
51 #include "lib/util/string_wrappers.h"
53 #include <gnutls/gnutls.h>
54 #include <gnutls/crypto.h>
57 #include "auth/kerberos/pac_utils.h"
60 #ifndef PAM_WINBIND_CONFIG_FILE
61 #define PAM_WINBIND_CONFIG_FILE "/etc/security/pam_winbind.conf"
64 #define WINBIND_KRB5_AUTH 0x00000080
67 #define DBGC_CLASS DBGC_WINBIND
69 #define INITIAL_BUFFER_SIZE 300
70 #define MAX_BUFFER_SIZE 630000
72 enum stdio_helper_mode
{
80 NTLM_CHANGE_PASSWORD_1
,
84 enum ntlm_auth_cli_state
{
91 struct ntlm_auth_state
{
93 enum stdio_helper_mode helper_mode
;
94 enum ntlm_auth_cli_state cli_state
;
95 struct ntlmssp_state
*ntlmssp_state
;
97 char *want_feature_list
;
98 bool have_session_key
;
99 DATA_BLOB session_key
;
100 DATA_BLOB initial_message
;
101 void *gensec_private_1
;
103 typedef void (*stdio_helper_function
)(enum stdio_helper_mode stdio_helper_mode
,
104 struct loadparm_context
*lp_ctx
,
105 struct ntlm_auth_state
*state
, char *buf
,
106 int length
, void **private2
);
108 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode
,
109 struct loadparm_context
*lp_ctx
,
110 char *buf
, int length
, void **private1
);
112 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode
,
113 struct loadparm_context
*lp_ctx
,
114 struct ntlm_auth_state
*state
,
115 stdio_helper_function fn
, void **private2
);
117 static void manage_squid_basic_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_squid_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_client_ntlmssp_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_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_gss_spnego_client_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_server_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 void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode
,
148 struct loadparm_context
*lp_ctx
,
149 struct ntlm_auth_state
*state
,
150 char *buf
, int length
, void **private2
);
152 static const struct {
153 enum stdio_helper_mode mode
;
155 stdio_helper_function fn
;
156 } stdio_helper_protocols
[] = {
157 { SQUID_2_4_BASIC
, "squid-2.4-basic", manage_squid_basic_request
},
158 { SQUID_2_5_BASIC
, "squid-2.5-basic", manage_squid_basic_request
},
159 { SQUID_2_5_NTLMSSP
, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request
},
160 { NTLMSSP_CLIENT_1
, "ntlmssp-client-1", manage_client_ntlmssp_request
},
161 { GSS_SPNEGO_SERVER
, "gss-spnego", manage_gss_spnego_request
},
162 { GSS_SPNEGO_CLIENT
, "gss-spnego-client", manage_gss_spnego_client_request
},
163 { NTLM_SERVER_1
, "ntlm-server-1", manage_ntlm_server_1_request
},
164 { NTLM_CHANGE_PASSWORD_1
, "ntlm-change-password-1", manage_ntlm_change_password_1_request
},
165 { NUM_HELPER_MODES
, NULL
, NULL
}
168 const char *opt_username
;
169 const char *opt_domain
;
170 const char *opt_workstation
;
171 const char *opt_password
;
172 static DATA_BLOB opt_challenge
;
173 static DATA_BLOB opt_lm_response
;
174 static DATA_BLOB opt_nt_response
;
175 static int request_lm_key
;
176 static int request_user_session_key
;
177 static int use_cached_creds
;
178 static int offline_logon
;
179 static int opt_allow_mschapv2
;
181 static const char *require_membership_of
;
182 static const char *require_membership_of_sid
;
183 static const char *opt_pam_winbind_conf
;
185 const char *opt_target_service
;
186 const char *opt_target_hostname
;
189 /* This is a bit hairy, but the basic idea is to do a password callback
190 to the calling application. The callback comes from within gensec */
192 static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mode
,
193 struct loadparm_context
*lp_ctx
,
194 struct ntlm_auth_state
*state
, char *buf
, int length
,
198 if (strlen(buf
) < 2) {
199 DEBUG(1, ("query [%s] invalid\n", buf
));
200 printf("BH Query invalid\n");
204 if (strlen(buf
) > 3) {
205 in
= base64_decode_data_blob(buf
+ 3);
207 in
= data_blob(NULL
, 0);
210 if (strncmp(buf
, "PW ", 3) == 0) {
212 *password
= talloc_strndup(NULL
,
213 (const char *)in
.data
, in
.length
);
215 if (*password
== NULL
) {
216 DEBUG(1, ("Out of memory\n"));
217 printf("BH Out of memory\n");
226 DEBUG(1, ("Asked for (and expected) a password\n"));
227 printf("BH Expected a password\n");
232 * Callback for password credentials. This is not async, and when
233 * GENSEC and the credentials code is made async, it will look rather
237 static const char *get_password(struct cli_credentials
*credentials
)
239 TALLOC_CTX
*frame
= talloc_stackframe();
240 char *password
= NULL
;
241 struct ntlm_auth_state
*state
;
243 state
= talloc_zero(frame
, struct ntlm_auth_state
);
245 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
246 fprintf(stderr
, "ERR\n");
250 state
->mem_ctx
= state
;
252 /* Ask for a password */
255 manage_squid_request(NUM_HELPER_MODES
/* bogus */, NULL
, state
, manage_gensec_get_pw_request
, (void **)&password
);
256 talloc_steal(credentials
, password
);
262 * A limited set of features are defined with text strings as needed
266 static void gensec_want_feature_list(struct gensec_security
*state
, char* feature_list
)
268 if (in_list("NTLMSSP_FEATURE_SESSION_KEY", feature_list
, true)) {
269 DEBUG(10, ("want GENSEC_FEATURE_SESSION_KEY\n"));
270 gensec_want_feature(state
, GENSEC_FEATURE_SESSION_KEY
);
272 if (in_list("NTLMSSP_FEATURE_SIGN", feature_list
, true)) {
273 DEBUG(10, ("want GENSEC_FEATURE_SIGN\n"));
274 gensec_want_feature(state
, GENSEC_FEATURE_SIGN
);
276 if (in_list("NTLMSSP_FEATURE_SEAL", feature_list
, true)) {
277 DEBUG(10, ("want GENSEC_FEATURE_SEAL\n"));
278 gensec_want_feature(state
, GENSEC_FEATURE_SEAL
);
280 if (in_list("NTLMSSP_FEATURE_CCACHE", feature_list
, true)) {
281 DEBUG(10, ("want GENSEC_FEATURE_NTLM_CCACHE\n"));
282 gensec_want_feature(state
, GENSEC_FEATURE_NTLM_CCACHE
);
286 static char winbind_separator(void)
288 struct wbcInterfaceDetails
*details
;
296 ret
= wbcInterfaceDetails(&details
);
297 if (!WBC_ERROR_IS_OK(ret
)) {
298 d_fprintf(stderr
, "could not obtain winbind separator!\n");
299 return *lp_winbind_separator();
302 sep
= details
->winbind_separator
;
304 wbcFreeMemory(details
);
309 d_fprintf(stderr
, "winbind separator was NULL!\n");
310 return *lp_winbind_separator();
316 const char *get_winbind_domain(void)
318 struct wbcInterfaceDetails
*details
;
321 static fstring winbind_domain
;
322 if (*winbind_domain
) {
323 return winbind_domain
;
326 /* Send off request */
328 ret
= wbcInterfaceDetails(&details
);
329 if (!WBC_ERROR_IS_OK(ret
)) {
330 DEBUG(1, ("could not obtain winbind domain name!\n"));
331 return lp_workgroup();
334 fstrcpy(winbind_domain
, details
->netbios_domain
);
336 wbcFreeMemory(details
);
338 return winbind_domain
;
342 const char *get_winbind_netbios_name(void)
344 struct wbcInterfaceDetails
*details
;
347 static fstring winbind_netbios_name
;
349 if (*winbind_netbios_name
) {
350 return winbind_netbios_name
;
353 /* Send off request */
355 ret
= wbcInterfaceDetails(&details
);
356 if (!WBC_ERROR_IS_OK(ret
)) {
357 DEBUG(1, ("could not obtain winbind netbios name!\n"));
358 return lp_netbios_name();
361 fstrcpy(winbind_netbios_name
, details
->netbios_name
);
363 wbcFreeMemory(details
);
365 return winbind_netbios_name
;
369 DATA_BLOB
get_challenge(void)
371 static DATA_BLOB chal
;
372 if (opt_challenge
.length
)
373 return opt_challenge
;
375 chal
= data_blob(NULL
, 8);
377 generate_random_buffer(chal
.data
, chal
.length
);
381 /* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
382 form DOMAIN/user into a domain and a user */
384 static bool parse_ntlm_auth_domain_user(const char *domuser
, fstring domain
,
388 char *p
= strchr(domuser
,winbind_separator());
395 fstrcpy(domain
, domuser
);
396 domain
[PTR_DIFF(p
, domuser
)] = 0;
397 return strupper_m(domain
);
400 static bool get_require_membership_sid(void) {
401 fstring domain
, name
, sidbuf
;
402 struct wbcDomainSid sid
;
403 enum wbcSidType type
;
406 if (!require_membership_of
) {
410 if (require_membership_of_sid
) {
414 /* Otherwise, ask winbindd for the name->sid request */
416 if (!parse_ntlm_auth_domain_user(require_membership_of
,
418 DEBUG(0, ("Could not parse %s into separate domain/name parts!\n",
419 require_membership_of
));
423 ret
= wbcLookupName(domain
, name
, &sid
, &type
);
424 if (!WBC_ERROR_IS_OK(ret
)) {
425 DEBUG(0, ("Winbindd lookupname failed to resolve %s into a SID!\n",
426 require_membership_of
));
430 wbcSidToStringBuf(&sid
, sidbuf
, sizeof(sidbuf
));
432 require_membership_of_sid
= SMB_STRDUP(sidbuf
);
434 if (require_membership_of_sid
)
441 * Get some configuration from pam_winbind.conf to see if we
442 * need to contact trusted domain
445 int get_pam_winbind_config(void)
448 struct tiniparser_dictionary
*d
= NULL
;
450 if (!opt_pam_winbind_conf
|| !*opt_pam_winbind_conf
) {
451 opt_pam_winbind_conf
= PAM_WINBIND_CONFIG_FILE
;
454 d
= tiniparser_load(opt_pam_winbind_conf
);
460 if (tiniparser_getboolean(d
, "global:krb5_auth", false)) {
461 ctrl
|= WINBIND_KRB5_AUTH
;
464 tiniparser_freedict(d
);
469 /* Authenticate a user with a plaintext password */
471 static bool check_plaintext_auth(const char *user
, const char *pass
,
472 bool stdout_diagnostics
)
474 struct winbindd_request request
;
475 struct winbindd_response response
;
478 if (!get_require_membership_sid()) {
482 /* Send off request */
484 ZERO_STRUCT(request
);
485 ZERO_STRUCT(response
);
487 fstrcpy(request
.data
.auth
.user
, user
);
488 fstrcpy(request
.data
.auth
.pass
, pass
);
489 if (require_membership_of_sid
) {
490 strlcpy(request
.data
.auth
.require_membership_of_sid
,
491 require_membership_of_sid
,
492 sizeof(request
.data
.auth
.require_membership_of_sid
));
496 request
.flags
|= WBFLAG_PAM_CACHED_LOGIN
;
499 ret
= wbcRequestResponse(NULL
, WINBINDD_PAM_AUTH
,
500 &request
, &response
);
502 /* Display response */
504 if (stdout_diagnostics
) {
505 if (!WBC_ERROR_IS_OK(ret
) && (response
.data
.auth
.nt_status
== 0)) {
506 d_fprintf(stderr
, "Reading winbind reply failed! (0x01)\n");
509 d_printf("%s: %s (0x%x)\n",
510 response
.data
.auth
.nt_status_string
,
511 response
.data
.auth
.error_string
,
512 response
.data
.auth
.nt_status
);
514 if (!WBC_ERROR_IS_OK(ret
) && (response
.data
.auth
.nt_status
== 0)) {
515 DEBUG(1, ("Reading winbind reply failed! (0x01)\n"));
518 DEBUG(3, ("%s: %s (0x%x)\n",
519 response
.data
.auth
.nt_status_string
,
520 response
.data
.auth
.error_string
,
521 response
.data
.auth
.nt_status
));
524 return WBC_ERROR_IS_OK(ret
);
527 /* authenticate a user with an encrypted username/password */
529 NTSTATUS
contact_winbind_auth_crap(const char *username
,
531 const char *workstation
,
532 const DATA_BLOB
*challenge
,
533 const DATA_BLOB
*lm_response
,
534 const DATA_BLOB
*nt_response
,
536 uint32_t extra_logon_parameters
,
538 uint8_t user_session_key
[16],
539 uint8_t *pauthoritative
,
545 struct winbindd_request request
;
546 struct winbindd_response response
;
550 if (!get_require_membership_sid()) {
551 return NT_STATUS_INVALID_PARAMETER
;
554 ZERO_STRUCT(request
);
555 ZERO_STRUCT(response
);
557 request
.flags
= flags
;
559 request
.data
.auth_crap
.logon_parameters
= extra_logon_parameters
560 | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
| MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT
;
562 if (opt_allow_mschapv2
) {
563 request
.data
.auth_crap
.logon_parameters
|= MSV1_0_ALLOW_MSVCHAPV2
;
566 if (require_membership_of_sid
)
567 fstrcpy(request
.data
.auth_crap
.require_membership_of_sid
, require_membership_of_sid
);
569 fstrcpy(request
.data
.auth_crap
.user
, username
);
570 fstrcpy(request
.data
.auth_crap
.domain
, domain
);
572 fstrcpy(request
.data
.auth_crap
.workstation
,
575 memcpy(request
.data
.auth_crap
.chal
, challenge
->data
, MIN(challenge
->length
, 8));
577 if (lm_response
&& lm_response
->length
) {
578 size_t capped_lm_response_len
= MIN(
580 sizeof(request
.data
.auth_crap
.lm_resp
));
582 memcpy(request
.data
.auth_crap
.lm_resp
,
584 capped_lm_response_len
);
585 request
.data
.auth_crap
.lm_resp_len
= capped_lm_response_len
;
588 if (nt_response
&& nt_response
->length
) {
589 if (nt_response
->length
> sizeof(request
.data
.auth_crap
.nt_resp
)) {
590 request
.flags
= request
.flags
| WBFLAG_BIG_NTLMV2_BLOB
;
591 request
.extra_len
= nt_response
->length
;
592 request
.extra_data
.data
= SMB_MALLOC_ARRAY(char, request
.extra_len
);
593 if (request
.extra_data
.data
== NULL
) {
594 return NT_STATUS_NO_MEMORY
;
596 memcpy(request
.extra_data
.data
, nt_response
->data
,
597 nt_response
->length
);
600 memcpy(request
.data
.auth_crap
.nt_resp
,
601 nt_response
->data
, nt_response
->length
);
603 request
.data
.auth_crap
.nt_resp_len
= nt_response
->length
;
606 ret
= wbcRequestResponsePriv(
608 WINBINDD_PAM_AUTH_CRAP
,
611 SAFE_FREE(request
.extra_data
.data
);
613 /* Display response */
615 if (!WBC_ERROR_IS_OK(ret
) && (response
.data
.auth
.nt_status
== 0)) {
616 nt_status
= NT_STATUS_UNSUCCESSFUL
;
618 *error_string
= smb_xstrdup("Reading winbind reply failed!");
619 winbindd_free_response(&response
);
623 nt_status
= (NT_STATUS(response
.data
.auth
.nt_status
));
624 if (!NT_STATUS_IS_OK(nt_status
)) {
626 *error_string
= smb_xstrdup(response
.data
.auth
.error_string
);
627 *pauthoritative
= response
.data
.auth
.authoritative
;
628 winbindd_free_response(&response
);
632 if ((flags
& WBFLAG_PAM_LMKEY
) && lm_key
) {
633 memcpy(lm_key
, response
.data
.auth
.first_8_lm_hash
,
634 sizeof(response
.data
.auth
.first_8_lm_hash
));
636 if ((flags
& WBFLAG_PAM_USER_SESSION_KEY
) && user_session_key
) {
637 memcpy(user_session_key
, response
.data
.auth
.user_session_key
,
638 sizeof(response
.data
.auth
.user_session_key
));
641 if (flags
& WBFLAG_PAM_UNIX_NAME
) {
642 *unix_name
= SMB_STRDUP(response
.data
.auth
.unix_username
);
644 winbindd_free_response(&response
);
645 return NT_STATUS_NO_MEMORY
;
649 winbindd_free_response(&response
);
653 /* contact server to change user password using auth crap */
654 static NTSTATUS
contact_winbind_change_pswd_auth_crap(const char *username
,
656 const DATA_BLOB new_nt_pswd
,
657 const DATA_BLOB old_nt_hash_enc
,
658 const DATA_BLOB new_lm_pswd
,
659 const DATA_BLOB old_lm_hash_enc
,
664 struct winbindd_request request
;
665 struct winbindd_response response
;
667 if (!get_require_membership_sid())
670 *error_string
= smb_xstrdup("Can't get membership sid.");
671 return NT_STATUS_INVALID_PARAMETER
;
674 ZERO_STRUCT(request
);
675 ZERO_STRUCT(response
);
678 fstrcpy(request
.data
.chng_pswd_auth_crap
.user
, username
);
680 fstrcpy(request
.data
.chng_pswd_auth_crap
.domain
,domain
);
682 if(new_nt_pswd
.length
)
684 memcpy(request
.data
.chng_pswd_auth_crap
.new_nt_pswd
, new_nt_pswd
.data
, sizeof(request
.data
.chng_pswd_auth_crap
.new_nt_pswd
));
685 request
.data
.chng_pswd_auth_crap
.new_nt_pswd_len
= new_nt_pswd
.length
;
688 if(old_nt_hash_enc
.length
)
690 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
));
691 request
.data
.chng_pswd_auth_crap
.old_nt_hash_enc_len
= old_nt_hash_enc
.length
;
694 if(new_lm_pswd
.length
)
696 memcpy(request
.data
.chng_pswd_auth_crap
.new_lm_pswd
, new_lm_pswd
.data
, sizeof(request
.data
.chng_pswd_auth_crap
.new_lm_pswd
));
697 request
.data
.chng_pswd_auth_crap
.new_lm_pswd_len
= new_lm_pswd
.length
;
700 if(old_lm_hash_enc
.length
)
702 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
));
703 request
.data
.chng_pswd_auth_crap
.old_lm_hash_enc_len
= old_lm_hash_enc
.length
;
706 ret
= wbcRequestResponse(NULL
, WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP
,
707 &request
, &response
);
709 /* Display response */
711 if (!WBC_ERROR_IS_OK(ret
) && (response
.data
.auth
.nt_status
== 0))
713 nt_status
= NT_STATUS_UNSUCCESSFUL
;
715 *error_string
= smb_xstrdup("Reading winbind reply failed!");
716 winbindd_free_response(&response
);
720 nt_status
= (NT_STATUS(response
.data
.auth
.nt_status
));
721 if (!NT_STATUS_IS_OK(nt_status
))
724 *error_string
= smb_xstrdup(response
.data
.auth
.error_string
);
725 winbindd_free_response(&response
);
729 winbindd_free_response(&response
);
734 static NTSTATUS
ntlm_auth_generate_session_info(struct auth4_context
*auth_context
,
736 void *server_returned_info
,
737 const char *original_user_name
,
738 uint32_t session_info_flags
,
739 struct auth_session_info
**session_info_out
)
741 const char *unix_username
= (const char *)server_returned_info
;
742 struct dom_sid
*sids
= NULL
;
743 struct auth_session_info
*session_info
= NULL
;
745 session_info
= talloc_zero(mem_ctx
, struct auth_session_info
);
746 if (session_info
== NULL
) {
747 return NT_STATUS_NO_MEMORY
;
750 session_info
->unix_info
= talloc_zero(session_info
, struct auth_user_info_unix
);
751 if (session_info
->unix_info
== NULL
) {
752 TALLOC_FREE(session_info
);
753 return NT_STATUS_NO_MEMORY
;
755 session_info
->unix_info
->unix_name
= talloc_strdup(session_info
->unix_info
,
757 if (session_info
->unix_info
->unix_name
== NULL
) {
758 TALLOC_FREE(session_info
);
759 return NT_STATUS_NO_MEMORY
;
762 session_info
->security_token
= talloc_zero(session_info
, struct security_token
);
763 if (session_info
->security_token
== NULL
) {
764 TALLOC_FREE(session_info
);
765 return NT_STATUS_NO_MEMORY
;
768 sids
= talloc_zero_array(session_info
->security_token
,
771 TALLOC_FREE(session_info
);
772 return NT_STATUS_NO_MEMORY
;
774 sid_copy(&sids
[0], &global_sid_World
);
775 sid_copy(&sids
[1], &global_sid_Network
);
776 sid_copy(&sids
[2], &global_sid_Authenticated_Users
);
778 session_info
->security_token
->num_sids
= talloc_array_length(sids
);
779 session_info
->security_token
->sids
= sids
;
781 *session_info_out
= session_info
;
786 static NTSTATUS
ntlm_auth_generate_session_info_pac(struct auth4_context
*auth_ctx
,
788 struct smb_krb5_context
*smb_krb5_context
,
790 const char *princ_name
,
791 const struct tsocket_address
*remote_address
,
792 uint32_t session_info_flags
,
793 struct auth_session_info
**session_info
)
796 struct PAC_LOGON_INFO
*logon_info
= NULL
;
799 const char *domain
= "";
800 const char *user
= "";
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
)) {
818 status
= NT_STATUS_ACCESS_DENIED
;
819 DBG_WARNING("Kerberos ticket for[%s] has no PAC: %s\n",
820 princ_name
, nt_errstr(status
));
824 if (logon_info
->info3
.base
.account_name
.string
!= NULL
) {
825 user
= logon_info
->info3
.base
.account_name
.string
;
829 if (logon_info
->info3
.base
.logon_domain
.string
!= NULL
) {
830 domain
= logon_info
->info3
.base
.logon_domain
.string
;
835 if (strlen(user
) == 0 || strlen(domain
) == 0) {
836 status
= NT_STATUS_ACCESS_DENIED
;
837 DBG_WARNING("Kerberos ticket for[%s] has invalid "
838 "account_name[%s]/logon_domain[%s]: %s\n",
840 logon_info
->info3
.base
.account_name
.string
,
841 logon_info
->info3
.base
.logon_domain
.string
,
846 DBG_NOTICE("Kerberos ticket principal name is [%s] "
847 "account_name[%s]/logon_domain[%s]\n",
848 princ_name
, user
, domain
);
850 if (!strequal(domain
, lp_workgroup())) {
851 if (!lp_allow_trusted_domains()) {
852 status
= NT_STATUS_LOGON_FAILURE
;
857 unixuser
= talloc_asprintf(tmp_ctx
, "%s%c%s", domain
, winbind_separator(), user
);
859 status
= NT_STATUS_NO_MEMORY
;
863 status
= ntlm_auth_generate_session_info(auth_ctx
, mem_ctx
, unixuser
, NULL
, session_info_flags
, session_info
);
866 TALLOC_FREE(tmp_ctx
);
873 * Return the challenge as determined by the authentication subsystem
874 * @return an 8 byte random challenge
877 static NTSTATUS
ntlm_auth_get_challenge(struct auth4_context
*auth_ctx
,
880 if (auth_ctx
->challenge
.data
.length
== 8) {
881 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
882 auth_ctx
->challenge
.set_by
));
883 memcpy(chal
, auth_ctx
->challenge
.data
.data
, 8);
887 if (!auth_ctx
->challenge
.set_by
) {
888 generate_random_buffer(chal
, 8);
890 auth_ctx
->challenge
.data
= data_blob_talloc(auth_ctx
, chal
, 8);
891 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.data
.data
);
892 auth_ctx
->challenge
.set_by
= "random";
895 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
896 auth_ctx
->challenge
.set_by
));
902 * NTLM2 authentication modifies the effective challenge,
903 * @param challenge The new challenge value
905 static NTSTATUS
ntlm_auth_set_challenge(struct auth4_context
*auth_ctx
, const uint8_t chal
[8], const char *set_by
)
907 auth_ctx
->challenge
.set_by
= talloc_strdup(auth_ctx
, set_by
);
908 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.set_by
);
910 auth_ctx
->challenge
.data
= data_blob_talloc(auth_ctx
, chal
, 8);
911 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.data
.data
);
917 * Check the password on an NTLMSSP login.
919 * Return the session keys used on the connection.
922 struct winbind_pw_check_state
{
923 uint8_t authoritative
;
925 DATA_BLOB nt_session_key
;
926 DATA_BLOB lm_session_key
;
929 static struct tevent_req
*winbind_pw_check_send(
931 struct tevent_context
*ev
,
932 struct auth4_context
*auth4_context
,
933 const struct auth_usersupplied_info
*user_info
)
935 struct tevent_req
*req
= NULL
;
936 struct winbind_pw_check_state
*state
= NULL
;
938 char *error_string
= NULL
;
940 uint8_t user_sess_key
[16];
941 char *unix_name
= NULL
;
943 req
= tevent_req_create(
944 mem_ctx
, &state
, struct winbind_pw_check_state
);
949 nt_status
= contact_winbind_auth_crap(
950 user_info
->client
.account_name
,
951 user_info
->client
.domain_name
,
952 user_info
->workstation_name
,
953 &auth4_context
->challenge
.data
,
954 &user_info
->password
.response
.lanman
,
955 &user_info
->password
.response
.nt
,
957 WBFLAG_PAM_USER_SESSION_KEY
|
958 WBFLAG_PAM_UNIX_NAME
,
960 lm_key
, user_sess_key
,
961 &state
->authoritative
,
965 if (tevent_req_nterror(req
, nt_status
)) {
966 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCESS_DENIED
)) {
967 DBG_ERR("Login for user [%s]\\[%s]@[%s] failed due "
969 user_info
->client
.domain_name
,
970 user_info
->client
.account_name
,
971 user_info
->workstation_name
,
974 "unknown error (NULL)");
976 DBG_NOTICE("Login for user [%s]\\[%s]@[%s] failed due "
978 user_info
->client
.domain_name
,
979 user_info
->client
.account_name
,
980 user_info
->workstation_name
,
983 "unknown error (NULL)");
988 if (!all_zero(lm_key
, 8)) {
989 state
->lm_session_key
= data_blob_talloc(state
, NULL
, 16);
990 if (tevent_req_nomem(state
->lm_session_key
.data
, req
)) {
993 memcpy(state
->lm_session_key
.data
, lm_key
, 8);
994 memset(state
->lm_session_key
.data
+8, '\0', 8);
996 if (!all_zero(user_sess_key
, 16)) {
997 state
->nt_session_key
= data_blob_talloc(
998 state
, user_sess_key
, 16);
999 if (tevent_req_nomem(state
->nt_session_key
.data
, req
)) {
1003 state
->server_info
= talloc_strdup(state
, unix_name
);
1004 if (tevent_req_nomem(state
->server_info
, req
)) {
1007 tevent_req_done(req
);
1010 SAFE_FREE(error_string
);
1011 SAFE_FREE(unix_name
);
1012 return tevent_req_post(req
, ev
);
1015 static NTSTATUS
winbind_pw_check_recv(struct tevent_req
*req
,
1016 TALLOC_CTX
*mem_ctx
,
1017 uint8_t *pauthoritative
,
1018 void **server_returned_info
,
1019 DATA_BLOB
*nt_session_key
,
1020 DATA_BLOB
*lm_session_key
)
1022 struct winbind_pw_check_state
*state
= tevent_req_data(
1023 req
, struct winbind_pw_check_state
);
1026 if (pauthoritative
!= NULL
) {
1027 *pauthoritative
= state
->authoritative
;
1030 if (tevent_req_is_nterror(req
, &status
)) {
1034 if (server_returned_info
!= NULL
) {
1035 *server_returned_info
= talloc_move(
1036 mem_ctx
, &state
->server_info
);
1038 if (nt_session_key
!= NULL
) {
1039 *nt_session_key
= (DATA_BLOB
) {
1040 .data
= talloc_move(
1041 mem_ctx
, &state
->nt_session_key
.data
),
1042 .length
= state
->nt_session_key
.length
,
1045 if (lm_session_key
!= NULL
) {
1046 *lm_session_key
= (DATA_BLOB
) {
1047 .data
= talloc_move(
1048 mem_ctx
, &state
->lm_session_key
.data
),
1049 .length
= state
->lm_session_key
.length
,
1053 return NT_STATUS_OK
;
1056 struct local_pw_check_state
{
1057 uint8_t authoritative
;
1059 DATA_BLOB nt_session_key
;
1060 DATA_BLOB lm_session_key
;
1063 static struct tevent_req
*local_pw_check_send(
1064 TALLOC_CTX
*mem_ctx
,
1065 struct tevent_context
*ev
,
1066 struct auth4_context
*auth4_context
,
1067 const struct auth_usersupplied_info
*user_info
)
1069 struct tevent_req
*req
= NULL
;
1070 struct local_pw_check_state
*state
= NULL
;
1071 struct samr_Password lm_pw
, nt_pw
;
1074 req
= tevent_req_create(
1075 mem_ctx
, &state
, struct local_pw_check_state
);
1079 state
->authoritative
= 1;
1081 nt_lm_owf_gen (opt_password
, nt_pw
.hash
, lm_pw
.hash
);
1083 nt_status
= ntlm_password_check(
1088 &auth4_context
->challenge
.data
,
1089 &user_info
->password
.response
.lanman
,
1090 &user_info
->password
.response
.nt
,
1091 user_info
->client
.account_name
,
1092 user_info
->client
.account_name
,
1093 user_info
->client
.domain_name
,
1096 &state
->nt_session_key
,
1097 &state
->lm_session_key
);
1099 if (tevent_req_nterror(req
, nt_status
)) {
1100 DBG_NOTICE("Login for user [%s]\\[%s]@[%s] failed due to "
1102 user_info
->client
.domain_name
,
1103 user_info
->client
.account_name
,
1104 user_info
->workstation_name
,
1105 nt_errstr(nt_status
));
1106 return tevent_req_post(req
, ev
);
1109 state
->server_info
= talloc_asprintf(
1112 user_info
->client
.domain_name
,
1113 *lp_winbind_separator(),
1114 user_info
->client
.account_name
);
1115 if (tevent_req_nomem(state
->server_info
, req
)) {
1116 return tevent_req_post(req
, ev
);
1119 tevent_req_done(req
);
1120 return tevent_req_post(req
, ev
);
1123 static NTSTATUS
local_pw_check_recv(struct tevent_req
*req
,
1124 TALLOC_CTX
*mem_ctx
,
1125 uint8_t *pauthoritative
,
1126 void **server_returned_info
,
1127 DATA_BLOB
*nt_session_key
,
1128 DATA_BLOB
*lm_session_key
)
1130 struct local_pw_check_state
*state
= tevent_req_data(
1131 req
, struct local_pw_check_state
);
1134 if (pauthoritative
!= NULL
) {
1135 *pauthoritative
= state
->authoritative
;
1138 if (tevent_req_is_nterror(req
, &status
)) {
1142 if (server_returned_info
!= NULL
) {
1143 *server_returned_info
= talloc_move(
1144 mem_ctx
, &state
->server_info
);
1146 if (nt_session_key
!= NULL
) {
1147 *nt_session_key
= (DATA_BLOB
) {
1148 .data
= talloc_move(
1149 mem_ctx
, &state
->nt_session_key
.data
),
1150 .length
= state
->nt_session_key
.length
,
1153 if (lm_session_key
!= NULL
) {
1154 *lm_session_key
= (DATA_BLOB
) {
1155 .data
= talloc_move(
1156 mem_ctx
, &state
->lm_session_key
.data
),
1157 .length
= state
->lm_session_key
.length
,
1161 return NT_STATUS_OK
;
1164 static NTSTATUS
ntlm_auth_prepare_gensec_client(TALLOC_CTX
*mem_ctx
,
1165 struct loadparm_context
*lp_ctx
,
1166 struct gensec_security
**gensec_security_out
)
1168 struct gensec_security
*gensec_security
= NULL
;
1170 TALLOC_CTX
*tmp_ctx
;
1171 const struct gensec_security_ops
**backends
= NULL
;
1172 struct gensec_settings
*gensec_settings
= NULL
;
1175 tmp_ctx
= talloc_new(mem_ctx
);
1176 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx
);
1178 gensec_settings
= lpcfg_gensec_settings(tmp_ctx
, lp_ctx
);
1179 if (gensec_settings
== NULL
) {
1180 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1181 TALLOC_FREE(tmp_ctx
);
1182 return NT_STATUS_NO_MEMORY
;
1185 backends
= talloc_zero_array(gensec_settings
,
1186 const struct gensec_security_ops
*, 4);
1187 if (backends
== NULL
) {
1188 TALLOC_FREE(tmp_ctx
);
1189 return NT_STATUS_NO_MEMORY
;
1191 gensec_settings
->backends
= backends
;
1195 /* These need to be in priority order, krb5 before NTLMSSP */
1196 #if defined(HAVE_KRB5)
1197 backends
[idx
++] = &gensec_gse_krb5_security_ops
;
1200 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_NTLMSSP
);
1202 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_SPNEGO
);
1204 nt_status
= gensec_client_start(NULL
, &gensec_security
,
1206 if (!NT_STATUS_IS_OK(nt_status
)) {
1207 TALLOC_FREE(tmp_ctx
);
1211 talloc_unlink(tmp_ctx
, gensec_settings
);
1213 if (opt_target_service
!= NULL
) {
1214 nt_status
= gensec_set_target_service(gensec_security
,
1215 opt_target_service
);
1216 if (!NT_STATUS_IS_OK(nt_status
)) {
1217 TALLOC_FREE(tmp_ctx
);
1222 if (opt_target_hostname
!= NULL
) {
1223 nt_status
= gensec_set_target_hostname(gensec_security
,
1224 opt_target_hostname
);
1225 if (!NT_STATUS_IS_OK(nt_status
)) {
1226 TALLOC_FREE(tmp_ctx
);
1231 *gensec_security_out
= talloc_steal(mem_ctx
, gensec_security
);
1232 TALLOC_FREE(tmp_ctx
);
1233 return NT_STATUS_OK
;
1236 static struct auth4_context
*make_auth4_context_ntlm_auth(TALLOC_CTX
*mem_ctx
, bool local_pw
)
1238 struct auth4_context
*auth4_context
= talloc_zero(mem_ctx
, struct auth4_context
);
1239 if (auth4_context
== NULL
) {
1240 DEBUG(10, ("failed to allocate auth4_context\n"));
1243 auth4_context
->generate_session_info
= ntlm_auth_generate_session_info
;
1244 auth4_context
->generate_session_info_pac
= ntlm_auth_generate_session_info_pac
;
1245 auth4_context
->get_ntlm_challenge
= ntlm_auth_get_challenge
;
1246 auth4_context
->set_ntlm_challenge
= ntlm_auth_set_challenge
;
1248 auth4_context
->check_ntlm_password_send
= local_pw_check_send
;
1249 auth4_context
->check_ntlm_password_recv
= local_pw_check_recv
;
1251 auth4_context
->check_ntlm_password_send
=
1252 winbind_pw_check_send
;
1253 auth4_context
->check_ntlm_password_recv
=
1254 winbind_pw_check_recv
;
1256 auth4_context
->private_data
= NULL
;
1257 return auth4_context
;
1260 static NTSTATUS
ntlm_auth_prepare_gensec_server(TALLOC_CTX
*mem_ctx
,
1261 struct loadparm_context
*lp_ctx
,
1262 struct gensec_security
**gensec_security_out
)
1264 struct gensec_security
*gensec_security
;
1267 TALLOC_CTX
*tmp_ctx
;
1268 const struct gensec_security_ops
**backends
;
1269 struct gensec_settings
*gensec_settings
;
1271 struct cli_credentials
*server_credentials
;
1273 struct auth4_context
*auth4_context
;
1275 tmp_ctx
= talloc_new(mem_ctx
);
1276 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx
);
1278 auth4_context
= make_auth4_context_ntlm_auth(tmp_ctx
, opt_password
);
1279 if (auth4_context
== NULL
) {
1280 TALLOC_FREE(tmp_ctx
);
1281 return NT_STATUS_NO_MEMORY
;
1284 gensec_settings
= lpcfg_gensec_settings(tmp_ctx
, lp_ctx
);
1285 if (lp_ctx
== NULL
) {
1286 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1287 TALLOC_FREE(tmp_ctx
);
1288 return NT_STATUS_NO_MEMORY
;
1292 * This should be a 'netbios domain -> DNS domain'
1293 * mapping, and can currently validly return NULL on
1294 * poorly configured systems.
1296 * This is used for the NTLMSSP server
1300 gensec_settings
->server_netbios_name
= lp_netbios_name();
1301 gensec_settings
->server_netbios_domain
= lp_workgroup();
1303 gensec_settings
->server_netbios_name
= get_winbind_netbios_name();
1304 gensec_settings
->server_netbios_domain
= get_winbind_domain();
1307 gensec_settings
->server_dns_domain
= strlower_talloc(gensec_settings
,
1308 get_mydnsdomname(talloc_tos()));
1309 gensec_settings
->server_dns_name
= strlower_talloc(gensec_settings
,
1310 get_mydnsfullname());
1312 backends
= talloc_zero_array(gensec_settings
,
1313 const struct gensec_security_ops
*, 4);
1315 if (backends
== NULL
) {
1316 TALLOC_FREE(tmp_ctx
);
1317 return NT_STATUS_NO_MEMORY
;
1319 gensec_settings
->backends
= backends
;
1323 /* These need to be in priority order, krb5 before NTLMSSP */
1324 #if defined(HAVE_KRB5)
1325 backends
[idx
++] = &gensec_gse_krb5_security_ops
;
1328 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_NTLMSSP
);
1330 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_SPNEGO
);
1333 * This is anonymous for now, because we just use it
1334 * to set the kerberos state at the moment
1336 server_credentials
= cli_credentials_init_anon(tmp_ctx
);
1337 if (!server_credentials
) {
1338 DBG_ERR("Failed to init server credentials\n");
1339 return NT_STATUS_NO_MEMORY
;
1342 cli_credentials_set_conf(server_credentials
, lp_ctx
);
1344 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC
|| lp_security() == SEC_ADS
|| USE_KERBEROS_KEYTAB
) {
1345 cli_credentials_set_kerberos_state(server_credentials
,
1346 CRED_USE_KERBEROS_DESIRED
,
1349 cli_credentials_set_kerberos_state(server_credentials
,
1350 CRED_USE_KERBEROS_DISABLED
,
1354 nt_status
= gensec_server_start(tmp_ctx
, gensec_settings
,
1355 auth4_context
, &gensec_security
);
1357 if (!NT_STATUS_IS_OK(nt_status
)) {
1358 TALLOC_FREE(tmp_ctx
);
1362 gensec_set_credentials(gensec_security
, server_credentials
);
1365 * TODO: Allow the caller to pass their own description here
1366 * via a command-line option
1368 nt_status
= gensec_set_target_service_description(gensec_security
,
1370 if (!NT_STATUS_IS_OK(nt_status
)) {
1371 TALLOC_FREE(tmp_ctx
);
1375 talloc_unlink(tmp_ctx
, lp_ctx
);
1376 talloc_unlink(tmp_ctx
, server_credentials
);
1377 talloc_unlink(tmp_ctx
, gensec_settings
);
1378 talloc_unlink(tmp_ctx
, auth4_context
);
1380 *gensec_security_out
= talloc_steal(mem_ctx
, gensec_security
);
1381 TALLOC_FREE(tmp_ctx
);
1382 return NT_STATUS_OK
;
1385 static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode
,
1386 struct loadparm_context
*lp_ctx
,
1387 struct ntlm_auth_state
*state
,
1388 char *buf
, int length
, void **private2
)
1390 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1394 static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode
,
1395 struct loadparm_context
*lp_ctx
,
1396 struct ntlm_auth_state
*state
,
1397 char *buf
, int length
, void **private2
)
1402 pass
=(char *)memchr(buf
,' ',length
);
1404 DEBUG(2, ("Password not found. Denying access\n"));
1411 if (state
->helper_mode
== SQUID_2_5_BASIC
) {
1412 char *end
= rfc1738_unescape(user
);
1413 if (end
== NULL
|| (end
- user
) != strlen(user
)) {
1414 DEBUG(2, ("Badly rfc1738 encoded username: %s; "
1415 "denying access\n", user
));
1419 end
= rfc1738_unescape(pass
);
1420 if (end
== NULL
|| (end
- pass
) != strlen(pass
)) {
1421 DEBUG(2, ("Badly encoded password for %s; "
1422 "denying access\n", user
));
1428 if (check_plaintext_auth(user
, pass
, False
)) {
1435 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode
,
1436 struct loadparm_context
*lp_ctx
,
1437 char *buf
, int length
, void **private1
)
1440 DATA_BLOB out
= data_blob(NULL
, 0);
1441 char *out_base64
= NULL
;
1442 const char *reply_arg
= NULL
;
1443 struct gensec_ntlm_state
{
1444 struct gensec_security
*gensec_state
;
1445 const char *set_password
;
1447 struct gensec_ntlm_state
*state
;
1451 const char *reply_code
;
1452 struct cli_credentials
*creds
;
1454 static char *want_feature_list
= NULL
;
1455 static DATA_BLOB session_key
;
1457 TALLOC_CTX
*mem_ctx
;
1459 mem_ctx
= talloc_named(NULL
, 0, "manage_gensec_request internal mem_ctx");
1460 if (mem_ctx
== NULL
) {
1461 printf("BH No Memory\n");
1466 state
= talloc_get_type(*private1
, struct gensec_ntlm_state
);
1467 if (state
== NULL
) {
1468 DBG_WARNING("*private1 is of type %s\n",
1469 talloc_get_name(*private1
));
1470 printf("BH *private1 is of type %s\n",
1471 talloc_get_name(*private1
));
1475 state
= talloc_zero(NULL
, struct gensec_ntlm_state
);
1477 printf("BH No Memory\n");
1482 state
->set_password
= opt_password
;
1486 if (strlen(buf
) < 2) {
1487 DEBUG(1, ("query [%s] invalid\n", buf
));
1488 printf("BH Query invalid\n");
1489 talloc_free(mem_ctx
);
1493 if (strlen(buf
) > 3) {
1494 if(strncmp(buf
, "SF ", 3) == 0) {
1495 DEBUG(10, ("Setting flags to negotiate\n"));
1496 talloc_free(want_feature_list
);
1497 want_feature_list
= talloc_strndup(state
, buf
+3, strlen(buf
)-3);
1499 talloc_free(mem_ctx
);
1502 in
= base64_decode_data_blob_talloc(mem_ctx
, buf
+ 3);
1504 in
= data_blob(NULL
, 0);
1507 if (strncmp(buf
, "YR", 2) == 0) {
1508 if (state
->gensec_state
) {
1509 talloc_free(state
->gensec_state
);
1510 state
->gensec_state
= NULL
;
1512 } else if ( (strncmp(buf
, "OK", 2) == 0)) {
1513 /* Just return BH, like ntlm_auth from Samba 3 does. */
1514 printf("BH Command expected\n");
1515 talloc_free(mem_ctx
);
1517 } else if ( (strncmp(buf
, "TT ", 3) != 0) &&
1518 (strncmp(buf
, "KK ", 3) != 0) &&
1519 (strncmp(buf
, "AF ", 3) != 0) &&
1520 (strncmp(buf
, "NA ", 3) != 0) &&
1521 (strncmp(buf
, "UG", 2) != 0) &&
1522 (strncmp(buf
, "PW ", 3) != 0) &&
1523 (strncmp(buf
, "GK", 2) != 0) &&
1524 (strncmp(buf
, "GF", 2) != 0)) {
1525 DEBUG(1, ("SPNEGO request [%s] invalid prefix\n", buf
));
1526 printf("BH SPNEGO request invalid prefix\n");
1527 talloc_free(mem_ctx
);
1532 if (!(state
->gensec_state
)) {
1533 switch (stdio_helper_mode
) {
1534 case GSS_SPNEGO_CLIENT
:
1536 * cached credentials are only supported by
1537 * NTLMSSP_CLIENT_1 for now.
1539 use_cached_creds
= false;
1541 case NTLMSSP_CLIENT_1
:
1542 /* setup the client side */
1544 if (state
->set_password
!= NULL
) {
1545 use_cached_creds
= false;
1548 if (use_cached_creds
) {
1549 struct wbcCredentialCacheParams params
;
1550 struct wbcCredentialCacheInfo
*info
= NULL
;
1551 struct wbcAuthErrorInfo
*error
= NULL
;
1554 params
.account_name
= opt_username
;
1555 params
.domain_name
= opt_domain
;
1556 params
.level
= WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP
;
1557 params
.num_blobs
= 0;
1558 params
.blobs
= NULL
;
1560 wbc_status
= wbcCredentialCache(¶ms
, &info
,
1562 wbcFreeMemory(error
);
1563 if (!WBC_ERROR_IS_OK(wbc_status
)) {
1564 use_cached_creds
= false;
1566 wbcFreeMemory(info
);
1569 nt_status
= ntlm_auth_prepare_gensec_client(state
, lp_ctx
,
1570 &state
->gensec_state
);
1571 if (!NT_STATUS_IS_OK(nt_status
)) {
1572 printf("BH GENSEC mech failed to start: %s\n",
1573 nt_errstr(nt_status
));
1574 talloc_free(mem_ctx
);
1578 creds
= cli_credentials_init(state
->gensec_state
);
1579 cli_credentials_set_conf(creds
, lp_ctx
);
1581 cli_credentials_set_username(creds
, opt_username
, CRED_SPECIFIED
);
1584 cli_credentials_set_domain(creds
, opt_domain
, CRED_SPECIFIED
);
1586 if (use_cached_creds
) {
1587 gensec_want_feature(state
->gensec_state
,
1588 GENSEC_FEATURE_NTLM_CCACHE
);
1589 } else if (state
->set_password
) {
1590 cli_credentials_set_password(creds
, state
->set_password
, CRED_SPECIFIED
);
1592 cli_credentials_set_password_callback(creds
, get_password
);
1594 if (opt_workstation
) {
1595 cli_credentials_set_workstation(creds
, opt_workstation
, CRED_SPECIFIED
);
1598 gensec_set_credentials(state
->gensec_state
, creds
);
1601 case GSS_SPNEGO_SERVER
:
1602 case SQUID_2_5_NTLMSSP
:
1604 nt_status
= ntlm_auth_prepare_gensec_server(state
, lp_ctx
,
1605 &state
->gensec_state
);
1606 if (!NT_STATUS_IS_OK(nt_status
)) {
1607 printf("BH GENSEC mech failed to start: %s\n",
1608 nt_errstr(nt_status
));
1609 talloc_free(mem_ctx
);
1615 talloc_free(mem_ctx
);
1619 gensec_want_feature_list(state
->gensec_state
, want_feature_list
);
1621 /* Session info is not complete, do not pass to auth log */
1622 gensec_want_feature(state
->gensec_state
, GENSEC_FEATURE_NO_AUTHZ_LOG
);
1624 switch (stdio_helper_mode
) {
1625 case GSS_SPNEGO_CLIENT
:
1626 case GSS_SPNEGO_SERVER
:
1627 nt_status
= gensec_start_mech_by_oid(state
->gensec_state
, GENSEC_OID_SPNEGO
);
1632 case NTLMSSP_CLIENT_1
:
1637 case SQUID_2_5_NTLMSSP
:
1638 nt_status
= gensec_start_mech_by_oid(state
->gensec_state
, GENSEC_OID_NTLMSSP
);
1641 talloc_free(mem_ctx
);
1645 if (!NT_STATUS_IS_OK(nt_status
)) {
1646 DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status
)));
1647 printf("BH GENSEC mech failed to start\n");
1648 talloc_free(mem_ctx
);
1656 if (strncmp(buf
, "PW ", 3) == 0) {
1657 state
->set_password
= talloc_strndup(state
,
1658 (const char *)in
.data
,
1661 cli_credentials_set_password(gensec_get_credentials(state
->gensec_state
),
1662 state
->set_password
,
1665 talloc_free(mem_ctx
);
1669 if (strncmp(buf
, "GK", 2) == 0) {
1671 DEBUG(10, ("Requested session key\n"));
1672 nt_status
= gensec_session_key(state
->gensec_state
, mem_ctx
, &session_key
);
1673 if(!NT_STATUS_IS_OK(nt_status
)) {
1674 DEBUG(1, ("gensec_session_key failed: %s\n", nt_errstr(nt_status
)));
1675 printf("BH No session key\n");
1676 talloc_free(mem_ctx
);
1679 base64_key
= base64_encode_data_blob(state
, session_key
);
1680 SMB_ASSERT(base64_key
!= NULL
);
1681 printf("GK %s\n", base64_key
);
1682 talloc_free(base64_key
);
1684 talloc_free(mem_ctx
);
1688 if (strncmp(buf
, "GF", 2) == 0) {
1691 DEBUG(10, ("Requested negotiated NTLMSSP feature flags\n"));
1693 neg_flags
= gensec_ntlmssp_neg_flags(state
->gensec_state
);
1694 if (neg_flags
== 0) {
1696 talloc_free(mem_ctx
);
1700 printf("GF 0x%08x\n", neg_flags
);
1701 talloc_free(mem_ctx
);
1705 nt_status
= gensec_update(state
->gensec_state
, mem_ctx
, in
, &out
);
1707 /* don't leak 'bad password'/'no such user' info to the network client */
1708 nt_status
= nt_status_squash(nt_status
);
1711 out_base64
= base64_encode_data_blob(mem_ctx
, out
);
1712 SMB_ASSERT(out_base64
!= NULL
);
1717 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1719 if (first
&& state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1721 } else if (state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1723 } else if (state
->gensec_state
->gensec_role
== GENSEC_SERVER
) {
1730 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCESS_DENIED
)) {
1731 reply_code
= "BH NT_STATUS_ACCESS_DENIED";
1732 reply_arg
= nt_errstr(nt_status
);
1733 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1734 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_UNSUCCESSFUL
)) {
1735 reply_code
= "BH NT_STATUS_UNSUCCESSFUL";
1736 reply_arg
= nt_errstr(nt_status
);
1737 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1738 } else if (!NT_STATUS_IS_OK(nt_status
)) {
1740 reply_arg
= nt_errstr(nt_status
);
1741 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1742 } else if /* OK */ (state
->gensec_state
->gensec_role
== GENSEC_SERVER
) {
1743 struct auth_session_info
*session_info
;
1745 nt_status
= gensec_session_info(state
->gensec_state
, mem_ctx
, &session_info
);
1746 if (!NT_STATUS_IS_OK(nt_status
)) {
1747 reply_code
= "BH Failed to retrieve session info";
1748 reply_arg
= nt_errstr(nt_status
);
1749 DEBUG(1, ("GENSEC failed to retrieve the session info: %s\n", nt_errstr(nt_status
)));
1753 reply_arg
= talloc_strdup(state
->gensec_state
, session_info
->unix_info
->unix_name
);
1754 if (reply_arg
== NULL
) {
1755 reply_code
= "BH out of memory";
1756 reply_arg
= nt_errstr(NT_STATUS_NO_MEMORY
);
1758 talloc_free(session_info
);
1760 } else if (state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1762 reply_arg
= out_base64
;
1767 switch (stdio_helper_mode
) {
1768 case GSS_SPNEGO_SERVER
:
1769 printf("%s %s %s\n", reply_code
,
1770 out_base64
? out_base64
: "*",
1771 reply_arg
? reply_arg
: "*");
1775 printf("%s %s\n", reply_code
, out_base64
);
1776 } else if (reply_arg
) {
1777 printf("%s %s\n", reply_code
, reply_arg
);
1779 printf("%s\n", reply_code
);
1783 talloc_free(mem_ctx
);
1787 static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode
,
1788 struct loadparm_context
*lp_ctx
,
1789 struct ntlm_auth_state
*state
,
1790 char *buf
, int length
, void **private2
)
1792 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1796 static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode
,
1797 struct loadparm_context
*lp_ctx
,
1798 struct ntlm_auth_state
*state
,
1799 char *buf
, int length
, void **private2
)
1801 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1805 static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode
,
1806 struct loadparm_context
*lp_ctx
,
1807 struct ntlm_auth_state
*state
,
1808 char *buf
, int length
, void **private2
)
1810 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1814 static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode
,
1815 struct loadparm_context
*lp_ctx
,
1816 struct ntlm_auth_state
*state
,
1817 char *buf
, int length
, void **private2
)
1819 char *request
, *parameter
;
1820 static DATA_BLOB challenge
;
1821 static DATA_BLOB lm_response
;
1822 static DATA_BLOB nt_response
;
1823 static char *full_username
;
1824 static char *username
;
1825 static char *domain
;
1826 static char *plaintext_password
;
1827 static bool ntlm_server_1_user_session_key
;
1828 static bool ntlm_server_1_lm_session_key
;
1830 if (strequal(buf
, ".")) {
1831 if (!full_username
&& !username
) {
1832 printf("Error: No username supplied!\n");
1833 } else if (plaintext_password
) {
1834 /* handle this request as plaintext */
1835 if (!full_username
) {
1836 if (asprintf(&full_username
, "%s%c%s", domain
, winbind_separator(), username
) == -1) {
1837 printf("Error: Out of memory in "
1842 if (check_plaintext_auth(full_username
, plaintext_password
, False
)) {
1843 printf("Authenticated: Yes\n");
1845 printf("Authenticated: No\n");
1847 } else if (!lm_response
.data
&& !nt_response
.data
) {
1848 printf("Error: No password supplied!\n");
1849 } else if (!challenge
.data
) {
1850 printf("Error: No lanman-challenge supplied!\n");
1852 char *error_string
= NULL
;
1854 uchar user_session_key
[16];
1857 if (full_username
&& !username
) {
1859 fstring fstr_domain
;
1861 if (!parse_ntlm_auth_domain_user(full_username
, fstr_user
, fstr_domain
)) {
1862 /* username might be 'tainted', don't print into our new-line deleimianted stream */
1863 printf("Error: Could not parse into "
1864 "domain and username\n");
1866 SAFE_FREE(username
);
1868 username
= smb_xstrdup(fstr_user
);
1869 domain
= smb_xstrdup(fstr_domain
);
1873 DATA_BLOB nt_session_key
, lm_session_key
;
1874 struct samr_Password lm_pw
, nt_pw
;
1875 TALLOC_CTX
*mem_ctx
= talloc_new(NULL
);
1876 ZERO_STRUCT(user_session_key
);
1877 ZERO_STRUCT(lm_key
);
1879 nt_lm_owf_gen (opt_password
, nt_pw
.hash
, lm_pw
.hash
);
1880 nt_status
= ntlm_password_check(mem_ctx
,
1893 error_string
= smb_xstrdup(get_friendly_nt_error_msg(nt_status
));
1894 if (ntlm_server_1_user_session_key
) {
1895 if (nt_session_key
.length
== sizeof(user_session_key
)) {
1896 memcpy(user_session_key
,
1897 nt_session_key
.data
,
1898 sizeof(user_session_key
));
1901 if (ntlm_server_1_lm_session_key
) {
1902 if (lm_session_key
.length
== sizeof(lm_key
)) {
1904 lm_session_key
.data
,
1908 TALLOC_FREE(mem_ctx
);
1911 uint8_t authoritative
= 1;
1914 domain
= smb_xstrdup(get_winbind_domain());
1917 if (ntlm_server_1_lm_session_key
)
1918 flags
|= WBFLAG_PAM_LMKEY
;
1920 if (ntlm_server_1_user_session_key
)
1921 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
1923 nt_status
= contact_winbind_auth_crap(username
,
1937 if (!NT_STATUS_IS_OK(nt_status
)) {
1938 printf("Authenticated: No\n");
1939 printf("Authentication-Error: %s\n.\n",
1943 char *hex_user_session_key
;
1945 printf("Authenticated: Yes\n");
1947 if (ntlm_server_1_lm_session_key
1948 && (!all_zero(lm_key
,
1950 hex_lm_key
= hex_encode_talloc(NULL
,
1951 (const unsigned char *)lm_key
,
1953 printf("LANMAN-Session-Key: %s\n",
1955 TALLOC_FREE(hex_lm_key
);
1958 if (ntlm_server_1_user_session_key
1959 && (!all_zero(user_session_key
,
1960 sizeof(user_session_key
)))) {
1961 hex_user_session_key
= hex_encode_talloc(NULL
,
1962 (const unsigned char *)user_session_key
,
1963 sizeof(user_session_key
));
1964 printf("User-Session-Key: %s\n",
1965 hex_user_session_key
);
1966 TALLOC_FREE(hex_user_session_key
);
1969 SAFE_FREE(error_string
);
1971 /* clear out the state */
1972 challenge
= data_blob_null
;
1973 nt_response
= data_blob_null
;
1974 lm_response
= data_blob_null
;
1975 SAFE_FREE(full_username
);
1976 SAFE_FREE(username
);
1978 SAFE_FREE(plaintext_password
);
1979 ntlm_server_1_user_session_key
= False
;
1980 ntlm_server_1_lm_session_key
= False
;
1988 /* Indicates a base64 encoded structure */
1989 parameter
= strstr_m(request
, ":: ");
1991 parameter
= strstr_m(request
, ": ");
1994 DEBUG(0, ("Parameter not found!\n"));
1995 printf("Error: Parameter not found!\n.\n");
2012 base64_decode_inplace(parameter
);
2015 if (strequal(request
, "LANMAN-Challenge")) {
2016 challenge
= strhex_to_data_blob(NULL
, parameter
);
2017 if (challenge
.length
!= 8) {
2018 printf("Error: hex decode of %s failed! "
2019 "(got %d bytes, expected 8)\n.\n",
2021 (int)challenge
.length
);
2022 challenge
= data_blob_null
;
2024 } else if (strequal(request
, "NT-Response")) {
2025 nt_response
= strhex_to_data_blob(NULL
, parameter
);
2026 if (nt_response
.length
< 24) {
2027 printf("Error: hex decode of %s failed! "
2028 "(only got %d bytes, needed at least 24)\n.\n",
2030 (int)nt_response
.length
);
2031 nt_response
= data_blob_null
;
2033 } else if (strequal(request
, "LANMAN-Response")) {
2034 lm_response
= strhex_to_data_blob(NULL
, parameter
);
2035 if (lm_response
.length
!= 24) {
2036 printf("Error: hex decode of %s failed! "
2037 "(got %d bytes, expected 24)\n.\n",
2039 (int)lm_response
.length
);
2040 lm_response
= data_blob_null
;
2042 } else if (strequal(request
, "Password")) {
2043 plaintext_password
= smb_xstrdup(parameter
);
2044 } else if (strequal(request
, "NT-Domain")) {
2045 domain
= smb_xstrdup(parameter
);
2046 } else if (strequal(request
, "Username")) {
2047 username
= smb_xstrdup(parameter
);
2048 } else if (strequal(request
, "Full-Username")) {
2049 full_username
= smb_xstrdup(parameter
);
2050 } else if (strequal(request
, "Request-User-Session-Key")) {
2051 ntlm_server_1_user_session_key
= strequal(parameter
, "Yes");
2052 } else if (strequal(request
, "Request-LanMan-Session-Key")) {
2053 ntlm_server_1_lm_session_key
= strequal(parameter
, "Yes");
2055 printf("Error: Unknown request %s\n.\n", request
);
2059 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode
,
2060 struct loadparm_context
*lp_ctx
,
2061 struct ntlm_auth_state
*state
,
2062 char *buf
, int length
, void **private2
)
2064 char *request
, *parameter
;
2065 static DATA_BLOB new_nt_pswd
;
2066 static DATA_BLOB old_nt_hash_enc
;
2067 static DATA_BLOB new_lm_pswd
;
2068 static DATA_BLOB old_lm_hash_enc
;
2069 static char *full_username
= NULL
;
2070 static char *username
= NULL
;
2071 static char *domain
= NULL
;
2072 static char *newpswd
= NULL
;
2073 static char *oldpswd
= NULL
;
2075 if (strequal(buf
, ".")) {
2076 if(newpswd
&& oldpswd
) {
2077 uchar old_nt_hash
[16];
2078 uchar old_lm_hash
[16];
2079 uchar new_nt_hash
[16];
2080 uchar new_lm_hash
[16];
2082 gnutls_cipher_hd_t cipher_hnd
= NULL
;
2083 gnutls_datum_t old_nt_key
= {
2084 .data
= old_nt_hash
,
2085 .size
= sizeof(old_nt_hash
),
2089 new_nt_pswd
= data_blob(NULL
, 516);
2090 old_nt_hash_enc
= data_blob(NULL
, 16);
2092 /* Calculate the MD4 hash (NT compatible) of the
2094 E_md4hash(oldpswd
, old_nt_hash
);
2095 E_md4hash(newpswd
, new_nt_hash
);
2097 /* E_deshash returns false for 'long'
2098 passwords (> 14 DOS chars).
2100 Therefore, don't send a buffer
2101 encrypted with the truncated hash
2102 (it could allow an even easier
2103 attack on the password)
2105 Likewise, obey the admin's restriction
2108 rc
= gnutls_cipher_init(&cipher_hnd
,
2109 GNUTLS_CIPHER_ARCFOUR_128
,
2113 DBG_ERR("gnutls_cipher_init failed: %s\n",
2114 gnutls_strerror(rc
));
2115 if (rc
== GNUTLS_E_UNWANTED_ALGORITHM
) {
2116 DBG_ERR("Running in FIPS mode, NTLM blocked\n");
2121 if (lp_client_lanman_auth() &&
2122 E_deshash(newpswd
, new_lm_hash
) &&
2123 E_deshash(oldpswd
, old_lm_hash
)) {
2124 new_lm_pswd
= data_blob(NULL
, 516);
2125 old_lm_hash_enc
= data_blob(NULL
, 16);
2126 encode_pw_buffer(new_lm_pswd
.data
, newpswd
,
2129 rc
= gnutls_cipher_encrypt(cipher_hnd
,
2133 gnutls_cipher_deinit(cipher_hnd
);
2136 rc
= E_old_pw_hash(new_nt_hash
, old_lm_hash
,
2137 old_lm_hash_enc
.data
);
2139 DBG_ERR("E_old_pw_hash failed: %s\n",
2140 gnutls_strerror(rc
));
2144 new_lm_pswd
.data
= NULL
;
2145 new_lm_pswd
.length
= 0;
2146 old_lm_hash_enc
.data
= NULL
;
2147 old_lm_hash_enc
.length
= 0;
2150 encode_pw_buffer(new_nt_pswd
.data
, newpswd
,
2153 rc
= gnutls_cipher_encrypt(cipher_hnd
,
2156 gnutls_cipher_deinit(cipher_hnd
);
2160 rc
= E_old_pw_hash(new_nt_hash
, old_nt_hash
,
2161 old_nt_hash_enc
.data
);
2163 DBG_ERR("E_old_pw_hash failed: %s\n",
2164 gnutls_strerror(rc
));
2168 ZERO_ARRAY(old_nt_hash
);
2169 ZERO_ARRAY(old_lm_hash
);
2170 ZERO_ARRAY(new_nt_hash
);
2171 ZERO_ARRAY(new_lm_hash
);
2174 if (!full_username
&& !username
) {
2175 printf("Error: No username supplied!\n");
2176 } else if ((!new_nt_pswd
.data
|| !old_nt_hash_enc
.data
) &&
2177 (!new_lm_pswd
.data
|| old_lm_hash_enc
.data
) ) {
2178 printf("Error: No NT or LM password "
2179 "blobs supplied!\n");
2181 char *error_string
= NULL
;
2183 if (full_username
&& !username
) {
2185 fstring fstr_domain
;
2187 if (!parse_ntlm_auth_domain_user(full_username
,
2190 /* username might be 'tainted', don't
2191 * print into our new-line
2192 * deleimianted stream */
2193 printf("Error: Could not "
2194 "parse into domain and "
2196 SAFE_FREE(username
);
2197 username
= smb_xstrdup(full_username
);
2199 SAFE_FREE(username
);
2201 username
= smb_xstrdup(fstr_user
);
2202 domain
= smb_xstrdup(fstr_domain
);
2207 if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
2214 printf("Password-Change: No\n");
2215 printf("Password-Change-Error: %s\n.\n",
2218 printf("Password-Change: Yes\n");
2221 SAFE_FREE(error_string
);
2223 /* clear out the state */
2224 new_nt_pswd
= data_blob_null
;
2225 old_nt_hash_enc
= data_blob_null
;
2226 new_lm_pswd
= data_blob_null
;
2227 old_nt_hash_enc
= data_blob_null
;
2228 SAFE_FREE(full_username
);
2229 SAFE_FREE(username
);
2240 /* Indicates a base64 encoded structure */
2241 parameter
= strstr_m(request
, ":: ");
2243 parameter
= strstr_m(request
, ": ");
2246 DEBUG(0, ("Parameter not found!\n"));
2247 printf("Error: Parameter not found!\n.\n");
2263 base64_decode_inplace(parameter
);
2266 if (strequal(request
, "new-nt-password-blob")) {
2267 new_nt_pswd
= strhex_to_data_blob(NULL
, parameter
);
2268 if (new_nt_pswd
.length
!= 516) {
2269 printf("Error: hex decode of %s failed! "
2270 "(got %d bytes, expected 516)\n.\n",
2272 (int)new_nt_pswd
.length
);
2273 new_nt_pswd
= data_blob_null
;
2275 } else if (strequal(request
, "old-nt-hash-blob")) {
2276 old_nt_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2277 if (old_nt_hash_enc
.length
!= 16) {
2278 printf("Error: hex decode of %s failed! "
2279 "(got %d bytes, expected 16)\n.\n",
2281 (int)old_nt_hash_enc
.length
);
2282 old_nt_hash_enc
= data_blob_null
;
2284 } else if (strequal(request
, "new-lm-password-blob")) {
2285 new_lm_pswd
= strhex_to_data_blob(NULL
, parameter
);
2286 if (new_lm_pswd
.length
!= 516) {
2287 printf("Error: hex decode of %s failed! "
2288 "(got %d bytes, expected 516)\n.\n",
2290 (int)new_lm_pswd
.length
);
2291 new_lm_pswd
= data_blob_null
;
2294 else if (strequal(request
, "old-lm-hash-blob")) {
2295 old_lm_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2296 if (old_lm_hash_enc
.length
!= 16)
2298 printf("Error: hex decode of %s failed! "
2299 "(got %d bytes, expected 16)\n.\n",
2301 (int)old_lm_hash_enc
.length
);
2302 old_lm_hash_enc
= data_blob_null
;
2304 } else if (strequal(request
, "nt-domain")) {
2305 domain
= smb_xstrdup(parameter
);
2306 } else if(strequal(request
, "username")) {
2307 username
= smb_xstrdup(parameter
);
2308 } else if(strequal(request
, "full-username")) {
2309 username
= smb_xstrdup(parameter
);
2310 } else if(strequal(request
, "new-password")) {
2311 newpswd
= smb_xstrdup(parameter
);
2312 } else if (strequal(request
, "old-password")) {
2313 oldpswd
= smb_xstrdup(parameter
);
2315 printf("Error: Unknown request %s\n.\n", request
);
2319 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode
,
2320 struct loadparm_context
*lp_ctx
,
2321 struct ntlm_auth_state
*state
,
2322 stdio_helper_function fn
, void **private2
)
2325 char tmp
[INITIAL_BUFFER_SIZE
+1];
2326 int length
, buf_size
= 0;
2329 buf
= talloc_strdup(state
->mem_ctx
, "");
2331 DEBUG(0, ("Failed to allocate input buffer.\n"));
2332 fprintf(stderr
, "ERR\n");
2338 /* this is not a typo - x_fgets doesn't work too well under
2340 if (fgets(tmp
, sizeof(tmp
)-1, stdin
) == NULL
) {
2341 if (ferror(stdin
)) {
2342 DEBUG(1, ("fgets() failed! dying..... errno=%d "
2343 "(%s)\n", ferror(stdin
),
2344 strerror(ferror(stdin
))));
2351 buf
= talloc_strdup_append_buffer(buf
, tmp
);
2352 buf_size
+= INITIAL_BUFFER_SIZE
;
2354 if (buf_size
> MAX_BUFFER_SIZE
) {
2355 DEBUG(2, ("Oversized message\n"));
2356 fprintf(stderr
, "ERR\n");
2361 c
= strchr(buf
, '\n');
2362 } while (c
== NULL
);
2367 DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf
,length
));
2369 if (buf
[0] == '\0') {
2370 DEBUG(2, ("Invalid Request\n"));
2371 fprintf(stderr
, "ERR\n");
2376 fn(stdio_helper_mode
, lp_ctx
, state
, buf
, length
, private2
);
2381 static void squid_stream(enum stdio_helper_mode stdio_mode
,
2382 struct loadparm_context
*lp_ctx
,
2383 stdio_helper_function fn
) {
2384 TALLOC_CTX
*mem_ctx
;
2385 struct ntlm_auth_state
*state
;
2387 /* initialize FDescs */
2388 setbuf(stdout
, NULL
);
2389 setbuf(stderr
, NULL
);
2391 mem_ctx
= talloc_init("ntlm_auth");
2393 DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
2394 fprintf(stderr
, "ERR\n");
2398 state
= talloc_zero(mem_ctx
, struct ntlm_auth_state
);
2400 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
2401 fprintf(stderr
, "ERR\n");
2405 state
->mem_ctx
= mem_ctx
;
2406 state
->helper_mode
= stdio_mode
;
2409 TALLOC_CTX
*frame
= talloc_stackframe();
2410 manage_squid_request(stdio_mode
, lp_ctx
, state
, fn
, NULL
);
2416 /* Authenticate a user with a challenge/response */
2418 static bool check_auth_crap(void)
2423 char user_session_key
[16];
2425 char *hex_user_session_key
;
2427 uint8_t authoritative
= 1;
2429 setbuf(stdout
, NULL
);
2432 flags
|= WBFLAG_PAM_LMKEY
;
2434 if (request_user_session_key
)
2435 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
2437 flags
|= WBFLAG_PAM_NT_STATUS_SQUASH
;
2439 nt_status
= contact_winbind_auth_crap(opt_username
, opt_domain
,
2445 (unsigned char *)lm_key
,
2446 (unsigned char *)user_session_key
,
2448 &error_string
, NULL
);
2450 if (!NT_STATUS_IS_OK(nt_status
)) {
2451 printf("%s (0x%x)\n", error_string
,
2452 NT_STATUS_V(nt_status
));
2453 SAFE_FREE(error_string
);
2458 && (!all_zero((uint8_t *)lm_key
, sizeof(lm_key
)))) {
2459 hex_lm_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)lm_key
,
2461 printf("LM_KEY: %s\n", hex_lm_key
);
2462 TALLOC_FREE(hex_lm_key
);
2464 if (request_user_session_key
2465 && (!all_zero((uint8_t *)user_session_key
,
2466 sizeof(user_session_key
)))) {
2467 hex_user_session_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)user_session_key
,
2468 sizeof(user_session_key
));
2469 printf("NT_KEY: %s\n", hex_user_session_key
);
2470 TALLOC_FREE(hex_user_session_key
);
2479 OPT_USERNAME
= 1000,
2488 OPT_USER_SESSION_KEY
,
2490 OPT_REQUIRE_MEMBERSHIP
,
2491 OPT_USE_CACHED_CREDS
,
2493 OPT_PAM_WINBIND_CONF
,
2495 OPT_TARGET_HOSTNAME
,
2499 int main(int argc
, const char **argv
)
2501 TALLOC_CTX
*frame
= talloc_stackframe();
2503 const char *helper_protocol
= NULL
;
2504 int diagnostics
= 0;
2506 const char *hex_challenge
= NULL
;
2507 const char *hex_lm_response
= NULL
;
2508 const char *hex_nt_response
= NULL
;
2509 struct loadparm_context
*lp_ctx
;
2513 /* NOTE: DO NOT change this interface without considering the implications!
2514 This is an external interface, which other programs will use to interact
2518 /* We do not use single-letter command abbreviations, because they harm future
2519 interface stability. */
2521 struct poptOption long_options
[] = {
2524 .longName
= "helper-protocol",
2526 .argInfo
= POPT_ARG_STRING
,
2527 .arg
= &helper_protocol
,
2529 .descrip
= "operate as a stdio-based helper",
2530 .argDescrip
= "helper protocol to use"
2533 .longName
= "username",
2535 .argInfo
= POPT_ARG_STRING
,
2536 .arg
= &opt_username
,
2537 .val
= OPT_USERNAME
,
2538 .descrip
= "username"
2541 .longName
= "domain",
2543 .argInfo
= POPT_ARG_STRING
,
2546 .descrip
= "domain name"
2549 .longName
= "workstation",
2551 .argInfo
= POPT_ARG_STRING
,
2552 .arg
= &opt_workstation
,
2553 .val
= OPT_WORKSTATION
,
2554 .descrip
= "workstation"
2557 .longName
= "challenge",
2559 .argInfo
= POPT_ARG_STRING
,
2560 .arg
= &hex_challenge
,
2561 .val
= OPT_CHALLENGE
,
2562 .descrip
= "challenge (HEX encoded)"
2565 .longName
= "lm-response",
2567 .argInfo
= POPT_ARG_STRING
,
2568 .arg
= &hex_lm_response
,
2570 .descrip
= "LM Response to the challenge (HEX encoded)"
2573 .longName
= "nt-response",
2575 .argInfo
= POPT_ARG_STRING
,
2576 .arg
= &hex_nt_response
,
2578 .descrip
= "NT or NTLMv2 Response to the challenge (HEX encoded)"
2581 .longName
= "password",
2583 .argInfo
= POPT_ARG_STRING
,
2584 .arg
= &opt_password
,
2585 .val
= OPT_PASSWORD
,
2586 .descrip
= "User's plaintext password"
2589 .longName
= "request-lm-key",
2591 .argInfo
= POPT_ARG_NONE
,
2592 .arg
= &request_lm_key
,
2594 .descrip
= "Retrieve LM session key (or, with --diagnostics, expect LM support)"
2597 .longName
= "request-nt-key",
2599 .argInfo
= POPT_ARG_NONE
,
2600 .arg
= &request_user_session_key
,
2601 .val
= OPT_USER_SESSION_KEY
,
2602 .descrip
= "Retrieve User (NT) session key"
2605 .longName
= "use-cached-creds",
2607 .argInfo
= POPT_ARG_NONE
,
2608 .arg
= &use_cached_creds
,
2609 .val
= OPT_USE_CACHED_CREDS
,
2610 .descrip
= "Use cached credentials if no password is given"
2613 .longName
= "allow-mschapv2",
2615 .argInfo
= POPT_ARG_NONE
,
2616 .arg
= &opt_allow_mschapv2
,
2617 .val
= OPT_ALLOW_MSCHAPV2
,
2618 .descrip
= "Explicitly allow MSCHAPv2",
2621 .longName
= "offline-logon",
2623 .argInfo
= POPT_ARG_NONE
,
2624 .arg
= &offline_logon
,
2625 .val
= OPT_OFFLINE_LOGON
,
2626 .descrip
= "Use cached passwords when DC is offline"
2629 .longName
= "diagnostics",
2631 .argInfo
= POPT_ARG_NONE
,
2632 .arg
= &diagnostics
,
2633 .val
= OPT_DIAGNOSTICS
,
2634 .descrip
= "Perform diagnostics on the authentication chain"
2637 .longName
= "require-membership-of",
2639 .argInfo
= POPT_ARG_STRING
,
2640 .arg
= &require_membership_of
,
2641 .val
= OPT_REQUIRE_MEMBERSHIP
,
2642 .descrip
= "Require that a user be a member of this group (either name or SID) for authentication to succeed",
2645 .longName
= "pam-winbind-conf",
2647 .argInfo
= POPT_ARG_STRING
,
2648 .arg
= &opt_pam_winbind_conf
,
2649 .val
= OPT_PAM_WINBIND_CONF
,
2650 .descrip
= "Require that request must set WBFLAG_PAM_CONTACT_TRUSTDOM when krb5 auth is required",
2653 .longName
= "target-service",
2655 .argInfo
= POPT_ARG_STRING
,
2656 .arg
= &opt_target_service
,
2657 .val
= OPT_TARGET_SERVICE
,
2658 .descrip
= "Target service (eg http)",
2661 .longName
= "target-hostname",
2663 .argInfo
= POPT_ARG_STRING
,
2664 .arg
= &opt_target_hostname
,
2665 .val
= OPT_TARGET_HOSTNAME
,
2666 .descrip
= "Target hostname",
2668 POPT_COMMON_DEBUG_ONLY
2669 POPT_COMMON_CONFIG_ONLY
2670 POPT_COMMON_OPTION_ONLY
2675 /* Samba client initialisation */
2678 ok
= samba_cmdline_init(frame
,
2679 SAMBA_CMDLINE_CONFIG_CLIENT
,
2680 false /* require_smbconf */);
2682 DBG_ERR("Failed to init cmdline parser!\n");
2687 pc
= samba_popt_get_context(getprogname(),
2691 POPT_CONTEXT_KEEP_FIRST
);
2693 DBG_ERR("Failed to setup popt context!\n");
2698 while((opt
= poptGetNextOpt(pc
)) != -1) {
2701 opt_challenge
= strhex_to_data_blob(NULL
, hex_challenge
);
2702 if (opt_challenge
.length
!= 8) {
2703 fprintf(stderr
, "hex decode of %s failed! "
2704 "(only got %d bytes)\n",
2706 (int)opt_challenge
.length
);
2711 opt_lm_response
= strhex_to_data_blob(NULL
, hex_lm_response
);
2712 if (opt_lm_response
.length
!= 24) {
2713 fprintf(stderr
, "hex decode of %s failed! "
2714 "(only got %d bytes)\n",
2716 (int)opt_lm_response
.length
);
2722 opt_nt_response
= strhex_to_data_blob(NULL
, hex_nt_response
);
2723 if (opt_nt_response
.length
< 24) {
2724 fprintf(stderr
, "hex decode of %s failed! "
2725 "(only got %d bytes)\n",
2727 (int)opt_nt_response
.length
);
2732 case OPT_REQUIRE_MEMBERSHIP
:
2733 if (strncasecmp_m("S-", require_membership_of
, 2) == 0) {
2734 require_membership_of_sid
= require_membership_of
;
2738 case POPT_ERROR_BADOPT
:
2739 fprintf(stderr
, "\nInvalid option %s: %s\n\n",
2740 poptBadOption(pc
, 0), poptStrerror(opt
));
2741 poptPrintUsage(pc
, stderr
, 0);
2747 char *domain
= SMB_STRDUP(opt_username
);
2748 char *p
= strchr_m(domain
, *lp_winbind_separator());
2752 if (opt_domain
&& !strequal(opt_domain
, domain
)) {
2753 fprintf(stderr
, "Domain specified in username (%s) "
2754 "doesn't match specified domain (%s)!\n\n",
2755 domain
, opt_domain
);
2756 poptPrintHelp(pc
, stderr
, 0);
2759 opt_domain
= domain
;
2765 /* Note: if opt_domain is "" then send no domain */
2766 if (opt_domain
== NULL
) {
2767 opt_domain
= get_winbind_domain();
2770 if (opt_workstation
== NULL
) {
2771 opt_workstation
= "";
2774 lp_ctx
= loadparm_init_s3(NULL
, loadparm_s3_helpers());
2775 if (lp_ctx
== NULL
) {
2776 fprintf(stderr
, "loadparm_init_s3() failed!\n");
2780 if (helper_protocol
) {
2782 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2783 if (strcmp(helper_protocol
, stdio_helper_protocols
[i
].name
) == 0) {
2784 squid_stream(stdio_helper_protocols
[i
].mode
, lp_ctx
, stdio_helper_protocols
[i
].fn
);
2788 fprintf(stderr
, "unknown helper protocol [%s]\n\n"
2789 "Valid helper protools:\n\n", helper_protocol
);
2791 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2792 fprintf(stderr
, "%s\n",
2793 stdio_helper_protocols
[i
].name
);
2799 if (!opt_username
|| !*opt_username
) {
2800 fprintf(stderr
, "username must be specified!\n\n");
2801 poptPrintHelp(pc
, stderr
, 0);
2805 if (opt_challenge
.length
) {
2806 if (!check_auth_crap()) {
2812 if (!opt_password
) {
2813 char pwd
[256] = {0};
2816 rc
= samba_getpass("Password: ", pwd
, sizeof(pwd
), false, false);
2818 opt_password
= SMB_STRDUP(pwd
);
2823 if (!diagnose_ntlm_auth(request_lm_key
)) {
2824 poptFreeContext(pc
);
2830 fstr_sprintf(user
, "%s%c%s", opt_domain
, winbind_separator(), opt_username
);
2831 if (!check_plaintext_auth(user
, opt_password
, True
)) {
2832 poptFreeContext(pc
);
2839 poptFreeContext(pc
);