2 Unix SMB/CIFS implementation.
4 Winbind status program.
6 Copyright (C) Tim Potter 2000-2003
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003-2004
8 Copyright (C) Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it> 2000
9 Copyright (C) Robert O'Callahan 2006 (added cached credential code).
10 Copyright (C) Kai Blin <kai@samba.org> 2008
11 Copyright (C) Simo Sorce 2010
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 3 of the License, or
16 (at your option) any later version.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 #include "lib/param/param.h"
29 #include "popt_common.h"
30 #include "libcli/security/security.h"
31 #include "utils/ntlm_auth.h"
32 #include "../libcli/auth/libcli_auth.h"
33 #include "auth/ntlmssp/ntlmssp.h"
34 #include "auth/gensec/gensec.h"
35 #include "auth/gensec/gensec_internal.h"
36 #include "auth/credentials/credentials.h"
37 #include "librpc/crypto/gse.h"
39 #include "lib/util/tiniparser.h"
40 #include "nsswitch/winbind_client.h"
41 #include "librpc/gen_ndr/krb5pac.h"
42 #include "../lib/util/asn1.h"
43 #include "auth/common_auth.h"
44 #include "source3/include/auth.h"
45 #include "source3/auth/proto.h"
46 #include "nsswitch/libwbclient/wbclient.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"
52 #include <gnutls/gnutls.h>
53 #include <gnutls/crypto.h>
56 #include "auth/kerberos/pac_utils.h"
59 #ifndef PAM_WINBIND_CONFIG_FILE
60 #define PAM_WINBIND_CONFIG_FILE "/etc/security/pam_winbind.conf"
63 #define WINBIND_KRB5_AUTH 0x00000080
66 #define DBGC_CLASS DBGC_WINBIND
68 #define INITIAL_BUFFER_SIZE 300
69 #define MAX_BUFFER_SIZE 630000
71 enum stdio_helper_mode
{
79 NTLM_CHANGE_PASSWORD_1
,
83 enum ntlm_auth_cli_state
{
90 struct ntlm_auth_state
{
92 enum stdio_helper_mode helper_mode
;
93 enum ntlm_auth_cli_state cli_state
;
94 struct ntlmssp_state
*ntlmssp_state
;
96 char *want_feature_list
;
97 bool have_session_key
;
98 DATA_BLOB session_key
;
99 DATA_BLOB initial_message
;
100 void *gensec_private_1
;
102 typedef void (*stdio_helper_function
)(enum stdio_helper_mode stdio_helper_mode
,
103 struct loadparm_context
*lp_ctx
,
104 struct ntlm_auth_state
*state
, char *buf
,
105 int length
, void **private2
);
107 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode
,
108 struct loadparm_context
*lp_ctx
,
109 char *buf
, int length
, void **private1
);
111 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode
,
112 struct loadparm_context
*lp_ctx
,
113 struct ntlm_auth_state
*state
,
114 stdio_helper_function fn
, void **private2
);
116 static void manage_squid_basic_request (enum stdio_helper_mode stdio_helper_mode
,
117 struct loadparm_context
*lp_ctx
,
118 struct ntlm_auth_state
*state
,
119 char *buf
, int length
, void **private2
);
121 static void manage_squid_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode
,
122 struct loadparm_context
*lp_ctx
,
123 struct ntlm_auth_state
*state
,
124 char *buf
, int length
, void **private2
);
126 static void manage_client_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode
,
127 struct loadparm_context
*lp_ctx
,
128 struct ntlm_auth_state
*state
,
129 char *buf
, int length
, void **private2
);
131 static void manage_gss_spnego_request (enum stdio_helper_mode stdio_helper_mode
,
132 struct loadparm_context
*lp_ctx
,
133 struct ntlm_auth_state
*state
,
134 char *buf
, int length
, void **private2
);
136 static void manage_gss_spnego_client_request (enum stdio_helper_mode stdio_helper_mode
,
137 struct loadparm_context
*lp_ctx
,
138 struct ntlm_auth_state
*state
,
139 char *buf
, int length
, void **private2
);
141 static void manage_ntlm_server_1_request (enum stdio_helper_mode stdio_helper_mode
,
142 struct loadparm_context
*lp_ctx
,
143 struct ntlm_auth_state
*state
,
144 char *buf
, int length
, void **private2
);
146 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode
,
147 struct loadparm_context
*lp_ctx
,
148 struct ntlm_auth_state
*state
,
149 char *buf
, int length
, void **private2
);
151 static const struct {
152 enum stdio_helper_mode mode
;
154 stdio_helper_function fn
;
155 } stdio_helper_protocols
[] = {
156 { SQUID_2_4_BASIC
, "squid-2.4-basic", manage_squid_basic_request
},
157 { SQUID_2_5_BASIC
, "squid-2.5-basic", manage_squid_basic_request
},
158 { SQUID_2_5_NTLMSSP
, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request
},
159 { NTLMSSP_CLIENT_1
, "ntlmssp-client-1", manage_client_ntlmssp_request
},
160 { GSS_SPNEGO_SERVER
, "gss-spnego", manage_gss_spnego_request
},
161 { GSS_SPNEGO_CLIENT
, "gss-spnego-client", manage_gss_spnego_client_request
},
162 { NTLM_SERVER_1
, "ntlm-server-1", manage_ntlm_server_1_request
},
163 { NTLM_CHANGE_PASSWORD_1
, "ntlm-change-password-1", manage_ntlm_change_password_1_request
},
164 { NUM_HELPER_MODES
, NULL
, NULL
}
167 const char *opt_username
;
168 const char *opt_domain
;
169 const char *opt_workstation
;
170 const char *opt_password
;
171 static DATA_BLOB opt_challenge
;
172 static DATA_BLOB opt_lm_response
;
173 static DATA_BLOB opt_nt_response
;
174 static int request_lm_key
;
175 static int request_user_session_key
;
176 static int use_cached_creds
;
177 static int offline_logon
;
178 static int opt_allow_mschapv2
;
180 static const char *require_membership_of
;
181 static const char *require_membership_of_sid
;
182 static const char *opt_pam_winbind_conf
;
184 const char *opt_target_service
;
185 const char *opt_target_hostname
;
188 /* This is a bit hairy, but the basic idea is to do a password callback
189 to the calling application. The callback comes from within gensec */
191 static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mode
,
192 struct loadparm_context
*lp_ctx
,
193 struct ntlm_auth_state
*state
, char *buf
, int length
,
197 if (strlen(buf
) < 2) {
198 DEBUG(1, ("query [%s] invalid", buf
));
199 printf("BH Query invalid\n");
203 if (strlen(buf
) > 3) {
204 in
= base64_decode_data_blob(buf
+ 3);
206 in
= data_blob(NULL
, 0);
209 if (strncmp(buf
, "PW ", 3) == 0) {
211 *password
= talloc_strndup(NULL
,
212 (const char *)in
.data
, in
.length
);
214 if (*password
== NULL
) {
215 DEBUG(1, ("Out of memory\n"));
216 printf("BH Out of memory\n");
225 DEBUG(1, ("Asked for (and expected) a password\n"));
226 printf("BH Expected a password\n");
231 * Callback for password credentials. This is not async, and when
232 * GENSEC and the credentials code is made async, it will look rather
236 static const char *get_password(struct cli_credentials
*credentials
)
238 TALLOC_CTX
*frame
= talloc_stackframe();
239 char *password
= NULL
;
240 struct ntlm_auth_state
*state
;
242 state
= talloc_zero(frame
, struct ntlm_auth_state
);
244 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
245 fprintf(stderr
, "ERR\n");
249 state
->mem_ctx
= state
;
251 /* Ask for a password */
254 manage_squid_request(NUM_HELPER_MODES
/* bogus */, NULL
, state
, manage_gensec_get_pw_request
, (void **)&password
);
255 talloc_steal(credentials
, password
);
261 * A limited set of features are defined with text strings as needed
265 static void gensec_want_feature_list(struct gensec_security
*state
, char* feature_list
)
267 if (in_list("NTLMSSP_FEATURE_SESSION_KEY", feature_list
, true)) {
268 DEBUG(10, ("want GENSEC_FEATURE_SESSION_KEY\n"));
269 gensec_want_feature(state
, GENSEC_FEATURE_SESSION_KEY
);
271 if (in_list("NTLMSSP_FEATURE_SIGN", feature_list
, true)) {
272 DEBUG(10, ("want GENSEC_FEATURE_SIGN\n"));
273 gensec_want_feature(state
, GENSEC_FEATURE_SIGN
);
275 if (in_list("NTLMSSP_FEATURE_SEAL", feature_list
, true)) {
276 DEBUG(10, ("want GENSEC_FEATURE_SEAL\n"));
277 gensec_want_feature(state
, GENSEC_FEATURE_SEAL
);
279 if (in_list("NTLMSSP_FEATURE_CCACHE", feature_list
, true)) {
280 DEBUG(10, ("want GENSEC_FEATURE_NTLM_CCACHE\n"));
281 gensec_want_feature(state
, GENSEC_FEATURE_NTLM_CCACHE
);
285 static char winbind_separator(void)
287 struct wbcInterfaceDetails
*details
;
295 ret
= wbcInterfaceDetails(&details
);
296 if (!WBC_ERROR_IS_OK(ret
)) {
297 d_fprintf(stderr
, "could not obtain winbind separator!\n");
298 return *lp_winbind_separator();
301 sep
= details
->winbind_separator
;
303 wbcFreeMemory(details
);
308 d_fprintf(stderr
, "winbind separator was NULL!\n");
309 return *lp_winbind_separator();
315 const char *get_winbind_domain(void)
317 struct wbcInterfaceDetails
*details
;
320 static fstring winbind_domain
;
321 if (*winbind_domain
) {
322 return winbind_domain
;
325 /* Send off request */
327 ret
= wbcInterfaceDetails(&details
);
328 if (!WBC_ERROR_IS_OK(ret
)) {
329 DEBUG(1, ("could not obtain winbind domain name!\n"));
330 return lp_workgroup();
333 fstrcpy(winbind_domain
, details
->netbios_domain
);
335 wbcFreeMemory(details
);
337 return winbind_domain
;
341 const char *get_winbind_netbios_name(void)
343 struct wbcInterfaceDetails
*details
;
346 static fstring winbind_netbios_name
;
348 if (*winbind_netbios_name
) {
349 return winbind_netbios_name
;
352 /* Send off request */
354 ret
= wbcInterfaceDetails(&details
);
355 if (!WBC_ERROR_IS_OK(ret
)) {
356 DEBUG(1, ("could not obtain winbind netbios name!\n"));
357 return lp_netbios_name();
360 fstrcpy(winbind_netbios_name
, details
->netbios_name
);
362 wbcFreeMemory(details
);
364 return winbind_netbios_name
;
368 DATA_BLOB
get_challenge(void)
370 static DATA_BLOB chal
;
371 if (opt_challenge
.length
)
372 return opt_challenge
;
374 chal
= data_blob(NULL
, 8);
376 generate_random_buffer(chal
.data
, chal
.length
);
380 /* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
381 form DOMAIN/user into a domain and a user */
383 static bool parse_ntlm_auth_domain_user(const char *domuser
, fstring domain
,
387 char *p
= strchr(domuser
,winbind_separator());
394 fstrcpy(domain
, domuser
);
395 domain
[PTR_DIFF(p
, domuser
)] = 0;
396 return strupper_m(domain
);
399 static bool get_require_membership_sid(void) {
400 fstring domain
, name
, sidbuf
;
401 struct wbcDomainSid sid
;
402 enum wbcSidType type
;
405 if (!require_membership_of
) {
409 if (require_membership_of_sid
) {
413 /* Otherwise, ask winbindd for the name->sid request */
415 if (!parse_ntlm_auth_domain_user(require_membership_of
,
417 DEBUG(0, ("Could not parse %s into separate domain/name parts!\n",
418 require_membership_of
));
422 ret
= wbcLookupName(domain
, name
, &sid
, &type
);
423 if (!WBC_ERROR_IS_OK(ret
)) {
424 DEBUG(0, ("Winbindd lookupname failed to resolve %s into a SID!\n",
425 require_membership_of
));
429 wbcSidToStringBuf(&sid
, sidbuf
, sizeof(sidbuf
));
431 require_membership_of_sid
= SMB_STRDUP(sidbuf
);
433 if (require_membership_of_sid
)
440 * Get some configuration from pam_winbind.conf to see if we
441 * need to contact trusted domain
444 int get_pam_winbind_config()
447 struct tiniparser_dictionary
*d
= NULL
;
449 if (!opt_pam_winbind_conf
|| !*opt_pam_winbind_conf
) {
450 opt_pam_winbind_conf
= PAM_WINBIND_CONFIG_FILE
;
453 d
= tiniparser_load(opt_pam_winbind_conf
);
459 if (tiniparser_getboolean(d
, "global:krb5_auth", false)) {
460 ctrl
|= WINBIND_KRB5_AUTH
;
463 tiniparser_freedict(d
);
468 /* Authenticate a user with a plaintext password */
470 static bool check_plaintext_auth(const char *user
, const char *pass
,
471 bool stdout_diagnostics
)
473 struct winbindd_request request
;
474 struct winbindd_response response
;
477 if (!get_require_membership_sid()) {
481 /* Send off request */
483 ZERO_STRUCT(request
);
484 ZERO_STRUCT(response
);
486 fstrcpy(request
.data
.auth
.user
, user
);
487 fstrcpy(request
.data
.auth
.pass
, pass
);
488 if (require_membership_of_sid
) {
489 strlcpy(request
.data
.auth
.require_membership_of_sid
,
490 require_membership_of_sid
,
491 sizeof(request
.data
.auth
.require_membership_of_sid
));
495 request
.flags
|= WBFLAG_PAM_CACHED_LOGIN
;
498 result
= winbindd_request_response(NULL
, WINBINDD_PAM_AUTH
, &request
, &response
);
500 /* Display response */
502 if (stdout_diagnostics
) {
503 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
504 d_fprintf(stderr
, "Reading winbind reply failed! (0x01)\n");
507 d_printf("%s: %s (0x%x)\n",
508 response
.data
.auth
.nt_status_string
,
509 response
.data
.auth
.error_string
,
510 response
.data
.auth
.nt_status
);
512 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
513 DEBUG(1, ("Reading winbind reply failed! (0x01)\n"));
516 DEBUG(3, ("%s: %s (0x%x)\n",
517 response
.data
.auth
.nt_status_string
,
518 response
.data
.auth
.error_string
,
519 response
.data
.auth
.nt_status
));
522 return (result
== NSS_STATUS_SUCCESS
);
525 /* authenticate a user with an encrypted username/password */
527 NTSTATUS
contact_winbind_auth_crap(const char *username
,
529 const char *workstation
,
530 const DATA_BLOB
*challenge
,
531 const DATA_BLOB
*lm_response
,
532 const DATA_BLOB
*nt_response
,
534 uint32_t extra_logon_parameters
,
536 uint8_t user_session_key
[16],
537 uint8_t *pauthoritative
,
543 struct winbindd_request request
;
544 struct winbindd_response response
;
548 if (!get_require_membership_sid()) {
549 return NT_STATUS_INVALID_PARAMETER
;
552 ZERO_STRUCT(request
);
553 ZERO_STRUCT(response
);
555 request
.flags
= flags
;
557 request
.data
.auth_crap
.logon_parameters
= extra_logon_parameters
558 | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
| MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT
;
560 if (opt_allow_mschapv2
) {
561 request
.data
.auth_crap
.logon_parameters
|= MSV1_0_ALLOW_MSVCHAPV2
;
564 if (require_membership_of_sid
)
565 fstrcpy(request
.data
.auth_crap
.require_membership_of_sid
, require_membership_of_sid
);
567 fstrcpy(request
.data
.auth_crap
.user
, username
);
568 fstrcpy(request
.data
.auth_crap
.domain
, domain
);
570 fstrcpy(request
.data
.auth_crap
.workstation
,
573 memcpy(request
.data
.auth_crap
.chal
, challenge
->data
, MIN(challenge
->length
, 8));
575 if (lm_response
&& lm_response
->length
) {
576 memcpy(request
.data
.auth_crap
.lm_resp
,
578 MIN(lm_response
->length
, sizeof(request
.data
.auth_crap
.lm_resp
)));
579 request
.data
.auth_crap
.lm_resp_len
= lm_response
->length
;
582 if (nt_response
&& nt_response
->length
) {
583 if (nt_response
->length
> sizeof(request
.data
.auth_crap
.nt_resp
)) {
584 request
.flags
= request
.flags
| WBFLAG_BIG_NTLMV2_BLOB
;
585 request
.extra_len
= nt_response
->length
;
586 request
.extra_data
.data
= SMB_MALLOC_ARRAY(char, request
.extra_len
);
587 if (request
.extra_data
.data
== NULL
) {
588 return NT_STATUS_NO_MEMORY
;
590 memcpy(request
.extra_data
.data
, nt_response
->data
,
591 nt_response
->length
);
594 memcpy(request
.data
.auth_crap
.nt_resp
,
595 nt_response
->data
, nt_response
->length
);
597 request
.data
.auth_crap
.nt_resp_len
= nt_response
->length
;
600 result
= winbindd_priv_request_response(
602 WINBINDD_PAM_AUTH_CRAP
,
605 SAFE_FREE(request
.extra_data
.data
);
607 /* Display response */
609 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
610 nt_status
= NT_STATUS_UNSUCCESSFUL
;
612 *error_string
= smb_xstrdup("Reading winbind reply failed!");
613 winbindd_free_response(&response
);
617 nt_status
= (NT_STATUS(response
.data
.auth
.nt_status
));
618 if (!NT_STATUS_IS_OK(nt_status
)) {
620 *error_string
= smb_xstrdup(response
.data
.auth
.error_string
);
621 *pauthoritative
= response
.data
.auth
.authoritative
;
622 winbindd_free_response(&response
);
626 if ((flags
& WBFLAG_PAM_LMKEY
) && lm_key
) {
627 memcpy(lm_key
, response
.data
.auth
.first_8_lm_hash
,
628 sizeof(response
.data
.auth
.first_8_lm_hash
));
630 if ((flags
& WBFLAG_PAM_USER_SESSION_KEY
) && user_session_key
) {
631 memcpy(user_session_key
, response
.data
.auth
.user_session_key
,
632 sizeof(response
.data
.auth
.user_session_key
));
635 if (flags
& WBFLAG_PAM_UNIX_NAME
) {
636 *unix_name
= SMB_STRDUP(response
.data
.auth
.unix_username
);
638 winbindd_free_response(&response
);
639 return NT_STATUS_NO_MEMORY
;
643 winbindd_free_response(&response
);
647 /* contact server to change user password using auth crap */
648 static NTSTATUS
contact_winbind_change_pswd_auth_crap(const char *username
,
650 const DATA_BLOB new_nt_pswd
,
651 const DATA_BLOB old_nt_hash_enc
,
652 const DATA_BLOB new_lm_pswd
,
653 const DATA_BLOB old_lm_hash_enc
,
658 struct winbindd_request request
;
659 struct winbindd_response response
;
661 if (!get_require_membership_sid())
664 *error_string
= smb_xstrdup("Can't get membership sid.");
665 return NT_STATUS_INVALID_PARAMETER
;
668 ZERO_STRUCT(request
);
669 ZERO_STRUCT(response
);
672 fstrcpy(request
.data
.chng_pswd_auth_crap
.user
, username
);
674 fstrcpy(request
.data
.chng_pswd_auth_crap
.domain
,domain
);
676 if(new_nt_pswd
.length
)
678 memcpy(request
.data
.chng_pswd_auth_crap
.new_nt_pswd
, new_nt_pswd
.data
, sizeof(request
.data
.chng_pswd_auth_crap
.new_nt_pswd
));
679 request
.data
.chng_pswd_auth_crap
.new_nt_pswd_len
= new_nt_pswd
.length
;
682 if(old_nt_hash_enc
.length
)
684 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
));
685 request
.data
.chng_pswd_auth_crap
.old_nt_hash_enc_len
= old_nt_hash_enc
.length
;
688 if(new_lm_pswd
.length
)
690 memcpy(request
.data
.chng_pswd_auth_crap
.new_lm_pswd
, new_lm_pswd
.data
, sizeof(request
.data
.chng_pswd_auth_crap
.new_lm_pswd
));
691 request
.data
.chng_pswd_auth_crap
.new_lm_pswd_len
= new_lm_pswd
.length
;
694 if(old_lm_hash_enc
.length
)
696 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
));
697 request
.data
.chng_pswd_auth_crap
.old_lm_hash_enc_len
= old_lm_hash_enc
.length
;
700 result
= winbindd_request_response(NULL
, WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP
, &request
, &response
);
702 /* Display response */
704 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0))
706 nt_status
= NT_STATUS_UNSUCCESSFUL
;
708 *error_string
= smb_xstrdup("Reading winbind reply failed!");
709 winbindd_free_response(&response
);
713 nt_status
= (NT_STATUS(response
.data
.auth
.nt_status
));
714 if (!NT_STATUS_IS_OK(nt_status
))
717 *error_string
= smb_xstrdup(response
.data
.auth
.error_string
);
718 winbindd_free_response(&response
);
722 winbindd_free_response(&response
);
727 static NTSTATUS
ntlm_auth_generate_session_info(struct auth4_context
*auth_context
,
729 void *server_returned_info
,
730 const char *original_user_name
,
731 uint32_t session_info_flags
,
732 struct auth_session_info
**session_info_out
)
734 const char *unix_username
= (const char *)server_returned_info
;
735 struct dom_sid
*sids
= NULL
;
736 struct auth_session_info
*session_info
= NULL
;
738 session_info
= talloc_zero(mem_ctx
, struct auth_session_info
);
739 if (session_info
== NULL
) {
740 return NT_STATUS_NO_MEMORY
;
743 session_info
->unix_info
= talloc_zero(session_info
, struct auth_user_info_unix
);
744 if (session_info
->unix_info
== NULL
) {
745 TALLOC_FREE(session_info
);
746 return NT_STATUS_NO_MEMORY
;
748 session_info
->unix_info
->unix_name
= talloc_strdup(session_info
->unix_info
,
750 if (session_info
->unix_info
->unix_name
== NULL
) {
751 TALLOC_FREE(session_info
);
752 return NT_STATUS_NO_MEMORY
;
755 session_info
->security_token
= talloc_zero(session_info
, struct security_token
);
756 if (session_info
->security_token
== NULL
) {
757 TALLOC_FREE(session_info
);
758 return NT_STATUS_NO_MEMORY
;
761 sids
= talloc_zero_array(session_info
->security_token
,
764 TALLOC_FREE(session_info
);
765 return NT_STATUS_NO_MEMORY
;
767 sid_copy(&sids
[0], &global_sid_World
);
768 sid_copy(&sids
[1], &global_sid_Network
);
769 sid_copy(&sids
[2], &global_sid_Authenticated_Users
);
771 session_info
->security_token
->num_sids
= talloc_array_length(sids
);
772 session_info
->security_token
->sids
= sids
;
774 *session_info_out
= session_info
;
779 static NTSTATUS
ntlm_auth_generate_session_info_pac(struct auth4_context
*auth_ctx
,
781 struct smb_krb5_context
*smb_krb5_context
,
783 const char *princ_name
,
784 const struct tsocket_address
*remote_address
,
785 uint32_t session_info_flags
,
786 struct auth_session_info
**session_info
)
789 struct PAC_LOGON_INFO
*logon_info
= NULL
;
797 tmp_ctx
= talloc_new(mem_ctx
);
799 return NT_STATUS_NO_MEMORY
;
804 status
= kerberos_pac_logon_info(tmp_ctx
, *pac_blob
, NULL
, NULL
,
805 NULL
, NULL
, 0, &logon_info
);
807 status
= NT_STATUS_ACCESS_DENIED
;
809 if (!NT_STATUS_IS_OK(status
)) {
814 DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name
));
816 p
= strchr_m(princ_name
, '@');
818 DEBUG(3, ("[%s] Doesn't look like a valid principal\n",
820 return NT_STATUS_LOGON_FAILURE
;
823 user
= talloc_strndup(mem_ctx
, princ_name
, p
- princ_name
);
825 return NT_STATUS_NO_MEMORY
;
828 realm
= talloc_strdup(talloc_tos(), p
+ 1);
830 return NT_STATUS_NO_MEMORY
;
833 if (!strequal(realm
, lp_realm())) {
834 DEBUG(3, ("Ticket for foreign realm %s@%s\n", user
, realm
));
835 if (!lp_allow_trusted_domains()) {
836 return NT_STATUS_LOGON_FAILURE
;
840 if (logon_info
&& logon_info
->info3
.base
.logon_domain
.string
) {
841 domain
= talloc_strdup(mem_ctx
,
842 logon_info
->info3
.base
.logon_domain
.string
);
844 return NT_STATUS_NO_MEMORY
;
846 DEBUG(10, ("Domain is [%s] (using PAC)\n", domain
));
849 /* If we have winbind running, we can (and must) shorten the
850 username by using the short netbios name. Otherwise we will
851 have inconsistent user names. With Kerberos, we get the
852 fully qualified realm, with ntlmssp we get the short
853 name. And even w2k3 does use ntlmssp if you for example
854 connect to an ip address. */
857 struct wbcDomainInfo
*info
= NULL
;
859 DEBUG(10, ("Mapping [%s] to short name using winbindd\n",
862 wbc_status
= wbcDomainInfo(realm
, &info
);
864 if (WBC_ERROR_IS_OK(wbc_status
)) {
865 domain
= talloc_strdup(mem_ctx
,
869 DEBUG(3, ("Could not find short name: %s\n",
870 wbcErrorString(wbc_status
)));
871 domain
= talloc_strdup(mem_ctx
, realm
);
874 return NT_STATUS_NO_MEMORY
;
876 DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain
));
879 unixuser
= talloc_asprintf(tmp_ctx
, "%s%c%s", domain
, winbind_separator(), user
);
881 status
= NT_STATUS_NO_MEMORY
;
885 status
= ntlm_auth_generate_session_info(auth_ctx
, mem_ctx
, unixuser
, NULL
, session_info_flags
, session_info
);
888 TALLOC_FREE(tmp_ctx
);
895 * Return the challenge as determined by the authentication subsystem
896 * @return an 8 byte random challenge
899 static NTSTATUS
ntlm_auth_get_challenge(struct auth4_context
*auth_ctx
,
902 if (auth_ctx
->challenge
.data
.length
== 8) {
903 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
904 auth_ctx
->challenge
.set_by
));
905 memcpy(chal
, auth_ctx
->challenge
.data
.data
, 8);
909 if (!auth_ctx
->challenge
.set_by
) {
910 generate_random_buffer(chal
, 8);
912 auth_ctx
->challenge
.data
= data_blob_talloc(auth_ctx
, chal
, 8);
913 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.data
.data
);
914 auth_ctx
->challenge
.set_by
= "random";
917 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
918 auth_ctx
->challenge
.set_by
));
924 * NTLM2 authentication modifies the effective challenge,
925 * @param challenge The new challenge value
927 static NTSTATUS
ntlm_auth_set_challenge(struct auth4_context
*auth_ctx
, const uint8_t chal
[8], const char *set_by
)
929 auth_ctx
->challenge
.set_by
= talloc_strdup(auth_ctx
, set_by
);
930 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.set_by
);
932 auth_ctx
->challenge
.data
= data_blob_talloc(auth_ctx
, chal
, 8);
933 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.data
.data
);
939 * Check the password on an NTLMSSP login.
941 * Return the session keys used on the connection.
944 struct winbind_pw_check_state
{
945 uint8_t authoritative
;
947 DATA_BLOB nt_session_key
;
948 DATA_BLOB lm_session_key
;
951 static struct tevent_req
*winbind_pw_check_send(
953 struct tevent_context
*ev
,
954 struct auth4_context
*auth4_context
,
955 const struct auth_usersupplied_info
*user_info
)
957 struct tevent_req
*req
= NULL
;
958 struct winbind_pw_check_state
*state
= NULL
;
960 char *error_string
= NULL
;
962 uint8_t user_sess_key
[16];
963 char *unix_name
= NULL
;
965 req
= tevent_req_create(
966 mem_ctx
, &state
, struct winbind_pw_check_state
);
971 nt_status
= contact_winbind_auth_crap(
972 user_info
->client
.account_name
,
973 user_info
->client
.domain_name
,
974 user_info
->workstation_name
,
975 &auth4_context
->challenge
.data
,
976 &user_info
->password
.response
.lanman
,
977 &user_info
->password
.response
.nt
,
979 WBFLAG_PAM_USER_SESSION_KEY
|
980 WBFLAG_PAM_UNIX_NAME
,
982 lm_key
, user_sess_key
,
983 &state
->authoritative
,
987 if (tevent_req_nterror(req
, nt_status
)) {
988 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCESS_DENIED
)) {
989 DBG_ERR("Login for user [%s]\\[%s]@[%s] failed due "
991 user_info
->client
.domain_name
,
992 user_info
->client
.account_name
,
993 user_info
->workstation_name
,
996 "unknown error (NULL)");
998 DBG_NOTICE("Login for user [%s]\\[%s]@[%s] failed due "
1000 user_info
->client
.domain_name
,
1001 user_info
->client
.account_name
,
1002 user_info
->workstation_name
,
1005 "unknown error (NULL)");
1010 if (!all_zero(lm_key
, 8)) {
1011 state
->lm_session_key
= data_blob_talloc(state
, NULL
, 16);
1012 if (tevent_req_nomem(state
->lm_session_key
.data
, req
)) {
1015 memcpy(state
->lm_session_key
.data
, lm_key
, 8);
1016 memset(state
->lm_session_key
.data
+8, '\0', 8);
1018 if (!all_zero(user_sess_key
, 16)) {
1019 state
->nt_session_key
= data_blob_talloc(
1020 state
, user_sess_key
, 16);
1021 if (tevent_req_nomem(state
->nt_session_key
.data
, req
)) {
1025 state
->server_info
= talloc_strdup(state
, unix_name
);
1026 if (tevent_req_nomem(state
->server_info
, req
)) {
1029 tevent_req_done(req
);
1032 SAFE_FREE(error_string
);
1033 SAFE_FREE(unix_name
);
1034 return tevent_req_post(req
, ev
);
1037 static NTSTATUS
winbind_pw_check_recv(struct tevent_req
*req
,
1038 TALLOC_CTX
*mem_ctx
,
1039 uint8_t *pauthoritative
,
1040 void **server_returned_info
,
1041 DATA_BLOB
*nt_session_key
,
1042 DATA_BLOB
*lm_session_key
)
1044 struct winbind_pw_check_state
*state
= tevent_req_data(
1045 req
, struct winbind_pw_check_state
);
1048 if (pauthoritative
!= NULL
) {
1049 *pauthoritative
= state
->authoritative
;
1052 if (tevent_req_is_nterror(req
, &status
)) {
1056 if (server_returned_info
!= NULL
) {
1057 *server_returned_info
= talloc_move(
1058 mem_ctx
, &state
->server_info
);
1060 if (nt_session_key
!= NULL
) {
1061 *nt_session_key
= (DATA_BLOB
) {
1062 .data
= talloc_move(
1063 mem_ctx
, &state
->nt_session_key
.data
),
1064 .length
= state
->nt_session_key
.length
,
1067 if (lm_session_key
!= NULL
) {
1068 *lm_session_key
= (DATA_BLOB
) {
1069 .data
= talloc_move(
1070 mem_ctx
, &state
->lm_session_key
.data
),
1071 .length
= state
->lm_session_key
.length
,
1075 return NT_STATUS_OK
;
1078 struct local_pw_check_state
{
1079 uint8_t authoritative
;
1081 DATA_BLOB nt_session_key
;
1082 DATA_BLOB lm_session_key
;
1085 static struct tevent_req
*local_pw_check_send(
1086 TALLOC_CTX
*mem_ctx
,
1087 struct tevent_context
*ev
,
1088 struct auth4_context
*auth4_context
,
1089 const struct auth_usersupplied_info
*user_info
)
1091 struct tevent_req
*req
= NULL
;
1092 struct local_pw_check_state
*state
= NULL
;
1093 struct samr_Password lm_pw
, nt_pw
;
1096 req
= tevent_req_create(
1097 mem_ctx
, &state
, struct local_pw_check_state
);
1101 state
->authoritative
= 1;
1103 nt_lm_owf_gen (opt_password
, nt_pw
.hash
, lm_pw
.hash
);
1105 nt_status
= ntlm_password_check(
1110 &auth4_context
->challenge
.data
,
1111 &user_info
->password
.response
.lanman
,
1112 &user_info
->password
.response
.nt
,
1113 user_info
->client
.account_name
,
1114 user_info
->client
.account_name
,
1115 user_info
->client
.domain_name
,
1118 &state
->nt_session_key
,
1119 &state
->lm_session_key
);
1121 if (tevent_req_nterror(req
, nt_status
)) {
1122 DBG_NOTICE("Login for user [%s]\\[%s]@[%s] failed due to "
1124 user_info
->client
.domain_name
,
1125 user_info
->client
.account_name
,
1126 user_info
->workstation_name
,
1127 nt_errstr(nt_status
));
1128 return tevent_req_post(req
, ev
);
1131 state
->server_info
= talloc_asprintf(
1134 user_info
->client
.domain_name
,
1135 *lp_winbind_separator(),
1136 user_info
->client
.account_name
);
1137 if (tevent_req_nomem(state
->server_info
, req
)) {
1138 return tevent_req_post(req
, ev
);
1141 tevent_req_done(req
);
1142 return tevent_req_post(req
, ev
);
1145 static NTSTATUS
local_pw_check_recv(struct tevent_req
*req
,
1146 TALLOC_CTX
*mem_ctx
,
1147 uint8_t *pauthoritative
,
1148 void **server_returned_info
,
1149 DATA_BLOB
*nt_session_key
,
1150 DATA_BLOB
*lm_session_key
)
1152 struct local_pw_check_state
*state
= tevent_req_data(
1153 req
, struct local_pw_check_state
);
1156 if (pauthoritative
!= NULL
) {
1157 *pauthoritative
= state
->authoritative
;
1160 if (tevent_req_is_nterror(req
, &status
)) {
1164 if (server_returned_info
!= NULL
) {
1165 *server_returned_info
= talloc_move(
1166 mem_ctx
, &state
->server_info
);
1168 if (nt_session_key
!= NULL
) {
1169 *nt_session_key
= (DATA_BLOB
) {
1170 .data
= talloc_move(
1171 mem_ctx
, &state
->nt_session_key
.data
),
1172 .length
= state
->nt_session_key
.length
,
1175 if (lm_session_key
!= NULL
) {
1176 *lm_session_key
= (DATA_BLOB
) {
1177 .data
= talloc_move(
1178 mem_ctx
, &state
->lm_session_key
.data
),
1179 .length
= state
->lm_session_key
.length
,
1183 return NT_STATUS_OK
;
1186 static NTSTATUS
ntlm_auth_prepare_gensec_client(TALLOC_CTX
*mem_ctx
,
1187 struct loadparm_context
*lp_ctx
,
1188 struct gensec_security
**gensec_security_out
)
1190 struct gensec_security
*gensec_security
= NULL
;
1192 TALLOC_CTX
*tmp_ctx
;
1193 const struct gensec_security_ops
**backends
= NULL
;
1194 struct gensec_settings
*gensec_settings
= NULL
;
1197 tmp_ctx
= talloc_new(mem_ctx
);
1198 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx
);
1200 gensec_settings
= lpcfg_gensec_settings(tmp_ctx
, lp_ctx
);
1201 if (gensec_settings
== NULL
) {
1202 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1203 TALLOC_FREE(tmp_ctx
);
1204 return NT_STATUS_NO_MEMORY
;
1207 backends
= talloc_zero_array(gensec_settings
,
1208 const struct gensec_security_ops
*, 4);
1209 if (backends
== NULL
) {
1210 TALLOC_FREE(tmp_ctx
);
1211 return NT_STATUS_NO_MEMORY
;
1213 gensec_settings
->backends
= backends
;
1217 /* These need to be in priority order, krb5 before NTLMSSP */
1218 #if defined(HAVE_KRB5)
1219 backends
[idx
++] = &gensec_gse_krb5_security_ops
;
1222 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_NTLMSSP
);
1224 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_SPNEGO
);
1226 nt_status
= gensec_client_start(NULL
, &gensec_security
,
1228 if (!NT_STATUS_IS_OK(nt_status
)) {
1229 TALLOC_FREE(tmp_ctx
);
1233 talloc_unlink(tmp_ctx
, gensec_settings
);
1235 if (opt_target_service
!= NULL
) {
1236 nt_status
= gensec_set_target_service(gensec_security
,
1237 opt_target_service
);
1238 if (!NT_STATUS_IS_OK(nt_status
)) {
1239 TALLOC_FREE(tmp_ctx
);
1244 if (opt_target_hostname
!= NULL
) {
1245 nt_status
= gensec_set_target_hostname(gensec_security
,
1246 opt_target_hostname
);
1247 if (!NT_STATUS_IS_OK(nt_status
)) {
1248 TALLOC_FREE(tmp_ctx
);
1253 *gensec_security_out
= talloc_steal(mem_ctx
, gensec_security
);
1254 TALLOC_FREE(tmp_ctx
);
1255 return NT_STATUS_OK
;
1258 static struct auth4_context
*make_auth4_context_ntlm_auth(TALLOC_CTX
*mem_ctx
, bool local_pw
)
1260 struct auth4_context
*auth4_context
= talloc_zero(mem_ctx
, struct auth4_context
);
1261 if (auth4_context
== NULL
) {
1262 DEBUG(10, ("failed to allocate auth4_context failed\n"));
1265 auth4_context
->generate_session_info
= ntlm_auth_generate_session_info
;
1266 auth4_context
->generate_session_info_pac
= ntlm_auth_generate_session_info_pac
;
1267 auth4_context
->get_ntlm_challenge
= ntlm_auth_get_challenge
;
1268 auth4_context
->set_ntlm_challenge
= ntlm_auth_set_challenge
;
1270 auth4_context
->check_ntlm_password_send
= local_pw_check_send
;
1271 auth4_context
->check_ntlm_password_recv
= local_pw_check_recv
;
1273 auth4_context
->check_ntlm_password_send
=
1274 winbind_pw_check_send
;
1275 auth4_context
->check_ntlm_password_recv
=
1276 winbind_pw_check_recv
;
1278 auth4_context
->private_data
= NULL
;
1279 return auth4_context
;
1282 static NTSTATUS
ntlm_auth_prepare_gensec_server(TALLOC_CTX
*mem_ctx
,
1283 struct loadparm_context
*lp_ctx
,
1284 struct gensec_security
**gensec_security_out
)
1286 struct gensec_security
*gensec_security
;
1289 TALLOC_CTX
*tmp_ctx
;
1290 const struct gensec_security_ops
**backends
;
1291 struct gensec_settings
*gensec_settings
;
1293 struct cli_credentials
*server_credentials
;
1295 struct auth4_context
*auth4_context
;
1297 tmp_ctx
= talloc_new(mem_ctx
);
1298 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx
);
1300 auth4_context
= make_auth4_context_ntlm_auth(tmp_ctx
, opt_password
);
1301 if (auth4_context
== NULL
) {
1302 TALLOC_FREE(tmp_ctx
);
1303 return NT_STATUS_NO_MEMORY
;
1306 gensec_settings
= lpcfg_gensec_settings(tmp_ctx
, lp_ctx
);
1307 if (lp_ctx
== NULL
) {
1308 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1309 TALLOC_FREE(tmp_ctx
);
1310 return NT_STATUS_NO_MEMORY
;
1314 * This should be a 'netbios domain -> DNS domain'
1315 * mapping, and can currently validly return NULL on
1316 * poorly configured systems.
1318 * This is used for the NTLMSSP server
1322 gensec_settings
->server_netbios_name
= lp_netbios_name();
1323 gensec_settings
->server_netbios_domain
= lp_workgroup();
1325 gensec_settings
->server_netbios_name
= get_winbind_netbios_name();
1326 gensec_settings
->server_netbios_domain
= get_winbind_domain();
1329 gensec_settings
->server_dns_domain
= strlower_talloc(gensec_settings
,
1330 get_mydnsdomname(talloc_tos()));
1331 gensec_settings
->server_dns_name
= strlower_talloc(gensec_settings
,
1332 get_mydnsfullname());
1334 backends
= talloc_zero_array(gensec_settings
,
1335 const struct gensec_security_ops
*, 4);
1337 if (backends
== NULL
) {
1338 TALLOC_FREE(tmp_ctx
);
1339 return NT_STATUS_NO_MEMORY
;
1341 gensec_settings
->backends
= backends
;
1345 /* These need to be in priority order, krb5 before NTLMSSP */
1346 #if defined(HAVE_KRB5)
1347 backends
[idx
++] = &gensec_gse_krb5_security_ops
;
1350 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_NTLMSSP
);
1352 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_SPNEGO
);
1355 * This is anonymous for now, because we just use it
1356 * to set the kerberos state at the moment
1358 server_credentials
= cli_credentials_init_anon(tmp_ctx
);
1359 if (!server_credentials
) {
1360 DBG_ERR("Failed to init server credentials\n");
1361 return NT_STATUS_NO_MEMORY
;
1364 cli_credentials_set_conf(server_credentials
, lp_ctx
);
1366 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC
|| lp_security() == SEC_ADS
|| USE_KERBEROS_KEYTAB
) {
1367 cli_credentials_set_kerberos_state(server_credentials
, CRED_AUTO_USE_KERBEROS
);
1369 cli_credentials_set_kerberos_state(server_credentials
, CRED_DONT_USE_KERBEROS
);
1372 nt_status
= gensec_server_start(tmp_ctx
, gensec_settings
,
1373 auth4_context
, &gensec_security
);
1375 if (!NT_STATUS_IS_OK(nt_status
)) {
1376 TALLOC_FREE(tmp_ctx
);
1380 gensec_set_credentials(gensec_security
, server_credentials
);
1383 * TODO: Allow the caller to pass their own description here
1384 * via a command-line option
1386 nt_status
= gensec_set_target_service_description(gensec_security
,
1388 if (!NT_STATUS_IS_OK(nt_status
)) {
1389 TALLOC_FREE(tmp_ctx
);
1393 talloc_unlink(tmp_ctx
, lp_ctx
);
1394 talloc_unlink(tmp_ctx
, server_credentials
);
1395 talloc_unlink(tmp_ctx
, gensec_settings
);
1396 talloc_unlink(tmp_ctx
, auth4_context
);
1398 *gensec_security_out
= talloc_steal(mem_ctx
, gensec_security
);
1399 TALLOC_FREE(tmp_ctx
);
1400 return NT_STATUS_OK
;
1403 static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode
,
1404 struct loadparm_context
*lp_ctx
,
1405 struct ntlm_auth_state
*state
,
1406 char *buf
, int length
, void **private2
)
1408 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1412 static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode
,
1413 struct loadparm_context
*lp_ctx
,
1414 struct ntlm_auth_state
*state
,
1415 char *buf
, int length
, void **private2
)
1420 pass
=(char *)memchr(buf
,' ',length
);
1422 DEBUG(2, ("Password not found. Denying access\n"));
1429 if (state
->helper_mode
== SQUID_2_5_BASIC
) {
1430 char *end
= rfc1738_unescape(user
);
1431 if (end
== NULL
|| (end
- user
) != strlen(user
)) {
1432 DEBUG(2, ("Badly rfc1738 encoded username: %s; "
1433 "denying access\n", user
));
1437 end
= rfc1738_unescape(pass
);
1438 if (end
== NULL
|| (end
- pass
) != strlen(pass
)) {
1439 DEBUG(2, ("Badly encoded password for %s; "
1440 "denying access\n", user
));
1446 if (check_plaintext_auth(user
, pass
, False
)) {
1453 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode
,
1454 struct loadparm_context
*lp_ctx
,
1455 char *buf
, int length
, void **private1
)
1458 DATA_BLOB out
= data_blob(NULL
, 0);
1459 char *out_base64
= NULL
;
1460 const char *reply_arg
= NULL
;
1461 struct gensec_ntlm_state
{
1462 struct gensec_security
*gensec_state
;
1463 const char *set_password
;
1465 struct gensec_ntlm_state
*state
;
1469 const char *reply_code
;
1470 struct cli_credentials
*creds
;
1472 static char *want_feature_list
= NULL
;
1473 static DATA_BLOB session_key
;
1475 TALLOC_CTX
*mem_ctx
;
1477 mem_ctx
= talloc_named(NULL
, 0, "manage_gensec_request internal mem_ctx");
1478 if (mem_ctx
== NULL
) {
1479 printf("BH No Memory\n");
1484 state
= talloc_get_type(*private1
, struct gensec_ntlm_state
);
1485 if (state
== NULL
) {
1486 DBG_WARNING("*private1 is of type %s\n",
1487 talloc_get_name(*private1
));
1488 printf("BH *private1 is of type %s\n",
1489 talloc_get_name(*private1
));
1493 state
= talloc_zero(NULL
, struct gensec_ntlm_state
);
1495 printf("BH No Memory\n");
1500 state
->set_password
= opt_password
;
1504 if (strlen(buf
) < 2) {
1505 DEBUG(1, ("query [%s] invalid", buf
));
1506 printf("BH Query invalid\n");
1507 talloc_free(mem_ctx
);
1511 if (strlen(buf
) > 3) {
1512 if(strncmp(buf
, "SF ", 3) == 0) {
1513 DEBUG(10, ("Setting flags to negotiate\n"));
1514 talloc_free(want_feature_list
);
1515 want_feature_list
= talloc_strndup(state
, buf
+3, strlen(buf
)-3);
1517 talloc_free(mem_ctx
);
1520 in
= base64_decode_data_blob_talloc(mem_ctx
, buf
+ 3);
1522 in
= data_blob(NULL
, 0);
1525 if (strncmp(buf
, "YR", 2) == 0) {
1526 if (state
->gensec_state
) {
1527 talloc_free(state
->gensec_state
);
1528 state
->gensec_state
= NULL
;
1530 } else if ( (strncmp(buf
, "OK", 2) == 0)) {
1531 /* Just return BH, like ntlm_auth from Samba 3 does. */
1532 printf("BH Command expected\n");
1533 talloc_free(mem_ctx
);
1535 } else if ( (strncmp(buf
, "TT ", 3) != 0) &&
1536 (strncmp(buf
, "KK ", 3) != 0) &&
1537 (strncmp(buf
, "AF ", 3) != 0) &&
1538 (strncmp(buf
, "NA ", 3) != 0) &&
1539 (strncmp(buf
, "UG", 2) != 0) &&
1540 (strncmp(buf
, "PW ", 3) != 0) &&
1541 (strncmp(buf
, "GK", 2) != 0) &&
1542 (strncmp(buf
, "GF", 2) != 0)) {
1543 DEBUG(1, ("SPNEGO request [%s] invalid prefix\n", buf
));
1544 printf("BH SPNEGO request invalid prefix\n");
1545 talloc_free(mem_ctx
);
1550 if (!(state
->gensec_state
)) {
1551 switch (stdio_helper_mode
) {
1552 case GSS_SPNEGO_CLIENT
:
1554 * cached credentials are only supported by
1555 * NTLMSSP_CLIENT_1 for now.
1557 use_cached_creds
= false;
1559 case NTLMSSP_CLIENT_1
:
1560 /* setup the client side */
1562 if (state
->set_password
!= NULL
) {
1563 use_cached_creds
= false;
1566 if (use_cached_creds
) {
1567 struct wbcCredentialCacheParams params
;
1568 struct wbcCredentialCacheInfo
*info
= NULL
;
1569 struct wbcAuthErrorInfo
*error
= NULL
;
1572 params
.account_name
= opt_username
;
1573 params
.domain_name
= opt_domain
;
1574 params
.level
= WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP
;
1575 params
.num_blobs
= 0;
1576 params
.blobs
= NULL
;
1578 wbc_status
= wbcCredentialCache(¶ms
, &info
,
1580 wbcFreeMemory(error
);
1581 if (!WBC_ERROR_IS_OK(wbc_status
)) {
1582 use_cached_creds
= false;
1584 wbcFreeMemory(info
);
1587 nt_status
= ntlm_auth_prepare_gensec_client(state
, lp_ctx
,
1588 &state
->gensec_state
);
1589 if (!NT_STATUS_IS_OK(nt_status
)) {
1590 printf("BH GENSEC mech failed to start: %s\n",
1591 nt_errstr(nt_status
));
1592 talloc_free(mem_ctx
);
1596 creds
= cli_credentials_init(state
->gensec_state
);
1597 cli_credentials_set_conf(creds
, lp_ctx
);
1599 cli_credentials_set_username(creds
, opt_username
, CRED_SPECIFIED
);
1602 cli_credentials_set_domain(creds
, opt_domain
, CRED_SPECIFIED
);
1604 if (use_cached_creds
) {
1605 gensec_want_feature(state
->gensec_state
,
1606 GENSEC_FEATURE_NTLM_CCACHE
);
1607 } else if (state
->set_password
) {
1608 cli_credentials_set_password(creds
, state
->set_password
, CRED_SPECIFIED
);
1610 cli_credentials_set_password_callback(creds
, get_password
);
1612 if (opt_workstation
) {
1613 cli_credentials_set_workstation(creds
, opt_workstation
, CRED_SPECIFIED
);
1616 gensec_set_credentials(state
->gensec_state
, creds
);
1619 case GSS_SPNEGO_SERVER
:
1620 case SQUID_2_5_NTLMSSP
:
1622 nt_status
= ntlm_auth_prepare_gensec_server(state
, lp_ctx
,
1623 &state
->gensec_state
);
1624 if (!NT_STATUS_IS_OK(nt_status
)) {
1625 printf("BH GENSEC mech failed to start: %s\n",
1626 nt_errstr(nt_status
));
1627 talloc_free(mem_ctx
);
1633 talloc_free(mem_ctx
);
1637 gensec_want_feature_list(state
->gensec_state
, want_feature_list
);
1639 /* Session info is not complete, do not pass to auth log */
1640 gensec_want_feature(state
->gensec_state
, GENSEC_FEATURE_NO_AUTHZ_LOG
);
1642 switch (stdio_helper_mode
) {
1643 case GSS_SPNEGO_CLIENT
:
1644 case GSS_SPNEGO_SERVER
:
1645 nt_status
= gensec_start_mech_by_oid(state
->gensec_state
, GENSEC_OID_SPNEGO
);
1650 case NTLMSSP_CLIENT_1
:
1655 case SQUID_2_5_NTLMSSP
:
1656 nt_status
= gensec_start_mech_by_oid(state
->gensec_state
, GENSEC_OID_NTLMSSP
);
1659 talloc_free(mem_ctx
);
1663 if (!NT_STATUS_IS_OK(nt_status
)) {
1664 DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status
)));
1665 printf("BH GENSEC mech failed to start\n");
1666 talloc_free(mem_ctx
);
1674 if (strncmp(buf
, "PW ", 3) == 0) {
1675 state
->set_password
= talloc_strndup(state
,
1676 (const char *)in
.data
,
1679 cli_credentials_set_password(gensec_get_credentials(state
->gensec_state
),
1680 state
->set_password
,
1683 talloc_free(mem_ctx
);
1687 if (strncmp(buf
, "GK", 2) == 0) {
1689 DEBUG(10, ("Requested session key\n"));
1690 nt_status
= gensec_session_key(state
->gensec_state
, mem_ctx
, &session_key
);
1691 if(!NT_STATUS_IS_OK(nt_status
)) {
1692 DEBUG(1, ("gensec_session_key failed: %s\n", nt_errstr(nt_status
)));
1693 printf("BH No session key\n");
1694 talloc_free(mem_ctx
);
1697 base64_key
= base64_encode_data_blob(state
, session_key
);
1698 SMB_ASSERT(base64_key
!= NULL
);
1699 printf("GK %s\n", base64_key
);
1700 talloc_free(base64_key
);
1702 talloc_free(mem_ctx
);
1706 if (strncmp(buf
, "GF", 2) == 0) {
1709 DEBUG(10, ("Requested negotiated NTLMSSP feature flags\n"));
1711 neg_flags
= gensec_ntlmssp_neg_flags(state
->gensec_state
);
1712 if (neg_flags
== 0) {
1714 talloc_free(mem_ctx
);
1718 printf("GF 0x%08x\n", neg_flags
);
1719 talloc_free(mem_ctx
);
1723 nt_status
= gensec_update(state
->gensec_state
, mem_ctx
, in
, &out
);
1725 /* don't leak 'bad password'/'no such user' info to the network client */
1726 nt_status
= nt_status_squash(nt_status
);
1729 out_base64
= base64_encode_data_blob(mem_ctx
, out
);
1730 SMB_ASSERT(out_base64
!= NULL
);
1735 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1737 if (first
&& state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1739 } else if (state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1741 } else if (state
->gensec_state
->gensec_role
== GENSEC_SERVER
) {
1748 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCESS_DENIED
)) {
1749 reply_code
= "BH NT_STATUS_ACCESS_DENIED";
1750 reply_arg
= nt_errstr(nt_status
);
1751 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1752 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_UNSUCCESSFUL
)) {
1753 reply_code
= "BH NT_STATUS_UNSUCCESSFUL";
1754 reply_arg
= nt_errstr(nt_status
);
1755 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1756 } else if (!NT_STATUS_IS_OK(nt_status
)) {
1758 reply_arg
= nt_errstr(nt_status
);
1759 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1760 } else if /* OK */ (state
->gensec_state
->gensec_role
== GENSEC_SERVER
) {
1761 struct auth_session_info
*session_info
;
1763 nt_status
= gensec_session_info(state
->gensec_state
, mem_ctx
, &session_info
);
1764 if (!NT_STATUS_IS_OK(nt_status
)) {
1765 reply_code
= "BH Failed to retrieve session info";
1766 reply_arg
= nt_errstr(nt_status
);
1767 DEBUG(1, ("GENSEC failed to retrieve the session info: %s\n", nt_errstr(nt_status
)));
1771 reply_arg
= talloc_strdup(state
->gensec_state
, session_info
->unix_info
->unix_name
);
1772 if (reply_arg
== NULL
) {
1773 reply_code
= "BH out of memory";
1774 reply_arg
= nt_errstr(NT_STATUS_NO_MEMORY
);
1776 talloc_free(session_info
);
1778 } else if (state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1780 reply_arg
= out_base64
;
1785 switch (stdio_helper_mode
) {
1786 case GSS_SPNEGO_SERVER
:
1787 printf("%s %s %s\n", reply_code
,
1788 out_base64
? out_base64
: "*",
1789 reply_arg
? reply_arg
: "*");
1793 printf("%s %s\n", reply_code
, out_base64
);
1794 } else if (reply_arg
) {
1795 printf("%s %s\n", reply_code
, reply_arg
);
1797 printf("%s\n", reply_code
);
1801 talloc_free(mem_ctx
);
1805 static void manage_gss_spnego_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_squid_ntlmssp_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 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1823 static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode
,
1824 struct loadparm_context
*lp_ctx
,
1825 struct ntlm_auth_state
*state
,
1826 char *buf
, int length
, void **private2
)
1828 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1832 static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode
,
1833 struct loadparm_context
*lp_ctx
,
1834 struct ntlm_auth_state
*state
,
1835 char *buf
, int length
, void **private2
)
1837 char *request
, *parameter
;
1838 static DATA_BLOB challenge
;
1839 static DATA_BLOB lm_response
;
1840 static DATA_BLOB nt_response
;
1841 static char *full_username
;
1842 static char *username
;
1843 static char *domain
;
1844 static char *plaintext_password
;
1845 static bool ntlm_server_1_user_session_key
;
1846 static bool ntlm_server_1_lm_session_key
;
1848 if (strequal(buf
, ".")) {
1849 if (!full_username
&& !username
) {
1850 printf("Error: No username supplied!\n");
1851 } else if (plaintext_password
) {
1852 /* handle this request as plaintext */
1853 if (!full_username
) {
1854 if (asprintf(&full_username
, "%s%c%s", domain
, winbind_separator(), username
) == -1) {
1855 printf("Error: Out of memory in "
1860 if (check_plaintext_auth(full_username
, plaintext_password
, False
)) {
1861 printf("Authenticated: Yes\n");
1863 printf("Authenticated: No\n");
1865 } else if (!lm_response
.data
&& !nt_response
.data
) {
1866 printf("Error: No password supplied!\n");
1867 } else if (!challenge
.data
) {
1868 printf("Error: No lanman-challenge supplied!\n");
1870 char *error_string
= NULL
;
1872 uchar user_session_key
[16];
1875 if (full_username
&& !username
) {
1877 fstring fstr_domain
;
1879 if (!parse_ntlm_auth_domain_user(full_username
, fstr_user
, fstr_domain
)) {
1880 /* username might be 'tainted', don't print into our new-line deleimianted stream */
1881 printf("Error: Could not parse into "
1882 "domain and username\n");
1884 SAFE_FREE(username
);
1886 username
= smb_xstrdup(fstr_user
);
1887 domain
= smb_xstrdup(fstr_domain
);
1891 DATA_BLOB nt_session_key
, lm_session_key
;
1892 struct samr_Password lm_pw
, nt_pw
;
1893 TALLOC_CTX
*mem_ctx
= talloc_new(NULL
);
1894 ZERO_STRUCT(user_session_key
);
1895 ZERO_STRUCT(lm_key
);
1897 nt_lm_owf_gen (opt_password
, nt_pw
.hash
, lm_pw
.hash
);
1898 nt_status
= ntlm_password_check(mem_ctx
,
1911 error_string
= smb_xstrdup(get_friendly_nt_error_msg(nt_status
));
1912 if (ntlm_server_1_user_session_key
) {
1913 if (nt_session_key
.length
== sizeof(user_session_key
)) {
1914 memcpy(user_session_key
,
1915 nt_session_key
.data
,
1916 sizeof(user_session_key
));
1919 if (ntlm_server_1_lm_session_key
) {
1920 if (lm_session_key
.length
== sizeof(lm_key
)) {
1922 lm_session_key
.data
,
1926 TALLOC_FREE(mem_ctx
);
1929 uint8_t authoritative
= 0;
1932 domain
= smb_xstrdup(get_winbind_domain());
1935 if (ntlm_server_1_lm_session_key
)
1936 flags
|= WBFLAG_PAM_LMKEY
;
1938 if (ntlm_server_1_user_session_key
)
1939 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
1941 nt_status
= contact_winbind_auth_crap(username
,
1955 if (!NT_STATUS_IS_OK(nt_status
)) {
1956 printf("Authenticated: No\n");
1957 printf("Authentication-Error: %s\n.\n",
1961 char *hex_user_session_key
;
1963 printf("Authenticated: Yes\n");
1965 if (ntlm_server_1_lm_session_key
1966 && (!all_zero(lm_key
,
1968 hex_lm_key
= hex_encode_talloc(NULL
,
1969 (const unsigned char *)lm_key
,
1971 printf("LANMAN-Session-Key: %s\n",
1973 TALLOC_FREE(hex_lm_key
);
1976 if (ntlm_server_1_user_session_key
1977 && (!all_zero(user_session_key
,
1978 sizeof(user_session_key
)))) {
1979 hex_user_session_key
= hex_encode_talloc(NULL
,
1980 (const unsigned char *)user_session_key
,
1981 sizeof(user_session_key
));
1982 printf("User-Session-Key: %s\n",
1983 hex_user_session_key
);
1984 TALLOC_FREE(hex_user_session_key
);
1987 SAFE_FREE(error_string
);
1989 /* clear out the state */
1990 challenge
= data_blob_null
;
1991 nt_response
= data_blob_null
;
1992 lm_response
= data_blob_null
;
1993 SAFE_FREE(full_username
);
1994 SAFE_FREE(username
);
1996 SAFE_FREE(plaintext_password
);
1997 ntlm_server_1_user_session_key
= False
;
1998 ntlm_server_1_lm_session_key
= False
;
2006 /* Indicates a base64 encoded structure */
2007 parameter
= strstr_m(request
, ":: ");
2009 parameter
= strstr_m(request
, ": ");
2012 DEBUG(0, ("Parameter not found!\n"));
2013 printf("Error: Parameter not found!\n.\n");
2030 base64_decode_inplace(parameter
);
2033 if (strequal(request
, "LANMAN-Challenge")) {
2034 challenge
= strhex_to_data_blob(NULL
, parameter
);
2035 if (challenge
.length
!= 8) {
2036 printf("Error: hex decode of %s failed! "
2037 "(got %d bytes, expected 8)\n.\n",
2039 (int)challenge
.length
);
2040 challenge
= data_blob_null
;
2042 } else if (strequal(request
, "NT-Response")) {
2043 nt_response
= strhex_to_data_blob(NULL
, parameter
);
2044 if (nt_response
.length
< 24) {
2045 printf("Error: hex decode of %s failed! "
2046 "(only got %d bytes, needed at least 24)\n.\n",
2048 (int)nt_response
.length
);
2049 nt_response
= data_blob_null
;
2051 } else if (strequal(request
, "LANMAN-Response")) {
2052 lm_response
= strhex_to_data_blob(NULL
, parameter
);
2053 if (lm_response
.length
!= 24) {
2054 printf("Error: hex decode of %s failed! "
2055 "(got %d bytes, expected 24)\n.\n",
2057 (int)lm_response
.length
);
2058 lm_response
= data_blob_null
;
2060 } else if (strequal(request
, "Password")) {
2061 plaintext_password
= smb_xstrdup(parameter
);
2062 } else if (strequal(request
, "NT-Domain")) {
2063 domain
= smb_xstrdup(parameter
);
2064 } else if (strequal(request
, "Username")) {
2065 username
= smb_xstrdup(parameter
);
2066 } else if (strequal(request
, "Full-Username")) {
2067 full_username
= smb_xstrdup(parameter
);
2068 } else if (strequal(request
, "Request-User-Session-Key")) {
2069 ntlm_server_1_user_session_key
= strequal(parameter
, "Yes");
2070 } else if (strequal(request
, "Request-LanMan-Session-Key")) {
2071 ntlm_server_1_lm_session_key
= strequal(parameter
, "Yes");
2073 printf("Error: Unknown request %s\n.\n", request
);
2077 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode
,
2078 struct loadparm_context
*lp_ctx
,
2079 struct ntlm_auth_state
*state
,
2080 char *buf
, int length
, void **private2
)
2082 char *request
, *parameter
;
2083 static DATA_BLOB new_nt_pswd
;
2084 static DATA_BLOB old_nt_hash_enc
;
2085 static DATA_BLOB new_lm_pswd
;
2086 static DATA_BLOB old_lm_hash_enc
;
2087 static char *full_username
= NULL
;
2088 static char *username
= NULL
;
2089 static char *domain
= NULL
;
2090 static char *newpswd
= NULL
;
2091 static char *oldpswd
= NULL
;
2093 if (strequal(buf
, ".")) {
2094 if(newpswd
&& oldpswd
) {
2095 uchar old_nt_hash
[16];
2096 uchar old_lm_hash
[16];
2097 uchar new_nt_hash
[16];
2098 uchar new_lm_hash
[16];
2100 gnutls_cipher_hd_t cipher_hnd
= NULL
;
2101 gnutls_datum_t old_nt_key
= {
2102 .data
= old_nt_hash
,
2103 .size
= sizeof(old_nt_hash
),
2107 new_nt_pswd
= data_blob(NULL
, 516);
2108 old_nt_hash_enc
= data_blob(NULL
, 16);
2110 /* Calculate the MD4 hash (NT compatible) of the
2112 E_md4hash(oldpswd
, old_nt_hash
);
2113 E_md4hash(newpswd
, new_nt_hash
);
2115 /* E_deshash returns false for 'long'
2116 passwords (> 14 DOS chars).
2118 Therefore, don't send a buffer
2119 encrypted with the truncated hash
2120 (it could allow an even easier
2121 attack on the password)
2123 Likewise, obey the admin's restriction
2126 rc
= gnutls_cipher_init(&cipher_hnd
,
2127 GNUTLS_CIPHER_ARCFOUR_128
,
2131 DBG_ERR("gnutls_cipher_init failed: %s\n",
2132 gnutls_strerror(rc
));
2133 if (rc
== GNUTLS_E_UNWANTED_ALGORITHM
) {
2134 DBG_ERR("Running in FIPS mode, NTLM blocked\n");
2139 if (lp_client_lanman_auth() &&
2140 E_deshash(newpswd
, new_lm_hash
) &&
2141 E_deshash(oldpswd
, old_lm_hash
)) {
2142 new_lm_pswd
= data_blob(NULL
, 516);
2143 old_lm_hash_enc
= data_blob(NULL
, 16);
2144 encode_pw_buffer(new_lm_pswd
.data
, newpswd
,
2147 rc
= gnutls_cipher_encrypt(cipher_hnd
,
2151 gnutls_cipher_deinit(cipher_hnd
);
2154 rc
= E_old_pw_hash(new_nt_hash
, old_lm_hash
,
2155 old_lm_hash_enc
.data
);
2157 DBG_ERR("E_old_pw_hash failed: %s\n",
2158 gnutls_strerror(rc
));
2162 new_lm_pswd
.data
= NULL
;
2163 new_lm_pswd
.length
= 0;
2164 old_lm_hash_enc
.data
= NULL
;
2165 old_lm_hash_enc
.length
= 0;
2168 encode_pw_buffer(new_nt_pswd
.data
, newpswd
,
2171 rc
= gnutls_cipher_encrypt(cipher_hnd
,
2174 gnutls_cipher_deinit(cipher_hnd
);
2178 rc
= E_old_pw_hash(new_nt_hash
, old_nt_hash
,
2179 old_nt_hash_enc
.data
);
2181 DBG_ERR("E_old_pw_hash failed: %s\n",
2182 gnutls_strerror(rc
));
2186 ZERO_ARRAY(old_nt_hash
);
2187 ZERO_ARRAY(old_lm_hash
);
2188 ZERO_ARRAY(new_nt_hash
);
2189 ZERO_ARRAY(new_lm_hash
);
2192 if (!full_username
&& !username
) {
2193 printf("Error: No username supplied!\n");
2194 } else if ((!new_nt_pswd
.data
|| !old_nt_hash_enc
.data
) &&
2195 (!new_lm_pswd
.data
|| old_lm_hash_enc
.data
) ) {
2196 printf("Error: No NT or LM password "
2197 "blobs supplied!\n");
2199 char *error_string
= NULL
;
2201 if (full_username
&& !username
) {
2203 fstring fstr_domain
;
2205 if (!parse_ntlm_auth_domain_user(full_username
,
2208 /* username might be 'tainted', don't
2209 * print into our new-line
2210 * deleimianted stream */
2211 printf("Error: Could not "
2212 "parse into domain and "
2214 SAFE_FREE(username
);
2215 username
= smb_xstrdup(full_username
);
2217 SAFE_FREE(username
);
2219 username
= smb_xstrdup(fstr_user
);
2220 domain
= smb_xstrdup(fstr_domain
);
2225 if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
2232 printf("Password-Change: No\n");
2233 printf("Password-Change-Error: %s\n.\n",
2236 printf("Password-Change: Yes\n");
2239 SAFE_FREE(error_string
);
2241 /* clear out the state */
2242 new_nt_pswd
= data_blob_null
;
2243 old_nt_hash_enc
= data_blob_null
;
2244 new_lm_pswd
= data_blob_null
;
2245 old_nt_hash_enc
= data_blob_null
;
2246 SAFE_FREE(full_username
);
2247 SAFE_FREE(username
);
2258 /* Indicates a base64 encoded structure */
2259 parameter
= strstr_m(request
, ":: ");
2261 parameter
= strstr_m(request
, ": ");
2264 DEBUG(0, ("Parameter not found!\n"));
2265 printf("Error: Parameter not found!\n.\n");
2281 base64_decode_inplace(parameter
);
2284 if (strequal(request
, "new-nt-password-blob")) {
2285 new_nt_pswd
= strhex_to_data_blob(NULL
, parameter
);
2286 if (new_nt_pswd
.length
!= 516) {
2287 printf("Error: hex decode of %s failed! "
2288 "(got %d bytes, expected 516)\n.\n",
2290 (int)new_nt_pswd
.length
);
2291 new_nt_pswd
= data_blob_null
;
2293 } else if (strequal(request
, "old-nt-hash-blob")) {
2294 old_nt_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2295 if (old_nt_hash_enc
.length
!= 16) {
2296 printf("Error: hex decode of %s failed! "
2297 "(got %d bytes, expected 16)\n.\n",
2299 (int)old_nt_hash_enc
.length
);
2300 old_nt_hash_enc
= data_blob_null
;
2302 } else if (strequal(request
, "new-lm-password-blob")) {
2303 new_lm_pswd
= strhex_to_data_blob(NULL
, parameter
);
2304 if (new_lm_pswd
.length
!= 516) {
2305 printf("Error: hex decode of %s failed! "
2306 "(got %d bytes, expected 516)\n.\n",
2308 (int)new_lm_pswd
.length
);
2309 new_lm_pswd
= data_blob_null
;
2312 else if (strequal(request
, "old-lm-hash-blob")) {
2313 old_lm_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2314 if (old_lm_hash_enc
.length
!= 16)
2316 printf("Error: hex decode of %s failed! "
2317 "(got %d bytes, expected 16)\n.\n",
2319 (int)old_lm_hash_enc
.length
);
2320 old_lm_hash_enc
= data_blob_null
;
2322 } else if (strequal(request
, "nt-domain")) {
2323 domain
= smb_xstrdup(parameter
);
2324 } else if(strequal(request
, "username")) {
2325 username
= smb_xstrdup(parameter
);
2326 } else if(strequal(request
, "full-username")) {
2327 username
= smb_xstrdup(parameter
);
2328 } else if(strequal(request
, "new-password")) {
2329 newpswd
= smb_xstrdup(parameter
);
2330 } else if (strequal(request
, "old-password")) {
2331 oldpswd
= smb_xstrdup(parameter
);
2333 printf("Error: Unknown request %s\n.\n", request
);
2337 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode
,
2338 struct loadparm_context
*lp_ctx
,
2339 struct ntlm_auth_state
*state
,
2340 stdio_helper_function fn
, void **private2
)
2343 char tmp
[INITIAL_BUFFER_SIZE
+1];
2344 int length
, buf_size
= 0;
2347 buf
= talloc_strdup(state
->mem_ctx
, "");
2349 DEBUG(0, ("Failed to allocate input buffer.\n"));
2350 fprintf(stderr
, "ERR\n");
2356 /* this is not a typo - x_fgets doesn't work too well under
2358 if (fgets(tmp
, sizeof(tmp
)-1, stdin
) == NULL
) {
2359 if (ferror(stdin
)) {
2360 DEBUG(1, ("fgets() failed! dying..... errno=%d "
2361 "(%s)\n", ferror(stdin
),
2362 strerror(ferror(stdin
))));
2369 buf
= talloc_strdup_append_buffer(buf
, tmp
);
2370 buf_size
+= INITIAL_BUFFER_SIZE
;
2372 if (buf_size
> MAX_BUFFER_SIZE
) {
2373 DEBUG(2, ("Oversized message\n"));
2374 fprintf(stderr
, "ERR\n");
2379 c
= strchr(buf
, '\n');
2380 } while (c
== NULL
);
2385 DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf
,length
));
2387 if (buf
[0] == '\0') {
2388 DEBUG(2, ("Invalid Request\n"));
2389 fprintf(stderr
, "ERR\n");
2394 fn(stdio_helper_mode
, lp_ctx
, state
, buf
, length
, private2
);
2399 static void squid_stream(enum stdio_helper_mode stdio_mode
,
2400 struct loadparm_context
*lp_ctx
,
2401 stdio_helper_function fn
) {
2402 TALLOC_CTX
*mem_ctx
;
2403 struct ntlm_auth_state
*state
;
2405 /* initialize FDescs */
2406 setbuf(stdout
, NULL
);
2407 setbuf(stderr
, NULL
);
2409 mem_ctx
= talloc_init("ntlm_auth");
2411 DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
2412 fprintf(stderr
, "ERR\n");
2416 state
= talloc_zero(mem_ctx
, struct ntlm_auth_state
);
2418 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
2419 fprintf(stderr
, "ERR\n");
2423 state
->mem_ctx
= mem_ctx
;
2424 state
->helper_mode
= stdio_mode
;
2427 TALLOC_CTX
*frame
= talloc_stackframe();
2428 manage_squid_request(stdio_mode
, lp_ctx
, state
, fn
, NULL
);
2434 /* Authenticate a user with a challenge/response */
2436 static bool check_auth_crap(void)
2441 char user_session_key
[16];
2443 char *hex_user_session_key
;
2445 uint8_t authoritative
= 0;
2447 setbuf(stdout
, NULL
);
2450 flags
|= WBFLAG_PAM_LMKEY
;
2452 if (request_user_session_key
)
2453 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
2455 flags
|= WBFLAG_PAM_NT_STATUS_SQUASH
;
2457 nt_status
= contact_winbind_auth_crap(opt_username
, opt_domain
,
2463 (unsigned char *)lm_key
,
2464 (unsigned char *)user_session_key
,
2466 &error_string
, NULL
);
2468 if (!NT_STATUS_IS_OK(nt_status
)) {
2469 printf("%s (0x%x)\n", error_string
,
2470 NT_STATUS_V(nt_status
));
2471 SAFE_FREE(error_string
);
2476 && (!all_zero((uint8_t *)lm_key
, sizeof(lm_key
)))) {
2477 hex_lm_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)lm_key
,
2479 printf("LM_KEY: %s\n", hex_lm_key
);
2480 TALLOC_FREE(hex_lm_key
);
2482 if (request_user_session_key
2483 && (!all_zero((uint8_t *)user_session_key
,
2484 sizeof(user_session_key
)))) {
2485 hex_user_session_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)user_session_key
,
2486 sizeof(user_session_key
));
2487 printf("NT_KEY: %s\n", hex_user_session_key
);
2488 TALLOC_FREE(hex_user_session_key
);
2497 OPT_USERNAME
= 1000,
2506 OPT_USER_SESSION_KEY
,
2508 OPT_REQUIRE_MEMBERSHIP
,
2509 OPT_USE_CACHED_CREDS
,
2511 OPT_PAM_WINBIND_CONF
,
2513 OPT_TARGET_HOSTNAME
,
2517 int main(int argc
, const char **argv
)
2519 TALLOC_CTX
*frame
= talloc_stackframe();
2521 const char *helper_protocol
= NULL
;
2522 int diagnostics
= 0;
2524 const char *hex_challenge
= NULL
;
2525 const char *hex_lm_response
= NULL
;
2526 const char *hex_nt_response
= NULL
;
2527 struct loadparm_context
*lp_ctx
;
2530 /* NOTE: DO NOT change this interface without considering the implications!
2531 This is an external interface, which other programs will use to interact
2535 /* We do not use single-letter command abbreviations, because they harm future
2536 interface stability. */
2538 struct poptOption long_options
[] = {
2541 .longName
= "helper-protocol",
2543 .argInfo
= POPT_ARG_STRING
,
2544 .arg
= &helper_protocol
,
2546 .descrip
= "operate as a stdio-based helper",
2547 .argDescrip
= "helper protocol to use"
2550 .longName
= "username",
2552 .argInfo
= POPT_ARG_STRING
,
2553 .arg
= &opt_username
,
2554 .val
= OPT_USERNAME
,
2555 .descrip
= "username"
2558 .longName
= "domain",
2560 .argInfo
= POPT_ARG_STRING
,
2563 .descrip
= "domain name"
2566 .longName
= "workstation",
2568 .argInfo
= POPT_ARG_STRING
,
2569 .arg
= &opt_workstation
,
2570 .val
= OPT_WORKSTATION
,
2571 .descrip
= "workstation"
2574 .longName
= "challenge",
2576 .argInfo
= POPT_ARG_STRING
,
2577 .arg
= &hex_challenge
,
2578 .val
= OPT_CHALLENGE
,
2579 .descrip
= "challenge (HEX encoded)"
2582 .longName
= "lm-response",
2584 .argInfo
= POPT_ARG_STRING
,
2585 .arg
= &hex_lm_response
,
2587 .descrip
= "LM Response to the challenge (HEX encoded)"
2590 .longName
= "nt-response",
2592 .argInfo
= POPT_ARG_STRING
,
2593 .arg
= &hex_nt_response
,
2595 .descrip
= "NT or NTLMv2 Response to the challenge (HEX encoded)"
2598 .longName
= "password",
2600 .argInfo
= POPT_ARG_STRING
,
2601 .arg
= &opt_password
,
2602 .val
= OPT_PASSWORD
,
2603 .descrip
= "User's plaintext password"
2606 .longName
= "request-lm-key",
2608 .argInfo
= POPT_ARG_NONE
,
2609 .arg
= &request_lm_key
,
2611 .descrip
= "Retrieve LM session key"
2614 .longName
= "request-nt-key",
2616 .argInfo
= POPT_ARG_NONE
,
2617 .arg
= &request_user_session_key
,
2618 .val
= OPT_USER_SESSION_KEY
,
2619 .descrip
= "Retrieve User (NT) session key"
2622 .longName
= "use-cached-creds",
2624 .argInfo
= POPT_ARG_NONE
,
2625 .arg
= &use_cached_creds
,
2626 .val
= OPT_USE_CACHED_CREDS
,
2627 .descrip
= "Use cached credentials if no password is given"
2630 .longName
= "allow-mschapv2",
2632 .argInfo
= POPT_ARG_NONE
,
2633 .arg
= &opt_allow_mschapv2
,
2634 .val
= OPT_ALLOW_MSCHAPV2
,
2635 .descrip
= "Explicitly allow MSCHAPv2",
2638 .longName
= "offline-logon",
2640 .argInfo
= POPT_ARG_NONE
,
2641 .arg
= &offline_logon
,
2642 .val
= OPT_OFFLINE_LOGON
,
2643 .descrip
= "Use cached passwords when DC is offline"
2646 .longName
= "diagnostics",
2648 .argInfo
= POPT_ARG_NONE
,
2649 .arg
= &diagnostics
,
2650 .val
= OPT_DIAGNOSTICS
,
2651 .descrip
= "Perform diagnostics on the authentication chain"
2654 .longName
= "require-membership-of",
2656 .argInfo
= POPT_ARG_STRING
,
2657 .arg
= &require_membership_of
,
2658 .val
= OPT_REQUIRE_MEMBERSHIP
,
2659 .descrip
= "Require that a user be a member of this group (either name or SID) for authentication to succeed",
2662 .longName
= "pam-winbind-conf",
2664 .argInfo
= POPT_ARG_STRING
,
2665 .arg
= &opt_pam_winbind_conf
,
2666 .val
= OPT_PAM_WINBIND_CONF
,
2667 .descrip
= "Require that request must set WBFLAG_PAM_CONTACT_TRUSTDOM when krb5 auth is required",
2670 .longName
= "target-service",
2672 .argInfo
= POPT_ARG_STRING
,
2673 .arg
= &opt_target_service
,
2674 .val
= OPT_TARGET_SERVICE
,
2675 .descrip
= "Target service (eg http)",
2678 .longName
= "target-hostname",
2680 .argInfo
= POPT_ARG_STRING
,
2681 .arg
= &opt_target_hostname
,
2682 .val
= OPT_TARGET_HOSTNAME
,
2683 .descrip
= "Target hostname",
2685 POPT_COMMON_CONFIGFILE
2691 /* Samba client initialisation */
2694 setup_logging("ntlm_auth", DEBUG_STDERR
);
2699 pc
= poptGetContext("ntlm_auth", argc
, argv
, long_options
, 0);
2701 /* Parse command line options */
2704 poptPrintHelp(pc
, stderr
, 0);
2705 poptFreeContext(pc
);
2709 while((opt
= poptGetNextOpt(pc
)) != -1) {
2710 /* Get generic config options like --configfile */
2713 poptFreeContext(pc
);
2715 if (!lp_load_global(get_dyn_CONFIGFILE())) {
2716 d_fprintf(stderr
, "ntlm_auth: error opening config file %s. Error was %s\n",
2717 get_dyn_CONFIGFILE(), strerror(errno
));
2721 pc
= poptGetContext(NULL
, argc
, (const char **)argv
, long_options
,
2722 POPT_CONTEXT_KEEP_FIRST
);
2724 while((opt
= poptGetNextOpt(pc
)) != -1) {
2727 opt_challenge
= strhex_to_data_blob(NULL
, hex_challenge
);
2728 if (opt_challenge
.length
!= 8) {
2729 fprintf(stderr
, "hex decode of %s failed! "
2730 "(only got %d bytes)\n",
2732 (int)opt_challenge
.length
);
2737 opt_lm_response
= strhex_to_data_blob(NULL
, hex_lm_response
);
2738 if (opt_lm_response
.length
!= 24) {
2739 fprintf(stderr
, "hex decode of %s failed! "
2740 "(only got %d bytes)\n",
2742 (int)opt_lm_response
.length
);
2748 opt_nt_response
= strhex_to_data_blob(NULL
, hex_nt_response
);
2749 if (opt_nt_response
.length
< 24) {
2750 fprintf(stderr
, "hex decode of %s failed! "
2751 "(only got %d bytes)\n",
2753 (int)opt_nt_response
.length
);
2758 case OPT_REQUIRE_MEMBERSHIP
:
2759 if (strncasecmp_m("S-", require_membership_of
, 2) == 0) {
2760 require_membership_of_sid
= require_membership_of
;
2767 char *domain
= SMB_STRDUP(opt_username
);
2768 char *p
= strchr_m(domain
, *lp_winbind_separator());
2772 if (opt_domain
&& !strequal(opt_domain
, domain
)) {
2773 fprintf(stderr
, "Domain specified in username (%s) "
2774 "doesn't match specified domain (%s)!\n\n",
2775 domain
, opt_domain
);
2776 poptPrintHelp(pc
, stderr
, 0);
2779 opt_domain
= domain
;
2785 /* Note: if opt_domain is "" then send no domain */
2786 if (opt_domain
== NULL
) {
2787 opt_domain
= get_winbind_domain();
2790 if (opt_workstation
== NULL
) {
2791 opt_workstation
= "";
2794 lp_ctx
= loadparm_init_s3(NULL
, loadparm_s3_helpers());
2795 if (lp_ctx
== NULL
) {
2796 fprintf(stderr
, "loadparm_init_s3() failed!\n");
2800 if (helper_protocol
) {
2802 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2803 if (strcmp(helper_protocol
, stdio_helper_protocols
[i
].name
) == 0) {
2804 squid_stream(stdio_helper_protocols
[i
].mode
, lp_ctx
, stdio_helper_protocols
[i
].fn
);
2808 fprintf(stderr
, "unknown helper protocol [%s]\n\n"
2809 "Valid helper protools:\n\n", helper_protocol
);
2811 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2812 fprintf(stderr
, "%s\n",
2813 stdio_helper_protocols
[i
].name
);
2819 if (!opt_username
|| !*opt_username
) {
2820 fprintf(stderr
, "username must be specified!\n\n");
2821 poptPrintHelp(pc
, stderr
, 0);
2825 if (opt_challenge
.length
) {
2826 if (!check_auth_crap()) {
2832 if (!opt_password
) {
2833 char pwd
[256] = {0};
2836 rc
= samba_getpass("Password: ", pwd
, sizeof(pwd
), false, false);
2838 opt_password
= SMB_STRDUP(pwd
);
2843 if (!diagnose_ntlm_auth()) {
2844 poptFreeContext(pc
);
2850 fstr_sprintf(user
, "%s%c%s", opt_domain
, winbind_separator(), opt_username
);
2851 if (!check_plaintext_auth(user
, opt_password
, True
)) {
2852 poptFreeContext(pc
);
2859 poptFreeContext(pc
);