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", 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 memcpy(request
.data
.auth_crap
.lm_resp
,
580 MIN(lm_response
->length
, sizeof(request
.data
.auth_crap
.lm_resp
)));
581 request
.data
.auth_crap
.lm_resp_len
= lm_response
->length
;
584 if (nt_response
&& nt_response
->length
) {
585 if (nt_response
->length
> sizeof(request
.data
.auth_crap
.nt_resp
)) {
586 request
.flags
= request
.flags
| WBFLAG_BIG_NTLMV2_BLOB
;
587 request
.extra_len
= nt_response
->length
;
588 request
.extra_data
.data
= SMB_MALLOC_ARRAY(char, request
.extra_len
);
589 if (request
.extra_data
.data
== NULL
) {
590 return NT_STATUS_NO_MEMORY
;
592 memcpy(request
.extra_data
.data
, nt_response
->data
,
593 nt_response
->length
);
596 memcpy(request
.data
.auth_crap
.nt_resp
,
597 nt_response
->data
, nt_response
->length
);
599 request
.data
.auth_crap
.nt_resp_len
= nt_response
->length
;
602 ret
= wbcRequestResponsePriv(
604 WINBINDD_PAM_AUTH_CRAP
,
607 SAFE_FREE(request
.extra_data
.data
);
609 /* Display response */
611 if (!WBC_ERROR_IS_OK(ret
) && (response
.data
.auth
.nt_status
== 0)) {
612 nt_status
= NT_STATUS_UNSUCCESSFUL
;
614 *error_string
= smb_xstrdup("Reading winbind reply failed!");
615 winbindd_free_response(&response
);
619 nt_status
= (NT_STATUS(response
.data
.auth
.nt_status
));
620 if (!NT_STATUS_IS_OK(nt_status
)) {
622 *error_string
= smb_xstrdup(response
.data
.auth
.error_string
);
623 *pauthoritative
= response
.data
.auth
.authoritative
;
624 winbindd_free_response(&response
);
628 if ((flags
& WBFLAG_PAM_LMKEY
) && lm_key
) {
629 memcpy(lm_key
, response
.data
.auth
.first_8_lm_hash
,
630 sizeof(response
.data
.auth
.first_8_lm_hash
));
632 if ((flags
& WBFLAG_PAM_USER_SESSION_KEY
) && user_session_key
) {
633 memcpy(user_session_key
, response
.data
.auth
.user_session_key
,
634 sizeof(response
.data
.auth
.user_session_key
));
637 if (flags
& WBFLAG_PAM_UNIX_NAME
) {
638 *unix_name
= SMB_STRDUP(response
.data
.auth
.unix_username
);
640 winbindd_free_response(&response
);
641 return NT_STATUS_NO_MEMORY
;
645 winbindd_free_response(&response
);
649 /* contact server to change user password using auth crap */
650 static NTSTATUS
contact_winbind_change_pswd_auth_crap(const char *username
,
652 const DATA_BLOB new_nt_pswd
,
653 const DATA_BLOB old_nt_hash_enc
,
654 const DATA_BLOB new_lm_pswd
,
655 const DATA_BLOB old_lm_hash_enc
,
660 struct winbindd_request request
;
661 struct winbindd_response response
;
663 if (!get_require_membership_sid())
666 *error_string
= smb_xstrdup("Can't get membership sid.");
667 return NT_STATUS_INVALID_PARAMETER
;
670 ZERO_STRUCT(request
);
671 ZERO_STRUCT(response
);
674 fstrcpy(request
.data
.chng_pswd_auth_crap
.user
, username
);
676 fstrcpy(request
.data
.chng_pswd_auth_crap
.domain
,domain
);
678 if(new_nt_pswd
.length
)
680 memcpy(request
.data
.chng_pswd_auth_crap
.new_nt_pswd
, new_nt_pswd
.data
, sizeof(request
.data
.chng_pswd_auth_crap
.new_nt_pswd
));
681 request
.data
.chng_pswd_auth_crap
.new_nt_pswd_len
= new_nt_pswd
.length
;
684 if(old_nt_hash_enc
.length
)
686 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
));
687 request
.data
.chng_pswd_auth_crap
.old_nt_hash_enc_len
= old_nt_hash_enc
.length
;
690 if(new_lm_pswd
.length
)
692 memcpy(request
.data
.chng_pswd_auth_crap
.new_lm_pswd
, new_lm_pswd
.data
, sizeof(request
.data
.chng_pswd_auth_crap
.new_lm_pswd
));
693 request
.data
.chng_pswd_auth_crap
.new_lm_pswd_len
= new_lm_pswd
.length
;
696 if(old_lm_hash_enc
.length
)
698 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
));
699 request
.data
.chng_pswd_auth_crap
.old_lm_hash_enc_len
= old_lm_hash_enc
.length
;
702 ret
= wbcRequestResponse(NULL
, WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP
,
703 &request
, &response
);
705 /* Display response */
707 if (!WBC_ERROR_IS_OK(ret
) && (response
.data
.auth
.nt_status
== 0))
709 nt_status
= NT_STATUS_UNSUCCESSFUL
;
711 *error_string
= smb_xstrdup("Reading winbind reply failed!");
712 winbindd_free_response(&response
);
716 nt_status
= (NT_STATUS(response
.data
.auth
.nt_status
));
717 if (!NT_STATUS_IS_OK(nt_status
))
720 *error_string
= smb_xstrdup(response
.data
.auth
.error_string
);
721 winbindd_free_response(&response
);
725 winbindd_free_response(&response
);
730 static NTSTATUS
ntlm_auth_generate_session_info(struct auth4_context
*auth_context
,
732 void *server_returned_info
,
733 const char *original_user_name
,
734 uint32_t session_info_flags
,
735 struct auth_session_info
**session_info_out
)
737 const char *unix_username
= (const char *)server_returned_info
;
738 struct dom_sid
*sids
= NULL
;
739 struct auth_session_info
*session_info
= NULL
;
741 session_info
= talloc_zero(mem_ctx
, struct auth_session_info
);
742 if (session_info
== NULL
) {
743 return NT_STATUS_NO_MEMORY
;
746 session_info
->unix_info
= talloc_zero(session_info
, struct auth_user_info_unix
);
747 if (session_info
->unix_info
== NULL
) {
748 TALLOC_FREE(session_info
);
749 return NT_STATUS_NO_MEMORY
;
751 session_info
->unix_info
->unix_name
= talloc_strdup(session_info
->unix_info
,
753 if (session_info
->unix_info
->unix_name
== NULL
) {
754 TALLOC_FREE(session_info
);
755 return NT_STATUS_NO_MEMORY
;
758 session_info
->security_token
= talloc_zero(session_info
, struct security_token
);
759 if (session_info
->security_token
== NULL
) {
760 TALLOC_FREE(session_info
);
761 return NT_STATUS_NO_MEMORY
;
764 sids
= talloc_zero_array(session_info
->security_token
,
767 TALLOC_FREE(session_info
);
768 return NT_STATUS_NO_MEMORY
;
770 sid_copy(&sids
[0], &global_sid_World
);
771 sid_copy(&sids
[1], &global_sid_Network
);
772 sid_copy(&sids
[2], &global_sid_Authenticated_Users
);
774 session_info
->security_token
->num_sids
= talloc_array_length(sids
);
775 session_info
->security_token
->sids
= sids
;
777 *session_info_out
= session_info
;
782 static NTSTATUS
ntlm_auth_generate_session_info_pac(struct auth4_context
*auth_ctx
,
784 struct smb_krb5_context
*smb_krb5_context
,
786 const char *princ_name
,
787 const struct tsocket_address
*remote_address
,
788 uint32_t session_info_flags
,
789 struct auth_session_info
**session_info
)
792 struct PAC_LOGON_INFO
*logon_info
= NULL
;
795 const char *domain
= "";
796 const char *user
= "";
798 tmp_ctx
= talloc_new(mem_ctx
);
800 return NT_STATUS_NO_MEMORY
;
805 status
= kerberos_pac_logon_info(tmp_ctx
, *pac_blob
, NULL
, NULL
,
806 NULL
, NULL
, 0, &logon_info
);
808 status
= NT_STATUS_ACCESS_DENIED
;
810 if (!NT_STATUS_IS_OK(status
)) {
814 status
= NT_STATUS_ACCESS_DENIED
;
815 DBG_WARNING("Kerberos ticket for[%s] has no PAC: %s\n",
816 princ_name
, nt_errstr(status
));
820 if (logon_info
->info3
.base
.account_name
.string
!= NULL
) {
821 user
= logon_info
->info3
.base
.account_name
.string
;
825 if (logon_info
->info3
.base
.logon_domain
.string
!= NULL
) {
826 domain
= logon_info
->info3
.base
.logon_domain
.string
;
831 if (strlen(user
) == 0 || strlen(domain
) == 0) {
832 status
= NT_STATUS_ACCESS_DENIED
;
833 DBG_WARNING("Kerberos ticket for[%s] has invalid "
834 "account_name[%s]/logon_domain[%s]: %s\n",
836 logon_info
->info3
.base
.account_name
.string
,
837 logon_info
->info3
.base
.logon_domain
.string
,
842 DBG_NOTICE("Kerberos ticket principal name is [%s] "
843 "account_name[%s]/logon_domain[%s]\n",
844 princ_name
, user
, domain
);
846 if (!strequal(domain
, lp_workgroup())) {
847 if (!lp_allow_trusted_domains()) {
848 status
= NT_STATUS_LOGON_FAILURE
;
853 unixuser
= talloc_asprintf(tmp_ctx
, "%s%c%s", domain
, winbind_separator(), user
);
855 status
= NT_STATUS_NO_MEMORY
;
859 status
= ntlm_auth_generate_session_info(auth_ctx
, mem_ctx
, unixuser
, NULL
, session_info_flags
, session_info
);
862 TALLOC_FREE(tmp_ctx
);
869 * Return the challenge as determined by the authentication subsystem
870 * @return an 8 byte random challenge
873 static NTSTATUS
ntlm_auth_get_challenge(struct auth4_context
*auth_ctx
,
876 if (auth_ctx
->challenge
.data
.length
== 8) {
877 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
878 auth_ctx
->challenge
.set_by
));
879 memcpy(chal
, auth_ctx
->challenge
.data
.data
, 8);
883 if (!auth_ctx
->challenge
.set_by
) {
884 generate_random_buffer(chal
, 8);
886 auth_ctx
->challenge
.data
= data_blob_talloc(auth_ctx
, chal
, 8);
887 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.data
.data
);
888 auth_ctx
->challenge
.set_by
= "random";
891 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
892 auth_ctx
->challenge
.set_by
));
898 * NTLM2 authentication modifies the effective challenge,
899 * @param challenge The new challenge value
901 static NTSTATUS
ntlm_auth_set_challenge(struct auth4_context
*auth_ctx
, const uint8_t chal
[8], const char *set_by
)
903 auth_ctx
->challenge
.set_by
= talloc_strdup(auth_ctx
, set_by
);
904 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.set_by
);
906 auth_ctx
->challenge
.data
= data_blob_talloc(auth_ctx
, chal
, 8);
907 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.data
.data
);
913 * Check the password on an NTLMSSP login.
915 * Return the session keys used on the connection.
918 struct winbind_pw_check_state
{
919 uint8_t authoritative
;
921 DATA_BLOB nt_session_key
;
922 DATA_BLOB lm_session_key
;
925 static struct tevent_req
*winbind_pw_check_send(
927 struct tevent_context
*ev
,
928 struct auth4_context
*auth4_context
,
929 const struct auth_usersupplied_info
*user_info
)
931 struct tevent_req
*req
= NULL
;
932 struct winbind_pw_check_state
*state
= NULL
;
934 char *error_string
= NULL
;
936 uint8_t user_sess_key
[16];
937 char *unix_name
= NULL
;
939 req
= tevent_req_create(
940 mem_ctx
, &state
, struct winbind_pw_check_state
);
945 nt_status
= contact_winbind_auth_crap(
946 user_info
->client
.account_name
,
947 user_info
->client
.domain_name
,
948 user_info
->workstation_name
,
949 &auth4_context
->challenge
.data
,
950 &user_info
->password
.response
.lanman
,
951 &user_info
->password
.response
.nt
,
953 WBFLAG_PAM_USER_SESSION_KEY
|
954 WBFLAG_PAM_UNIX_NAME
,
956 lm_key
, user_sess_key
,
957 &state
->authoritative
,
961 if (tevent_req_nterror(req
, nt_status
)) {
962 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCESS_DENIED
)) {
963 DBG_ERR("Login for user [%s]\\[%s]@[%s] failed due "
965 user_info
->client
.domain_name
,
966 user_info
->client
.account_name
,
967 user_info
->workstation_name
,
970 "unknown error (NULL)");
972 DBG_NOTICE("Login for user [%s]\\[%s]@[%s] failed due "
974 user_info
->client
.domain_name
,
975 user_info
->client
.account_name
,
976 user_info
->workstation_name
,
979 "unknown error (NULL)");
984 if (!all_zero(lm_key
, 8)) {
985 state
->lm_session_key
= data_blob_talloc(state
, NULL
, 16);
986 if (tevent_req_nomem(state
->lm_session_key
.data
, req
)) {
989 memcpy(state
->lm_session_key
.data
, lm_key
, 8);
990 memset(state
->lm_session_key
.data
+8, '\0', 8);
992 if (!all_zero(user_sess_key
, 16)) {
993 state
->nt_session_key
= data_blob_talloc(
994 state
, user_sess_key
, 16);
995 if (tevent_req_nomem(state
->nt_session_key
.data
, req
)) {
999 state
->server_info
= talloc_strdup(state
, unix_name
);
1000 if (tevent_req_nomem(state
->server_info
, req
)) {
1003 tevent_req_done(req
);
1006 SAFE_FREE(error_string
);
1007 SAFE_FREE(unix_name
);
1008 return tevent_req_post(req
, ev
);
1011 static NTSTATUS
winbind_pw_check_recv(struct tevent_req
*req
,
1012 TALLOC_CTX
*mem_ctx
,
1013 uint8_t *pauthoritative
,
1014 void **server_returned_info
,
1015 DATA_BLOB
*nt_session_key
,
1016 DATA_BLOB
*lm_session_key
)
1018 struct winbind_pw_check_state
*state
= tevent_req_data(
1019 req
, struct winbind_pw_check_state
);
1022 if (pauthoritative
!= NULL
) {
1023 *pauthoritative
= state
->authoritative
;
1026 if (tevent_req_is_nterror(req
, &status
)) {
1030 if (server_returned_info
!= NULL
) {
1031 *server_returned_info
= talloc_move(
1032 mem_ctx
, &state
->server_info
);
1034 if (nt_session_key
!= NULL
) {
1035 *nt_session_key
= (DATA_BLOB
) {
1036 .data
= talloc_move(
1037 mem_ctx
, &state
->nt_session_key
.data
),
1038 .length
= state
->nt_session_key
.length
,
1041 if (lm_session_key
!= NULL
) {
1042 *lm_session_key
= (DATA_BLOB
) {
1043 .data
= talloc_move(
1044 mem_ctx
, &state
->lm_session_key
.data
),
1045 .length
= state
->lm_session_key
.length
,
1049 return NT_STATUS_OK
;
1052 struct local_pw_check_state
{
1053 uint8_t authoritative
;
1055 DATA_BLOB nt_session_key
;
1056 DATA_BLOB lm_session_key
;
1059 static struct tevent_req
*local_pw_check_send(
1060 TALLOC_CTX
*mem_ctx
,
1061 struct tevent_context
*ev
,
1062 struct auth4_context
*auth4_context
,
1063 const struct auth_usersupplied_info
*user_info
)
1065 struct tevent_req
*req
= NULL
;
1066 struct local_pw_check_state
*state
= NULL
;
1067 struct samr_Password lm_pw
, nt_pw
;
1070 req
= tevent_req_create(
1071 mem_ctx
, &state
, struct local_pw_check_state
);
1075 state
->authoritative
= 1;
1077 nt_lm_owf_gen (opt_password
, nt_pw
.hash
, lm_pw
.hash
);
1079 nt_status
= ntlm_password_check(
1084 &auth4_context
->challenge
.data
,
1085 &user_info
->password
.response
.lanman
,
1086 &user_info
->password
.response
.nt
,
1087 user_info
->client
.account_name
,
1088 user_info
->client
.account_name
,
1089 user_info
->client
.domain_name
,
1092 &state
->nt_session_key
,
1093 &state
->lm_session_key
);
1095 if (tevent_req_nterror(req
, nt_status
)) {
1096 DBG_NOTICE("Login for user [%s]\\[%s]@[%s] failed due to "
1098 user_info
->client
.domain_name
,
1099 user_info
->client
.account_name
,
1100 user_info
->workstation_name
,
1101 nt_errstr(nt_status
));
1102 return tevent_req_post(req
, ev
);
1105 state
->server_info
= talloc_asprintf(
1108 user_info
->client
.domain_name
,
1109 *lp_winbind_separator(),
1110 user_info
->client
.account_name
);
1111 if (tevent_req_nomem(state
->server_info
, req
)) {
1112 return tevent_req_post(req
, ev
);
1115 tevent_req_done(req
);
1116 return tevent_req_post(req
, ev
);
1119 static NTSTATUS
local_pw_check_recv(struct tevent_req
*req
,
1120 TALLOC_CTX
*mem_ctx
,
1121 uint8_t *pauthoritative
,
1122 void **server_returned_info
,
1123 DATA_BLOB
*nt_session_key
,
1124 DATA_BLOB
*lm_session_key
)
1126 struct local_pw_check_state
*state
= tevent_req_data(
1127 req
, struct local_pw_check_state
);
1130 if (pauthoritative
!= NULL
) {
1131 *pauthoritative
= state
->authoritative
;
1134 if (tevent_req_is_nterror(req
, &status
)) {
1138 if (server_returned_info
!= NULL
) {
1139 *server_returned_info
= talloc_move(
1140 mem_ctx
, &state
->server_info
);
1142 if (nt_session_key
!= NULL
) {
1143 *nt_session_key
= (DATA_BLOB
) {
1144 .data
= talloc_move(
1145 mem_ctx
, &state
->nt_session_key
.data
),
1146 .length
= state
->nt_session_key
.length
,
1149 if (lm_session_key
!= NULL
) {
1150 *lm_session_key
= (DATA_BLOB
) {
1151 .data
= talloc_move(
1152 mem_ctx
, &state
->lm_session_key
.data
),
1153 .length
= state
->lm_session_key
.length
,
1157 return NT_STATUS_OK
;
1160 static NTSTATUS
ntlm_auth_prepare_gensec_client(TALLOC_CTX
*mem_ctx
,
1161 struct loadparm_context
*lp_ctx
,
1162 struct gensec_security
**gensec_security_out
)
1164 struct gensec_security
*gensec_security
= NULL
;
1166 TALLOC_CTX
*tmp_ctx
;
1167 const struct gensec_security_ops
**backends
= NULL
;
1168 struct gensec_settings
*gensec_settings
= NULL
;
1171 tmp_ctx
= talloc_new(mem_ctx
);
1172 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx
);
1174 gensec_settings
= lpcfg_gensec_settings(tmp_ctx
, lp_ctx
);
1175 if (gensec_settings
== NULL
) {
1176 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1177 TALLOC_FREE(tmp_ctx
);
1178 return NT_STATUS_NO_MEMORY
;
1181 backends
= talloc_zero_array(gensec_settings
,
1182 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
);
1200 nt_status
= gensec_client_start(NULL
, &gensec_security
,
1202 if (!NT_STATUS_IS_OK(nt_status
)) {
1203 TALLOC_FREE(tmp_ctx
);
1207 talloc_unlink(tmp_ctx
, gensec_settings
);
1209 if (opt_target_service
!= NULL
) {
1210 nt_status
= gensec_set_target_service(gensec_security
,
1211 opt_target_service
);
1212 if (!NT_STATUS_IS_OK(nt_status
)) {
1213 TALLOC_FREE(tmp_ctx
);
1218 if (opt_target_hostname
!= NULL
) {
1219 nt_status
= gensec_set_target_hostname(gensec_security
,
1220 opt_target_hostname
);
1221 if (!NT_STATUS_IS_OK(nt_status
)) {
1222 TALLOC_FREE(tmp_ctx
);
1227 *gensec_security_out
= talloc_steal(mem_ctx
, gensec_security
);
1228 TALLOC_FREE(tmp_ctx
);
1229 return NT_STATUS_OK
;
1232 static struct auth4_context
*make_auth4_context_ntlm_auth(TALLOC_CTX
*mem_ctx
, bool local_pw
)
1234 struct auth4_context
*auth4_context
= talloc_zero(mem_ctx
, struct auth4_context
);
1235 if (auth4_context
== NULL
) {
1236 DEBUG(10, ("failed to allocate auth4_context failed\n"));
1239 auth4_context
->generate_session_info
= ntlm_auth_generate_session_info
;
1240 auth4_context
->generate_session_info_pac
= ntlm_auth_generate_session_info_pac
;
1241 auth4_context
->get_ntlm_challenge
= ntlm_auth_get_challenge
;
1242 auth4_context
->set_ntlm_challenge
= ntlm_auth_set_challenge
;
1244 auth4_context
->check_ntlm_password_send
= local_pw_check_send
;
1245 auth4_context
->check_ntlm_password_recv
= local_pw_check_recv
;
1247 auth4_context
->check_ntlm_password_send
=
1248 winbind_pw_check_send
;
1249 auth4_context
->check_ntlm_password_recv
=
1250 winbind_pw_check_recv
;
1252 auth4_context
->private_data
= NULL
;
1253 return auth4_context
;
1256 static NTSTATUS
ntlm_auth_prepare_gensec_server(TALLOC_CTX
*mem_ctx
,
1257 struct loadparm_context
*lp_ctx
,
1258 struct gensec_security
**gensec_security_out
)
1260 struct gensec_security
*gensec_security
;
1263 TALLOC_CTX
*tmp_ctx
;
1264 const struct gensec_security_ops
**backends
;
1265 struct gensec_settings
*gensec_settings
;
1267 struct cli_credentials
*server_credentials
;
1269 struct auth4_context
*auth4_context
;
1271 tmp_ctx
= talloc_new(mem_ctx
);
1272 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx
);
1274 auth4_context
= make_auth4_context_ntlm_auth(tmp_ctx
, opt_password
);
1275 if (auth4_context
== NULL
) {
1276 TALLOC_FREE(tmp_ctx
);
1277 return NT_STATUS_NO_MEMORY
;
1280 gensec_settings
= lpcfg_gensec_settings(tmp_ctx
, lp_ctx
);
1281 if (lp_ctx
== NULL
) {
1282 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1283 TALLOC_FREE(tmp_ctx
);
1284 return NT_STATUS_NO_MEMORY
;
1288 * This should be a 'netbios domain -> DNS domain'
1289 * mapping, and can currently validly return NULL on
1290 * poorly configured systems.
1292 * This is used for the NTLMSSP server
1296 gensec_settings
->server_netbios_name
= lp_netbios_name();
1297 gensec_settings
->server_netbios_domain
= lp_workgroup();
1299 gensec_settings
->server_netbios_name
= get_winbind_netbios_name();
1300 gensec_settings
->server_netbios_domain
= get_winbind_domain();
1303 gensec_settings
->server_dns_domain
= strlower_talloc(gensec_settings
,
1304 get_mydnsdomname(talloc_tos()));
1305 gensec_settings
->server_dns_name
= strlower_talloc(gensec_settings
,
1306 get_mydnsfullname());
1308 backends
= talloc_zero_array(gensec_settings
,
1309 const struct gensec_security_ops
*, 4);
1311 if (backends
== NULL
) {
1312 TALLOC_FREE(tmp_ctx
);
1313 return NT_STATUS_NO_MEMORY
;
1315 gensec_settings
->backends
= backends
;
1319 /* These need to be in priority order, krb5 before NTLMSSP */
1320 #if defined(HAVE_KRB5)
1321 backends
[idx
++] = &gensec_gse_krb5_security_ops
;
1324 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_NTLMSSP
);
1326 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_SPNEGO
);
1329 * This is anonymous for now, because we just use it
1330 * to set the kerberos state at the moment
1332 server_credentials
= cli_credentials_init_anon(tmp_ctx
);
1333 if (!server_credentials
) {
1334 DBG_ERR("Failed to init server credentials\n");
1335 return NT_STATUS_NO_MEMORY
;
1338 cli_credentials_set_conf(server_credentials
, lp_ctx
);
1340 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC
|| lp_security() == SEC_ADS
|| USE_KERBEROS_KEYTAB
) {
1341 cli_credentials_set_kerberos_state(server_credentials
,
1342 CRED_USE_KERBEROS_DESIRED
,
1345 cli_credentials_set_kerberos_state(server_credentials
,
1346 CRED_USE_KERBEROS_DISABLED
,
1350 nt_status
= gensec_server_start(tmp_ctx
, gensec_settings
,
1351 auth4_context
, &gensec_security
);
1353 if (!NT_STATUS_IS_OK(nt_status
)) {
1354 TALLOC_FREE(tmp_ctx
);
1358 gensec_set_credentials(gensec_security
, server_credentials
);
1361 * TODO: Allow the caller to pass their own description here
1362 * via a command-line option
1364 nt_status
= gensec_set_target_service_description(gensec_security
,
1366 if (!NT_STATUS_IS_OK(nt_status
)) {
1367 TALLOC_FREE(tmp_ctx
);
1371 talloc_unlink(tmp_ctx
, lp_ctx
);
1372 talloc_unlink(tmp_ctx
, server_credentials
);
1373 talloc_unlink(tmp_ctx
, gensec_settings
);
1374 talloc_unlink(tmp_ctx
, auth4_context
);
1376 *gensec_security_out
= talloc_steal(mem_ctx
, gensec_security
);
1377 TALLOC_FREE(tmp_ctx
);
1378 return NT_STATUS_OK
;
1381 static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode
,
1382 struct loadparm_context
*lp_ctx
,
1383 struct ntlm_auth_state
*state
,
1384 char *buf
, int length
, void **private2
)
1386 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1390 static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode
,
1391 struct loadparm_context
*lp_ctx
,
1392 struct ntlm_auth_state
*state
,
1393 char *buf
, int length
, void **private2
)
1398 pass
=(char *)memchr(buf
,' ',length
);
1400 DEBUG(2, ("Password not found. Denying access\n"));
1407 if (state
->helper_mode
== SQUID_2_5_BASIC
) {
1408 char *end
= rfc1738_unescape(user
);
1409 if (end
== NULL
|| (end
- user
) != strlen(user
)) {
1410 DEBUG(2, ("Badly rfc1738 encoded username: %s; "
1411 "denying access\n", user
));
1415 end
= rfc1738_unescape(pass
);
1416 if (end
== NULL
|| (end
- pass
) != strlen(pass
)) {
1417 DEBUG(2, ("Badly encoded password for %s; "
1418 "denying access\n", user
));
1424 if (check_plaintext_auth(user
, pass
, False
)) {
1431 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode
,
1432 struct loadparm_context
*lp_ctx
,
1433 char *buf
, int length
, void **private1
)
1436 DATA_BLOB out
= data_blob(NULL
, 0);
1437 char *out_base64
= NULL
;
1438 const char *reply_arg
= NULL
;
1439 struct gensec_ntlm_state
{
1440 struct gensec_security
*gensec_state
;
1441 const char *set_password
;
1443 struct gensec_ntlm_state
*state
;
1447 const char *reply_code
;
1448 struct cli_credentials
*creds
;
1450 static char *want_feature_list
= NULL
;
1451 static DATA_BLOB session_key
;
1453 TALLOC_CTX
*mem_ctx
;
1455 mem_ctx
= talloc_named(NULL
, 0, "manage_gensec_request internal mem_ctx");
1456 if (mem_ctx
== NULL
) {
1457 printf("BH No Memory\n");
1462 state
= talloc_get_type(*private1
, struct gensec_ntlm_state
);
1463 if (state
== NULL
) {
1464 DBG_WARNING("*private1 is of type %s\n",
1465 talloc_get_name(*private1
));
1466 printf("BH *private1 is of type %s\n",
1467 talloc_get_name(*private1
));
1471 state
= talloc_zero(NULL
, struct gensec_ntlm_state
);
1473 printf("BH No Memory\n");
1478 state
->set_password
= opt_password
;
1482 if (strlen(buf
) < 2) {
1483 DEBUG(1, ("query [%s] invalid", buf
));
1484 printf("BH Query invalid\n");
1485 talloc_free(mem_ctx
);
1489 if (strlen(buf
) > 3) {
1490 if(strncmp(buf
, "SF ", 3) == 0) {
1491 DEBUG(10, ("Setting flags to negotiate\n"));
1492 talloc_free(want_feature_list
);
1493 want_feature_list
= talloc_strndup(state
, buf
+3, strlen(buf
)-3);
1495 talloc_free(mem_ctx
);
1498 in
= base64_decode_data_blob_talloc(mem_ctx
, buf
+ 3);
1500 in
= data_blob(NULL
, 0);
1503 if (strncmp(buf
, "YR", 2) == 0) {
1504 if (state
->gensec_state
) {
1505 talloc_free(state
->gensec_state
);
1506 state
->gensec_state
= NULL
;
1508 } else if ( (strncmp(buf
, "OK", 2) == 0)) {
1509 /* Just return BH, like ntlm_auth from Samba 3 does. */
1510 printf("BH Command expected\n");
1511 talloc_free(mem_ctx
);
1513 } else if ( (strncmp(buf
, "TT ", 3) != 0) &&
1514 (strncmp(buf
, "KK ", 3) != 0) &&
1515 (strncmp(buf
, "AF ", 3) != 0) &&
1516 (strncmp(buf
, "NA ", 3) != 0) &&
1517 (strncmp(buf
, "UG", 2) != 0) &&
1518 (strncmp(buf
, "PW ", 3) != 0) &&
1519 (strncmp(buf
, "GK", 2) != 0) &&
1520 (strncmp(buf
, "GF", 2) != 0)) {
1521 DEBUG(1, ("SPNEGO request [%s] invalid prefix\n", buf
));
1522 printf("BH SPNEGO request invalid prefix\n");
1523 talloc_free(mem_ctx
);
1528 if (!(state
->gensec_state
)) {
1529 switch (stdio_helper_mode
) {
1530 case GSS_SPNEGO_CLIENT
:
1532 * cached credentials are only supported by
1533 * NTLMSSP_CLIENT_1 for now.
1535 use_cached_creds
= false;
1537 case NTLMSSP_CLIENT_1
:
1538 /* setup the client side */
1540 if (state
->set_password
!= NULL
) {
1541 use_cached_creds
= false;
1544 if (use_cached_creds
) {
1545 struct wbcCredentialCacheParams params
;
1546 struct wbcCredentialCacheInfo
*info
= NULL
;
1547 struct wbcAuthErrorInfo
*error
= NULL
;
1550 params
.account_name
= opt_username
;
1551 params
.domain_name
= opt_domain
;
1552 params
.level
= WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP
;
1553 params
.num_blobs
= 0;
1554 params
.blobs
= NULL
;
1556 wbc_status
= wbcCredentialCache(¶ms
, &info
,
1558 wbcFreeMemory(error
);
1559 if (!WBC_ERROR_IS_OK(wbc_status
)) {
1560 use_cached_creds
= false;
1562 wbcFreeMemory(info
);
1565 nt_status
= ntlm_auth_prepare_gensec_client(state
, lp_ctx
,
1566 &state
->gensec_state
);
1567 if (!NT_STATUS_IS_OK(nt_status
)) {
1568 printf("BH GENSEC mech failed to start: %s\n",
1569 nt_errstr(nt_status
));
1570 talloc_free(mem_ctx
);
1574 creds
= cli_credentials_init(state
->gensec_state
);
1575 cli_credentials_set_conf(creds
, lp_ctx
);
1577 cli_credentials_set_username(creds
, opt_username
, CRED_SPECIFIED
);
1580 cli_credentials_set_domain(creds
, opt_domain
, CRED_SPECIFIED
);
1582 if (use_cached_creds
) {
1583 gensec_want_feature(state
->gensec_state
,
1584 GENSEC_FEATURE_NTLM_CCACHE
);
1585 } else if (state
->set_password
) {
1586 cli_credentials_set_password(creds
, state
->set_password
, CRED_SPECIFIED
);
1588 cli_credentials_set_password_callback(creds
, get_password
);
1590 if (opt_workstation
) {
1591 cli_credentials_set_workstation(creds
, opt_workstation
, CRED_SPECIFIED
);
1594 gensec_set_credentials(state
->gensec_state
, creds
);
1597 case GSS_SPNEGO_SERVER
:
1598 case SQUID_2_5_NTLMSSP
:
1600 nt_status
= ntlm_auth_prepare_gensec_server(state
, lp_ctx
,
1601 &state
->gensec_state
);
1602 if (!NT_STATUS_IS_OK(nt_status
)) {
1603 printf("BH GENSEC mech failed to start: %s\n",
1604 nt_errstr(nt_status
));
1605 talloc_free(mem_ctx
);
1611 talloc_free(mem_ctx
);
1615 gensec_want_feature_list(state
->gensec_state
, want_feature_list
);
1617 /* Session info is not complete, do not pass to auth log */
1618 gensec_want_feature(state
->gensec_state
, GENSEC_FEATURE_NO_AUTHZ_LOG
);
1620 switch (stdio_helper_mode
) {
1621 case GSS_SPNEGO_CLIENT
:
1622 case GSS_SPNEGO_SERVER
:
1623 nt_status
= gensec_start_mech_by_oid(state
->gensec_state
, GENSEC_OID_SPNEGO
);
1628 case NTLMSSP_CLIENT_1
:
1633 case SQUID_2_5_NTLMSSP
:
1634 nt_status
= gensec_start_mech_by_oid(state
->gensec_state
, GENSEC_OID_NTLMSSP
);
1637 talloc_free(mem_ctx
);
1641 if (!NT_STATUS_IS_OK(nt_status
)) {
1642 DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status
)));
1643 printf("BH GENSEC mech failed to start\n");
1644 talloc_free(mem_ctx
);
1652 if (strncmp(buf
, "PW ", 3) == 0) {
1653 state
->set_password
= talloc_strndup(state
,
1654 (const char *)in
.data
,
1657 cli_credentials_set_password(gensec_get_credentials(state
->gensec_state
),
1658 state
->set_password
,
1661 talloc_free(mem_ctx
);
1665 if (strncmp(buf
, "GK", 2) == 0) {
1667 DEBUG(10, ("Requested session key\n"));
1668 nt_status
= gensec_session_key(state
->gensec_state
, mem_ctx
, &session_key
);
1669 if(!NT_STATUS_IS_OK(nt_status
)) {
1670 DEBUG(1, ("gensec_session_key failed: %s\n", nt_errstr(nt_status
)));
1671 printf("BH No session key\n");
1672 talloc_free(mem_ctx
);
1675 base64_key
= base64_encode_data_blob(state
, session_key
);
1676 SMB_ASSERT(base64_key
!= NULL
);
1677 printf("GK %s\n", base64_key
);
1678 talloc_free(base64_key
);
1680 talloc_free(mem_ctx
);
1684 if (strncmp(buf
, "GF", 2) == 0) {
1687 DEBUG(10, ("Requested negotiated NTLMSSP feature flags\n"));
1689 neg_flags
= gensec_ntlmssp_neg_flags(state
->gensec_state
);
1690 if (neg_flags
== 0) {
1692 talloc_free(mem_ctx
);
1696 printf("GF 0x%08x\n", neg_flags
);
1697 talloc_free(mem_ctx
);
1701 nt_status
= gensec_update(state
->gensec_state
, mem_ctx
, in
, &out
);
1703 /* don't leak 'bad password'/'no such user' info to the network client */
1704 nt_status
= nt_status_squash(nt_status
);
1707 out_base64
= base64_encode_data_blob(mem_ctx
, out
);
1708 SMB_ASSERT(out_base64
!= NULL
);
1713 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1715 if (first
&& state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1717 } else if (state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1719 } else if (state
->gensec_state
->gensec_role
== GENSEC_SERVER
) {
1726 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCESS_DENIED
)) {
1727 reply_code
= "BH NT_STATUS_ACCESS_DENIED";
1728 reply_arg
= nt_errstr(nt_status
);
1729 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1730 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_UNSUCCESSFUL
)) {
1731 reply_code
= "BH NT_STATUS_UNSUCCESSFUL";
1732 reply_arg
= nt_errstr(nt_status
);
1733 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1734 } else if (!NT_STATUS_IS_OK(nt_status
)) {
1736 reply_arg
= nt_errstr(nt_status
);
1737 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1738 } else if /* OK */ (state
->gensec_state
->gensec_role
== GENSEC_SERVER
) {
1739 struct auth_session_info
*session_info
;
1741 nt_status
= gensec_session_info(state
->gensec_state
, mem_ctx
, &session_info
);
1742 if (!NT_STATUS_IS_OK(nt_status
)) {
1743 reply_code
= "BH Failed to retrieve session info";
1744 reply_arg
= nt_errstr(nt_status
);
1745 DEBUG(1, ("GENSEC failed to retrieve the session info: %s\n", nt_errstr(nt_status
)));
1749 reply_arg
= talloc_strdup(state
->gensec_state
, session_info
->unix_info
->unix_name
);
1750 if (reply_arg
== NULL
) {
1751 reply_code
= "BH out of memory";
1752 reply_arg
= nt_errstr(NT_STATUS_NO_MEMORY
);
1754 talloc_free(session_info
);
1756 } else if (state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1758 reply_arg
= out_base64
;
1763 switch (stdio_helper_mode
) {
1764 case GSS_SPNEGO_SERVER
:
1765 printf("%s %s %s\n", reply_code
,
1766 out_base64
? out_base64
: "*",
1767 reply_arg
? reply_arg
: "*");
1771 printf("%s %s\n", reply_code
, out_base64
);
1772 } else if (reply_arg
) {
1773 printf("%s %s\n", reply_code
, reply_arg
);
1775 printf("%s\n", reply_code
);
1779 talloc_free(mem_ctx
);
1783 static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode
,
1784 struct loadparm_context
*lp_ctx
,
1785 struct ntlm_auth_state
*state
,
1786 char *buf
, int length
, void **private2
)
1788 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1792 static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode
,
1793 struct loadparm_context
*lp_ctx
,
1794 struct ntlm_auth_state
*state
,
1795 char *buf
, int length
, void **private2
)
1797 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1801 static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode
,
1802 struct loadparm_context
*lp_ctx
,
1803 struct ntlm_auth_state
*state
,
1804 char *buf
, int length
, void **private2
)
1806 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1810 static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode
,
1811 struct loadparm_context
*lp_ctx
,
1812 struct ntlm_auth_state
*state
,
1813 char *buf
, int length
, void **private2
)
1815 char *request
, *parameter
;
1816 static DATA_BLOB challenge
;
1817 static DATA_BLOB lm_response
;
1818 static DATA_BLOB nt_response
;
1819 static char *full_username
;
1820 static char *username
;
1821 static char *domain
;
1822 static char *plaintext_password
;
1823 static bool ntlm_server_1_user_session_key
;
1824 static bool ntlm_server_1_lm_session_key
;
1826 if (strequal(buf
, ".")) {
1827 if (!full_username
&& !username
) {
1828 printf("Error: No username supplied!\n");
1829 } else if (plaintext_password
) {
1830 /* handle this request as plaintext */
1831 if (!full_username
) {
1832 if (asprintf(&full_username
, "%s%c%s", domain
, winbind_separator(), username
) == -1) {
1833 printf("Error: Out of memory in "
1838 if (check_plaintext_auth(full_username
, plaintext_password
, False
)) {
1839 printf("Authenticated: Yes\n");
1841 printf("Authenticated: No\n");
1843 } else if (!lm_response
.data
&& !nt_response
.data
) {
1844 printf("Error: No password supplied!\n");
1845 } else if (!challenge
.data
) {
1846 printf("Error: No lanman-challenge supplied!\n");
1848 char *error_string
= NULL
;
1850 uchar user_session_key
[16];
1853 if (full_username
&& !username
) {
1855 fstring fstr_domain
;
1857 if (!parse_ntlm_auth_domain_user(full_username
, fstr_user
, fstr_domain
)) {
1858 /* username might be 'tainted', don't print into our new-line deleimianted stream */
1859 printf("Error: Could not parse into "
1860 "domain and username\n");
1862 SAFE_FREE(username
);
1864 username
= smb_xstrdup(fstr_user
);
1865 domain
= smb_xstrdup(fstr_domain
);
1869 DATA_BLOB nt_session_key
, lm_session_key
;
1870 struct samr_Password lm_pw
, nt_pw
;
1871 TALLOC_CTX
*mem_ctx
= talloc_new(NULL
);
1872 ZERO_STRUCT(user_session_key
);
1873 ZERO_STRUCT(lm_key
);
1875 nt_lm_owf_gen (opt_password
, nt_pw
.hash
, lm_pw
.hash
);
1876 nt_status
= ntlm_password_check(mem_ctx
,
1889 error_string
= smb_xstrdup(get_friendly_nt_error_msg(nt_status
));
1890 if (ntlm_server_1_user_session_key
) {
1891 if (nt_session_key
.length
== sizeof(user_session_key
)) {
1892 memcpy(user_session_key
,
1893 nt_session_key
.data
,
1894 sizeof(user_session_key
));
1897 if (ntlm_server_1_lm_session_key
) {
1898 if (lm_session_key
.length
== sizeof(lm_key
)) {
1900 lm_session_key
.data
,
1904 TALLOC_FREE(mem_ctx
);
1907 uint8_t authoritative
= 1;
1910 domain
= smb_xstrdup(get_winbind_domain());
1913 if (ntlm_server_1_lm_session_key
)
1914 flags
|= WBFLAG_PAM_LMKEY
;
1916 if (ntlm_server_1_user_session_key
)
1917 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
1919 nt_status
= contact_winbind_auth_crap(username
,
1933 if (!NT_STATUS_IS_OK(nt_status
)) {
1934 printf("Authenticated: No\n");
1935 printf("Authentication-Error: %s\n.\n",
1939 char *hex_user_session_key
;
1941 printf("Authenticated: Yes\n");
1943 if (ntlm_server_1_lm_session_key
1944 && (!all_zero(lm_key
,
1946 hex_lm_key
= hex_encode_talloc(NULL
,
1947 (const unsigned char *)lm_key
,
1949 printf("LANMAN-Session-Key: %s\n",
1951 TALLOC_FREE(hex_lm_key
);
1954 if (ntlm_server_1_user_session_key
1955 && (!all_zero(user_session_key
,
1956 sizeof(user_session_key
)))) {
1957 hex_user_session_key
= hex_encode_talloc(NULL
,
1958 (const unsigned char *)user_session_key
,
1959 sizeof(user_session_key
));
1960 printf("User-Session-Key: %s\n",
1961 hex_user_session_key
);
1962 TALLOC_FREE(hex_user_session_key
);
1965 SAFE_FREE(error_string
);
1967 /* clear out the state */
1968 challenge
= data_blob_null
;
1969 nt_response
= data_blob_null
;
1970 lm_response
= data_blob_null
;
1971 SAFE_FREE(full_username
);
1972 SAFE_FREE(username
);
1974 SAFE_FREE(plaintext_password
);
1975 ntlm_server_1_user_session_key
= False
;
1976 ntlm_server_1_lm_session_key
= False
;
1984 /* Indicates a base64 encoded structure */
1985 parameter
= strstr_m(request
, ":: ");
1987 parameter
= strstr_m(request
, ": ");
1990 DEBUG(0, ("Parameter not found!\n"));
1991 printf("Error: Parameter not found!\n.\n");
2008 base64_decode_inplace(parameter
);
2011 if (strequal(request
, "LANMAN-Challenge")) {
2012 challenge
= strhex_to_data_blob(NULL
, parameter
);
2013 if (challenge
.length
!= 8) {
2014 printf("Error: hex decode of %s failed! "
2015 "(got %d bytes, expected 8)\n.\n",
2017 (int)challenge
.length
);
2018 challenge
= data_blob_null
;
2020 } else if (strequal(request
, "NT-Response")) {
2021 nt_response
= strhex_to_data_blob(NULL
, parameter
);
2022 if (nt_response
.length
< 24) {
2023 printf("Error: hex decode of %s failed! "
2024 "(only got %d bytes, needed at least 24)\n.\n",
2026 (int)nt_response
.length
);
2027 nt_response
= data_blob_null
;
2029 } else if (strequal(request
, "LANMAN-Response")) {
2030 lm_response
= strhex_to_data_blob(NULL
, parameter
);
2031 if (lm_response
.length
!= 24) {
2032 printf("Error: hex decode of %s failed! "
2033 "(got %d bytes, expected 24)\n.\n",
2035 (int)lm_response
.length
);
2036 lm_response
= data_blob_null
;
2038 } else if (strequal(request
, "Password")) {
2039 plaintext_password
= smb_xstrdup(parameter
);
2040 } else if (strequal(request
, "NT-Domain")) {
2041 domain
= smb_xstrdup(parameter
);
2042 } else if (strequal(request
, "Username")) {
2043 username
= smb_xstrdup(parameter
);
2044 } else if (strequal(request
, "Full-Username")) {
2045 full_username
= smb_xstrdup(parameter
);
2046 } else if (strequal(request
, "Request-User-Session-Key")) {
2047 ntlm_server_1_user_session_key
= strequal(parameter
, "Yes");
2048 } else if (strequal(request
, "Request-LanMan-Session-Key")) {
2049 ntlm_server_1_lm_session_key
= strequal(parameter
, "Yes");
2051 printf("Error: Unknown request %s\n.\n", request
);
2055 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode
,
2056 struct loadparm_context
*lp_ctx
,
2057 struct ntlm_auth_state
*state
,
2058 char *buf
, int length
, void **private2
)
2060 char *request
, *parameter
;
2061 static DATA_BLOB new_nt_pswd
;
2062 static DATA_BLOB old_nt_hash_enc
;
2063 static DATA_BLOB new_lm_pswd
;
2064 static DATA_BLOB old_lm_hash_enc
;
2065 static char *full_username
= NULL
;
2066 static char *username
= NULL
;
2067 static char *domain
= NULL
;
2068 static char *newpswd
= NULL
;
2069 static char *oldpswd
= NULL
;
2071 if (strequal(buf
, ".")) {
2072 if(newpswd
&& oldpswd
) {
2073 uchar old_nt_hash
[16];
2074 uchar old_lm_hash
[16];
2075 uchar new_nt_hash
[16];
2076 uchar new_lm_hash
[16];
2078 gnutls_cipher_hd_t cipher_hnd
= NULL
;
2079 gnutls_datum_t old_nt_key
= {
2080 .data
= old_nt_hash
,
2081 .size
= sizeof(old_nt_hash
),
2085 new_nt_pswd
= data_blob(NULL
, 516);
2086 old_nt_hash_enc
= data_blob(NULL
, 16);
2088 /* Calculate the MD4 hash (NT compatible) of the
2090 E_md4hash(oldpswd
, old_nt_hash
);
2091 E_md4hash(newpswd
, new_nt_hash
);
2093 /* E_deshash returns false for 'long'
2094 passwords (> 14 DOS chars).
2096 Therefore, don't send a buffer
2097 encrypted with the truncated hash
2098 (it could allow an even easier
2099 attack on the password)
2101 Likewise, obey the admin's restriction
2104 rc
= gnutls_cipher_init(&cipher_hnd
,
2105 GNUTLS_CIPHER_ARCFOUR_128
,
2109 DBG_ERR("gnutls_cipher_init failed: %s\n",
2110 gnutls_strerror(rc
));
2111 if (rc
== GNUTLS_E_UNWANTED_ALGORITHM
) {
2112 DBG_ERR("Running in FIPS mode, NTLM blocked\n");
2117 if (lp_client_lanman_auth() &&
2118 E_deshash(newpswd
, new_lm_hash
) &&
2119 E_deshash(oldpswd
, old_lm_hash
)) {
2120 new_lm_pswd
= data_blob(NULL
, 516);
2121 old_lm_hash_enc
= data_blob(NULL
, 16);
2122 encode_pw_buffer(new_lm_pswd
.data
, newpswd
,
2125 rc
= gnutls_cipher_encrypt(cipher_hnd
,
2129 gnutls_cipher_deinit(cipher_hnd
);
2132 rc
= E_old_pw_hash(new_nt_hash
, old_lm_hash
,
2133 old_lm_hash_enc
.data
);
2135 DBG_ERR("E_old_pw_hash failed: %s\n",
2136 gnutls_strerror(rc
));
2140 new_lm_pswd
.data
= NULL
;
2141 new_lm_pswd
.length
= 0;
2142 old_lm_hash_enc
.data
= NULL
;
2143 old_lm_hash_enc
.length
= 0;
2146 encode_pw_buffer(new_nt_pswd
.data
, newpswd
,
2149 rc
= gnutls_cipher_encrypt(cipher_hnd
,
2152 gnutls_cipher_deinit(cipher_hnd
);
2156 rc
= E_old_pw_hash(new_nt_hash
, old_nt_hash
,
2157 old_nt_hash_enc
.data
);
2159 DBG_ERR("E_old_pw_hash failed: %s\n",
2160 gnutls_strerror(rc
));
2164 ZERO_ARRAY(old_nt_hash
);
2165 ZERO_ARRAY(old_lm_hash
);
2166 ZERO_ARRAY(new_nt_hash
);
2167 ZERO_ARRAY(new_lm_hash
);
2170 if (!full_username
&& !username
) {
2171 printf("Error: No username supplied!\n");
2172 } else if ((!new_nt_pswd
.data
|| !old_nt_hash_enc
.data
) &&
2173 (!new_lm_pswd
.data
|| old_lm_hash_enc
.data
) ) {
2174 printf("Error: No NT or LM password "
2175 "blobs supplied!\n");
2177 char *error_string
= NULL
;
2179 if (full_username
&& !username
) {
2181 fstring fstr_domain
;
2183 if (!parse_ntlm_auth_domain_user(full_username
,
2186 /* username might be 'tainted', don't
2187 * print into our new-line
2188 * deleimianted stream */
2189 printf("Error: Could not "
2190 "parse into domain and "
2192 SAFE_FREE(username
);
2193 username
= smb_xstrdup(full_username
);
2195 SAFE_FREE(username
);
2197 username
= smb_xstrdup(fstr_user
);
2198 domain
= smb_xstrdup(fstr_domain
);
2203 if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
2210 printf("Password-Change: No\n");
2211 printf("Password-Change-Error: %s\n.\n",
2214 printf("Password-Change: Yes\n");
2217 SAFE_FREE(error_string
);
2219 /* clear out the state */
2220 new_nt_pswd
= data_blob_null
;
2221 old_nt_hash_enc
= data_blob_null
;
2222 new_lm_pswd
= data_blob_null
;
2223 old_nt_hash_enc
= data_blob_null
;
2224 SAFE_FREE(full_username
);
2225 SAFE_FREE(username
);
2236 /* Indicates a base64 encoded structure */
2237 parameter
= strstr_m(request
, ":: ");
2239 parameter
= strstr_m(request
, ": ");
2242 DEBUG(0, ("Parameter not found!\n"));
2243 printf("Error: Parameter not found!\n.\n");
2259 base64_decode_inplace(parameter
);
2262 if (strequal(request
, "new-nt-password-blob")) {
2263 new_nt_pswd
= strhex_to_data_blob(NULL
, parameter
);
2264 if (new_nt_pswd
.length
!= 516) {
2265 printf("Error: hex decode of %s failed! "
2266 "(got %d bytes, expected 516)\n.\n",
2268 (int)new_nt_pswd
.length
);
2269 new_nt_pswd
= data_blob_null
;
2271 } else if (strequal(request
, "old-nt-hash-blob")) {
2272 old_nt_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2273 if (old_nt_hash_enc
.length
!= 16) {
2274 printf("Error: hex decode of %s failed! "
2275 "(got %d bytes, expected 16)\n.\n",
2277 (int)old_nt_hash_enc
.length
);
2278 old_nt_hash_enc
= data_blob_null
;
2280 } else if (strequal(request
, "new-lm-password-blob")) {
2281 new_lm_pswd
= strhex_to_data_blob(NULL
, parameter
);
2282 if (new_lm_pswd
.length
!= 516) {
2283 printf("Error: hex decode of %s failed! "
2284 "(got %d bytes, expected 516)\n.\n",
2286 (int)new_lm_pswd
.length
);
2287 new_lm_pswd
= data_blob_null
;
2290 else if (strequal(request
, "old-lm-hash-blob")) {
2291 old_lm_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2292 if (old_lm_hash_enc
.length
!= 16)
2294 printf("Error: hex decode of %s failed! "
2295 "(got %d bytes, expected 16)\n.\n",
2297 (int)old_lm_hash_enc
.length
);
2298 old_lm_hash_enc
= data_blob_null
;
2300 } else if (strequal(request
, "nt-domain")) {
2301 domain
= smb_xstrdup(parameter
);
2302 } else if(strequal(request
, "username")) {
2303 username
= smb_xstrdup(parameter
);
2304 } else if(strequal(request
, "full-username")) {
2305 username
= smb_xstrdup(parameter
);
2306 } else if(strequal(request
, "new-password")) {
2307 newpswd
= smb_xstrdup(parameter
);
2308 } else if (strequal(request
, "old-password")) {
2309 oldpswd
= smb_xstrdup(parameter
);
2311 printf("Error: Unknown request %s\n.\n", request
);
2315 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode
,
2316 struct loadparm_context
*lp_ctx
,
2317 struct ntlm_auth_state
*state
,
2318 stdio_helper_function fn
, void **private2
)
2321 char tmp
[INITIAL_BUFFER_SIZE
+1];
2322 int length
, buf_size
= 0;
2325 buf
= talloc_strdup(state
->mem_ctx
, "");
2327 DEBUG(0, ("Failed to allocate input buffer.\n"));
2328 fprintf(stderr
, "ERR\n");
2334 /* this is not a typo - x_fgets doesn't work too well under
2336 if (fgets(tmp
, sizeof(tmp
)-1, stdin
) == NULL
) {
2337 if (ferror(stdin
)) {
2338 DEBUG(1, ("fgets() failed! dying..... errno=%d "
2339 "(%s)\n", ferror(stdin
),
2340 strerror(ferror(stdin
))));
2347 buf
= talloc_strdup_append_buffer(buf
, tmp
);
2348 buf_size
+= INITIAL_BUFFER_SIZE
;
2350 if (buf_size
> MAX_BUFFER_SIZE
) {
2351 DEBUG(2, ("Oversized message\n"));
2352 fprintf(stderr
, "ERR\n");
2357 c
= strchr(buf
, '\n');
2358 } while (c
== NULL
);
2363 DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf
,length
));
2365 if (buf
[0] == '\0') {
2366 DEBUG(2, ("Invalid Request\n"));
2367 fprintf(stderr
, "ERR\n");
2372 fn(stdio_helper_mode
, lp_ctx
, state
, buf
, length
, private2
);
2377 static void squid_stream(enum stdio_helper_mode stdio_mode
,
2378 struct loadparm_context
*lp_ctx
,
2379 stdio_helper_function fn
) {
2380 TALLOC_CTX
*mem_ctx
;
2381 struct ntlm_auth_state
*state
;
2383 /* initialize FDescs */
2384 setbuf(stdout
, NULL
);
2385 setbuf(stderr
, NULL
);
2387 mem_ctx
= talloc_init("ntlm_auth");
2389 DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
2390 fprintf(stderr
, "ERR\n");
2394 state
= talloc_zero(mem_ctx
, struct ntlm_auth_state
);
2396 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
2397 fprintf(stderr
, "ERR\n");
2401 state
->mem_ctx
= mem_ctx
;
2402 state
->helper_mode
= stdio_mode
;
2405 TALLOC_CTX
*frame
= talloc_stackframe();
2406 manage_squid_request(stdio_mode
, lp_ctx
, state
, fn
, NULL
);
2412 /* Authenticate a user with a challenge/response */
2414 static bool check_auth_crap(void)
2419 char user_session_key
[16];
2421 char *hex_user_session_key
;
2423 uint8_t authoritative
= 1;
2425 setbuf(stdout
, NULL
);
2428 flags
|= WBFLAG_PAM_LMKEY
;
2430 if (request_user_session_key
)
2431 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
2433 flags
|= WBFLAG_PAM_NT_STATUS_SQUASH
;
2435 nt_status
= contact_winbind_auth_crap(opt_username
, opt_domain
,
2441 (unsigned char *)lm_key
,
2442 (unsigned char *)user_session_key
,
2444 &error_string
, NULL
);
2446 if (!NT_STATUS_IS_OK(nt_status
)) {
2447 printf("%s (0x%x)\n", error_string
,
2448 NT_STATUS_V(nt_status
));
2449 SAFE_FREE(error_string
);
2454 && (!all_zero((uint8_t *)lm_key
, sizeof(lm_key
)))) {
2455 hex_lm_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)lm_key
,
2457 printf("LM_KEY: %s\n", hex_lm_key
);
2458 TALLOC_FREE(hex_lm_key
);
2460 if (request_user_session_key
2461 && (!all_zero((uint8_t *)user_session_key
,
2462 sizeof(user_session_key
)))) {
2463 hex_user_session_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)user_session_key
,
2464 sizeof(user_session_key
));
2465 printf("NT_KEY: %s\n", hex_user_session_key
);
2466 TALLOC_FREE(hex_user_session_key
);
2475 OPT_USERNAME
= 1000,
2484 OPT_USER_SESSION_KEY
,
2486 OPT_REQUIRE_MEMBERSHIP
,
2487 OPT_USE_CACHED_CREDS
,
2489 OPT_PAM_WINBIND_CONF
,
2491 OPT_TARGET_HOSTNAME
,
2495 int main(int argc
, const char **argv
)
2497 TALLOC_CTX
*frame
= talloc_stackframe();
2499 const char *helper_protocol
= NULL
;
2500 int diagnostics
= 0;
2502 const char *hex_challenge
= NULL
;
2503 const char *hex_lm_response
= NULL
;
2504 const char *hex_nt_response
= NULL
;
2505 struct loadparm_context
*lp_ctx
;
2509 /* NOTE: DO NOT change this interface without considering the implications!
2510 This is an external interface, which other programs will use to interact
2514 /* We do not use single-letter command abbreviations, because they harm future
2515 interface stability. */
2517 struct poptOption long_options
[] = {
2520 .longName
= "helper-protocol",
2522 .argInfo
= POPT_ARG_STRING
,
2523 .arg
= &helper_protocol
,
2525 .descrip
= "operate as a stdio-based helper",
2526 .argDescrip
= "helper protocol to use"
2529 .longName
= "username",
2531 .argInfo
= POPT_ARG_STRING
,
2532 .arg
= &opt_username
,
2533 .val
= OPT_USERNAME
,
2534 .descrip
= "username"
2537 .longName
= "domain",
2539 .argInfo
= POPT_ARG_STRING
,
2542 .descrip
= "domain name"
2545 .longName
= "workstation",
2547 .argInfo
= POPT_ARG_STRING
,
2548 .arg
= &opt_workstation
,
2549 .val
= OPT_WORKSTATION
,
2550 .descrip
= "workstation"
2553 .longName
= "challenge",
2555 .argInfo
= POPT_ARG_STRING
,
2556 .arg
= &hex_challenge
,
2557 .val
= OPT_CHALLENGE
,
2558 .descrip
= "challenge (HEX encoded)"
2561 .longName
= "lm-response",
2563 .argInfo
= POPT_ARG_STRING
,
2564 .arg
= &hex_lm_response
,
2566 .descrip
= "LM Response to the challenge (HEX encoded)"
2569 .longName
= "nt-response",
2571 .argInfo
= POPT_ARG_STRING
,
2572 .arg
= &hex_nt_response
,
2574 .descrip
= "NT or NTLMv2 Response to the challenge (HEX encoded)"
2577 .longName
= "password",
2579 .argInfo
= POPT_ARG_STRING
,
2580 .arg
= &opt_password
,
2581 .val
= OPT_PASSWORD
,
2582 .descrip
= "User's plaintext password"
2585 .longName
= "request-lm-key",
2587 .argInfo
= POPT_ARG_NONE
,
2588 .arg
= &request_lm_key
,
2590 .descrip
= "Retrieve LM session key (or, with --diagnostics, expect LM support)"
2593 .longName
= "request-nt-key",
2595 .argInfo
= POPT_ARG_NONE
,
2596 .arg
= &request_user_session_key
,
2597 .val
= OPT_USER_SESSION_KEY
,
2598 .descrip
= "Retrieve User (NT) session key"
2601 .longName
= "use-cached-creds",
2603 .argInfo
= POPT_ARG_NONE
,
2604 .arg
= &use_cached_creds
,
2605 .val
= OPT_USE_CACHED_CREDS
,
2606 .descrip
= "Use cached credentials if no password is given"
2609 .longName
= "allow-mschapv2",
2611 .argInfo
= POPT_ARG_NONE
,
2612 .arg
= &opt_allow_mschapv2
,
2613 .val
= OPT_ALLOW_MSCHAPV2
,
2614 .descrip
= "Explicitly allow MSCHAPv2",
2617 .longName
= "offline-logon",
2619 .argInfo
= POPT_ARG_NONE
,
2620 .arg
= &offline_logon
,
2621 .val
= OPT_OFFLINE_LOGON
,
2622 .descrip
= "Use cached passwords when DC is offline"
2625 .longName
= "diagnostics",
2627 .argInfo
= POPT_ARG_NONE
,
2628 .arg
= &diagnostics
,
2629 .val
= OPT_DIAGNOSTICS
,
2630 .descrip
= "Perform diagnostics on the authentication chain"
2633 .longName
= "require-membership-of",
2635 .argInfo
= POPT_ARG_STRING
,
2636 .arg
= &require_membership_of
,
2637 .val
= OPT_REQUIRE_MEMBERSHIP
,
2638 .descrip
= "Require that a user be a member of this group (either name or SID) for authentication to succeed",
2641 .longName
= "pam-winbind-conf",
2643 .argInfo
= POPT_ARG_STRING
,
2644 .arg
= &opt_pam_winbind_conf
,
2645 .val
= OPT_PAM_WINBIND_CONF
,
2646 .descrip
= "Require that request must set WBFLAG_PAM_CONTACT_TRUSTDOM when krb5 auth is required",
2649 .longName
= "target-service",
2651 .argInfo
= POPT_ARG_STRING
,
2652 .arg
= &opt_target_service
,
2653 .val
= OPT_TARGET_SERVICE
,
2654 .descrip
= "Target service (eg http)",
2657 .longName
= "target-hostname",
2659 .argInfo
= POPT_ARG_STRING
,
2660 .arg
= &opt_target_hostname
,
2661 .val
= OPT_TARGET_HOSTNAME
,
2662 .descrip
= "Target hostname",
2664 POPT_COMMON_DEBUG_ONLY
2665 POPT_COMMON_CONFIG_ONLY
2666 POPT_COMMON_OPTION_ONLY
2671 /* Samba client initialisation */
2674 ok
= samba_cmdline_init(frame
,
2675 SAMBA_CMDLINE_CONFIG_CLIENT
,
2676 false /* require_smbconf */);
2678 DBG_ERR("Failed to init cmdline parser!\n");
2683 pc
= samba_popt_get_context(getprogname(),
2687 POPT_CONTEXT_KEEP_FIRST
);
2689 DBG_ERR("Failed to setup popt context!\n");
2694 while((opt
= poptGetNextOpt(pc
)) != -1) {
2697 opt_challenge
= strhex_to_data_blob(NULL
, hex_challenge
);
2698 if (opt_challenge
.length
!= 8) {
2699 fprintf(stderr
, "hex decode of %s failed! "
2700 "(only got %d bytes)\n",
2702 (int)opt_challenge
.length
);
2707 opt_lm_response
= strhex_to_data_blob(NULL
, hex_lm_response
);
2708 if (opt_lm_response
.length
!= 24) {
2709 fprintf(stderr
, "hex decode of %s failed! "
2710 "(only got %d bytes)\n",
2712 (int)opt_lm_response
.length
);
2718 opt_nt_response
= strhex_to_data_blob(NULL
, hex_nt_response
);
2719 if (opt_nt_response
.length
< 24) {
2720 fprintf(stderr
, "hex decode of %s failed! "
2721 "(only got %d bytes)\n",
2723 (int)opt_nt_response
.length
);
2728 case OPT_REQUIRE_MEMBERSHIP
:
2729 if (strncasecmp_m("S-", require_membership_of
, 2) == 0) {
2730 require_membership_of_sid
= require_membership_of
;
2734 case POPT_ERROR_BADOPT
:
2735 fprintf(stderr
, "\nInvalid option %s: %s\n\n",
2736 poptBadOption(pc
, 0), poptStrerror(opt
));
2737 poptPrintUsage(pc
, stderr
, 0);
2743 char *domain
= SMB_STRDUP(opt_username
);
2744 char *p
= strchr_m(domain
, *lp_winbind_separator());
2748 if (opt_domain
&& !strequal(opt_domain
, domain
)) {
2749 fprintf(stderr
, "Domain specified in username (%s) "
2750 "doesn't match specified domain (%s)!\n\n",
2751 domain
, opt_domain
);
2752 poptPrintHelp(pc
, stderr
, 0);
2755 opt_domain
= domain
;
2761 /* Note: if opt_domain is "" then send no domain */
2762 if (opt_domain
== NULL
) {
2763 opt_domain
= get_winbind_domain();
2766 if (opt_workstation
== NULL
) {
2767 opt_workstation
= "";
2770 lp_ctx
= loadparm_init_s3(NULL
, loadparm_s3_helpers());
2771 if (lp_ctx
== NULL
) {
2772 fprintf(stderr
, "loadparm_init_s3() failed!\n");
2776 if (helper_protocol
) {
2778 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2779 if (strcmp(helper_protocol
, stdio_helper_protocols
[i
].name
) == 0) {
2780 squid_stream(stdio_helper_protocols
[i
].mode
, lp_ctx
, stdio_helper_protocols
[i
].fn
);
2784 fprintf(stderr
, "unknown helper protocol [%s]\n\n"
2785 "Valid helper protools:\n\n", helper_protocol
);
2787 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2788 fprintf(stderr
, "%s\n",
2789 stdio_helper_protocols
[i
].name
);
2795 if (!opt_username
|| !*opt_username
) {
2796 fprintf(stderr
, "username must be specified!\n\n");
2797 poptPrintHelp(pc
, stderr
, 0);
2801 if (opt_challenge
.length
) {
2802 if (!check_auth_crap()) {
2808 if (!opt_password
) {
2809 char pwd
[256] = {0};
2812 rc
= samba_getpass("Password: ", pwd
, sizeof(pwd
), false, false);
2814 opt_password
= SMB_STRDUP(pwd
);
2819 if (!diagnose_ntlm_auth(request_lm_key
)) {
2820 poptFreeContext(pc
);
2826 fstr_sprintf(user
, "%s%c%s", opt_domain
, winbind_separator(), opt_username
);
2827 if (!check_plaintext_auth(user
, opt_password
, True
)) {
2828 poptFreeContext(pc
);
2835 poptFreeContext(pc
);