2 Unix SMB/CIFS implementation.
4 Winbind status program.
6 Copyright (C) Tim Potter 2000-2003
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003-2004
8 Copyright (C) Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it> 2000
9 Copyright (C) Robert O'Callahan 2006 (added cached credential code).
10 Copyright (C) Kai Blin <kai@samba.org> 2008
11 Copyright (C) Simo Sorce 2010
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 3 of the License, or
16 (at your option) any later version.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 #include "lib/param/param.h"
29 #include "popt_common.h"
30 #include "libcli/security/security.h"
31 #include "utils/ntlm_auth.h"
32 #include "../libcli/auth/libcli_auth.h"
33 #include "auth/ntlmssp/ntlmssp.h"
34 #include "auth/gensec/gensec.h"
35 #include "auth/gensec/gensec_internal.h"
36 #include "auth/credentials/credentials.h"
37 #include "librpc/crypto/gse.h"
39 #include "lib/util/tiniparser.h"
40 #include "../lib/crypto/arcfour.h"
41 #include "nsswitch/winbind_client.h"
42 #include "librpc/gen_ndr/krb5pac.h"
43 #include "../lib/util/asn1.h"
44 #include "auth/common_auth.h"
45 #include "source3/include/auth.h"
46 #include "source3/auth/proto.h"
47 #include "nsswitch/libwbclient/wbclient.h"
48 #include "lib/param/loadparm.h"
49 #include "lib/util/base64.h"
52 #include "auth/kerberos/pac_utils.h"
55 #ifndef PAM_WINBIND_CONFIG_FILE
56 #define PAM_WINBIND_CONFIG_FILE "/etc/security/pam_winbind.conf"
59 #define WINBIND_KRB5_AUTH 0x00000080
62 #define DBGC_CLASS DBGC_WINBIND
64 #define INITIAL_BUFFER_SIZE 300
65 #define MAX_BUFFER_SIZE 630000
67 enum stdio_helper_mode
{
75 NTLM_CHANGE_PASSWORD_1
,
79 enum ntlm_auth_cli_state
{
86 struct ntlm_auth_state
{
88 enum stdio_helper_mode helper_mode
;
89 enum ntlm_auth_cli_state cli_state
;
90 struct ntlmssp_state
*ntlmssp_state
;
92 char *want_feature_list
;
93 bool have_session_key
;
94 DATA_BLOB session_key
;
95 DATA_BLOB initial_message
;
96 void *gensec_private_1
;
98 typedef void (*stdio_helper_function
)(enum stdio_helper_mode stdio_helper_mode
,
99 struct loadparm_context
*lp_ctx
,
100 struct ntlm_auth_state
*state
, char *buf
,
101 int length
, void **private2
);
103 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode
,
104 struct loadparm_context
*lp_ctx
,
105 char *buf
, int length
, void **private1
);
107 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode
,
108 struct loadparm_context
*lp_ctx
,
109 struct ntlm_auth_state
*state
,
110 stdio_helper_function fn
, void **private2
);
112 static void manage_squid_basic_request (enum stdio_helper_mode stdio_helper_mode
,
113 struct loadparm_context
*lp_ctx
,
114 struct ntlm_auth_state
*state
,
115 char *buf
, int length
, void **private2
);
117 static void manage_squid_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode
,
118 struct loadparm_context
*lp_ctx
,
119 struct ntlm_auth_state
*state
,
120 char *buf
, int length
, void **private2
);
122 static void manage_client_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode
,
123 struct loadparm_context
*lp_ctx
,
124 struct ntlm_auth_state
*state
,
125 char *buf
, int length
, void **private2
);
127 static void manage_gss_spnego_request (enum stdio_helper_mode stdio_helper_mode
,
128 struct loadparm_context
*lp_ctx
,
129 struct ntlm_auth_state
*state
,
130 char *buf
, int length
, void **private2
);
132 static void manage_gss_spnego_client_request (enum stdio_helper_mode stdio_helper_mode
,
133 struct loadparm_context
*lp_ctx
,
134 struct ntlm_auth_state
*state
,
135 char *buf
, int length
, void **private2
);
137 static void manage_ntlm_server_1_request (enum stdio_helper_mode stdio_helper_mode
,
138 struct loadparm_context
*lp_ctx
,
139 struct ntlm_auth_state
*state
,
140 char *buf
, int length
, void **private2
);
142 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode
,
143 struct loadparm_context
*lp_ctx
,
144 struct ntlm_auth_state
*state
,
145 char *buf
, int length
, void **private2
);
147 static const struct {
148 enum stdio_helper_mode mode
;
150 stdio_helper_function fn
;
151 } stdio_helper_protocols
[] = {
152 { SQUID_2_4_BASIC
, "squid-2.4-basic", manage_squid_basic_request
},
153 { SQUID_2_5_BASIC
, "squid-2.5-basic", manage_squid_basic_request
},
154 { SQUID_2_5_NTLMSSP
, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request
},
155 { NTLMSSP_CLIENT_1
, "ntlmssp-client-1", manage_client_ntlmssp_request
},
156 { GSS_SPNEGO_SERVER
, "gss-spnego", manage_gss_spnego_request
},
157 { GSS_SPNEGO_CLIENT
, "gss-spnego-client", manage_gss_spnego_client_request
},
158 { NTLM_SERVER_1
, "ntlm-server-1", manage_ntlm_server_1_request
},
159 { NTLM_CHANGE_PASSWORD_1
, "ntlm-change-password-1", manage_ntlm_change_password_1_request
},
160 { NUM_HELPER_MODES
, NULL
, NULL
}
163 const char *opt_username
;
164 const char *opt_domain
;
165 const char *opt_workstation
;
166 const char *opt_password
;
167 static DATA_BLOB opt_challenge
;
168 static DATA_BLOB opt_lm_response
;
169 static DATA_BLOB opt_nt_response
;
170 static int request_lm_key
;
171 static int request_user_session_key
;
172 static int use_cached_creds
;
173 static int offline_logon
;
174 static int opt_allow_mschapv2
;
176 static const char *require_membership_of
;
177 static const char *require_membership_of_sid
;
178 static const char *opt_pam_winbind_conf
;
180 const char *opt_target_service
;
181 const char *opt_target_hostname
;
184 /* This is a bit hairy, but the basic idea is to do a password callback
185 to the calling application. The callback comes from within gensec */
187 static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mode
,
188 struct loadparm_context
*lp_ctx
,
189 struct ntlm_auth_state
*state
, char *buf
, int length
,
193 if (strlen(buf
) < 2) {
194 DEBUG(1, ("query [%s] invalid", buf
));
195 x_fprintf(x_stdout
, "BH Query invalid\n");
199 if (strlen(buf
) > 3) {
200 in
= base64_decode_data_blob(buf
+ 3);
202 in
= data_blob(NULL
, 0);
205 if (strncmp(buf
, "PW ", 3) == 0) {
207 *password
= talloc_strndup(NULL
,
208 (const char *)in
.data
, in
.length
);
210 if (*password
== NULL
) {
211 DEBUG(1, ("Out of memory\n"));
212 x_fprintf(x_stdout
, "BH Out of memory\n");
217 x_fprintf(x_stdout
, "OK\n");
221 DEBUG(1, ("Asked for (and expected) a password\n"));
222 x_fprintf(x_stdout
, "BH Expected a password\n");
227 * Callback for password credentials. This is not async, and when
228 * GENSEC and the credentials code is made async, it will look rather
232 static const char *get_password(struct cli_credentials
*credentials
)
234 TALLOC_CTX
*frame
= talloc_stackframe();
235 char *password
= NULL
;
236 struct ntlm_auth_state
*state
;
238 state
= talloc_zero(frame
, struct ntlm_auth_state
);
240 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
241 x_fprintf(x_stderr
, "ERR\n");
245 state
->mem_ctx
= state
;
247 /* Ask for a password */
248 x_fprintf(x_stdout
, "PW\n");
250 manage_squid_request(NUM_HELPER_MODES
/* bogus */, NULL
, state
, manage_gensec_get_pw_request
, (void **)&password
);
251 talloc_steal(credentials
, password
);
257 * A limited set of features are defined with text strings as needed
261 static void gensec_want_feature_list(struct gensec_security
*state
, char* feature_list
)
263 if (in_list("NTLMSSP_FEATURE_SESSION_KEY", feature_list
, true)) {
264 DEBUG(10, ("want GENSEC_FEATURE_SESSION_KEY\n"));
265 gensec_want_feature(state
, GENSEC_FEATURE_SESSION_KEY
);
267 if (in_list("NTLMSSP_FEATURE_SIGN", feature_list
, true)) {
268 DEBUG(10, ("want GENSEC_FEATURE_SIGN\n"));
269 gensec_want_feature(state
, GENSEC_FEATURE_SIGN
);
271 if (in_list("NTLMSSP_FEATURE_SEAL", feature_list
, true)) {
272 DEBUG(10, ("want GENSEC_FEATURE_SEAL\n"));
273 gensec_want_feature(state
, GENSEC_FEATURE_SEAL
);
275 if (in_list("NTLMSSP_FEATURE_CCACHE", feature_list
, true)) {
276 DEBUG(10, ("want GENSEC_FEATURE_NTLM_CCACHE\n"));
277 gensec_want_feature(state
, GENSEC_FEATURE_NTLM_CCACHE
);
281 static char winbind_separator(void)
283 struct winbindd_response response
;
290 ZERO_STRUCT(response
);
292 /* Send off request */
294 if (winbindd_request_response(NULL
, WINBINDD_INFO
, NULL
, &response
) !=
295 NSS_STATUS_SUCCESS
) {
296 d_printf("could not obtain winbind separator!\n");
297 return *lp_winbind_separator();
300 sep
= response
.data
.info
.winbind_separator
;
304 d_printf("winbind separator was NULL!\n");
305 return *lp_winbind_separator();
311 const char *get_winbind_domain(void)
313 struct winbindd_response response
;
315 static fstring winbind_domain
;
316 if (*winbind_domain
) {
317 return winbind_domain
;
320 ZERO_STRUCT(response
);
322 /* Send off request */
324 if (winbindd_request_response(NULL
, WINBINDD_DOMAIN_NAME
, NULL
, &response
) !=
325 NSS_STATUS_SUCCESS
) {
326 DEBUG(1, ("could not obtain winbind domain name!\n"));
327 return lp_workgroup();
330 fstrcpy(winbind_domain
, response
.data
.domain_name
);
332 return winbind_domain
;
336 const char *get_winbind_netbios_name(void)
338 struct winbindd_response response
;
340 static fstring winbind_netbios_name
;
342 if (*winbind_netbios_name
) {
343 return winbind_netbios_name
;
346 ZERO_STRUCT(response
);
348 /* Send off request */
350 if (winbindd_request_response(NULL
, WINBINDD_NETBIOS_NAME
, NULL
, &response
) !=
351 NSS_STATUS_SUCCESS
) {
352 DEBUG(1, ("could not obtain winbind netbios name!\n"));
353 return lp_netbios_name();
356 fstrcpy(winbind_netbios_name
, response
.data
.netbios_name
);
358 return winbind_netbios_name
;
362 DATA_BLOB
get_challenge(void)
364 static DATA_BLOB chal
;
365 if (opt_challenge
.length
)
366 return opt_challenge
;
368 chal
= data_blob(NULL
, 8);
370 generate_random_buffer(chal
.data
, chal
.length
);
374 /* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
375 form DOMAIN/user into a domain and a user */
377 static bool parse_ntlm_auth_domain_user(const char *domuser
, fstring domain
,
381 char *p
= strchr(domuser
,winbind_separator());
388 fstrcpy(domain
, domuser
);
389 domain
[PTR_DIFF(p
, domuser
)] = 0;
390 return strupper_m(domain
);
393 static bool get_require_membership_sid(void) {
394 struct winbindd_request request
;
395 struct winbindd_response response
;
397 if (!require_membership_of
) {
401 if (require_membership_of_sid
) {
405 /* Otherwise, ask winbindd for the name->sid request */
407 ZERO_STRUCT(request
);
408 ZERO_STRUCT(response
);
410 if (!parse_ntlm_auth_domain_user(require_membership_of
,
411 request
.data
.name
.dom_name
,
412 request
.data
.name
.name
)) {
413 DEBUG(0, ("Could not parse %s into separate domain/name parts!\n",
414 require_membership_of
));
418 if (winbindd_request_response(NULL
, WINBINDD_LOOKUPNAME
, &request
, &response
) !=
419 NSS_STATUS_SUCCESS
) {
420 DEBUG(0, ("Winbindd lookupname failed to resolve %s into a SID!\n",
421 require_membership_of
));
425 require_membership_of_sid
= SMB_STRDUP(response
.data
.sid
.sid
);
427 if (require_membership_of_sid
)
434 * Get some configuration from pam_winbind.conf to see if we
435 * need to contact trusted domain
438 int get_pam_winbind_config()
441 struct tiniparser_dictionary
*d
= NULL
;
443 if (!opt_pam_winbind_conf
|| !*opt_pam_winbind_conf
) {
444 opt_pam_winbind_conf
= PAM_WINBIND_CONFIG_FILE
;
447 d
= tiniparser_load(opt_pam_winbind_conf
);
453 if (tiniparser_getboolean(d
, "global:krb5_auth", false)) {
454 ctrl
|= WINBIND_KRB5_AUTH
;
457 tiniparser_freedict(d
);
462 /* Authenticate a user with a plaintext password */
464 static bool check_plaintext_auth(const char *user
, const char *pass
,
465 bool stdout_diagnostics
)
467 struct winbindd_request request
;
468 struct winbindd_response response
;
471 if (!get_require_membership_sid()) {
475 /* Send off request */
477 ZERO_STRUCT(request
);
478 ZERO_STRUCT(response
);
480 fstrcpy(request
.data
.auth
.user
, user
);
481 fstrcpy(request
.data
.auth
.pass
, pass
);
482 if (require_membership_of_sid
) {
483 strlcpy(request
.data
.auth
.require_membership_of_sid
,
484 require_membership_of_sid
,
485 sizeof(request
.data
.auth
.require_membership_of_sid
));
489 request
.flags
|= WBFLAG_PAM_CACHED_LOGIN
;
492 result
= winbindd_request_response(NULL
, WINBINDD_PAM_AUTH
, &request
, &response
);
494 /* Display response */
496 if (stdout_diagnostics
) {
497 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
498 d_printf("Reading winbind reply failed! (0x01)\n");
501 d_printf("%s: %s (0x%x)\n",
502 response
.data
.auth
.nt_status_string
,
503 response
.data
.auth
.error_string
,
504 response
.data
.auth
.nt_status
);
506 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
507 DEBUG(1, ("Reading winbind reply failed! (0x01)\n"));
510 DEBUG(3, ("%s: %s (0x%x)\n",
511 response
.data
.auth
.nt_status_string
,
512 response
.data
.auth
.error_string
,
513 response
.data
.auth
.nt_status
));
516 return (result
== NSS_STATUS_SUCCESS
);
519 /* authenticate a user with an encrypted username/password */
521 NTSTATUS
contact_winbind_auth_crap(const char *username
,
523 const char *workstation
,
524 const DATA_BLOB
*challenge
,
525 const DATA_BLOB
*lm_response
,
526 const DATA_BLOB
*nt_response
,
528 uint32_t extra_logon_parameters
,
530 uint8_t user_session_key
[16],
536 struct winbindd_request request
;
537 struct winbindd_response response
;
539 if (!get_require_membership_sid()) {
540 return NT_STATUS_INVALID_PARAMETER
;
543 ZERO_STRUCT(request
);
544 ZERO_STRUCT(response
);
546 request
.flags
= flags
;
548 request
.data
.auth_crap
.logon_parameters
= extra_logon_parameters
549 | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
| MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT
;
551 if (opt_allow_mschapv2
) {
552 request
.data
.auth_crap
.logon_parameters
|= MSV1_0_ALLOW_MSVCHAPV2
;
555 if (require_membership_of_sid
)
556 fstrcpy(request
.data
.auth_crap
.require_membership_of_sid
, require_membership_of_sid
);
558 fstrcpy(request
.data
.auth_crap
.user
, username
);
559 fstrcpy(request
.data
.auth_crap
.domain
, domain
);
561 fstrcpy(request
.data
.auth_crap
.workstation
,
564 memcpy(request
.data
.auth_crap
.chal
, challenge
->data
, MIN(challenge
->length
, 8));
566 if (lm_response
&& lm_response
->length
) {
567 memcpy(request
.data
.auth_crap
.lm_resp
,
569 MIN(lm_response
->length
, sizeof(request
.data
.auth_crap
.lm_resp
)));
570 request
.data
.auth_crap
.lm_resp_len
= lm_response
->length
;
573 if (nt_response
&& nt_response
->length
) {
574 if (nt_response
->length
> sizeof(request
.data
.auth_crap
.nt_resp
)) {
575 request
.flags
= request
.flags
| WBFLAG_BIG_NTLMV2_BLOB
;
576 request
.extra_len
= nt_response
->length
;
577 request
.extra_data
.data
= SMB_MALLOC_ARRAY(char, request
.extra_len
);
578 if (request
.extra_data
.data
== NULL
) {
579 return NT_STATUS_NO_MEMORY
;
581 memcpy(request
.extra_data
.data
, nt_response
->data
,
582 nt_response
->length
);
585 memcpy(request
.data
.auth_crap
.nt_resp
,
586 nt_response
->data
, nt_response
->length
);
588 request
.data
.auth_crap
.nt_resp_len
= nt_response
->length
;
591 result
= winbindd_request_response(NULL
, WINBINDD_PAM_AUTH_CRAP
, &request
, &response
);
592 SAFE_FREE(request
.extra_data
.data
);
594 /* Display response */
596 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
597 nt_status
= NT_STATUS_UNSUCCESSFUL
;
599 *error_string
= smb_xstrdup("Reading winbind reply failed!");
600 winbindd_free_response(&response
);
604 nt_status
= (NT_STATUS(response
.data
.auth
.nt_status
));
605 if (!NT_STATUS_IS_OK(nt_status
)) {
607 *error_string
= smb_xstrdup(response
.data
.auth
.error_string
);
608 winbindd_free_response(&response
);
612 if ((flags
& WBFLAG_PAM_LMKEY
) && lm_key
) {
613 memcpy(lm_key
, response
.data
.auth
.first_8_lm_hash
,
614 sizeof(response
.data
.auth
.first_8_lm_hash
));
616 if ((flags
& WBFLAG_PAM_USER_SESSION_KEY
) && user_session_key
) {
617 memcpy(user_session_key
, response
.data
.auth
.user_session_key
,
618 sizeof(response
.data
.auth
.user_session_key
));
621 if (flags
& WBFLAG_PAM_UNIX_NAME
) {
622 *unix_name
= SMB_STRDUP(response
.data
.auth
.unix_username
);
624 winbindd_free_response(&response
);
625 return NT_STATUS_NO_MEMORY
;
629 winbindd_free_response(&response
);
633 /* contact server to change user password using auth crap */
634 static NTSTATUS
contact_winbind_change_pswd_auth_crap(const char *username
,
636 const DATA_BLOB new_nt_pswd
,
637 const DATA_BLOB old_nt_hash_enc
,
638 const DATA_BLOB new_lm_pswd
,
639 const DATA_BLOB old_lm_hash_enc
,
644 struct winbindd_request request
;
645 struct winbindd_response response
;
647 if (!get_require_membership_sid())
650 *error_string
= smb_xstrdup("Can't get membership sid.");
651 return NT_STATUS_INVALID_PARAMETER
;
654 ZERO_STRUCT(request
);
655 ZERO_STRUCT(response
);
658 fstrcpy(request
.data
.chng_pswd_auth_crap
.user
, username
);
660 fstrcpy(request
.data
.chng_pswd_auth_crap
.domain
,domain
);
662 if(new_nt_pswd
.length
)
664 memcpy(request
.data
.chng_pswd_auth_crap
.new_nt_pswd
, new_nt_pswd
.data
, sizeof(request
.data
.chng_pswd_auth_crap
.new_nt_pswd
));
665 request
.data
.chng_pswd_auth_crap
.new_nt_pswd_len
= new_nt_pswd
.length
;
668 if(old_nt_hash_enc
.length
)
670 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
));
671 request
.data
.chng_pswd_auth_crap
.old_nt_hash_enc_len
= old_nt_hash_enc
.length
;
674 if(new_lm_pswd
.length
)
676 memcpy(request
.data
.chng_pswd_auth_crap
.new_lm_pswd
, new_lm_pswd
.data
, sizeof(request
.data
.chng_pswd_auth_crap
.new_lm_pswd
));
677 request
.data
.chng_pswd_auth_crap
.new_lm_pswd_len
= new_lm_pswd
.length
;
680 if(old_lm_hash_enc
.length
)
682 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
));
683 request
.data
.chng_pswd_auth_crap
.old_lm_hash_enc_len
= old_lm_hash_enc
.length
;
686 result
= winbindd_request_response(NULL
, WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP
, &request
, &response
);
688 /* Display response */
690 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0))
692 nt_status
= NT_STATUS_UNSUCCESSFUL
;
694 *error_string
= smb_xstrdup("Reading winbind reply failed!");
695 winbindd_free_response(&response
);
699 nt_status
= (NT_STATUS(response
.data
.auth
.nt_status
));
700 if (!NT_STATUS_IS_OK(nt_status
))
703 *error_string
= smb_xstrdup(response
.data
.auth
.error_string
);
704 winbindd_free_response(&response
);
708 winbindd_free_response(&response
);
713 static NTSTATUS
ntlm_auth_generate_session_info(struct auth4_context
*auth_context
,
715 void *server_returned_info
,
716 const char *original_user_name
,
717 uint32_t session_info_flags
,
718 struct auth_session_info
**session_info_out
)
720 const char *unix_username
= (const char *)server_returned_info
;
722 struct dom_sid
*sids
= NULL
;
723 struct auth_session_info
*session_info
= NULL
;
725 session_info
= talloc_zero(mem_ctx
, struct auth_session_info
);
726 if (session_info
== NULL
) {
727 return NT_STATUS_NO_MEMORY
;
730 session_info
->unix_info
= talloc_zero(session_info
, struct auth_user_info_unix
);
731 if (session_info
->unix_info
== NULL
) {
732 TALLOC_FREE(session_info
);
733 return NT_STATUS_NO_MEMORY
;
735 session_info
->unix_info
->unix_name
= talloc_strdup(session_info
->unix_info
,
737 if (session_info
->unix_info
->unix_name
== NULL
) {
738 TALLOC_FREE(session_info
);
739 return NT_STATUS_NO_MEMORY
;
742 session_info
->security_token
= talloc_zero(session_info
, struct security_token
);
743 if (session_info
->security_token
== NULL
) {
744 TALLOC_FREE(session_info
);
745 return NT_STATUS_NO_MEMORY
;
748 sids
= talloc_zero_array(session_info
->security_token
,
751 TALLOC_FREE(session_info
);
752 return NT_STATUS_NO_MEMORY
;
754 ok
= dom_sid_parse(SID_WORLD
, &sids
[0]);
756 TALLOC_FREE(session_info
);
757 return NT_STATUS_INTERNAL_ERROR
;
759 ok
= dom_sid_parse(SID_NT_NETWORK
, &sids
[1]);
761 TALLOC_FREE(session_info
);
762 return NT_STATUS_INTERNAL_ERROR
;
764 ok
= dom_sid_parse(SID_NT_AUTHENTICATED_USERS
, &sids
[2]);
766 TALLOC_FREE(session_info
);
767 return NT_STATUS_INTERNAL_ERROR
;
770 session_info
->security_token
->num_sids
= talloc_array_length(sids
);
771 session_info
->security_token
->sids
= sids
;
773 *session_info_out
= session_info
;
778 static NTSTATUS
ntlm_auth_generate_session_info_pac(struct auth4_context
*auth_ctx
,
780 struct smb_krb5_context
*smb_krb5_context
,
782 const char *princ_name
,
783 const struct tsocket_address
*remote_address
,
784 uint32_t session_info_flags
,
785 struct auth_session_info
**session_info
)
788 struct PAC_LOGON_INFO
*logon_info
= NULL
;
796 tmp_ctx
= talloc_new(mem_ctx
);
798 return NT_STATUS_NO_MEMORY
;
803 status
= kerberos_pac_logon_info(tmp_ctx
, *pac_blob
, NULL
, NULL
,
804 NULL
, NULL
, 0, &logon_info
);
806 status
= NT_STATUS_ACCESS_DENIED
;
808 if (!NT_STATUS_IS_OK(status
)) {
813 DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name
));
815 p
= strchr_m(princ_name
, '@');
817 DEBUG(3, ("[%s] Doesn't look like a valid principal\n",
819 return NT_STATUS_LOGON_FAILURE
;
822 user
= talloc_strndup(mem_ctx
, princ_name
, p
- princ_name
);
824 return NT_STATUS_NO_MEMORY
;
827 realm
= talloc_strdup(talloc_tos(), p
+ 1);
829 return NT_STATUS_NO_MEMORY
;
832 if (!strequal(realm
, lp_realm())) {
833 DEBUG(3, ("Ticket for foreign realm %s@%s\n", user
, realm
));
834 if (!lp_allow_trusted_domains()) {
835 return NT_STATUS_LOGON_FAILURE
;
839 if (logon_info
&& logon_info
->info3
.base
.logon_domain
.string
) {
840 domain
= talloc_strdup(mem_ctx
,
841 logon_info
->info3
.base
.logon_domain
.string
);
843 return NT_STATUS_NO_MEMORY
;
845 DEBUG(10, ("Domain is [%s] (using PAC)\n", domain
));
848 /* If we have winbind running, we can (and must) shorten the
849 username by using the short netbios name. Otherwise we will
850 have inconsistent user names. With Kerberos, we get the
851 fully qualified realm, with ntlmssp we get the short
852 name. And even w2k3 does use ntlmssp if you for example
853 connect to an ip address. */
856 struct wbcDomainInfo
*info
= NULL
;
858 DEBUG(10, ("Mapping [%s] to short name using winbindd\n",
861 wbc_status
= wbcDomainInfo(realm
, &info
);
863 if (WBC_ERROR_IS_OK(wbc_status
)) {
864 domain
= talloc_strdup(mem_ctx
,
868 DEBUG(3, ("Could not find short name: %s\n",
869 wbcErrorString(wbc_status
)));
870 domain
= talloc_strdup(mem_ctx
, realm
);
873 return NT_STATUS_NO_MEMORY
;
875 DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain
));
878 unixuser
= talloc_asprintf(tmp_ctx
, "%s%c%s", domain
, winbind_separator(), user
);
880 status
= NT_STATUS_NO_MEMORY
;
884 status
= ntlm_auth_generate_session_info(auth_ctx
, mem_ctx
, unixuser
, NULL
, session_info_flags
, session_info
);
887 TALLOC_FREE(tmp_ctx
);
894 * Return the challenge as determined by the authentication subsystem
895 * @return an 8 byte random challenge
898 static NTSTATUS
ntlm_auth_get_challenge(struct auth4_context
*auth_ctx
,
901 if (auth_ctx
->challenge
.data
.length
== 8) {
902 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
903 auth_ctx
->challenge
.set_by
));
904 memcpy(chal
, auth_ctx
->challenge
.data
.data
, 8);
908 if (!auth_ctx
->challenge
.set_by
) {
909 generate_random_buffer(chal
, 8);
911 auth_ctx
->challenge
.data
= data_blob_talloc(auth_ctx
, chal
, 8);
912 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.data
.data
);
913 auth_ctx
->challenge
.set_by
= "random";
916 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
917 auth_ctx
->challenge
.set_by
));
923 * NTLM2 authentication modifies the effective challenge,
924 * @param challenge The new challenge value
926 static NTSTATUS
ntlm_auth_set_challenge(struct auth4_context
*auth_ctx
, const uint8_t chal
[8], const char *set_by
)
928 auth_ctx
->challenge
.set_by
= talloc_strdup(auth_ctx
, set_by
);
929 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.set_by
);
931 auth_ctx
->challenge
.data
= data_blob_talloc(auth_ctx
, chal
, 8);
932 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.data
.data
);
938 * Check the password on an NTLMSSP login.
940 * Return the session keys used on the connection.
943 static NTSTATUS
winbind_pw_check(struct auth4_context
*auth4_context
,
945 const struct auth_usersupplied_info
*user_info
,
946 void **server_returned_info
,
947 DATA_BLOB
*session_key
, DATA_BLOB
*lm_session_key
)
949 static const char zeros
[16] = { 0, };
951 char *error_string
= NULL
;
953 uint8_t user_sess_key
[16];
954 char *unix_name
= NULL
;
956 nt_status
= contact_winbind_auth_crap(user_info
->client
.account_name
, user_info
->client
.domain_name
,
957 user_info
->workstation_name
,
958 &auth4_context
->challenge
.data
,
959 &user_info
->password
.response
.lanman
,
960 &user_info
->password
.response
.nt
,
961 WBFLAG_PAM_LMKEY
| WBFLAG_PAM_USER_SESSION_KEY
| WBFLAG_PAM_UNIX_NAME
,
963 lm_key
, user_sess_key
,
964 &error_string
, &unix_name
);
966 if (NT_STATUS_IS_OK(nt_status
)) {
967 if (memcmp(lm_key
, zeros
, 8) != 0) {
968 *lm_session_key
= data_blob_talloc(mem_ctx
, NULL
, 16);
969 memcpy(lm_session_key
->data
, lm_key
, 8);
970 memset(lm_session_key
->data
+8, '\0', 8);
973 if (memcmp(user_sess_key
, zeros
, 16) != 0) {
974 *session_key
= data_blob_talloc(mem_ctx
, user_sess_key
, 16);
976 *server_returned_info
= talloc_strdup(mem_ctx
,
979 DEBUG(NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCESS_DENIED
) ? 0 : 3,
980 ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
981 user_info
->client
.domain_name
, user_info
->client
.account_name
,
982 user_info
->workstation_name
,
983 error_string
? error_string
: "unknown error (NULL)"));
986 SAFE_FREE(error_string
);
987 SAFE_FREE(unix_name
);
991 static NTSTATUS
local_pw_check(struct auth4_context
*auth4_context
,
993 const struct auth_usersupplied_info
*user_info
,
994 void **server_returned_info
,
995 DATA_BLOB
*session_key
, DATA_BLOB
*lm_session_key
)
998 struct samr_Password lm_pw
, nt_pw
;
1000 nt_lm_owf_gen (opt_password
, nt_pw
.hash
, lm_pw
.hash
);
1002 nt_status
= ntlm_password_check(mem_ctx
,
1004 &auth4_context
->challenge
.data
,
1005 &user_info
->password
.response
.lanman
,
1006 &user_info
->password
.response
.nt
,
1007 user_info
->client
.account_name
,
1008 user_info
->client
.account_name
,
1009 user_info
->client
.domain_name
,
1010 &lm_pw
, &nt_pw
, session_key
, lm_session_key
);
1012 if (NT_STATUS_IS_OK(nt_status
)) {
1013 *server_returned_info
= talloc_asprintf(mem_ctx
,
1014 "%s%c%s", user_info
->client
.domain_name
,
1015 *lp_winbind_separator(),
1016 user_info
->client
.account_name
);
1018 DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
1019 user_info
->client
.domain_name
, user_info
->client
.account_name
,
1020 user_info
->workstation_name
,
1021 nt_errstr(nt_status
)));
1026 static NTSTATUS
ntlm_auth_prepare_gensec_client(TALLOC_CTX
*mem_ctx
,
1027 struct loadparm_context
*lp_ctx
,
1028 struct gensec_security
**gensec_security_out
)
1030 struct gensec_security
*gensec_security
= NULL
;
1032 TALLOC_CTX
*tmp_ctx
;
1033 const struct gensec_security_ops
**backends
= NULL
;
1034 struct gensec_settings
*gensec_settings
= NULL
;
1037 tmp_ctx
= talloc_new(mem_ctx
);
1038 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx
);
1040 gensec_settings
= lpcfg_gensec_settings(tmp_ctx
, lp_ctx
);
1041 if (gensec_settings
== NULL
) {
1042 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1043 TALLOC_FREE(tmp_ctx
);
1044 return NT_STATUS_NO_MEMORY
;
1047 backends
= talloc_zero_array(gensec_settings
,
1048 const struct gensec_security_ops
*, 4);
1049 if (backends
== NULL
) {
1050 TALLOC_FREE(tmp_ctx
);
1051 return NT_STATUS_NO_MEMORY
;
1053 gensec_settings
->backends
= backends
;
1057 /* These need to be in priority order, krb5 before NTLMSSP */
1058 #if defined(HAVE_KRB5)
1059 backends
[idx
++] = &gensec_gse_krb5_security_ops
;
1062 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_NTLMSSP
);
1064 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_SPNEGO
);
1066 nt_status
= gensec_client_start(NULL
, &gensec_security
,
1068 if (!NT_STATUS_IS_OK(nt_status
)) {
1069 TALLOC_FREE(tmp_ctx
);
1073 talloc_unlink(tmp_ctx
, gensec_settings
);
1075 if (opt_target_service
!= NULL
) {
1076 nt_status
= gensec_set_target_service(gensec_security
,
1077 opt_target_service
);
1078 if (!NT_STATUS_IS_OK(nt_status
)) {
1079 TALLOC_FREE(tmp_ctx
);
1084 if (opt_target_hostname
!= NULL
) {
1085 nt_status
= gensec_set_target_hostname(gensec_security
,
1086 opt_target_hostname
);
1087 if (!NT_STATUS_IS_OK(nt_status
)) {
1088 TALLOC_FREE(tmp_ctx
);
1093 *gensec_security_out
= talloc_steal(mem_ctx
, gensec_security
);
1094 TALLOC_FREE(tmp_ctx
);
1095 return NT_STATUS_OK
;
1098 static struct auth4_context
*make_auth4_context_ntlm_auth(TALLOC_CTX
*mem_ctx
, bool local_pw
)
1100 struct auth4_context
*auth4_context
= talloc_zero(mem_ctx
, struct auth4_context
);
1101 if (auth4_context
== NULL
) {
1102 DEBUG(10, ("failed to allocate auth4_context failed\n"));
1105 auth4_context
->generate_session_info
= ntlm_auth_generate_session_info
;
1106 auth4_context
->generate_session_info_pac
= ntlm_auth_generate_session_info_pac
;
1107 auth4_context
->get_ntlm_challenge
= ntlm_auth_get_challenge
;
1108 auth4_context
->set_ntlm_challenge
= ntlm_auth_set_challenge
;
1110 auth4_context
->check_ntlm_password
= local_pw_check
;
1112 auth4_context
->check_ntlm_password
= winbind_pw_check
;
1114 auth4_context
->private_data
= NULL
;
1115 return auth4_context
;
1118 static NTSTATUS
ntlm_auth_prepare_gensec_server(TALLOC_CTX
*mem_ctx
,
1119 struct loadparm_context
*lp_ctx
,
1120 struct gensec_security
**gensec_security_out
)
1122 struct gensec_security
*gensec_security
;
1125 TALLOC_CTX
*tmp_ctx
;
1126 const struct gensec_security_ops
**backends
;
1127 struct gensec_settings
*gensec_settings
;
1129 struct cli_credentials
*server_credentials
;
1131 struct auth4_context
*auth4_context
;
1133 tmp_ctx
= talloc_new(mem_ctx
);
1134 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx
);
1136 auth4_context
= make_auth4_context_ntlm_auth(tmp_ctx
, opt_password
);
1137 if (auth4_context
== NULL
) {
1138 TALLOC_FREE(tmp_ctx
);
1139 return NT_STATUS_NO_MEMORY
;
1142 gensec_settings
= lpcfg_gensec_settings(tmp_ctx
, lp_ctx
);
1143 if (lp_ctx
== NULL
) {
1144 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1145 TALLOC_FREE(tmp_ctx
);
1146 return NT_STATUS_NO_MEMORY
;
1150 * This should be a 'netbios domain -> DNS domain'
1151 * mapping, and can currently validly return NULL on
1152 * poorly configured systems.
1154 * This is used for the NTLMSSP server
1158 gensec_settings
->server_netbios_name
= lp_netbios_name();
1159 gensec_settings
->server_netbios_domain
= lp_workgroup();
1161 gensec_settings
->server_netbios_name
= get_winbind_netbios_name();
1162 gensec_settings
->server_netbios_domain
= get_winbind_domain();
1165 gensec_settings
->server_dns_domain
= strlower_talloc(gensec_settings
,
1166 get_mydnsdomname(talloc_tos()));
1167 gensec_settings
->server_dns_name
= strlower_talloc(gensec_settings
,
1168 get_mydnsfullname());
1170 backends
= talloc_zero_array(gensec_settings
,
1171 const struct gensec_security_ops
*, 4);
1173 if (backends
== NULL
) {
1174 TALLOC_FREE(tmp_ctx
);
1175 return NT_STATUS_NO_MEMORY
;
1177 gensec_settings
->backends
= backends
;
1181 /* These need to be in priority order, krb5 before NTLMSSP */
1182 #if defined(HAVE_KRB5)
1183 backends
[idx
++] = &gensec_gse_krb5_security_ops
;
1186 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_NTLMSSP
);
1188 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_SPNEGO
);
1191 * This is anonymous for now, because we just use it
1192 * to set the kerberos state at the moment
1194 server_credentials
= cli_credentials_init_anon(tmp_ctx
);
1195 if (!server_credentials
) {
1196 DEBUG(0, ("auth_generic_prepare: Failed to init server credentials\n"));
1197 return NT_STATUS_NO_MEMORY
;
1200 cli_credentials_set_conf(server_credentials
, lp_ctx
);
1202 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC
|| lp_security() == SEC_ADS
|| USE_KERBEROS_KEYTAB
) {
1203 cli_credentials_set_kerberos_state(server_credentials
, CRED_AUTO_USE_KERBEROS
);
1205 cli_credentials_set_kerberos_state(server_credentials
, CRED_DONT_USE_KERBEROS
);
1208 nt_status
= gensec_server_start(tmp_ctx
, gensec_settings
,
1209 auth4_context
, &gensec_security
);
1211 if (!NT_STATUS_IS_OK(nt_status
)) {
1212 TALLOC_FREE(tmp_ctx
);
1216 gensec_set_credentials(gensec_security
, server_credentials
);
1218 gensec_want_feature(gensec_security
, GENSEC_FEATURE_SIGN
);
1219 gensec_want_feature(gensec_security
, GENSEC_FEATURE_SEAL
);
1221 talloc_unlink(tmp_ctx
, lp_ctx
);
1222 talloc_unlink(tmp_ctx
, server_credentials
);
1223 talloc_unlink(tmp_ctx
, gensec_settings
);
1224 talloc_unlink(tmp_ctx
, auth4_context
);
1226 *gensec_security_out
= talloc_steal(mem_ctx
, gensec_security
);
1227 TALLOC_FREE(tmp_ctx
);
1228 return NT_STATUS_OK
;
1231 static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode
,
1232 struct loadparm_context
*lp_ctx
,
1233 struct ntlm_auth_state
*state
,
1234 char *buf
, int length
, void **private2
)
1236 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1240 static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode
,
1241 struct loadparm_context
*lp_ctx
,
1242 struct ntlm_auth_state
*state
,
1243 char *buf
, int length
, void **private2
)
1248 pass
=(char *)memchr(buf
,' ',length
);
1250 DEBUG(2, ("Password not found. Denying access\n"));
1251 x_fprintf(x_stdout
, "ERR\n");
1257 if (state
->helper_mode
== SQUID_2_5_BASIC
) {
1258 rfc1738_unescape(user
);
1259 rfc1738_unescape(pass
);
1262 if (check_plaintext_auth(user
, pass
, False
)) {
1263 x_fprintf(x_stdout
, "OK\n");
1265 x_fprintf(x_stdout
, "ERR\n");
1269 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode
,
1270 struct loadparm_context
*lp_ctx
,
1271 char *buf
, int length
, void **private1
)
1274 DATA_BLOB out
= data_blob(NULL
, 0);
1275 char *out_base64
= NULL
;
1276 const char *reply_arg
= NULL
;
1277 struct gensec_ntlm_state
{
1278 struct gensec_security
*gensec_state
;
1279 const char *set_password
;
1281 struct gensec_ntlm_state
*state
;
1285 const char *reply_code
;
1286 struct cli_credentials
*creds
;
1288 static char *want_feature_list
= NULL
;
1289 static DATA_BLOB session_key
;
1291 TALLOC_CTX
*mem_ctx
;
1294 state
= (struct gensec_ntlm_state
*)*private1
;
1296 state
= talloc_zero(NULL
, struct gensec_ntlm_state
);
1298 x_fprintf(x_stdout
, "BH No Memory\n");
1303 state
->set_password
= opt_password
;
1307 if (strlen(buf
) < 2) {
1308 DEBUG(1, ("query [%s] invalid", buf
));
1309 x_fprintf(x_stdout
, "BH Query invalid\n");
1313 if (strlen(buf
) > 3) {
1314 if(strncmp(buf
, "SF ", 3) == 0) {
1315 DEBUG(10, ("Setting flags to negotiate\n"));
1316 talloc_free(want_feature_list
);
1317 want_feature_list
= talloc_strndup(state
, buf
+3, strlen(buf
)-3);
1318 x_fprintf(x_stdout
, "OK\n");
1321 in
= base64_decode_data_blob(buf
+ 3);
1323 in
= data_blob(NULL
, 0);
1326 if (strncmp(buf
, "YR", 2) == 0) {
1327 if (state
->gensec_state
) {
1328 talloc_free(state
->gensec_state
);
1329 state
->gensec_state
= NULL
;
1331 } else if ( (strncmp(buf
, "OK", 2) == 0)) {
1332 /* Just return BH, like ntlm_auth from Samba 3 does. */
1333 x_fprintf(x_stdout
, "BH Command expected\n");
1334 data_blob_free(&in
);
1336 } else if ( (strncmp(buf
, "TT ", 3) != 0) &&
1337 (strncmp(buf
, "KK ", 3) != 0) &&
1338 (strncmp(buf
, "AF ", 3) != 0) &&
1339 (strncmp(buf
, "NA ", 3) != 0) &&
1340 (strncmp(buf
, "UG", 2) != 0) &&
1341 (strncmp(buf
, "PW ", 3) != 0) &&
1342 (strncmp(buf
, "GK", 2) != 0) &&
1343 (strncmp(buf
, "GF", 2) != 0)) {
1344 DEBUG(1, ("SPNEGO request [%s] invalid prefix\n", buf
));
1345 x_fprintf(x_stdout
, "BH SPNEGO request invalid prefix\n");
1346 data_blob_free(&in
);
1350 mem_ctx
= talloc_named(NULL
, 0, "manage_gensec_request internal mem_ctx");
1353 if (!(state
->gensec_state
)) {
1354 switch (stdio_helper_mode
) {
1355 case GSS_SPNEGO_CLIENT
:
1357 * cached credentials are only supported by
1358 * NTLMSSP_CLIENT_1 for now.
1360 use_cached_creds
= false;
1362 case NTLMSSP_CLIENT_1
:
1363 /* setup the client side */
1365 if (state
->set_password
!= NULL
) {
1366 use_cached_creds
= false;
1369 if (use_cached_creds
) {
1370 struct wbcCredentialCacheParams params
;
1371 struct wbcCredentialCacheInfo
*info
= NULL
;
1372 struct wbcAuthErrorInfo
*error
= NULL
;
1375 params
.account_name
= opt_username
;
1376 params
.domain_name
= opt_domain
;
1377 params
.level
= WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP
;
1378 params
.num_blobs
= 0;
1379 params
.blobs
= NULL
;
1381 wbc_status
= wbcCredentialCache(¶ms
, &info
,
1383 wbcFreeMemory(error
);
1384 if (!WBC_ERROR_IS_OK(wbc_status
)) {
1385 use_cached_creds
= false;
1387 wbcFreeMemory(info
);
1390 nt_status
= ntlm_auth_prepare_gensec_client(state
, lp_ctx
,
1391 &state
->gensec_state
);
1392 if (!NT_STATUS_IS_OK(nt_status
)) {
1393 x_fprintf(x_stdout
, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status
));
1394 talloc_free(mem_ctx
);
1398 creds
= cli_credentials_init(state
->gensec_state
);
1399 cli_credentials_set_conf(creds
, lp_ctx
);
1401 cli_credentials_set_username(creds
, opt_username
, CRED_SPECIFIED
);
1404 cli_credentials_set_domain(creds
, opt_domain
, CRED_SPECIFIED
);
1406 if (use_cached_creds
) {
1407 gensec_want_feature(state
->gensec_state
,
1408 GENSEC_FEATURE_NTLM_CCACHE
);
1409 } else if (state
->set_password
) {
1410 cli_credentials_set_password(creds
, state
->set_password
, CRED_SPECIFIED
);
1412 cli_credentials_set_password_callback(creds
, get_password
);
1414 if (opt_workstation
) {
1415 cli_credentials_set_workstation(creds
, opt_workstation
, CRED_SPECIFIED
);
1418 gensec_set_credentials(state
->gensec_state
, creds
);
1421 case GSS_SPNEGO_SERVER
:
1422 case SQUID_2_5_NTLMSSP
:
1424 nt_status
= ntlm_auth_prepare_gensec_server(state
, lp_ctx
,
1425 &state
->gensec_state
);
1426 if (!NT_STATUS_IS_OK(nt_status
)) {
1427 x_fprintf(x_stdout
, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status
));
1428 talloc_free(mem_ctx
);
1434 talloc_free(mem_ctx
);
1438 gensec_want_feature_list(state
->gensec_state
, want_feature_list
);
1440 switch (stdio_helper_mode
) {
1441 case GSS_SPNEGO_CLIENT
:
1442 case GSS_SPNEGO_SERVER
:
1443 nt_status
= gensec_start_mech_by_oid(state
->gensec_state
, GENSEC_OID_SPNEGO
);
1448 case NTLMSSP_CLIENT_1
:
1453 case SQUID_2_5_NTLMSSP
:
1454 nt_status
= gensec_start_mech_by_oid(state
->gensec_state
, GENSEC_OID_NTLMSSP
);
1457 talloc_free(mem_ctx
);
1461 if (!NT_STATUS_IS_OK(nt_status
)) {
1462 DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status
)));
1463 x_fprintf(x_stdout
, "BH GENSEC mech failed to start\n");
1464 talloc_free(mem_ctx
);
1472 if (strncmp(buf
, "PW ", 3) == 0) {
1473 state
->set_password
= talloc_strndup(state
,
1474 (const char *)in
.data
,
1477 cli_credentials_set_password(gensec_get_credentials(state
->gensec_state
),
1478 state
->set_password
,
1480 x_fprintf(x_stdout
, "OK\n");
1481 data_blob_free(&in
);
1482 talloc_free(mem_ctx
);
1486 if (strncmp(buf
, "GK", 2) == 0) {
1488 DEBUG(10, ("Requested session key\n"));
1489 nt_status
= gensec_session_key(state
->gensec_state
, mem_ctx
, &session_key
);
1490 if(!NT_STATUS_IS_OK(nt_status
)) {
1491 DEBUG(1, ("gensec_session_key failed: %s\n", nt_errstr(nt_status
)));
1492 x_fprintf(x_stdout
, "BH No session key\n");
1493 talloc_free(mem_ctx
);
1496 base64_key
= base64_encode_data_blob(state
, session_key
);
1497 SMB_ASSERT(base64_key
!= NULL
);
1498 x_fprintf(x_stdout
, "GK %s\n", base64_key
);
1499 talloc_free(base64_key
);
1501 talloc_free(mem_ctx
);
1505 if (strncmp(buf
, "GF", 2) == 0) {
1508 DEBUG(10, ("Requested negotiated NTLMSSP feature flags\n"));
1510 neg_flags
= gensec_ntlmssp_neg_flags(state
->gensec_state
);
1511 if (neg_flags
== 0) {
1512 x_fprintf(x_stdout
, "BH\n");
1516 x_fprintf(x_stdout
, "GF 0x%08x\n", neg_flags
);
1520 nt_status
= gensec_update(state
->gensec_state
, mem_ctx
, in
, &out
);
1522 /* don't leak 'bad password'/'no such user' info to the network client */
1523 nt_status
= nt_status_squash(nt_status
);
1526 out_base64
= base64_encode_data_blob(mem_ctx
, out
);
1527 SMB_ASSERT(out_base64
!= NULL
);
1532 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1534 if (first
&& state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1536 } else if (state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1538 } else if (state
->gensec_state
->gensec_role
== GENSEC_SERVER
) {
1545 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCESS_DENIED
)) {
1546 reply_code
= "BH NT_STATUS_ACCESS_DENIED";
1547 reply_arg
= nt_errstr(nt_status
);
1548 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1549 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_UNSUCCESSFUL
)) {
1550 reply_code
= "BH NT_STATUS_UNSUCCESSFUL";
1551 reply_arg
= nt_errstr(nt_status
);
1552 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1553 } else if (!NT_STATUS_IS_OK(nt_status
)) {
1555 reply_arg
= nt_errstr(nt_status
);
1556 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1557 } else if /* OK */ (state
->gensec_state
->gensec_role
== GENSEC_SERVER
) {
1558 struct auth_session_info
*session_info
;
1560 nt_status
= gensec_session_info(state
->gensec_state
, mem_ctx
, &session_info
);
1561 if (!NT_STATUS_IS_OK(nt_status
)) {
1562 reply_code
= "BH Failed to retrive session info";
1563 reply_arg
= nt_errstr(nt_status
);
1564 DEBUG(1, ("GENSEC failed to retrieve the session info: %s\n", nt_errstr(nt_status
)));
1568 reply_arg
= talloc_strdup(state
->gensec_state
, session_info
->unix_info
->unix_name
);
1569 if (reply_arg
== NULL
) {
1570 reply_code
= "BH out of memory";
1571 reply_arg
= nt_errstr(NT_STATUS_NO_MEMORY
);
1573 talloc_free(session_info
);
1575 } else if (state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1577 reply_arg
= out_base64
;
1582 switch (stdio_helper_mode
) {
1583 case GSS_SPNEGO_SERVER
:
1584 x_fprintf(x_stdout
, "%s %s %s\n", reply_code
,
1585 out_base64
? out_base64
: "*",
1586 reply_arg
? reply_arg
: "*");
1590 x_fprintf(x_stdout
, "%s %s\n", reply_code
, out_base64
);
1591 } else if (reply_arg
) {
1592 x_fprintf(x_stdout
, "%s %s\n", reply_code
, reply_arg
);
1594 x_fprintf(x_stdout
, "%s\n", reply_code
);
1598 talloc_free(mem_ctx
);
1602 static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode
,
1603 struct loadparm_context
*lp_ctx
,
1604 struct ntlm_auth_state
*state
,
1605 char *buf
, int length
, void **private2
)
1607 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1611 static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode
,
1612 struct loadparm_context
*lp_ctx
,
1613 struct ntlm_auth_state
*state
,
1614 char *buf
, int length
, void **private2
)
1616 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1620 static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode
,
1621 struct loadparm_context
*lp_ctx
,
1622 struct ntlm_auth_state
*state
,
1623 char *buf
, int length
, void **private2
)
1625 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1629 static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode
,
1630 struct loadparm_context
*lp_ctx
,
1631 struct ntlm_auth_state
*state
,
1632 char *buf
, int length
, void **private2
)
1634 char *request
, *parameter
;
1635 static DATA_BLOB challenge
;
1636 static DATA_BLOB lm_response
;
1637 static DATA_BLOB nt_response
;
1638 static char *full_username
;
1639 static char *username
;
1640 static char *domain
;
1641 static char *plaintext_password
;
1642 static bool ntlm_server_1_user_session_key
;
1643 static bool ntlm_server_1_lm_session_key
;
1645 if (strequal(buf
, ".")) {
1646 if (!full_username
&& !username
) {
1647 x_fprintf(x_stdout
, "Error: No username supplied!\n");
1648 } else if (plaintext_password
) {
1649 /* handle this request as plaintext */
1650 if (!full_username
) {
1651 if (asprintf(&full_username
, "%s%c%s", domain
, winbind_separator(), username
) == -1) {
1652 x_fprintf(x_stdout
, "Error: Out of memory in asprintf!\n.\n");
1656 if (check_plaintext_auth(full_username
, plaintext_password
, False
)) {
1657 x_fprintf(x_stdout
, "Authenticated: Yes\n");
1659 x_fprintf(x_stdout
, "Authenticated: No\n");
1661 } else if (!lm_response
.data
&& !nt_response
.data
) {
1662 x_fprintf(x_stdout
, "Error: No password supplied!\n");
1663 } else if (!challenge
.data
) {
1664 x_fprintf(x_stdout
, "Error: No lanman-challenge supplied!\n");
1666 char *error_string
= NULL
;
1668 uchar user_session_key
[16];
1671 if (full_username
&& !username
) {
1673 fstring fstr_domain
;
1675 if (!parse_ntlm_auth_domain_user(full_username
, fstr_user
, fstr_domain
)) {
1676 /* username might be 'tainted', don't print into our new-line deleimianted stream */
1677 x_fprintf(x_stdout
, "Error: Could not parse into domain and username\n");
1679 SAFE_FREE(username
);
1681 username
= smb_xstrdup(fstr_user
);
1682 domain
= smb_xstrdup(fstr_domain
);
1686 DATA_BLOB nt_session_key
, lm_session_key
;
1687 struct samr_Password lm_pw
, nt_pw
;
1688 TALLOC_CTX
*mem_ctx
= talloc_new(NULL
);
1689 ZERO_STRUCT(user_session_key
);
1690 ZERO_STRUCT(lm_key
);
1692 nt_lm_owf_gen (opt_password
, nt_pw
.hash
, lm_pw
.hash
);
1693 nt_status
= ntlm_password_check(mem_ctx
,
1704 error_string
= smb_xstrdup(get_friendly_nt_error_msg(nt_status
));
1705 if (ntlm_server_1_user_session_key
) {
1706 if (nt_session_key
.length
== sizeof(user_session_key
)) {
1707 memcpy(user_session_key
,
1708 nt_session_key
.data
,
1709 sizeof(user_session_key
));
1712 if (ntlm_server_1_lm_session_key
) {
1713 if (lm_session_key
.length
== sizeof(lm_key
)) {
1715 lm_session_key
.data
,
1719 TALLOC_FREE(mem_ctx
);
1723 domain
= smb_xstrdup(get_winbind_domain());
1726 if (ntlm_server_1_lm_session_key
)
1727 flags
|= WBFLAG_PAM_LMKEY
;
1729 if (ntlm_server_1_user_session_key
)
1730 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
1732 nt_status
= contact_winbind_auth_crap(username
,
1745 if (!NT_STATUS_IS_OK(nt_status
)) {
1746 x_fprintf(x_stdout
, "Authenticated: No\n");
1747 x_fprintf(x_stdout
, "Authentication-Error: %s\n.\n", error_string
);
1749 static char zeros
[16];
1751 char *hex_user_session_key
;
1753 x_fprintf(x_stdout
, "Authenticated: Yes\n");
1755 if (ntlm_server_1_lm_session_key
1756 && (memcmp(zeros
, lm_key
,
1757 sizeof(lm_key
)) != 0)) {
1758 hex_lm_key
= hex_encode_talloc(NULL
,
1759 (const unsigned char *)lm_key
,
1761 x_fprintf(x_stdout
, "LANMAN-Session-Key: %s\n", hex_lm_key
);
1762 TALLOC_FREE(hex_lm_key
);
1765 if (ntlm_server_1_user_session_key
1766 && (memcmp(zeros
, user_session_key
,
1767 sizeof(user_session_key
)) != 0)) {
1768 hex_user_session_key
= hex_encode_talloc(NULL
,
1769 (const unsigned char *)user_session_key
,
1770 sizeof(user_session_key
));
1771 x_fprintf(x_stdout
, "User-Session-Key: %s\n", hex_user_session_key
);
1772 TALLOC_FREE(hex_user_session_key
);
1775 SAFE_FREE(error_string
);
1777 /* clear out the state */
1778 challenge
= data_blob_null
;
1779 nt_response
= data_blob_null
;
1780 lm_response
= data_blob_null
;
1781 SAFE_FREE(full_username
);
1782 SAFE_FREE(username
);
1784 SAFE_FREE(plaintext_password
);
1785 ntlm_server_1_user_session_key
= False
;
1786 ntlm_server_1_lm_session_key
= False
;
1787 x_fprintf(x_stdout
, ".\n");
1794 /* Indicates a base64 encoded structure */
1795 parameter
= strstr_m(request
, ":: ");
1797 parameter
= strstr_m(request
, ": ");
1800 DEBUG(0, ("Parameter not found!\n"));
1801 x_fprintf(x_stdout
, "Error: Parameter not found!\n.\n");
1818 base64_decode_inplace(parameter
);
1821 if (strequal(request
, "LANMAN-Challenge")) {
1822 challenge
= strhex_to_data_blob(NULL
, parameter
);
1823 if (challenge
.length
!= 8) {
1824 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (got %d bytes, expected 8)\n.\n",
1826 (int)challenge
.length
);
1827 challenge
= data_blob_null
;
1829 } else if (strequal(request
, "NT-Response")) {
1830 nt_response
= strhex_to_data_blob(NULL
, parameter
);
1831 if (nt_response
.length
< 24) {
1832 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (only got %d bytes, needed at least 24)\n.\n",
1834 (int)nt_response
.length
);
1835 nt_response
= data_blob_null
;
1837 } else if (strequal(request
, "LANMAN-Response")) {
1838 lm_response
= strhex_to_data_blob(NULL
, parameter
);
1839 if (lm_response
.length
!= 24) {
1840 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (got %d bytes, expected 24)\n.\n",
1842 (int)lm_response
.length
);
1843 lm_response
= data_blob_null
;
1845 } else if (strequal(request
, "Password")) {
1846 plaintext_password
= smb_xstrdup(parameter
);
1847 } else if (strequal(request
, "NT-Domain")) {
1848 domain
= smb_xstrdup(parameter
);
1849 } else if (strequal(request
, "Username")) {
1850 username
= smb_xstrdup(parameter
);
1851 } else if (strequal(request
, "Full-Username")) {
1852 full_username
= smb_xstrdup(parameter
);
1853 } else if (strequal(request
, "Request-User-Session-Key")) {
1854 ntlm_server_1_user_session_key
= strequal(parameter
, "Yes");
1855 } else if (strequal(request
, "Request-LanMan-Session-Key")) {
1856 ntlm_server_1_lm_session_key
= strequal(parameter
, "Yes");
1858 x_fprintf(x_stdout
, "Error: Unknown request %s\n.\n", request
);
1862 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode
,
1863 struct loadparm_context
*lp_ctx
,
1864 struct ntlm_auth_state
*state
,
1865 char *buf
, int length
, void **private2
)
1867 char *request
, *parameter
;
1868 static DATA_BLOB new_nt_pswd
;
1869 static DATA_BLOB old_nt_hash_enc
;
1870 static DATA_BLOB new_lm_pswd
;
1871 static DATA_BLOB old_lm_hash_enc
;
1872 static char *full_username
= NULL
;
1873 static char *username
= NULL
;
1874 static char *domain
= NULL
;
1875 static char *newpswd
= NULL
;
1876 static char *oldpswd
= NULL
;
1878 if (strequal(buf
, ".")) {
1879 if(newpswd
&& oldpswd
) {
1880 uchar old_nt_hash
[16];
1881 uchar old_lm_hash
[16];
1882 uchar new_nt_hash
[16];
1883 uchar new_lm_hash
[16];
1885 new_nt_pswd
= data_blob(NULL
, 516);
1886 old_nt_hash_enc
= data_blob(NULL
, 16);
1888 /* Calculate the MD4 hash (NT compatible) of the
1890 E_md4hash(oldpswd
, old_nt_hash
);
1891 E_md4hash(newpswd
, new_nt_hash
);
1893 /* E_deshash returns false for 'long'
1894 passwords (> 14 DOS chars).
1896 Therefore, don't send a buffer
1897 encrypted with the truncated hash
1898 (it could allow an even easier
1899 attack on the password)
1901 Likewise, obey the admin's restriction
1904 if (lp_client_lanman_auth() &&
1905 E_deshash(newpswd
, new_lm_hash
) &&
1906 E_deshash(oldpswd
, old_lm_hash
)) {
1907 new_lm_pswd
= data_blob(NULL
, 516);
1908 old_lm_hash_enc
= data_blob(NULL
, 16);
1909 encode_pw_buffer(new_lm_pswd
.data
, newpswd
,
1912 arcfour_crypt(new_lm_pswd
.data
, old_nt_hash
, 516);
1913 E_old_pw_hash(new_nt_hash
, old_lm_hash
,
1914 old_lm_hash_enc
.data
);
1916 new_lm_pswd
.data
= NULL
;
1917 new_lm_pswd
.length
= 0;
1918 old_lm_hash_enc
.data
= NULL
;
1919 old_lm_hash_enc
.length
= 0;
1922 encode_pw_buffer(new_nt_pswd
.data
, newpswd
,
1925 arcfour_crypt(new_nt_pswd
.data
, old_nt_hash
, 516);
1926 E_old_pw_hash(new_nt_hash
, old_nt_hash
,
1927 old_nt_hash_enc
.data
);
1930 if (!full_username
&& !username
) {
1931 x_fprintf(x_stdout
, "Error: No username supplied!\n");
1932 } else if ((!new_nt_pswd
.data
|| !old_nt_hash_enc
.data
) &&
1933 (!new_lm_pswd
.data
|| old_lm_hash_enc
.data
) ) {
1934 x_fprintf(x_stdout
, "Error: No NT or LM password "
1935 "blobs supplied!\n");
1937 char *error_string
= NULL
;
1939 if (full_username
&& !username
) {
1941 fstring fstr_domain
;
1943 if (!parse_ntlm_auth_domain_user(full_username
,
1946 /* username might be 'tainted', don't
1947 * print into our new-line
1948 * deleimianted stream */
1949 x_fprintf(x_stdout
, "Error: Could not "
1950 "parse into domain and "
1952 SAFE_FREE(username
);
1953 username
= smb_xstrdup(full_username
);
1955 SAFE_FREE(username
);
1957 username
= smb_xstrdup(fstr_user
);
1958 domain
= smb_xstrdup(fstr_domain
);
1963 if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
1970 x_fprintf(x_stdout
, "Password-Change: No\n");
1971 x_fprintf(x_stdout
, "Password-Change-Error: "
1972 "%s\n.\n", error_string
);
1974 x_fprintf(x_stdout
, "Password-Change: Yes\n");
1977 SAFE_FREE(error_string
);
1979 /* clear out the state */
1980 new_nt_pswd
= data_blob_null
;
1981 old_nt_hash_enc
= data_blob_null
;
1982 new_lm_pswd
= data_blob_null
;
1983 old_nt_hash_enc
= data_blob_null
;
1984 SAFE_FREE(full_username
);
1985 SAFE_FREE(username
);
1989 x_fprintf(x_stdout
, ".\n");
1996 /* Indicates a base64 encoded structure */
1997 parameter
= strstr_m(request
, ":: ");
1999 parameter
= strstr_m(request
, ": ");
2002 DEBUG(0, ("Parameter not found!\n"));
2003 x_fprintf(x_stdout
, "Error: Parameter not found!\n.\n");
2019 base64_decode_inplace(parameter
);
2022 if (strequal(request
, "new-nt-password-blob")) {
2023 new_nt_pswd
= strhex_to_data_blob(NULL
, parameter
);
2024 if (new_nt_pswd
.length
!= 516) {
2025 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2026 "(got %d bytes, expected 516)\n.\n",
2028 (int)new_nt_pswd
.length
);
2029 new_nt_pswd
= data_blob_null
;
2031 } else if (strequal(request
, "old-nt-hash-blob")) {
2032 old_nt_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2033 if (old_nt_hash_enc
.length
!= 16) {
2034 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2035 "(got %d bytes, expected 16)\n.\n",
2037 (int)old_nt_hash_enc
.length
);
2038 old_nt_hash_enc
= data_blob_null
;
2040 } else if (strequal(request
, "new-lm-password-blob")) {
2041 new_lm_pswd
= strhex_to_data_blob(NULL
, parameter
);
2042 if (new_lm_pswd
.length
!= 516) {
2043 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2044 "(got %d bytes, expected 516)\n.\n",
2046 (int)new_lm_pswd
.length
);
2047 new_lm_pswd
= data_blob_null
;
2050 else if (strequal(request
, "old-lm-hash-blob")) {
2051 old_lm_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2052 if (old_lm_hash_enc
.length
!= 16)
2054 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2055 "(got %d bytes, expected 16)\n.\n",
2057 (int)old_lm_hash_enc
.length
);
2058 old_lm_hash_enc
= data_blob_null
;
2060 } else if (strequal(request
, "nt-domain")) {
2061 domain
= smb_xstrdup(parameter
);
2062 } else if(strequal(request
, "username")) {
2063 username
= smb_xstrdup(parameter
);
2064 } else if(strequal(request
, "full-username")) {
2065 username
= smb_xstrdup(parameter
);
2066 } else if(strequal(request
, "new-password")) {
2067 newpswd
= smb_xstrdup(parameter
);
2068 } else if (strequal(request
, "old-password")) {
2069 oldpswd
= smb_xstrdup(parameter
);
2071 x_fprintf(x_stdout
, "Error: Unknown request %s\n.\n", request
);
2075 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode
,
2076 struct loadparm_context
*lp_ctx
,
2077 struct ntlm_auth_state
*state
,
2078 stdio_helper_function fn
, void **private2
)
2081 char tmp
[INITIAL_BUFFER_SIZE
+1];
2082 int length
, buf_size
= 0;
2085 buf
= talloc_strdup(state
->mem_ctx
, "");
2087 DEBUG(0, ("Failed to allocate input buffer.\n"));
2088 x_fprintf(x_stderr
, "ERR\n");
2094 /* this is not a typo - x_fgets doesn't work too well under
2096 if (fgets(tmp
, sizeof(tmp
)-1, stdin
) == NULL
) {
2097 if (ferror(stdin
)) {
2098 DEBUG(1, ("fgets() failed! dying..... errno=%d "
2099 "(%s)\n", ferror(stdin
),
2100 strerror(ferror(stdin
))));
2107 buf
= talloc_strdup_append_buffer(buf
, tmp
);
2108 buf_size
+= INITIAL_BUFFER_SIZE
;
2110 if (buf_size
> MAX_BUFFER_SIZE
) {
2111 DEBUG(2, ("Oversized message\n"));
2112 x_fprintf(x_stderr
, "ERR\n");
2117 c
= strchr(buf
, '\n');
2118 } while (c
== NULL
);
2123 DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf
,length
));
2125 if (buf
[0] == '\0') {
2126 DEBUG(2, ("Invalid Request\n"));
2127 x_fprintf(x_stderr
, "ERR\n");
2132 fn(stdio_helper_mode
, lp_ctx
, state
, buf
, length
, private2
);
2137 static void squid_stream(enum stdio_helper_mode stdio_mode
,
2138 struct loadparm_context
*lp_ctx
,
2139 stdio_helper_function fn
) {
2140 TALLOC_CTX
*mem_ctx
;
2141 struct ntlm_auth_state
*state
;
2143 /* initialize FDescs */
2144 x_setbuf(x_stdout
, NULL
);
2145 x_setbuf(x_stderr
, NULL
);
2147 mem_ctx
= talloc_init("ntlm_auth");
2149 DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
2150 x_fprintf(x_stderr
, "ERR\n");
2154 state
= talloc_zero(mem_ctx
, struct ntlm_auth_state
);
2156 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
2157 x_fprintf(x_stderr
, "ERR\n");
2161 state
->mem_ctx
= mem_ctx
;
2162 state
->helper_mode
= stdio_mode
;
2165 TALLOC_CTX
*frame
= talloc_stackframe();
2166 manage_squid_request(stdio_mode
, lp_ctx
, state
, fn
, NULL
);
2172 /* Authenticate a user with a challenge/response */
2174 static bool check_auth_crap(void)
2179 char user_session_key
[16];
2181 char *hex_user_session_key
;
2183 static uint8_t zeros
[16];
2185 x_setbuf(x_stdout
, NULL
);
2188 flags
|= WBFLAG_PAM_LMKEY
;
2190 if (request_user_session_key
)
2191 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
2193 flags
|= WBFLAG_PAM_NT_STATUS_SQUASH
;
2195 nt_status
= contact_winbind_auth_crap(opt_username
, opt_domain
,
2201 (unsigned char *)lm_key
,
2202 (unsigned char *)user_session_key
,
2203 &error_string
, NULL
);
2205 if (!NT_STATUS_IS_OK(nt_status
)) {
2206 x_fprintf(x_stdout
, "%s (0x%x)\n",
2208 NT_STATUS_V(nt_status
));
2209 SAFE_FREE(error_string
);
2214 && (memcmp(zeros
, lm_key
,
2215 sizeof(lm_key
)) != 0)) {
2216 hex_lm_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)lm_key
,
2218 x_fprintf(x_stdout
, "LM_KEY: %s\n", hex_lm_key
);
2219 TALLOC_FREE(hex_lm_key
);
2221 if (request_user_session_key
2222 && (memcmp(zeros
, user_session_key
,
2223 sizeof(user_session_key
)) != 0)) {
2224 hex_user_session_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)user_session_key
,
2225 sizeof(user_session_key
));
2226 x_fprintf(x_stdout
, "NT_KEY: %s\n", hex_user_session_key
);
2227 TALLOC_FREE(hex_user_session_key
);
2236 OPT_USERNAME
= 1000,
2245 OPT_USER_SESSION_KEY
,
2247 OPT_REQUIRE_MEMBERSHIP
,
2248 OPT_USE_CACHED_CREDS
,
2250 OPT_PAM_WINBIND_CONF
,
2252 OPT_TARGET_HOSTNAME
,
2256 int main(int argc
, const char **argv
)
2258 TALLOC_CTX
*frame
= talloc_stackframe();
2260 static const char *helper_protocol
;
2261 static int diagnostics
;
2263 static const char *hex_challenge
;
2264 static const char *hex_lm_response
;
2265 static const char *hex_nt_response
;
2266 struct loadparm_context
*lp_ctx
;
2269 /* NOTE: DO NOT change this interface without considering the implications!
2270 This is an external interface, which other programs will use to interact
2274 /* We do not use single-letter command abbreviations, because they harm future
2275 interface stability. */
2277 struct poptOption long_options
[] = {
2279 { "helper-protocol", 0, POPT_ARG_STRING
, &helper_protocol
, OPT_DOMAIN
, "operate as a stdio-based helper", "helper protocol to use"},
2280 { "username", 0, POPT_ARG_STRING
, &opt_username
, OPT_USERNAME
, "username"},
2281 { "domain", 0, POPT_ARG_STRING
, &opt_domain
, OPT_DOMAIN
, "domain name"},
2282 { "workstation", 0, POPT_ARG_STRING
, &opt_workstation
, OPT_WORKSTATION
, "workstation"},
2283 { "challenge", 0, POPT_ARG_STRING
, &hex_challenge
, OPT_CHALLENGE
, "challenge (HEX encoded)"},
2284 { "lm-response", 0, POPT_ARG_STRING
, &hex_lm_response
, OPT_LM
, "LM Response to the challenge (HEX encoded)"},
2285 { "nt-response", 0, POPT_ARG_STRING
, &hex_nt_response
, OPT_NT
, "NT or NTLMv2 Response to the challenge (HEX encoded)"},
2286 { "password", 0, POPT_ARG_STRING
, &opt_password
, OPT_PASSWORD
, "User's plaintext password"},
2287 { "request-lm-key", 0, POPT_ARG_NONE
, &request_lm_key
, OPT_LM_KEY
, "Retrieve LM session key"},
2288 { "request-nt-key", 0, POPT_ARG_NONE
, &request_user_session_key
, OPT_USER_SESSION_KEY
, "Retrieve User (NT) session key"},
2289 { "use-cached-creds", 0, POPT_ARG_NONE
, &use_cached_creds
, OPT_USE_CACHED_CREDS
, "Use cached credentials if no password is given"},
2290 { "allow-mschapv2", 0, POPT_ARG_NONE
, &opt_allow_mschapv2
, OPT_ALLOW_MSCHAPV2
, "Explicitly allow MSCHAPv2" },
2291 { "offline-logon", 0, POPT_ARG_NONE
, &offline_logon
,
2293 "Use cached passwords when DC is offline"},
2294 { "diagnostics", 0, POPT_ARG_NONE
, &diagnostics
,
2296 "Perform diagnostics on the authentication chain"},
2297 { "require-membership-of", 0, POPT_ARG_STRING
, &require_membership_of
, OPT_REQUIRE_MEMBERSHIP
, "Require that a user be a member of this group (either name or SID) for authentication to succeed" },
2298 { "pam-winbind-conf", 0, POPT_ARG_STRING
, &opt_pam_winbind_conf
, OPT_PAM_WINBIND_CONF
, "Require that request must set WBFLAG_PAM_CONTACT_TRUSTDOM when krb5 auth is required" },
2299 { "target-service", 0, POPT_ARG_STRING
, &opt_target_service
, OPT_TARGET_SERVICE
, "Target service (eg http)" },
2300 { "target-hostname", 0, POPT_ARG_STRING
, &opt_target_hostname
, OPT_TARGET_HOSTNAME
, "Target hostname" },
2301 POPT_COMMON_CONFIGFILE
2307 /* Samba client initialisation */
2310 setup_logging("ntlm_auth", DEBUG_STDERR
);
2315 pc
= poptGetContext("ntlm_auth", argc
, argv
, long_options
, 0);
2317 /* Parse command line options */
2320 poptPrintHelp(pc
, stderr
, 0);
2324 while((opt
= poptGetNextOpt(pc
)) != -1) {
2325 /* Get generic config options like --configfile */
2328 poptFreeContext(pc
);
2330 if (!lp_load_global(get_dyn_CONFIGFILE())) {
2331 d_fprintf(stderr
, "ntlm_auth: error opening config file %s. Error was %s\n",
2332 get_dyn_CONFIGFILE(), strerror(errno
));
2336 pc
= poptGetContext(NULL
, argc
, (const char **)argv
, long_options
,
2337 POPT_CONTEXT_KEEP_FIRST
);
2339 while((opt
= poptGetNextOpt(pc
)) != -1) {
2342 opt_challenge
= strhex_to_data_blob(NULL
, hex_challenge
);
2343 if (opt_challenge
.length
!= 8) {
2344 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2346 (int)opt_challenge
.length
);
2351 opt_lm_response
= strhex_to_data_blob(NULL
, hex_lm_response
);
2352 if (opt_lm_response
.length
!= 24) {
2353 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2355 (int)opt_lm_response
.length
);
2361 opt_nt_response
= strhex_to_data_blob(NULL
, hex_nt_response
);
2362 if (opt_nt_response
.length
< 24) {
2363 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2365 (int)opt_nt_response
.length
);
2370 case OPT_REQUIRE_MEMBERSHIP
:
2371 if (strncasecmp_m("S-", require_membership_of
, 2) == 0) {
2372 require_membership_of_sid
= require_membership_of
;
2379 char *domain
= SMB_STRDUP(opt_username
);
2380 char *p
= strchr_m(domain
, *lp_winbind_separator());
2384 if (opt_domain
&& !strequal(opt_domain
, domain
)) {
2385 x_fprintf(x_stderr
, "Domain specified in username (%s) "
2386 "doesn't match specified domain (%s)!\n\n",
2387 domain
, opt_domain
);
2388 poptPrintHelp(pc
, stderr
, 0);
2391 opt_domain
= domain
;
2397 /* Note: if opt_domain is "" then send no domain */
2398 if (opt_domain
== NULL
) {
2399 opt_domain
= get_winbind_domain();
2402 if (opt_workstation
== NULL
) {
2403 opt_workstation
= "";
2406 lp_ctx
= loadparm_init_s3(NULL
, loadparm_s3_helpers());
2407 if (lp_ctx
== NULL
) {
2408 x_fprintf(x_stderr
, "loadparm_init_s3() failed!\n");
2412 if (helper_protocol
) {
2414 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2415 if (strcmp(helper_protocol
, stdio_helper_protocols
[i
].name
) == 0) {
2416 squid_stream(stdio_helper_protocols
[i
].mode
, lp_ctx
, stdio_helper_protocols
[i
].fn
);
2420 x_fprintf(x_stderr
, "unknown helper protocol [%s]\n\nValid helper protools:\n\n", helper_protocol
);
2422 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2423 x_fprintf(x_stderr
, "%s\n", stdio_helper_protocols
[i
].name
);
2429 if (!opt_username
|| !*opt_username
) {
2430 x_fprintf(x_stderr
, "username must be specified!\n\n");
2431 poptPrintHelp(pc
, stderr
, 0);
2435 if (opt_challenge
.length
) {
2436 if (!check_auth_crap()) {
2442 if (!opt_password
) {
2443 char pwd
[256] = {0};
2446 rc
= samba_getpass("Password: ", pwd
, sizeof(pwd
), false, false);
2448 opt_password
= SMB_STRDUP(pwd
);
2453 if (!diagnose_ntlm_auth()) {
2459 fstr_sprintf(user
, "%s%c%s", opt_domain
, winbind_separator(), opt_username
);
2460 if (!check_plaintext_auth(user
, opt_password
, True
)) {
2467 poptFreeContext(pc
);