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 talloc_unlink(tmp_ctx
, lp_ctx
);
1219 talloc_unlink(tmp_ctx
, server_credentials
);
1220 talloc_unlink(tmp_ctx
, gensec_settings
);
1221 talloc_unlink(tmp_ctx
, auth4_context
);
1223 *gensec_security_out
= talloc_steal(mem_ctx
, gensec_security
);
1224 TALLOC_FREE(tmp_ctx
);
1225 return NT_STATUS_OK
;
1228 static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode
,
1229 struct loadparm_context
*lp_ctx
,
1230 struct ntlm_auth_state
*state
,
1231 char *buf
, int length
, void **private2
)
1233 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1237 static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode
,
1238 struct loadparm_context
*lp_ctx
,
1239 struct ntlm_auth_state
*state
,
1240 char *buf
, int length
, void **private2
)
1245 pass
=(char *)memchr(buf
,' ',length
);
1247 DEBUG(2, ("Password not found. Denying access\n"));
1248 x_fprintf(x_stdout
, "ERR\n");
1254 if (state
->helper_mode
== SQUID_2_5_BASIC
) {
1255 rfc1738_unescape(user
);
1256 rfc1738_unescape(pass
);
1259 if (check_plaintext_auth(user
, pass
, False
)) {
1260 x_fprintf(x_stdout
, "OK\n");
1262 x_fprintf(x_stdout
, "ERR\n");
1266 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode
,
1267 struct loadparm_context
*lp_ctx
,
1268 char *buf
, int length
, void **private1
)
1271 DATA_BLOB out
= data_blob(NULL
, 0);
1272 char *out_base64
= NULL
;
1273 const char *reply_arg
= NULL
;
1274 struct gensec_ntlm_state
{
1275 struct gensec_security
*gensec_state
;
1276 const char *set_password
;
1278 struct gensec_ntlm_state
*state
;
1282 const char *reply_code
;
1283 struct cli_credentials
*creds
;
1285 static char *want_feature_list
= NULL
;
1286 static DATA_BLOB session_key
;
1288 TALLOC_CTX
*mem_ctx
;
1291 state
= (struct gensec_ntlm_state
*)*private1
;
1293 state
= talloc_zero(NULL
, struct gensec_ntlm_state
);
1295 x_fprintf(x_stdout
, "BH No Memory\n");
1300 state
->set_password
= opt_password
;
1304 if (strlen(buf
) < 2) {
1305 DEBUG(1, ("query [%s] invalid", buf
));
1306 x_fprintf(x_stdout
, "BH Query invalid\n");
1310 if (strlen(buf
) > 3) {
1311 if(strncmp(buf
, "SF ", 3) == 0) {
1312 DEBUG(10, ("Setting flags to negotiate\n"));
1313 talloc_free(want_feature_list
);
1314 want_feature_list
= talloc_strndup(state
, buf
+3, strlen(buf
)-3);
1315 x_fprintf(x_stdout
, "OK\n");
1318 in
= base64_decode_data_blob(buf
+ 3);
1320 in
= data_blob(NULL
, 0);
1323 if (strncmp(buf
, "YR", 2) == 0) {
1324 if (state
->gensec_state
) {
1325 talloc_free(state
->gensec_state
);
1326 state
->gensec_state
= NULL
;
1328 } else if ( (strncmp(buf
, "OK", 2) == 0)) {
1329 /* Just return BH, like ntlm_auth from Samba 3 does. */
1330 x_fprintf(x_stdout
, "BH Command expected\n");
1331 data_blob_free(&in
);
1333 } else if ( (strncmp(buf
, "TT ", 3) != 0) &&
1334 (strncmp(buf
, "KK ", 3) != 0) &&
1335 (strncmp(buf
, "AF ", 3) != 0) &&
1336 (strncmp(buf
, "NA ", 3) != 0) &&
1337 (strncmp(buf
, "UG", 2) != 0) &&
1338 (strncmp(buf
, "PW ", 3) != 0) &&
1339 (strncmp(buf
, "GK", 2) != 0) &&
1340 (strncmp(buf
, "GF", 2) != 0)) {
1341 DEBUG(1, ("SPNEGO request [%s] invalid prefix\n", buf
));
1342 x_fprintf(x_stdout
, "BH SPNEGO request invalid prefix\n");
1343 data_blob_free(&in
);
1347 mem_ctx
= talloc_named(NULL
, 0, "manage_gensec_request internal mem_ctx");
1350 if (!(state
->gensec_state
)) {
1351 switch (stdio_helper_mode
) {
1352 case GSS_SPNEGO_CLIENT
:
1354 * cached credentials are only supported by
1355 * NTLMSSP_CLIENT_1 for now.
1357 use_cached_creds
= false;
1359 case NTLMSSP_CLIENT_1
:
1360 /* setup the client side */
1362 if (state
->set_password
!= NULL
) {
1363 use_cached_creds
= false;
1366 if (use_cached_creds
) {
1367 struct wbcCredentialCacheParams params
;
1368 struct wbcCredentialCacheInfo
*info
= NULL
;
1369 struct wbcAuthErrorInfo
*error
= NULL
;
1372 params
.account_name
= opt_username
;
1373 params
.domain_name
= opt_domain
;
1374 params
.level
= WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP
;
1375 params
.num_blobs
= 0;
1376 params
.blobs
= NULL
;
1378 wbc_status
= wbcCredentialCache(¶ms
, &info
,
1380 wbcFreeMemory(error
);
1381 if (!WBC_ERROR_IS_OK(wbc_status
)) {
1382 use_cached_creds
= false;
1384 wbcFreeMemory(info
);
1387 nt_status
= ntlm_auth_prepare_gensec_client(state
, lp_ctx
,
1388 &state
->gensec_state
);
1389 if (!NT_STATUS_IS_OK(nt_status
)) {
1390 x_fprintf(x_stdout
, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status
));
1391 talloc_free(mem_ctx
);
1395 creds
= cli_credentials_init(state
->gensec_state
);
1396 cli_credentials_set_conf(creds
, lp_ctx
);
1398 cli_credentials_set_username(creds
, opt_username
, CRED_SPECIFIED
);
1401 cli_credentials_set_domain(creds
, opt_domain
, CRED_SPECIFIED
);
1403 if (use_cached_creds
) {
1404 gensec_want_feature(state
->gensec_state
,
1405 GENSEC_FEATURE_NTLM_CCACHE
);
1406 } else if (state
->set_password
) {
1407 cli_credentials_set_password(creds
, state
->set_password
, CRED_SPECIFIED
);
1409 cli_credentials_set_password_callback(creds
, get_password
);
1411 if (opt_workstation
) {
1412 cli_credentials_set_workstation(creds
, opt_workstation
, CRED_SPECIFIED
);
1415 gensec_set_credentials(state
->gensec_state
, creds
);
1418 case GSS_SPNEGO_SERVER
:
1419 case SQUID_2_5_NTLMSSP
:
1421 nt_status
= ntlm_auth_prepare_gensec_server(state
, lp_ctx
,
1422 &state
->gensec_state
);
1423 if (!NT_STATUS_IS_OK(nt_status
)) {
1424 x_fprintf(x_stdout
, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status
));
1425 talloc_free(mem_ctx
);
1431 talloc_free(mem_ctx
);
1435 gensec_want_feature_list(state
->gensec_state
, want_feature_list
);
1437 switch (stdio_helper_mode
) {
1438 case GSS_SPNEGO_CLIENT
:
1439 case GSS_SPNEGO_SERVER
:
1440 nt_status
= gensec_start_mech_by_oid(state
->gensec_state
, GENSEC_OID_SPNEGO
);
1445 case NTLMSSP_CLIENT_1
:
1450 case SQUID_2_5_NTLMSSP
:
1451 nt_status
= gensec_start_mech_by_oid(state
->gensec_state
, GENSEC_OID_NTLMSSP
);
1454 talloc_free(mem_ctx
);
1458 if (!NT_STATUS_IS_OK(nt_status
)) {
1459 DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status
)));
1460 x_fprintf(x_stdout
, "BH GENSEC mech failed to start\n");
1461 talloc_free(mem_ctx
);
1469 if (strncmp(buf
, "PW ", 3) == 0) {
1470 state
->set_password
= talloc_strndup(state
,
1471 (const char *)in
.data
,
1474 cli_credentials_set_password(gensec_get_credentials(state
->gensec_state
),
1475 state
->set_password
,
1477 x_fprintf(x_stdout
, "OK\n");
1478 data_blob_free(&in
);
1479 talloc_free(mem_ctx
);
1483 if (strncmp(buf
, "GK", 2) == 0) {
1485 DEBUG(10, ("Requested session key\n"));
1486 nt_status
= gensec_session_key(state
->gensec_state
, mem_ctx
, &session_key
);
1487 if(!NT_STATUS_IS_OK(nt_status
)) {
1488 DEBUG(1, ("gensec_session_key failed: %s\n", nt_errstr(nt_status
)));
1489 x_fprintf(x_stdout
, "BH No session key\n");
1490 talloc_free(mem_ctx
);
1493 base64_key
= base64_encode_data_blob(state
, session_key
);
1494 SMB_ASSERT(base64_key
!= NULL
);
1495 x_fprintf(x_stdout
, "GK %s\n", base64_key
);
1496 talloc_free(base64_key
);
1498 talloc_free(mem_ctx
);
1502 if (strncmp(buf
, "GF", 2) == 0) {
1505 DEBUG(10, ("Requested negotiated NTLMSSP feature flags\n"));
1507 neg_flags
= gensec_ntlmssp_neg_flags(state
->gensec_state
);
1508 if (neg_flags
== 0) {
1509 x_fprintf(x_stdout
, "BH\n");
1513 x_fprintf(x_stdout
, "GF 0x%08x\n", neg_flags
);
1517 nt_status
= gensec_update(state
->gensec_state
, mem_ctx
, in
, &out
);
1519 /* don't leak 'bad password'/'no such user' info to the network client */
1520 nt_status
= nt_status_squash(nt_status
);
1523 out_base64
= base64_encode_data_blob(mem_ctx
, out
);
1524 SMB_ASSERT(out_base64
!= NULL
);
1529 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1531 if (first
&& state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1533 } else if (state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1535 } else if (state
->gensec_state
->gensec_role
== GENSEC_SERVER
) {
1542 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCESS_DENIED
)) {
1543 reply_code
= "BH NT_STATUS_ACCESS_DENIED";
1544 reply_arg
= nt_errstr(nt_status
);
1545 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1546 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_UNSUCCESSFUL
)) {
1547 reply_code
= "BH NT_STATUS_UNSUCCESSFUL";
1548 reply_arg
= nt_errstr(nt_status
);
1549 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1550 } else if (!NT_STATUS_IS_OK(nt_status
)) {
1552 reply_arg
= nt_errstr(nt_status
);
1553 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1554 } else if /* OK */ (state
->gensec_state
->gensec_role
== GENSEC_SERVER
) {
1555 struct auth_session_info
*session_info
;
1557 nt_status
= gensec_session_info(state
->gensec_state
, mem_ctx
, &session_info
);
1558 if (!NT_STATUS_IS_OK(nt_status
)) {
1559 reply_code
= "BH Failed to retrive session info";
1560 reply_arg
= nt_errstr(nt_status
);
1561 DEBUG(1, ("GENSEC failed to retrieve the session info: %s\n", nt_errstr(nt_status
)));
1565 reply_arg
= talloc_strdup(state
->gensec_state
, session_info
->unix_info
->unix_name
);
1566 if (reply_arg
== NULL
) {
1567 reply_code
= "BH out of memory";
1568 reply_arg
= nt_errstr(NT_STATUS_NO_MEMORY
);
1570 talloc_free(session_info
);
1572 } else if (state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1574 reply_arg
= out_base64
;
1579 switch (stdio_helper_mode
) {
1580 case GSS_SPNEGO_SERVER
:
1581 x_fprintf(x_stdout
, "%s %s %s\n", reply_code
,
1582 out_base64
? out_base64
: "*",
1583 reply_arg
? reply_arg
: "*");
1587 x_fprintf(x_stdout
, "%s %s\n", reply_code
, out_base64
);
1588 } else if (reply_arg
) {
1589 x_fprintf(x_stdout
, "%s %s\n", reply_code
, reply_arg
);
1591 x_fprintf(x_stdout
, "%s\n", reply_code
);
1595 talloc_free(mem_ctx
);
1599 static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode
,
1600 struct loadparm_context
*lp_ctx
,
1601 struct ntlm_auth_state
*state
,
1602 char *buf
, int length
, void **private2
)
1604 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1608 static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode
,
1609 struct loadparm_context
*lp_ctx
,
1610 struct ntlm_auth_state
*state
,
1611 char *buf
, int length
, void **private2
)
1613 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1617 static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode
,
1618 struct loadparm_context
*lp_ctx
,
1619 struct ntlm_auth_state
*state
,
1620 char *buf
, int length
, void **private2
)
1622 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1626 static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode
,
1627 struct loadparm_context
*lp_ctx
,
1628 struct ntlm_auth_state
*state
,
1629 char *buf
, int length
, void **private2
)
1631 char *request
, *parameter
;
1632 static DATA_BLOB challenge
;
1633 static DATA_BLOB lm_response
;
1634 static DATA_BLOB nt_response
;
1635 static char *full_username
;
1636 static char *username
;
1637 static char *domain
;
1638 static char *plaintext_password
;
1639 static bool ntlm_server_1_user_session_key
;
1640 static bool ntlm_server_1_lm_session_key
;
1642 if (strequal(buf
, ".")) {
1643 if (!full_username
&& !username
) {
1644 x_fprintf(x_stdout
, "Error: No username supplied!\n");
1645 } else if (plaintext_password
) {
1646 /* handle this request as plaintext */
1647 if (!full_username
) {
1648 if (asprintf(&full_username
, "%s%c%s", domain
, winbind_separator(), username
) == -1) {
1649 x_fprintf(x_stdout
, "Error: Out of memory in asprintf!\n.\n");
1653 if (check_plaintext_auth(full_username
, plaintext_password
, False
)) {
1654 x_fprintf(x_stdout
, "Authenticated: Yes\n");
1656 x_fprintf(x_stdout
, "Authenticated: No\n");
1658 } else if (!lm_response
.data
&& !nt_response
.data
) {
1659 x_fprintf(x_stdout
, "Error: No password supplied!\n");
1660 } else if (!challenge
.data
) {
1661 x_fprintf(x_stdout
, "Error: No lanman-challenge supplied!\n");
1663 char *error_string
= NULL
;
1665 uchar user_session_key
[16];
1668 if (full_username
&& !username
) {
1670 fstring fstr_domain
;
1672 if (!parse_ntlm_auth_domain_user(full_username
, fstr_user
, fstr_domain
)) {
1673 /* username might be 'tainted', don't print into our new-line deleimianted stream */
1674 x_fprintf(x_stdout
, "Error: Could not parse into domain and username\n");
1676 SAFE_FREE(username
);
1678 username
= smb_xstrdup(fstr_user
);
1679 domain
= smb_xstrdup(fstr_domain
);
1683 DATA_BLOB nt_session_key
, lm_session_key
;
1684 struct samr_Password lm_pw
, nt_pw
;
1685 TALLOC_CTX
*mem_ctx
= talloc_new(NULL
);
1686 ZERO_STRUCT(user_session_key
);
1687 ZERO_STRUCT(lm_key
);
1689 nt_lm_owf_gen (opt_password
, nt_pw
.hash
, lm_pw
.hash
);
1690 nt_status
= ntlm_password_check(mem_ctx
,
1701 error_string
= smb_xstrdup(get_friendly_nt_error_msg(nt_status
));
1702 if (ntlm_server_1_user_session_key
) {
1703 if (nt_session_key
.length
== sizeof(user_session_key
)) {
1704 memcpy(user_session_key
,
1705 nt_session_key
.data
,
1706 sizeof(user_session_key
));
1709 if (ntlm_server_1_lm_session_key
) {
1710 if (lm_session_key
.length
== sizeof(lm_key
)) {
1712 lm_session_key
.data
,
1716 TALLOC_FREE(mem_ctx
);
1720 domain
= smb_xstrdup(get_winbind_domain());
1723 if (ntlm_server_1_lm_session_key
)
1724 flags
|= WBFLAG_PAM_LMKEY
;
1726 if (ntlm_server_1_user_session_key
)
1727 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
1729 nt_status
= contact_winbind_auth_crap(username
,
1742 if (!NT_STATUS_IS_OK(nt_status
)) {
1743 x_fprintf(x_stdout
, "Authenticated: No\n");
1744 x_fprintf(x_stdout
, "Authentication-Error: %s\n.\n", error_string
);
1746 static char zeros
[16];
1748 char *hex_user_session_key
;
1750 x_fprintf(x_stdout
, "Authenticated: Yes\n");
1752 if (ntlm_server_1_lm_session_key
1753 && (memcmp(zeros
, lm_key
,
1754 sizeof(lm_key
)) != 0)) {
1755 hex_lm_key
= hex_encode_talloc(NULL
,
1756 (const unsigned char *)lm_key
,
1758 x_fprintf(x_stdout
, "LANMAN-Session-Key: %s\n", hex_lm_key
);
1759 TALLOC_FREE(hex_lm_key
);
1762 if (ntlm_server_1_user_session_key
1763 && (memcmp(zeros
, user_session_key
,
1764 sizeof(user_session_key
)) != 0)) {
1765 hex_user_session_key
= hex_encode_talloc(NULL
,
1766 (const unsigned char *)user_session_key
,
1767 sizeof(user_session_key
));
1768 x_fprintf(x_stdout
, "User-Session-Key: %s\n", hex_user_session_key
);
1769 TALLOC_FREE(hex_user_session_key
);
1772 SAFE_FREE(error_string
);
1774 /* clear out the state */
1775 challenge
= data_blob_null
;
1776 nt_response
= data_blob_null
;
1777 lm_response
= data_blob_null
;
1778 SAFE_FREE(full_username
);
1779 SAFE_FREE(username
);
1781 SAFE_FREE(plaintext_password
);
1782 ntlm_server_1_user_session_key
= False
;
1783 ntlm_server_1_lm_session_key
= False
;
1784 x_fprintf(x_stdout
, ".\n");
1791 /* Indicates a base64 encoded structure */
1792 parameter
= strstr_m(request
, ":: ");
1794 parameter
= strstr_m(request
, ": ");
1797 DEBUG(0, ("Parameter not found!\n"));
1798 x_fprintf(x_stdout
, "Error: Parameter not found!\n.\n");
1815 base64_decode_inplace(parameter
);
1818 if (strequal(request
, "LANMAN-Challenge")) {
1819 challenge
= strhex_to_data_blob(NULL
, parameter
);
1820 if (challenge
.length
!= 8) {
1821 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (got %d bytes, expected 8)\n.\n",
1823 (int)challenge
.length
);
1824 challenge
= data_blob_null
;
1826 } else if (strequal(request
, "NT-Response")) {
1827 nt_response
= strhex_to_data_blob(NULL
, parameter
);
1828 if (nt_response
.length
< 24) {
1829 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (only got %d bytes, needed at least 24)\n.\n",
1831 (int)nt_response
.length
);
1832 nt_response
= data_blob_null
;
1834 } else if (strequal(request
, "LANMAN-Response")) {
1835 lm_response
= strhex_to_data_blob(NULL
, parameter
);
1836 if (lm_response
.length
!= 24) {
1837 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (got %d bytes, expected 24)\n.\n",
1839 (int)lm_response
.length
);
1840 lm_response
= data_blob_null
;
1842 } else if (strequal(request
, "Password")) {
1843 plaintext_password
= smb_xstrdup(parameter
);
1844 } else if (strequal(request
, "NT-Domain")) {
1845 domain
= smb_xstrdup(parameter
);
1846 } else if (strequal(request
, "Username")) {
1847 username
= smb_xstrdup(parameter
);
1848 } else if (strequal(request
, "Full-Username")) {
1849 full_username
= smb_xstrdup(parameter
);
1850 } else if (strequal(request
, "Request-User-Session-Key")) {
1851 ntlm_server_1_user_session_key
= strequal(parameter
, "Yes");
1852 } else if (strequal(request
, "Request-LanMan-Session-Key")) {
1853 ntlm_server_1_lm_session_key
= strequal(parameter
, "Yes");
1855 x_fprintf(x_stdout
, "Error: Unknown request %s\n.\n", request
);
1859 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode
,
1860 struct loadparm_context
*lp_ctx
,
1861 struct ntlm_auth_state
*state
,
1862 char *buf
, int length
, void **private2
)
1864 char *request
, *parameter
;
1865 static DATA_BLOB new_nt_pswd
;
1866 static DATA_BLOB old_nt_hash_enc
;
1867 static DATA_BLOB new_lm_pswd
;
1868 static DATA_BLOB old_lm_hash_enc
;
1869 static char *full_username
= NULL
;
1870 static char *username
= NULL
;
1871 static char *domain
= NULL
;
1872 static char *newpswd
= NULL
;
1873 static char *oldpswd
= NULL
;
1875 if (strequal(buf
, ".")) {
1876 if(newpswd
&& oldpswd
) {
1877 uchar old_nt_hash
[16];
1878 uchar old_lm_hash
[16];
1879 uchar new_nt_hash
[16];
1880 uchar new_lm_hash
[16];
1882 new_nt_pswd
= data_blob(NULL
, 516);
1883 old_nt_hash_enc
= data_blob(NULL
, 16);
1885 /* Calculate the MD4 hash (NT compatible) of the
1887 E_md4hash(oldpswd
, old_nt_hash
);
1888 E_md4hash(newpswd
, new_nt_hash
);
1890 /* E_deshash returns false for 'long'
1891 passwords (> 14 DOS chars).
1893 Therefore, don't send a buffer
1894 encrypted with the truncated hash
1895 (it could allow an even easier
1896 attack on the password)
1898 Likewise, obey the admin's restriction
1901 if (lp_client_lanman_auth() &&
1902 E_deshash(newpswd
, new_lm_hash
) &&
1903 E_deshash(oldpswd
, old_lm_hash
)) {
1904 new_lm_pswd
= data_blob(NULL
, 516);
1905 old_lm_hash_enc
= data_blob(NULL
, 16);
1906 encode_pw_buffer(new_lm_pswd
.data
, newpswd
,
1909 arcfour_crypt(new_lm_pswd
.data
, old_nt_hash
, 516);
1910 E_old_pw_hash(new_nt_hash
, old_lm_hash
,
1911 old_lm_hash_enc
.data
);
1913 new_lm_pswd
.data
= NULL
;
1914 new_lm_pswd
.length
= 0;
1915 old_lm_hash_enc
.data
= NULL
;
1916 old_lm_hash_enc
.length
= 0;
1919 encode_pw_buffer(new_nt_pswd
.data
, newpswd
,
1922 arcfour_crypt(new_nt_pswd
.data
, old_nt_hash
, 516);
1923 E_old_pw_hash(new_nt_hash
, old_nt_hash
,
1924 old_nt_hash_enc
.data
);
1927 if (!full_username
&& !username
) {
1928 x_fprintf(x_stdout
, "Error: No username supplied!\n");
1929 } else if ((!new_nt_pswd
.data
|| !old_nt_hash_enc
.data
) &&
1930 (!new_lm_pswd
.data
|| old_lm_hash_enc
.data
) ) {
1931 x_fprintf(x_stdout
, "Error: No NT or LM password "
1932 "blobs supplied!\n");
1934 char *error_string
= NULL
;
1936 if (full_username
&& !username
) {
1938 fstring fstr_domain
;
1940 if (!parse_ntlm_auth_domain_user(full_username
,
1943 /* username might be 'tainted', don't
1944 * print into our new-line
1945 * deleimianted stream */
1946 x_fprintf(x_stdout
, "Error: Could not "
1947 "parse into domain and "
1949 SAFE_FREE(username
);
1950 username
= smb_xstrdup(full_username
);
1952 SAFE_FREE(username
);
1954 username
= smb_xstrdup(fstr_user
);
1955 domain
= smb_xstrdup(fstr_domain
);
1960 if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
1967 x_fprintf(x_stdout
, "Password-Change: No\n");
1968 x_fprintf(x_stdout
, "Password-Change-Error: "
1969 "%s\n.\n", error_string
);
1971 x_fprintf(x_stdout
, "Password-Change: Yes\n");
1974 SAFE_FREE(error_string
);
1976 /* clear out the state */
1977 new_nt_pswd
= data_blob_null
;
1978 old_nt_hash_enc
= data_blob_null
;
1979 new_lm_pswd
= data_blob_null
;
1980 old_nt_hash_enc
= data_blob_null
;
1981 SAFE_FREE(full_username
);
1982 SAFE_FREE(username
);
1986 x_fprintf(x_stdout
, ".\n");
1993 /* Indicates a base64 encoded structure */
1994 parameter
= strstr_m(request
, ":: ");
1996 parameter
= strstr_m(request
, ": ");
1999 DEBUG(0, ("Parameter not found!\n"));
2000 x_fprintf(x_stdout
, "Error: Parameter not found!\n.\n");
2016 base64_decode_inplace(parameter
);
2019 if (strequal(request
, "new-nt-password-blob")) {
2020 new_nt_pswd
= strhex_to_data_blob(NULL
, parameter
);
2021 if (new_nt_pswd
.length
!= 516) {
2022 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2023 "(got %d bytes, expected 516)\n.\n",
2025 (int)new_nt_pswd
.length
);
2026 new_nt_pswd
= data_blob_null
;
2028 } else if (strequal(request
, "old-nt-hash-blob")) {
2029 old_nt_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2030 if (old_nt_hash_enc
.length
!= 16) {
2031 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2032 "(got %d bytes, expected 16)\n.\n",
2034 (int)old_nt_hash_enc
.length
);
2035 old_nt_hash_enc
= data_blob_null
;
2037 } else if (strequal(request
, "new-lm-password-blob")) {
2038 new_lm_pswd
= strhex_to_data_blob(NULL
, parameter
);
2039 if (new_lm_pswd
.length
!= 516) {
2040 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2041 "(got %d bytes, expected 516)\n.\n",
2043 (int)new_lm_pswd
.length
);
2044 new_lm_pswd
= data_blob_null
;
2047 else if (strequal(request
, "old-lm-hash-blob")) {
2048 old_lm_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2049 if (old_lm_hash_enc
.length
!= 16)
2051 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2052 "(got %d bytes, expected 16)\n.\n",
2054 (int)old_lm_hash_enc
.length
);
2055 old_lm_hash_enc
= data_blob_null
;
2057 } else if (strequal(request
, "nt-domain")) {
2058 domain
= smb_xstrdup(parameter
);
2059 } else if(strequal(request
, "username")) {
2060 username
= smb_xstrdup(parameter
);
2061 } else if(strequal(request
, "full-username")) {
2062 username
= smb_xstrdup(parameter
);
2063 } else if(strequal(request
, "new-password")) {
2064 newpswd
= smb_xstrdup(parameter
);
2065 } else if (strequal(request
, "old-password")) {
2066 oldpswd
= smb_xstrdup(parameter
);
2068 x_fprintf(x_stdout
, "Error: Unknown request %s\n.\n", request
);
2072 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode
,
2073 struct loadparm_context
*lp_ctx
,
2074 struct ntlm_auth_state
*state
,
2075 stdio_helper_function fn
, void **private2
)
2078 char tmp
[INITIAL_BUFFER_SIZE
+1];
2079 int length
, buf_size
= 0;
2082 buf
= talloc_strdup(state
->mem_ctx
, "");
2084 DEBUG(0, ("Failed to allocate input buffer.\n"));
2085 x_fprintf(x_stderr
, "ERR\n");
2091 /* this is not a typo - x_fgets doesn't work too well under
2093 if (fgets(tmp
, sizeof(tmp
)-1, stdin
) == NULL
) {
2094 if (ferror(stdin
)) {
2095 DEBUG(1, ("fgets() failed! dying..... errno=%d "
2096 "(%s)\n", ferror(stdin
),
2097 strerror(ferror(stdin
))));
2104 buf
= talloc_strdup_append_buffer(buf
, tmp
);
2105 buf_size
+= INITIAL_BUFFER_SIZE
;
2107 if (buf_size
> MAX_BUFFER_SIZE
) {
2108 DEBUG(2, ("Oversized message\n"));
2109 x_fprintf(x_stderr
, "ERR\n");
2114 c
= strchr(buf
, '\n');
2115 } while (c
== NULL
);
2120 DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf
,length
));
2122 if (buf
[0] == '\0') {
2123 DEBUG(2, ("Invalid Request\n"));
2124 x_fprintf(x_stderr
, "ERR\n");
2129 fn(stdio_helper_mode
, lp_ctx
, state
, buf
, length
, private2
);
2134 static void squid_stream(enum stdio_helper_mode stdio_mode
,
2135 struct loadparm_context
*lp_ctx
,
2136 stdio_helper_function fn
) {
2137 TALLOC_CTX
*mem_ctx
;
2138 struct ntlm_auth_state
*state
;
2140 /* initialize FDescs */
2141 x_setbuf(x_stdout
, NULL
);
2142 x_setbuf(x_stderr
, NULL
);
2144 mem_ctx
= talloc_init("ntlm_auth");
2146 DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
2147 x_fprintf(x_stderr
, "ERR\n");
2151 state
= talloc_zero(mem_ctx
, struct ntlm_auth_state
);
2153 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
2154 x_fprintf(x_stderr
, "ERR\n");
2158 state
->mem_ctx
= mem_ctx
;
2159 state
->helper_mode
= stdio_mode
;
2162 TALLOC_CTX
*frame
= talloc_stackframe();
2163 manage_squid_request(stdio_mode
, lp_ctx
, state
, fn
, NULL
);
2169 /* Authenticate a user with a challenge/response */
2171 static bool check_auth_crap(void)
2176 char user_session_key
[16];
2178 char *hex_user_session_key
;
2180 static uint8_t zeros
[16];
2182 x_setbuf(x_stdout
, NULL
);
2185 flags
|= WBFLAG_PAM_LMKEY
;
2187 if (request_user_session_key
)
2188 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
2190 flags
|= WBFLAG_PAM_NT_STATUS_SQUASH
;
2192 nt_status
= contact_winbind_auth_crap(opt_username
, opt_domain
,
2198 (unsigned char *)lm_key
,
2199 (unsigned char *)user_session_key
,
2200 &error_string
, NULL
);
2202 if (!NT_STATUS_IS_OK(nt_status
)) {
2203 x_fprintf(x_stdout
, "%s (0x%x)\n",
2205 NT_STATUS_V(nt_status
));
2206 SAFE_FREE(error_string
);
2211 && (memcmp(zeros
, lm_key
,
2212 sizeof(lm_key
)) != 0)) {
2213 hex_lm_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)lm_key
,
2215 x_fprintf(x_stdout
, "LM_KEY: %s\n", hex_lm_key
);
2216 TALLOC_FREE(hex_lm_key
);
2218 if (request_user_session_key
2219 && (memcmp(zeros
, user_session_key
,
2220 sizeof(user_session_key
)) != 0)) {
2221 hex_user_session_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)user_session_key
,
2222 sizeof(user_session_key
));
2223 x_fprintf(x_stdout
, "NT_KEY: %s\n", hex_user_session_key
);
2224 TALLOC_FREE(hex_user_session_key
);
2233 OPT_USERNAME
= 1000,
2242 OPT_USER_SESSION_KEY
,
2244 OPT_REQUIRE_MEMBERSHIP
,
2245 OPT_USE_CACHED_CREDS
,
2247 OPT_PAM_WINBIND_CONF
,
2249 OPT_TARGET_HOSTNAME
,
2253 int main(int argc
, const char **argv
)
2255 TALLOC_CTX
*frame
= talloc_stackframe();
2257 static const char *helper_protocol
;
2258 static int diagnostics
;
2260 static const char *hex_challenge
;
2261 static const char *hex_lm_response
;
2262 static const char *hex_nt_response
;
2263 struct loadparm_context
*lp_ctx
;
2266 /* NOTE: DO NOT change this interface without considering the implications!
2267 This is an external interface, which other programs will use to interact
2271 /* We do not use single-letter command abbreviations, because they harm future
2272 interface stability. */
2274 struct poptOption long_options
[] = {
2276 { "helper-protocol", 0, POPT_ARG_STRING
, &helper_protocol
, OPT_DOMAIN
, "operate as a stdio-based helper", "helper protocol to use"},
2277 { "username", 0, POPT_ARG_STRING
, &opt_username
, OPT_USERNAME
, "username"},
2278 { "domain", 0, POPT_ARG_STRING
, &opt_domain
, OPT_DOMAIN
, "domain name"},
2279 { "workstation", 0, POPT_ARG_STRING
, &opt_workstation
, OPT_WORKSTATION
, "workstation"},
2280 { "challenge", 0, POPT_ARG_STRING
, &hex_challenge
, OPT_CHALLENGE
, "challenge (HEX encoded)"},
2281 { "lm-response", 0, POPT_ARG_STRING
, &hex_lm_response
, OPT_LM
, "LM Response to the challenge (HEX encoded)"},
2282 { "nt-response", 0, POPT_ARG_STRING
, &hex_nt_response
, OPT_NT
, "NT or NTLMv2 Response to the challenge (HEX encoded)"},
2283 { "password", 0, POPT_ARG_STRING
, &opt_password
, OPT_PASSWORD
, "User's plaintext password"},
2284 { "request-lm-key", 0, POPT_ARG_NONE
, &request_lm_key
, OPT_LM_KEY
, "Retrieve LM session key"},
2285 { "request-nt-key", 0, POPT_ARG_NONE
, &request_user_session_key
, OPT_USER_SESSION_KEY
, "Retrieve User (NT) session key"},
2286 { "use-cached-creds", 0, POPT_ARG_NONE
, &use_cached_creds
, OPT_USE_CACHED_CREDS
, "Use cached credentials if no password is given"},
2287 { "allow-mschapv2", 0, POPT_ARG_NONE
, &opt_allow_mschapv2
, OPT_ALLOW_MSCHAPV2
, "Explicitly allow MSCHAPv2" },
2288 { "offline-logon", 0, POPT_ARG_NONE
, &offline_logon
,
2290 "Use cached passwords when DC is offline"},
2291 { "diagnostics", 0, POPT_ARG_NONE
, &diagnostics
,
2293 "Perform diagnostics on the authentication chain"},
2294 { "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" },
2295 { "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" },
2296 { "target-service", 0, POPT_ARG_STRING
, &opt_target_service
, OPT_TARGET_SERVICE
, "Target service (eg http)" },
2297 { "target-hostname", 0, POPT_ARG_STRING
, &opt_target_hostname
, OPT_TARGET_HOSTNAME
, "Target hostname" },
2298 POPT_COMMON_CONFIGFILE
2304 /* Samba client initialisation */
2307 setup_logging("ntlm_auth", DEBUG_STDERR
);
2312 pc
= poptGetContext("ntlm_auth", argc
, argv
, long_options
, 0);
2314 /* Parse command line options */
2317 poptPrintHelp(pc
, stderr
, 0);
2321 while((opt
= poptGetNextOpt(pc
)) != -1) {
2322 /* Get generic config options like --configfile */
2325 poptFreeContext(pc
);
2327 if (!lp_load_global(get_dyn_CONFIGFILE())) {
2328 d_fprintf(stderr
, "ntlm_auth: error opening config file %s. Error was %s\n",
2329 get_dyn_CONFIGFILE(), strerror(errno
));
2333 pc
= poptGetContext(NULL
, argc
, (const char **)argv
, long_options
,
2334 POPT_CONTEXT_KEEP_FIRST
);
2336 while((opt
= poptGetNextOpt(pc
)) != -1) {
2339 opt_challenge
= strhex_to_data_blob(NULL
, hex_challenge
);
2340 if (opt_challenge
.length
!= 8) {
2341 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2343 (int)opt_challenge
.length
);
2348 opt_lm_response
= strhex_to_data_blob(NULL
, hex_lm_response
);
2349 if (opt_lm_response
.length
!= 24) {
2350 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2352 (int)opt_lm_response
.length
);
2358 opt_nt_response
= strhex_to_data_blob(NULL
, hex_nt_response
);
2359 if (opt_nt_response
.length
< 24) {
2360 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2362 (int)opt_nt_response
.length
);
2367 case OPT_REQUIRE_MEMBERSHIP
:
2368 if (strncasecmp_m("S-", require_membership_of
, 2) == 0) {
2369 require_membership_of_sid
= require_membership_of
;
2376 char *domain
= SMB_STRDUP(opt_username
);
2377 char *p
= strchr_m(domain
, *lp_winbind_separator());
2381 if (opt_domain
&& !strequal(opt_domain
, domain
)) {
2382 x_fprintf(x_stderr
, "Domain specified in username (%s) "
2383 "doesn't match specified domain (%s)!\n\n",
2384 domain
, opt_domain
);
2385 poptPrintHelp(pc
, stderr
, 0);
2388 opt_domain
= domain
;
2394 /* Note: if opt_domain is "" then send no domain */
2395 if (opt_domain
== NULL
) {
2396 opt_domain
= get_winbind_domain();
2399 if (opt_workstation
== NULL
) {
2400 opt_workstation
= "";
2403 lp_ctx
= loadparm_init_s3(NULL
, loadparm_s3_helpers());
2404 if (lp_ctx
== NULL
) {
2405 x_fprintf(x_stderr
, "loadparm_init_s3() failed!\n");
2409 if (helper_protocol
) {
2411 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2412 if (strcmp(helper_protocol
, stdio_helper_protocols
[i
].name
) == 0) {
2413 squid_stream(stdio_helper_protocols
[i
].mode
, lp_ctx
, stdio_helper_protocols
[i
].fn
);
2417 x_fprintf(x_stderr
, "unknown helper protocol [%s]\n\nValid helper protools:\n\n", helper_protocol
);
2419 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2420 x_fprintf(x_stderr
, "%s\n", stdio_helper_protocols
[i
].name
);
2426 if (!opt_username
|| !*opt_username
) {
2427 x_fprintf(x_stderr
, "username must be specified!\n\n");
2428 poptPrintHelp(pc
, stderr
, 0);
2432 if (opt_challenge
.length
) {
2433 if (!check_auth_crap()) {
2439 if (!opt_password
) {
2440 char pwd
[256] = {0};
2443 rc
= samba_getpass("Password: ", pwd
, sizeof(pwd
), false, false);
2445 opt_password
= SMB_STRDUP(pwd
);
2450 if (!diagnose_ntlm_auth()) {
2456 fstr_sprintf(user
, "%s%c%s", opt_domain
, winbind_separator(), opt_username
);
2457 if (!check_plaintext_auth(user
, opt_password
, True
)) {
2464 poptFreeContext(pc
);