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"
51 #include "auth/kerberos/pac_utils.h"
54 #ifndef PAM_WINBIND_CONFIG_FILE
55 #define PAM_WINBIND_CONFIG_FILE "/etc/security/pam_winbind.conf"
58 #define WINBIND_KRB5_AUTH 0x00000080
61 #define DBGC_CLASS DBGC_WINBIND
63 #define INITIAL_BUFFER_SIZE 300
64 #define MAX_BUFFER_SIZE 630000
66 enum stdio_helper_mode
{
74 NTLM_CHANGE_PASSWORD_1
,
78 enum ntlm_auth_cli_state
{
85 struct ntlm_auth_state
{
87 enum stdio_helper_mode helper_mode
;
88 enum ntlm_auth_cli_state cli_state
;
89 struct ntlmssp_state
*ntlmssp_state
;
91 char *want_feature_list
;
92 bool have_session_key
;
93 DATA_BLOB session_key
;
94 DATA_BLOB initial_message
;
95 void *gensec_private_1
;
97 typedef void (*stdio_helper_function
)(enum stdio_helper_mode stdio_helper_mode
,
98 struct loadparm_context
*lp_ctx
,
99 struct ntlm_auth_state
*state
, char *buf
,
100 int length
, void **private2
);
102 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode
,
103 struct loadparm_context
*lp_ctx
,
104 char *buf
, int length
, void **private1
);
106 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode
,
107 struct loadparm_context
*lp_ctx
,
108 struct ntlm_auth_state
*state
,
109 stdio_helper_function fn
, void **private2
);
111 static void manage_squid_basic_request (enum stdio_helper_mode stdio_helper_mode
,
112 struct loadparm_context
*lp_ctx
,
113 struct ntlm_auth_state
*state
,
114 char *buf
, int length
, void **private2
);
116 static void manage_squid_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode
,
117 struct loadparm_context
*lp_ctx
,
118 struct ntlm_auth_state
*state
,
119 char *buf
, int length
, void **private2
);
121 static void manage_client_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode
,
122 struct loadparm_context
*lp_ctx
,
123 struct ntlm_auth_state
*state
,
124 char *buf
, int length
, void **private2
);
126 static void manage_gss_spnego_request (enum stdio_helper_mode stdio_helper_mode
,
127 struct loadparm_context
*lp_ctx
,
128 struct ntlm_auth_state
*state
,
129 char *buf
, int length
, void **private2
);
131 static void manage_gss_spnego_client_request (enum stdio_helper_mode stdio_helper_mode
,
132 struct loadparm_context
*lp_ctx
,
133 struct ntlm_auth_state
*state
,
134 char *buf
, int length
, void **private2
);
136 static void manage_ntlm_server_1_request (enum stdio_helper_mode stdio_helper_mode
,
137 struct loadparm_context
*lp_ctx
,
138 struct ntlm_auth_state
*state
,
139 char *buf
, int length
, void **private2
);
141 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode
,
142 struct loadparm_context
*lp_ctx
,
143 struct ntlm_auth_state
*state
,
144 char *buf
, int length
, void **private2
);
146 static const struct {
147 enum stdio_helper_mode mode
;
149 stdio_helper_function fn
;
150 } stdio_helper_protocols
[] = {
151 { SQUID_2_4_BASIC
, "squid-2.4-basic", manage_squid_basic_request
},
152 { SQUID_2_5_BASIC
, "squid-2.5-basic", manage_squid_basic_request
},
153 { SQUID_2_5_NTLMSSP
, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request
},
154 { NTLMSSP_CLIENT_1
, "ntlmssp-client-1", manage_client_ntlmssp_request
},
155 { GSS_SPNEGO_SERVER
, "gss-spnego", manage_gss_spnego_request
},
156 { GSS_SPNEGO_CLIENT
, "gss-spnego-client", manage_gss_spnego_client_request
},
157 { NTLM_SERVER_1
, "ntlm-server-1", manage_ntlm_server_1_request
},
158 { NTLM_CHANGE_PASSWORD_1
, "ntlm-change-password-1", manage_ntlm_change_password_1_request
},
159 { NUM_HELPER_MODES
, NULL
, NULL
}
162 const char *opt_username
;
163 const char *opt_domain
;
164 const char *opt_workstation
;
165 const char *opt_password
;
166 static DATA_BLOB opt_challenge
;
167 static DATA_BLOB opt_lm_response
;
168 static DATA_BLOB opt_nt_response
;
169 static int request_lm_key
;
170 static int request_user_session_key
;
171 static int use_cached_creds
;
172 static int offline_logon
;
174 static const char *require_membership_of
;
175 static const char *require_membership_of_sid
;
176 static const char *opt_pam_winbind_conf
;
178 const char *opt_target_service
;
179 const char *opt_target_hostname
;
182 /* This is a bit hairy, but the basic idea is to do a password callback
183 to the calling application. The callback comes from within gensec */
185 static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mode
,
186 struct loadparm_context
*lp_ctx
,
187 struct ntlm_auth_state
*state
, char *buf
, int length
,
191 if (strlen(buf
) < 2) {
192 DEBUG(1, ("query [%s] invalid", buf
));
193 x_fprintf(x_stdout
, "BH Query invalid\n");
197 if (strlen(buf
) > 3) {
198 in
= base64_decode_data_blob(buf
+ 3);
200 in
= data_blob(NULL
, 0);
203 if (strncmp(buf
, "PW ", 3) == 0) {
205 *password
= talloc_strndup(NULL
,
206 (const char *)in
.data
, in
.length
);
208 if (*password
== NULL
) {
209 DEBUG(1, ("Out of memory\n"));
210 x_fprintf(x_stdout
, "BH Out of memory\n");
215 x_fprintf(x_stdout
, "OK\n");
219 DEBUG(1, ("Asked for (and expected) a password\n"));
220 x_fprintf(x_stdout
, "BH Expected a password\n");
225 * Callback for password credentials. This is not async, and when
226 * GENSEC and the credentials code is made async, it will look rather
230 static const char *get_password(struct cli_credentials
*credentials
)
232 TALLOC_CTX
*frame
= talloc_stackframe();
233 char *password
= NULL
;
234 struct ntlm_auth_state
*state
;
236 state
= talloc_zero(frame
, struct ntlm_auth_state
);
238 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
239 x_fprintf(x_stderr
, "ERR\n");
243 state
->mem_ctx
= state
;
245 /* Ask for a password */
246 x_fprintf(x_stdout
, "PW\n");
248 manage_squid_request(NUM_HELPER_MODES
/* bogus */, NULL
, state
, manage_gensec_get_pw_request
, (void **)&password
);
249 talloc_steal(credentials
, password
);
255 * A limited set of features are defined with text strings as needed
259 static void gensec_want_feature_list(struct gensec_security
*state
, char* feature_list
)
261 if (in_list("NTLMSSP_FEATURE_SESSION_KEY", feature_list
, true)) {
262 DEBUG(10, ("want GENSEC_FEATURE_SESSION_KEY\n"));
263 gensec_want_feature(state
, GENSEC_FEATURE_SESSION_KEY
);
265 if (in_list("NTLMSSP_FEATURE_SIGN", feature_list
, true)) {
266 DEBUG(10, ("want GENSEC_FEATURE_SIGN\n"));
267 gensec_want_feature(state
, GENSEC_FEATURE_SIGN
);
269 if (in_list("NTLMSSP_FEATURE_SEAL", feature_list
, true)) {
270 DEBUG(10, ("want GENSEC_FEATURE_SEAL\n"));
271 gensec_want_feature(state
, GENSEC_FEATURE_SEAL
);
273 if (in_list("NTLMSSP_FEATURE_CCACHE", feature_list
, true)) {
274 DEBUG(10, ("want GENSEC_FEATURE_NTLM_CCACHE\n"));
275 gensec_want_feature(state
, GENSEC_FEATURE_NTLM_CCACHE
);
279 static char winbind_separator(void)
281 struct winbindd_response response
;
288 ZERO_STRUCT(response
);
290 /* Send off request */
292 if (winbindd_request_response(NULL
, WINBINDD_INFO
, NULL
, &response
) !=
293 NSS_STATUS_SUCCESS
) {
294 d_fprintf(stderr
, "could not obtain winbind separator!\n");
295 return *lp_winbind_separator();
298 sep
= response
.data
.info
.winbind_separator
;
302 d_fprintf(stderr
, "winbind separator was NULL!\n");
303 return *lp_winbind_separator();
309 const char *get_winbind_domain(void)
311 struct winbindd_response response
;
313 static fstring winbind_domain
;
314 if (*winbind_domain
) {
315 return winbind_domain
;
318 ZERO_STRUCT(response
);
320 /* Send off request */
322 if (winbindd_request_response(NULL
, WINBINDD_DOMAIN_NAME
, NULL
, &response
) !=
323 NSS_STATUS_SUCCESS
) {
324 DEBUG(1, ("could not obtain winbind domain name!\n"));
325 return lp_workgroup();
328 fstrcpy(winbind_domain
, response
.data
.domain_name
);
330 return winbind_domain
;
334 const char *get_winbind_netbios_name(void)
336 struct winbindd_response response
;
338 static fstring winbind_netbios_name
;
340 if (*winbind_netbios_name
) {
341 return winbind_netbios_name
;
344 ZERO_STRUCT(response
);
346 /* Send off request */
348 if (winbindd_request_response(NULL
, WINBINDD_NETBIOS_NAME
, NULL
, &response
) !=
349 NSS_STATUS_SUCCESS
) {
350 DEBUG(1, ("could not obtain winbind netbios name!\n"));
351 return lp_netbios_name();
354 fstrcpy(winbind_netbios_name
, response
.data
.netbios_name
);
356 return winbind_netbios_name
;
360 DATA_BLOB
get_challenge(void)
362 static DATA_BLOB chal
;
363 if (opt_challenge
.length
)
364 return opt_challenge
;
366 chal
= data_blob(NULL
, 8);
368 generate_random_buffer(chal
.data
, chal
.length
);
372 /* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
373 form DOMAIN/user into a domain and a user */
375 static bool parse_ntlm_auth_domain_user(const char *domuser
, fstring domain
,
379 char *p
= strchr(domuser
,winbind_separator());
386 fstrcpy(domain
, domuser
);
387 domain
[PTR_DIFF(p
, domuser
)] = 0;
388 return strupper_m(domain
);
391 static bool get_require_membership_sid(void) {
392 struct winbindd_request request
;
393 struct winbindd_response response
;
395 if (!require_membership_of
) {
399 if (require_membership_of_sid
) {
403 /* Otherwise, ask winbindd for the name->sid request */
405 ZERO_STRUCT(request
);
406 ZERO_STRUCT(response
);
408 if (!parse_ntlm_auth_domain_user(require_membership_of
,
409 request
.data
.name
.dom_name
,
410 request
.data
.name
.name
)) {
411 DEBUG(0, ("Could not parse %s into separate domain/name parts!\n",
412 require_membership_of
));
416 if (winbindd_request_response(NULL
, WINBINDD_LOOKUPNAME
, &request
, &response
) !=
417 NSS_STATUS_SUCCESS
) {
418 DEBUG(0, ("Winbindd lookupname failed to resolve %s into a SID!\n",
419 require_membership_of
));
423 require_membership_of_sid
= SMB_STRDUP(response
.data
.sid
.sid
);
425 if (require_membership_of_sid
)
432 * Get some configuration from pam_winbind.conf to see if we
433 * need to contact trusted domain
436 int get_pam_winbind_config()
439 struct tiniparser_dictionary
*d
= NULL
;
441 if (!opt_pam_winbind_conf
|| !*opt_pam_winbind_conf
) {
442 opt_pam_winbind_conf
= PAM_WINBIND_CONFIG_FILE
;
445 d
= tiniparser_load(opt_pam_winbind_conf
);
451 if (tiniparser_getboolean(d
, "global:krb5_auth", false)) {
452 ctrl
|= WINBIND_KRB5_AUTH
;
455 tiniparser_freedict(d
);
460 /* Authenticate a user with a plaintext password */
462 static bool check_plaintext_auth(const char *user
, const char *pass
,
463 bool stdout_diagnostics
)
465 struct winbindd_request request
;
466 struct winbindd_response response
;
469 if (!get_require_membership_sid()) {
473 /* Send off request */
475 ZERO_STRUCT(request
);
476 ZERO_STRUCT(response
);
478 fstrcpy(request
.data
.auth
.user
, user
);
479 fstrcpy(request
.data
.auth
.pass
, pass
);
480 if (require_membership_of_sid
) {
481 strlcpy(request
.data
.auth
.require_membership_of_sid
,
482 require_membership_of_sid
,
483 sizeof(request
.data
.auth
.require_membership_of_sid
));
487 request
.flags
|= WBFLAG_PAM_CACHED_LOGIN
;
490 result
= winbindd_request_response(NULL
, WINBINDD_PAM_AUTH
, &request
, &response
);
492 /* Display response */
494 if (stdout_diagnostics
) {
495 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
496 d_fprintf(stderr
, "Reading winbind reply failed! (0x01)\n");
499 d_printf("%s: %s (0x%x)\n",
500 response
.data
.auth
.nt_status_string
,
501 response
.data
.auth
.error_string
,
502 response
.data
.auth
.nt_status
);
504 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
505 DEBUG(1, ("Reading winbind reply failed! (0x01)\n"));
508 DEBUG(3, ("%s: %s (0x%x)\n",
509 response
.data
.auth
.nt_status_string
,
510 response
.data
.auth
.error_string
,
511 response
.data
.auth
.nt_status
));
514 return (result
== NSS_STATUS_SUCCESS
);
517 /* authenticate a user with an encrypted username/password */
519 NTSTATUS
contact_winbind_auth_crap(const char *username
,
521 const char *workstation
,
522 const DATA_BLOB
*challenge
,
523 const DATA_BLOB
*lm_response
,
524 const DATA_BLOB
*nt_response
,
526 uint32_t extra_logon_parameters
,
528 uint8_t user_session_key
[16],
534 struct winbindd_request request
;
535 struct winbindd_response response
;
537 if (!get_require_membership_sid()) {
538 return NT_STATUS_INVALID_PARAMETER
;
541 ZERO_STRUCT(request
);
542 ZERO_STRUCT(response
);
544 request
.flags
= flags
;
546 request
.data
.auth_crap
.logon_parameters
= extra_logon_parameters
547 | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
| MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT
;
549 if (require_membership_of_sid
)
550 fstrcpy(request
.data
.auth_crap
.require_membership_of_sid
, require_membership_of_sid
);
552 fstrcpy(request
.data
.auth_crap
.user
, username
);
553 fstrcpy(request
.data
.auth_crap
.domain
, domain
);
555 fstrcpy(request
.data
.auth_crap
.workstation
,
558 memcpy(request
.data
.auth_crap
.chal
, challenge
->data
, MIN(challenge
->length
, 8));
560 if (lm_response
&& lm_response
->length
) {
561 memcpy(request
.data
.auth_crap
.lm_resp
,
563 MIN(lm_response
->length
, sizeof(request
.data
.auth_crap
.lm_resp
)));
564 request
.data
.auth_crap
.lm_resp_len
= lm_response
->length
;
567 if (nt_response
&& nt_response
->length
) {
568 if (nt_response
->length
> sizeof(request
.data
.auth_crap
.nt_resp
)) {
569 request
.flags
= request
.flags
| WBFLAG_BIG_NTLMV2_BLOB
;
570 request
.extra_len
= nt_response
->length
;
571 request
.extra_data
.data
= SMB_MALLOC_ARRAY(char, request
.extra_len
);
572 if (request
.extra_data
.data
== NULL
) {
573 return NT_STATUS_NO_MEMORY
;
575 memcpy(request
.extra_data
.data
, nt_response
->data
,
576 nt_response
->length
);
579 memcpy(request
.data
.auth_crap
.nt_resp
,
580 nt_response
->data
, nt_response
->length
);
582 request
.data
.auth_crap
.nt_resp_len
= nt_response
->length
;
585 result
= winbindd_request_response(NULL
, WINBINDD_PAM_AUTH_CRAP
, &request
, &response
);
586 SAFE_FREE(request
.extra_data
.data
);
588 /* Display response */
590 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
591 nt_status
= NT_STATUS_UNSUCCESSFUL
;
593 *error_string
= smb_xstrdup("Reading winbind reply failed!");
594 winbindd_free_response(&response
);
598 nt_status
= (NT_STATUS(response
.data
.auth
.nt_status
));
599 if (!NT_STATUS_IS_OK(nt_status
)) {
601 *error_string
= smb_xstrdup(response
.data
.auth
.error_string
);
602 winbindd_free_response(&response
);
606 if ((flags
& WBFLAG_PAM_LMKEY
) && lm_key
) {
607 memcpy(lm_key
, response
.data
.auth
.first_8_lm_hash
,
608 sizeof(response
.data
.auth
.first_8_lm_hash
));
610 if ((flags
& WBFLAG_PAM_USER_SESSION_KEY
) && user_session_key
) {
611 memcpy(user_session_key
, response
.data
.auth
.user_session_key
,
612 sizeof(response
.data
.auth
.user_session_key
));
615 if (flags
& WBFLAG_PAM_UNIX_NAME
) {
616 *unix_name
= SMB_STRDUP(response
.data
.auth
.unix_username
);
618 winbindd_free_response(&response
);
619 return NT_STATUS_NO_MEMORY
;
623 winbindd_free_response(&response
);
627 /* contact server to change user password using auth crap */
628 static NTSTATUS
contact_winbind_change_pswd_auth_crap(const char *username
,
630 const DATA_BLOB new_nt_pswd
,
631 const DATA_BLOB old_nt_hash_enc
,
632 const DATA_BLOB new_lm_pswd
,
633 const DATA_BLOB old_lm_hash_enc
,
638 struct winbindd_request request
;
639 struct winbindd_response response
;
641 if (!get_require_membership_sid())
644 *error_string
= smb_xstrdup("Can't get membership sid.");
645 return NT_STATUS_INVALID_PARAMETER
;
648 ZERO_STRUCT(request
);
649 ZERO_STRUCT(response
);
652 fstrcpy(request
.data
.chng_pswd_auth_crap
.user
, username
);
654 fstrcpy(request
.data
.chng_pswd_auth_crap
.domain
,domain
);
656 if(new_nt_pswd
.length
)
658 memcpy(request
.data
.chng_pswd_auth_crap
.new_nt_pswd
, new_nt_pswd
.data
, sizeof(request
.data
.chng_pswd_auth_crap
.new_nt_pswd
));
659 request
.data
.chng_pswd_auth_crap
.new_nt_pswd_len
= new_nt_pswd
.length
;
662 if(old_nt_hash_enc
.length
)
664 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
));
665 request
.data
.chng_pswd_auth_crap
.old_nt_hash_enc_len
= old_nt_hash_enc
.length
;
668 if(new_lm_pswd
.length
)
670 memcpy(request
.data
.chng_pswd_auth_crap
.new_lm_pswd
, new_lm_pswd
.data
, sizeof(request
.data
.chng_pswd_auth_crap
.new_lm_pswd
));
671 request
.data
.chng_pswd_auth_crap
.new_lm_pswd_len
= new_lm_pswd
.length
;
674 if(old_lm_hash_enc
.length
)
676 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
));
677 request
.data
.chng_pswd_auth_crap
.old_lm_hash_enc_len
= old_lm_hash_enc
.length
;
680 result
= winbindd_request_response(NULL
, WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP
, &request
, &response
);
682 /* Display response */
684 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0))
686 nt_status
= NT_STATUS_UNSUCCESSFUL
;
688 *error_string
= smb_xstrdup("Reading winbind reply failed!");
689 winbindd_free_response(&response
);
693 nt_status
= (NT_STATUS(response
.data
.auth
.nt_status
));
694 if (!NT_STATUS_IS_OK(nt_status
))
697 *error_string
= smb_xstrdup(response
.data
.auth
.error_string
);
698 winbindd_free_response(&response
);
702 winbindd_free_response(&response
);
707 static NTSTATUS
ntlm_auth_generate_session_info(struct auth4_context
*auth_context
,
709 void *server_returned_info
,
710 const char *original_user_name
,
711 uint32_t session_info_flags
,
712 struct auth_session_info
**session_info_out
)
714 const char *unix_username
= (const char *)server_returned_info
;
716 struct dom_sid
*sids
= NULL
;
717 struct auth_session_info
*session_info
= NULL
;
719 session_info
= talloc_zero(mem_ctx
, struct auth_session_info
);
720 if (session_info
== NULL
) {
721 return NT_STATUS_NO_MEMORY
;
724 session_info
->unix_info
= talloc_zero(session_info
, struct auth_user_info_unix
);
725 if (session_info
->unix_info
== NULL
) {
726 TALLOC_FREE(session_info
);
727 return NT_STATUS_NO_MEMORY
;
729 session_info
->unix_info
->unix_name
= talloc_strdup(session_info
->unix_info
,
731 if (session_info
->unix_info
->unix_name
== NULL
) {
732 TALLOC_FREE(session_info
);
733 return NT_STATUS_NO_MEMORY
;
736 session_info
->security_token
= talloc_zero(session_info
, struct security_token
);
737 if (session_info
->security_token
== NULL
) {
738 TALLOC_FREE(session_info
);
739 return NT_STATUS_NO_MEMORY
;
742 sids
= talloc_zero_array(session_info
->security_token
,
745 TALLOC_FREE(session_info
);
746 return NT_STATUS_NO_MEMORY
;
748 ok
= dom_sid_parse(SID_WORLD
, &sids
[0]);
750 TALLOC_FREE(session_info
);
751 return NT_STATUS_INTERNAL_ERROR
;
753 ok
= dom_sid_parse(SID_NT_NETWORK
, &sids
[1]);
755 TALLOC_FREE(session_info
);
756 return NT_STATUS_INTERNAL_ERROR
;
758 ok
= dom_sid_parse(SID_NT_AUTHENTICATED_USERS
, &sids
[2]);
760 TALLOC_FREE(session_info
);
761 return NT_STATUS_INTERNAL_ERROR
;
764 session_info
->security_token
->num_sids
= talloc_array_length(sids
);
765 session_info
->security_token
->sids
= sids
;
767 *session_info_out
= session_info
;
772 static NTSTATUS
ntlm_auth_generate_session_info_pac(struct auth4_context
*auth_ctx
,
774 struct smb_krb5_context
*smb_krb5_context
,
776 const char *princ_name
,
777 const struct tsocket_address
*remote_address
,
778 uint32_t session_info_flags
,
779 struct auth_session_info
**session_info
)
782 struct PAC_LOGON_INFO
*logon_info
= NULL
;
790 tmp_ctx
= talloc_new(mem_ctx
);
792 return NT_STATUS_NO_MEMORY
;
797 status
= kerberos_pac_logon_info(tmp_ctx
, *pac_blob
, NULL
, NULL
,
798 NULL
, NULL
, 0, &logon_info
);
800 status
= NT_STATUS_ACCESS_DENIED
;
802 if (!NT_STATUS_IS_OK(status
)) {
807 DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name
));
809 p
= strchr_m(princ_name
, '@');
811 DEBUG(3, ("[%s] Doesn't look like a valid principal\n",
813 return NT_STATUS_LOGON_FAILURE
;
816 user
= talloc_strndup(mem_ctx
, princ_name
, p
- princ_name
);
818 return NT_STATUS_NO_MEMORY
;
821 realm
= talloc_strdup(talloc_tos(), p
+ 1);
823 return NT_STATUS_NO_MEMORY
;
826 if (!strequal(realm
, lp_realm())) {
827 DEBUG(3, ("Ticket for foreign realm %s@%s\n", user
, realm
));
828 if (!lp_allow_trusted_domains()) {
829 return NT_STATUS_LOGON_FAILURE
;
833 if (logon_info
&& logon_info
->info3
.base
.logon_domain
.string
) {
834 domain
= talloc_strdup(mem_ctx
,
835 logon_info
->info3
.base
.logon_domain
.string
);
837 return NT_STATUS_NO_MEMORY
;
839 DEBUG(10, ("Domain is [%s] (using PAC)\n", domain
));
842 /* If we have winbind running, we can (and must) shorten the
843 username by using the short netbios name. Otherwise we will
844 have inconsistent user names. With Kerberos, we get the
845 fully qualified realm, with ntlmssp we get the short
846 name. And even w2k3 does use ntlmssp if you for example
847 connect to an ip address. */
850 struct wbcDomainInfo
*info
= NULL
;
852 DEBUG(10, ("Mapping [%s] to short name using winbindd\n",
855 wbc_status
= wbcDomainInfo(realm
, &info
);
857 if (WBC_ERROR_IS_OK(wbc_status
)) {
858 domain
= talloc_strdup(mem_ctx
,
862 DEBUG(3, ("Could not find short name: %s\n",
863 wbcErrorString(wbc_status
)));
864 domain
= talloc_strdup(mem_ctx
, realm
);
867 return NT_STATUS_NO_MEMORY
;
869 DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain
));
872 unixuser
= talloc_asprintf(tmp_ctx
, "%s%c%s", domain
, winbind_separator(), user
);
874 status
= NT_STATUS_NO_MEMORY
;
878 status
= ntlm_auth_generate_session_info(auth_ctx
, mem_ctx
, unixuser
, NULL
, session_info_flags
, session_info
);
881 TALLOC_FREE(tmp_ctx
);
888 * Return the challenge as determined by the authentication subsystem
889 * @return an 8 byte random challenge
892 static NTSTATUS
ntlm_auth_get_challenge(struct auth4_context
*auth_ctx
,
895 if (auth_ctx
->challenge
.data
.length
== 8) {
896 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
897 auth_ctx
->challenge
.set_by
));
898 memcpy(chal
, auth_ctx
->challenge
.data
.data
, 8);
902 if (!auth_ctx
->challenge
.set_by
) {
903 generate_random_buffer(chal
, 8);
905 auth_ctx
->challenge
.data
= data_blob_talloc(auth_ctx
, chal
, 8);
906 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.data
.data
);
907 auth_ctx
->challenge
.set_by
= "random";
910 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
911 auth_ctx
->challenge
.set_by
));
917 * NTLM2 authentication modifies the effective challenge,
918 * @param challenge The new challenge value
920 static NTSTATUS
ntlm_auth_set_challenge(struct auth4_context
*auth_ctx
, const uint8_t chal
[8], const char *set_by
)
922 auth_ctx
->challenge
.set_by
= talloc_strdup(auth_ctx
, set_by
);
923 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.set_by
);
925 auth_ctx
->challenge
.data
= data_blob_talloc(auth_ctx
, chal
, 8);
926 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.data
.data
);
932 * Check the password on an NTLMSSP login.
934 * Return the session keys used on the connection.
937 static NTSTATUS
winbind_pw_check(struct auth4_context
*auth4_context
,
939 const struct auth_usersupplied_info
*user_info
,
940 void **server_returned_info
,
941 DATA_BLOB
*session_key
, DATA_BLOB
*lm_session_key
)
943 static const char zeros
[16] = { 0, };
945 char *error_string
= NULL
;
947 uint8_t user_sess_key
[16];
948 char *unix_name
= NULL
;
950 nt_status
= contact_winbind_auth_crap(user_info
->client
.account_name
, user_info
->client
.domain_name
,
951 user_info
->workstation_name
,
952 &auth4_context
->challenge
.data
,
953 &user_info
->password
.response
.lanman
,
954 &user_info
->password
.response
.nt
,
955 WBFLAG_PAM_LMKEY
| WBFLAG_PAM_USER_SESSION_KEY
| WBFLAG_PAM_UNIX_NAME
,
957 lm_key
, user_sess_key
,
958 &error_string
, &unix_name
);
960 if (NT_STATUS_IS_OK(nt_status
)) {
961 if (memcmp(lm_key
, zeros
, 8) != 0) {
962 *lm_session_key
= data_blob_talloc(mem_ctx
, NULL
, 16);
963 memcpy(lm_session_key
->data
, lm_key
, 8);
964 memset(lm_session_key
->data
+8, '\0', 8);
967 if (memcmp(user_sess_key
, zeros
, 16) != 0) {
968 *session_key
= data_blob_talloc(mem_ctx
, user_sess_key
, 16);
970 *server_returned_info
= talloc_strdup(mem_ctx
,
973 DEBUG(NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCESS_DENIED
) ? 0 : 3,
974 ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
975 user_info
->client
.domain_name
, user_info
->client
.account_name
,
976 user_info
->workstation_name
,
977 error_string
? error_string
: "unknown error (NULL)"));
980 SAFE_FREE(error_string
);
981 SAFE_FREE(unix_name
);
985 static NTSTATUS
local_pw_check(struct auth4_context
*auth4_context
,
987 const struct auth_usersupplied_info
*user_info
,
988 void **server_returned_info
,
989 DATA_BLOB
*session_key
, DATA_BLOB
*lm_session_key
)
992 struct samr_Password lm_pw
, nt_pw
;
994 nt_lm_owf_gen (opt_password
, nt_pw
.hash
, lm_pw
.hash
);
996 nt_status
= ntlm_password_check(mem_ctx
,
998 &auth4_context
->challenge
.data
,
999 &user_info
->password
.response
.lanman
,
1000 &user_info
->password
.response
.nt
,
1001 user_info
->client
.account_name
,
1002 user_info
->client
.account_name
,
1003 user_info
->client
.domain_name
,
1004 &lm_pw
, &nt_pw
, session_key
, lm_session_key
);
1006 if (NT_STATUS_IS_OK(nt_status
)) {
1007 *server_returned_info
= talloc_asprintf(mem_ctx
,
1008 "%s%c%s", user_info
->client
.domain_name
,
1009 *lp_winbind_separator(),
1010 user_info
->client
.account_name
);
1012 DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
1013 user_info
->client
.domain_name
, user_info
->client
.account_name
,
1014 user_info
->workstation_name
,
1015 nt_errstr(nt_status
)));
1020 static NTSTATUS
ntlm_auth_prepare_gensec_client(TALLOC_CTX
*mem_ctx
,
1021 struct loadparm_context
*lp_ctx
,
1022 struct gensec_security
**gensec_security_out
)
1024 struct gensec_security
*gensec_security
= NULL
;
1026 TALLOC_CTX
*tmp_ctx
;
1027 const struct gensec_security_ops
**backends
= NULL
;
1028 struct gensec_settings
*gensec_settings
= NULL
;
1031 tmp_ctx
= talloc_new(mem_ctx
);
1032 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx
);
1034 gensec_settings
= lpcfg_gensec_settings(tmp_ctx
, lp_ctx
);
1035 if (gensec_settings
== NULL
) {
1036 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1037 TALLOC_FREE(tmp_ctx
);
1038 return NT_STATUS_NO_MEMORY
;
1041 backends
= talloc_zero_array(gensec_settings
,
1042 const struct gensec_security_ops
*, 4);
1043 if (backends
== NULL
) {
1044 TALLOC_FREE(tmp_ctx
);
1045 return NT_STATUS_NO_MEMORY
;
1047 gensec_settings
->backends
= backends
;
1051 /* These need to be in priority order, krb5 before NTLMSSP */
1052 #if defined(HAVE_KRB5)
1053 backends
[idx
++] = &gensec_gse_krb5_security_ops
;
1056 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_NTLMSSP
);
1058 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_SPNEGO
);
1060 nt_status
= gensec_client_start(NULL
, &gensec_security
,
1062 if (!NT_STATUS_IS_OK(nt_status
)) {
1063 TALLOC_FREE(tmp_ctx
);
1067 talloc_unlink(tmp_ctx
, gensec_settings
);
1069 if (opt_target_service
!= NULL
) {
1070 nt_status
= gensec_set_target_service(gensec_security
,
1071 opt_target_service
);
1072 if (!NT_STATUS_IS_OK(nt_status
)) {
1073 TALLOC_FREE(tmp_ctx
);
1078 if (opt_target_hostname
!= NULL
) {
1079 nt_status
= gensec_set_target_hostname(gensec_security
,
1080 opt_target_hostname
);
1081 if (!NT_STATUS_IS_OK(nt_status
)) {
1082 TALLOC_FREE(tmp_ctx
);
1087 *gensec_security_out
= talloc_steal(mem_ctx
, gensec_security
);
1088 TALLOC_FREE(tmp_ctx
);
1089 return NT_STATUS_OK
;
1092 static struct auth4_context
*make_auth4_context_ntlm_auth(TALLOC_CTX
*mem_ctx
, bool local_pw
)
1094 struct auth4_context
*auth4_context
= talloc_zero(mem_ctx
, struct auth4_context
);
1095 if (auth4_context
== NULL
) {
1096 DEBUG(10, ("failed to allocate auth4_context failed\n"));
1099 auth4_context
->generate_session_info
= ntlm_auth_generate_session_info
;
1100 auth4_context
->generate_session_info_pac
= ntlm_auth_generate_session_info_pac
;
1101 auth4_context
->get_ntlm_challenge
= ntlm_auth_get_challenge
;
1102 auth4_context
->set_ntlm_challenge
= ntlm_auth_set_challenge
;
1104 auth4_context
->check_ntlm_password
= local_pw_check
;
1106 auth4_context
->check_ntlm_password
= winbind_pw_check
;
1108 auth4_context
->private_data
= NULL
;
1109 return auth4_context
;
1112 static NTSTATUS
ntlm_auth_prepare_gensec_server(TALLOC_CTX
*mem_ctx
,
1113 struct loadparm_context
*lp_ctx
,
1114 struct gensec_security
**gensec_security_out
)
1116 struct gensec_security
*gensec_security
;
1119 TALLOC_CTX
*tmp_ctx
;
1120 const struct gensec_security_ops
**backends
;
1121 struct gensec_settings
*gensec_settings
;
1123 struct cli_credentials
*server_credentials
;
1125 struct auth4_context
*auth4_context
;
1127 tmp_ctx
= talloc_new(mem_ctx
);
1128 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx
);
1130 auth4_context
= make_auth4_context_ntlm_auth(tmp_ctx
, opt_password
);
1131 if (auth4_context
== NULL
) {
1132 TALLOC_FREE(tmp_ctx
);
1133 return NT_STATUS_NO_MEMORY
;
1136 gensec_settings
= lpcfg_gensec_settings(tmp_ctx
, lp_ctx
);
1137 if (lp_ctx
== NULL
) {
1138 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1139 TALLOC_FREE(tmp_ctx
);
1140 return NT_STATUS_NO_MEMORY
;
1144 * This should be a 'netbios domain -> DNS domain'
1145 * mapping, and can currently validly return NULL on
1146 * poorly configured systems.
1148 * This is used for the NTLMSSP server
1152 gensec_settings
->server_netbios_name
= lp_netbios_name();
1153 gensec_settings
->server_netbios_domain
= lp_workgroup();
1155 gensec_settings
->server_netbios_name
= get_winbind_netbios_name();
1156 gensec_settings
->server_netbios_domain
= get_winbind_domain();
1159 gensec_settings
->server_dns_domain
= strlower_talloc(gensec_settings
,
1160 get_mydnsdomname(talloc_tos()));
1161 gensec_settings
->server_dns_name
= strlower_talloc(gensec_settings
,
1162 get_mydnsfullname());
1164 backends
= talloc_zero_array(gensec_settings
,
1165 const struct gensec_security_ops
*, 4);
1167 if (backends
== NULL
) {
1168 TALLOC_FREE(tmp_ctx
);
1169 return NT_STATUS_NO_MEMORY
;
1171 gensec_settings
->backends
= backends
;
1175 /* These need to be in priority order, krb5 before NTLMSSP */
1176 #if defined(HAVE_KRB5)
1177 backends
[idx
++] = &gensec_gse_krb5_security_ops
;
1180 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_NTLMSSP
);
1182 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_SPNEGO
);
1185 * This is anonymous for now, because we just use it
1186 * to set the kerberos state at the moment
1188 server_credentials
= cli_credentials_init_anon(tmp_ctx
);
1189 if (!server_credentials
) {
1190 DEBUG(0, ("auth_generic_prepare: Failed to init server credentials\n"));
1191 return NT_STATUS_NO_MEMORY
;
1194 cli_credentials_set_conf(server_credentials
, lp_ctx
);
1196 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC
|| lp_security() == SEC_ADS
|| USE_KERBEROS_KEYTAB
) {
1197 cli_credentials_set_kerberos_state(server_credentials
, CRED_AUTO_USE_KERBEROS
);
1199 cli_credentials_set_kerberos_state(server_credentials
, CRED_DONT_USE_KERBEROS
);
1202 nt_status
= gensec_server_start(tmp_ctx
, gensec_settings
,
1203 auth4_context
, &gensec_security
);
1205 if (!NT_STATUS_IS_OK(nt_status
)) {
1206 TALLOC_FREE(tmp_ctx
);
1210 gensec_set_credentials(gensec_security
, server_credentials
);
1212 gensec_want_feature(gensec_security
, GENSEC_FEATURE_SIGN
);
1213 gensec_want_feature(gensec_security
, GENSEC_FEATURE_SEAL
);
1215 talloc_unlink(tmp_ctx
, lp_ctx
);
1216 talloc_unlink(tmp_ctx
, server_credentials
);
1217 talloc_unlink(tmp_ctx
, gensec_settings
);
1218 talloc_unlink(tmp_ctx
, auth4_context
);
1220 *gensec_security_out
= talloc_steal(mem_ctx
, gensec_security
);
1221 TALLOC_FREE(tmp_ctx
);
1222 return NT_STATUS_OK
;
1225 static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode
,
1226 struct loadparm_context
*lp_ctx
,
1227 struct ntlm_auth_state
*state
,
1228 char *buf
, int length
, void **private2
)
1230 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1234 static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode
,
1235 struct loadparm_context
*lp_ctx
,
1236 struct ntlm_auth_state
*state
,
1237 char *buf
, int length
, void **private2
)
1242 pass
=(char *)memchr(buf
,' ',length
);
1244 DEBUG(2, ("Password not found. Denying access\n"));
1245 x_fprintf(x_stdout
, "ERR\n");
1251 if (state
->helper_mode
== SQUID_2_5_BASIC
) {
1252 rfc1738_unescape(user
);
1253 rfc1738_unescape(pass
);
1256 if (check_plaintext_auth(user
, pass
, False
)) {
1257 x_fprintf(x_stdout
, "OK\n");
1259 x_fprintf(x_stdout
, "ERR\n");
1263 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode
,
1264 struct loadparm_context
*lp_ctx
,
1265 char *buf
, int length
, void **private1
)
1268 DATA_BLOB out
= data_blob(NULL
, 0);
1269 char *out_base64
= NULL
;
1270 const char *reply_arg
= NULL
;
1271 struct gensec_ntlm_state
{
1272 struct gensec_security
*gensec_state
;
1273 const char *set_password
;
1275 struct gensec_ntlm_state
*state
;
1279 const char *reply_code
;
1280 struct cli_credentials
*creds
;
1282 static char *want_feature_list
= NULL
;
1283 static DATA_BLOB session_key
;
1285 TALLOC_CTX
*mem_ctx
;
1288 state
= (struct gensec_ntlm_state
*)*private1
;
1290 state
= talloc_zero(NULL
, struct gensec_ntlm_state
);
1292 x_fprintf(x_stdout
, "BH No Memory\n");
1297 state
->set_password
= opt_password
;
1301 if (strlen(buf
) < 2) {
1302 DEBUG(1, ("query [%s] invalid", buf
));
1303 x_fprintf(x_stdout
, "BH Query invalid\n");
1307 if (strlen(buf
) > 3) {
1308 if(strncmp(buf
, "SF ", 3) == 0) {
1309 DEBUG(10, ("Setting flags to negotiate\n"));
1310 talloc_free(want_feature_list
);
1311 want_feature_list
= talloc_strndup(state
, buf
+3, strlen(buf
)-3);
1312 x_fprintf(x_stdout
, "OK\n");
1315 in
= base64_decode_data_blob(buf
+ 3);
1317 in
= data_blob(NULL
, 0);
1320 if (strncmp(buf
, "YR", 2) == 0) {
1321 if (state
->gensec_state
) {
1322 talloc_free(state
->gensec_state
);
1323 state
->gensec_state
= NULL
;
1325 } else if ( (strncmp(buf
, "OK", 2) == 0)) {
1326 /* Just return BH, like ntlm_auth from Samba 3 does. */
1327 x_fprintf(x_stdout
, "BH Command expected\n");
1328 data_blob_free(&in
);
1330 } else if ( (strncmp(buf
, "TT ", 3) != 0) &&
1331 (strncmp(buf
, "KK ", 3) != 0) &&
1332 (strncmp(buf
, "AF ", 3) != 0) &&
1333 (strncmp(buf
, "NA ", 3) != 0) &&
1334 (strncmp(buf
, "UG", 2) != 0) &&
1335 (strncmp(buf
, "PW ", 3) != 0) &&
1336 (strncmp(buf
, "GK", 2) != 0) &&
1337 (strncmp(buf
, "GF", 2) != 0)) {
1338 DEBUG(1, ("SPNEGO request [%s] invalid prefix\n", buf
));
1339 x_fprintf(x_stdout
, "BH SPNEGO request invalid prefix\n");
1340 data_blob_free(&in
);
1344 mem_ctx
= talloc_named(NULL
, 0, "manage_gensec_request internal mem_ctx");
1347 if (!(state
->gensec_state
)) {
1348 switch (stdio_helper_mode
) {
1349 case GSS_SPNEGO_CLIENT
:
1351 * cached credentials are only supported by
1352 * NTLMSSP_CLIENT_1 for now.
1354 use_cached_creds
= false;
1356 case NTLMSSP_CLIENT_1
:
1357 /* setup the client side */
1359 if (state
->set_password
!= NULL
) {
1360 use_cached_creds
= false;
1363 if (use_cached_creds
) {
1364 struct wbcCredentialCacheParams params
;
1365 struct wbcCredentialCacheInfo
*info
= NULL
;
1366 struct wbcAuthErrorInfo
*error
= NULL
;
1369 params
.account_name
= opt_username
;
1370 params
.domain_name
= opt_domain
;
1371 params
.level
= WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP
;
1372 params
.num_blobs
= 0;
1373 params
.blobs
= NULL
;
1375 wbc_status
= wbcCredentialCache(¶ms
, &info
,
1377 wbcFreeMemory(error
);
1378 if (!WBC_ERROR_IS_OK(wbc_status
)) {
1379 use_cached_creds
= false;
1381 wbcFreeMemory(info
);
1384 nt_status
= ntlm_auth_prepare_gensec_client(state
, lp_ctx
,
1385 &state
->gensec_state
);
1386 if (!NT_STATUS_IS_OK(nt_status
)) {
1387 x_fprintf(x_stdout
, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status
));
1388 talloc_free(mem_ctx
);
1392 creds
= cli_credentials_init(state
->gensec_state
);
1393 cli_credentials_set_conf(creds
, lp_ctx
);
1395 cli_credentials_set_username(creds
, opt_username
, CRED_SPECIFIED
);
1398 cli_credentials_set_domain(creds
, opt_domain
, CRED_SPECIFIED
);
1400 if (use_cached_creds
) {
1401 gensec_want_feature(state
->gensec_state
,
1402 GENSEC_FEATURE_NTLM_CCACHE
);
1403 } else if (state
->set_password
) {
1404 cli_credentials_set_password(creds
, state
->set_password
, CRED_SPECIFIED
);
1406 cli_credentials_set_password_callback(creds
, get_password
);
1408 if (opt_workstation
) {
1409 cli_credentials_set_workstation(creds
, opt_workstation
, CRED_SPECIFIED
);
1412 gensec_set_credentials(state
->gensec_state
, creds
);
1415 case GSS_SPNEGO_SERVER
:
1416 case SQUID_2_5_NTLMSSP
:
1418 nt_status
= ntlm_auth_prepare_gensec_server(state
, lp_ctx
,
1419 &state
->gensec_state
);
1420 if (!NT_STATUS_IS_OK(nt_status
)) {
1421 x_fprintf(x_stdout
, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status
));
1422 talloc_free(mem_ctx
);
1428 talloc_free(mem_ctx
);
1432 gensec_want_feature_list(state
->gensec_state
, want_feature_list
);
1434 switch (stdio_helper_mode
) {
1435 case GSS_SPNEGO_CLIENT
:
1436 case GSS_SPNEGO_SERVER
:
1437 nt_status
= gensec_start_mech_by_oid(state
->gensec_state
, GENSEC_OID_SPNEGO
);
1442 case NTLMSSP_CLIENT_1
:
1447 case SQUID_2_5_NTLMSSP
:
1448 nt_status
= gensec_start_mech_by_oid(state
->gensec_state
, GENSEC_OID_NTLMSSP
);
1451 talloc_free(mem_ctx
);
1455 if (!NT_STATUS_IS_OK(nt_status
)) {
1456 DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status
)));
1457 x_fprintf(x_stdout
, "BH GENSEC mech failed to start\n");
1458 talloc_free(mem_ctx
);
1466 if (strncmp(buf
, "PW ", 3) == 0) {
1467 state
->set_password
= talloc_strndup(state
,
1468 (const char *)in
.data
,
1471 cli_credentials_set_password(gensec_get_credentials(state
->gensec_state
),
1472 state
->set_password
,
1474 x_fprintf(x_stdout
, "OK\n");
1475 data_blob_free(&in
);
1476 talloc_free(mem_ctx
);
1480 if (strncmp(buf
, "GK", 2) == 0) {
1482 DEBUG(10, ("Requested session key\n"));
1483 nt_status
= gensec_session_key(state
->gensec_state
, mem_ctx
, &session_key
);
1484 if(!NT_STATUS_IS_OK(nt_status
)) {
1485 DEBUG(1, ("gensec_session_key failed: %s\n", nt_errstr(nt_status
)));
1486 x_fprintf(x_stdout
, "BH No session key\n");
1487 talloc_free(mem_ctx
);
1490 base64_key
= base64_encode_data_blob(state
, session_key
);
1491 x_fprintf(x_stdout
, "GK %s\n", base64_key
);
1492 talloc_free(base64_key
);
1494 talloc_free(mem_ctx
);
1498 if (strncmp(buf
, "GF", 2) == 0) {
1501 DEBUG(10, ("Requested negotiated NTLMSSP feature flags\n"));
1503 neg_flags
= gensec_ntlmssp_neg_flags(state
->gensec_state
);
1504 if (neg_flags
== 0) {
1505 x_fprintf(x_stdout
, "BH\n");
1509 x_fprintf(x_stdout
, "GF 0x%08x\n", neg_flags
);
1513 nt_status
= gensec_update(state
->gensec_state
, mem_ctx
, in
, &out
);
1515 /* don't leak 'bad password'/'no such user' info to the network client */
1516 nt_status
= nt_status_squash(nt_status
);
1519 out_base64
= base64_encode_data_blob(mem_ctx
, out
);
1524 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1526 if (first
&& state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1528 } else if (state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1530 } else if (state
->gensec_state
->gensec_role
== GENSEC_SERVER
) {
1537 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCESS_DENIED
)) {
1538 reply_code
= "BH NT_STATUS_ACCESS_DENIED";
1539 reply_arg
= nt_errstr(nt_status
);
1540 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1541 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_UNSUCCESSFUL
)) {
1542 reply_code
= "BH NT_STATUS_UNSUCCESSFUL";
1543 reply_arg
= nt_errstr(nt_status
);
1544 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1545 } else if (!NT_STATUS_IS_OK(nt_status
)) {
1547 reply_arg
= nt_errstr(nt_status
);
1548 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1549 } else if /* OK */ (state
->gensec_state
->gensec_role
== GENSEC_SERVER
) {
1550 struct auth_session_info
*session_info
;
1552 nt_status
= gensec_session_info(state
->gensec_state
, mem_ctx
, &session_info
);
1553 if (!NT_STATUS_IS_OK(nt_status
)) {
1554 reply_code
= "BH Failed to retrive session info";
1555 reply_arg
= nt_errstr(nt_status
);
1556 DEBUG(1, ("GENSEC failed to retrieve the session info: %s\n", nt_errstr(nt_status
)));
1560 reply_arg
= talloc_strdup(state
->gensec_state
, session_info
->unix_info
->unix_name
);
1561 if (reply_arg
== NULL
) {
1562 reply_code
= "BH out of memory";
1563 reply_arg
= nt_errstr(NT_STATUS_NO_MEMORY
);
1565 talloc_free(session_info
);
1567 } else if (state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1569 reply_arg
= out_base64
;
1574 switch (stdio_helper_mode
) {
1575 case GSS_SPNEGO_SERVER
:
1576 x_fprintf(x_stdout
, "%s %s %s\n", reply_code
,
1577 out_base64
? out_base64
: "*",
1578 reply_arg
? reply_arg
: "*");
1582 x_fprintf(x_stdout
, "%s %s\n", reply_code
, out_base64
);
1583 } else if (reply_arg
) {
1584 x_fprintf(x_stdout
, "%s %s\n", reply_code
, reply_arg
);
1586 x_fprintf(x_stdout
, "%s\n", reply_code
);
1590 talloc_free(mem_ctx
);
1594 static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode
,
1595 struct loadparm_context
*lp_ctx
,
1596 struct ntlm_auth_state
*state
,
1597 char *buf
, int length
, void **private2
)
1599 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1603 static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode
,
1604 struct loadparm_context
*lp_ctx
,
1605 struct ntlm_auth_state
*state
,
1606 char *buf
, int length
, void **private2
)
1608 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1612 static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode
,
1613 struct loadparm_context
*lp_ctx
,
1614 struct ntlm_auth_state
*state
,
1615 char *buf
, int length
, void **private2
)
1617 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1621 static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode
,
1622 struct loadparm_context
*lp_ctx
,
1623 struct ntlm_auth_state
*state
,
1624 char *buf
, int length
, void **private2
)
1626 char *request
, *parameter
;
1627 static DATA_BLOB challenge
;
1628 static DATA_BLOB lm_response
;
1629 static DATA_BLOB nt_response
;
1630 static char *full_username
;
1631 static char *username
;
1632 static char *domain
;
1633 static char *plaintext_password
;
1634 static bool ntlm_server_1_user_session_key
;
1635 static bool ntlm_server_1_lm_session_key
;
1637 if (strequal(buf
, ".")) {
1638 if (!full_username
&& !username
) {
1639 x_fprintf(x_stdout
, "Error: No username supplied!\n");
1640 } else if (plaintext_password
) {
1641 /* handle this request as plaintext */
1642 if (!full_username
) {
1643 if (asprintf(&full_username
, "%s%c%s", domain
, winbind_separator(), username
) == -1) {
1644 x_fprintf(x_stdout
, "Error: Out of memory in asprintf!\n.\n");
1648 if (check_plaintext_auth(full_username
, plaintext_password
, False
)) {
1649 x_fprintf(x_stdout
, "Authenticated: Yes\n");
1651 x_fprintf(x_stdout
, "Authenticated: No\n");
1653 } else if (!lm_response
.data
&& !nt_response
.data
) {
1654 x_fprintf(x_stdout
, "Error: No password supplied!\n");
1655 } else if (!challenge
.data
) {
1656 x_fprintf(x_stdout
, "Error: No lanman-challenge supplied!\n");
1658 char *error_string
= NULL
;
1660 uchar user_session_key
[16];
1663 if (full_username
&& !username
) {
1665 fstring fstr_domain
;
1667 if (!parse_ntlm_auth_domain_user(full_username
, fstr_user
, fstr_domain
)) {
1668 /* username might be 'tainted', don't print into our new-line deleimianted stream */
1669 x_fprintf(x_stdout
, "Error: Could not parse into domain and username\n");
1671 SAFE_FREE(username
);
1673 username
= smb_xstrdup(fstr_user
);
1674 domain
= smb_xstrdup(fstr_domain
);
1678 DATA_BLOB nt_session_key
, lm_session_key
;
1679 struct samr_Password lm_pw
, nt_pw
;
1680 TALLOC_CTX
*mem_ctx
= talloc_new(NULL
);
1681 ZERO_STRUCT(user_session_key
);
1682 ZERO_STRUCT(lm_key
);
1684 nt_lm_owf_gen (opt_password
, nt_pw
.hash
, lm_pw
.hash
);
1685 nt_status
= ntlm_password_check(mem_ctx
,
1696 error_string
= smb_xstrdup(get_friendly_nt_error_msg(nt_status
));
1697 if (ntlm_server_1_user_session_key
) {
1698 if (nt_session_key
.length
== sizeof(user_session_key
)) {
1699 memcpy(user_session_key
,
1700 nt_session_key
.data
,
1701 sizeof(user_session_key
));
1704 if (ntlm_server_1_lm_session_key
) {
1705 if (lm_session_key
.length
== sizeof(lm_key
)) {
1707 lm_session_key
.data
,
1711 TALLOC_FREE(mem_ctx
);
1715 domain
= smb_xstrdup(get_winbind_domain());
1718 if (ntlm_server_1_lm_session_key
)
1719 flags
|= WBFLAG_PAM_LMKEY
;
1721 if (ntlm_server_1_user_session_key
)
1722 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
1724 nt_status
= contact_winbind_auth_crap(username
,
1737 if (!NT_STATUS_IS_OK(nt_status
)) {
1738 x_fprintf(x_stdout
, "Authenticated: No\n");
1739 x_fprintf(x_stdout
, "Authentication-Error: %s\n.\n", error_string
);
1741 static char zeros
[16];
1743 char *hex_user_session_key
;
1745 x_fprintf(x_stdout
, "Authenticated: Yes\n");
1747 if (ntlm_server_1_lm_session_key
1748 && (memcmp(zeros
, lm_key
,
1749 sizeof(lm_key
)) != 0)) {
1750 hex_lm_key
= hex_encode_talloc(NULL
,
1751 (const unsigned char *)lm_key
,
1753 x_fprintf(x_stdout
, "LANMAN-Session-Key: %s\n", hex_lm_key
);
1754 TALLOC_FREE(hex_lm_key
);
1757 if (ntlm_server_1_user_session_key
1758 && (memcmp(zeros
, user_session_key
,
1759 sizeof(user_session_key
)) != 0)) {
1760 hex_user_session_key
= hex_encode_talloc(NULL
,
1761 (const unsigned char *)user_session_key
,
1762 sizeof(user_session_key
));
1763 x_fprintf(x_stdout
, "User-Session-Key: %s\n", hex_user_session_key
);
1764 TALLOC_FREE(hex_user_session_key
);
1767 SAFE_FREE(error_string
);
1769 /* clear out the state */
1770 challenge
= data_blob_null
;
1771 nt_response
= data_blob_null
;
1772 lm_response
= data_blob_null
;
1773 SAFE_FREE(full_username
);
1774 SAFE_FREE(username
);
1776 SAFE_FREE(plaintext_password
);
1777 ntlm_server_1_user_session_key
= False
;
1778 ntlm_server_1_lm_session_key
= False
;
1779 x_fprintf(x_stdout
, ".\n");
1786 /* Indicates a base64 encoded structure */
1787 parameter
= strstr_m(request
, ":: ");
1789 parameter
= strstr_m(request
, ": ");
1792 DEBUG(0, ("Parameter not found!\n"));
1793 x_fprintf(x_stdout
, "Error: Parameter not found!\n.\n");
1810 base64_decode_inplace(parameter
);
1813 if (strequal(request
, "LANMAN-Challenge")) {
1814 challenge
= strhex_to_data_blob(NULL
, parameter
);
1815 if (challenge
.length
!= 8) {
1816 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (got %d bytes, expected 8)\n.\n",
1818 (int)challenge
.length
);
1819 challenge
= data_blob_null
;
1821 } else if (strequal(request
, "NT-Response")) {
1822 nt_response
= strhex_to_data_blob(NULL
, parameter
);
1823 if (nt_response
.length
< 24) {
1824 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (only got %d bytes, needed at least 24)\n.\n",
1826 (int)nt_response
.length
);
1827 nt_response
= data_blob_null
;
1829 } else if (strequal(request
, "LANMAN-Response")) {
1830 lm_response
= strhex_to_data_blob(NULL
, parameter
);
1831 if (lm_response
.length
!= 24) {
1832 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (got %d bytes, expected 24)\n.\n",
1834 (int)lm_response
.length
);
1835 lm_response
= data_blob_null
;
1837 } else if (strequal(request
, "Password")) {
1838 plaintext_password
= smb_xstrdup(parameter
);
1839 } else if (strequal(request
, "NT-Domain")) {
1840 domain
= smb_xstrdup(parameter
);
1841 } else if (strequal(request
, "Username")) {
1842 username
= smb_xstrdup(parameter
);
1843 } else if (strequal(request
, "Full-Username")) {
1844 full_username
= smb_xstrdup(parameter
);
1845 } else if (strequal(request
, "Request-User-Session-Key")) {
1846 ntlm_server_1_user_session_key
= strequal(parameter
, "Yes");
1847 } else if (strequal(request
, "Request-LanMan-Session-Key")) {
1848 ntlm_server_1_lm_session_key
= strequal(parameter
, "Yes");
1850 x_fprintf(x_stdout
, "Error: Unknown request %s\n.\n", request
);
1854 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode
,
1855 struct loadparm_context
*lp_ctx
,
1856 struct ntlm_auth_state
*state
,
1857 char *buf
, int length
, void **private2
)
1859 char *request
, *parameter
;
1860 static DATA_BLOB new_nt_pswd
;
1861 static DATA_BLOB old_nt_hash_enc
;
1862 static DATA_BLOB new_lm_pswd
;
1863 static DATA_BLOB old_lm_hash_enc
;
1864 static char *full_username
= NULL
;
1865 static char *username
= NULL
;
1866 static char *domain
= NULL
;
1867 static char *newpswd
= NULL
;
1868 static char *oldpswd
= NULL
;
1870 if (strequal(buf
, ".")) {
1871 if(newpswd
&& oldpswd
) {
1872 uchar old_nt_hash
[16];
1873 uchar old_lm_hash
[16];
1874 uchar new_nt_hash
[16];
1875 uchar new_lm_hash
[16];
1877 new_nt_pswd
= data_blob(NULL
, 516);
1878 old_nt_hash_enc
= data_blob(NULL
, 16);
1880 /* Calculate the MD4 hash (NT compatible) of the
1882 E_md4hash(oldpswd
, old_nt_hash
);
1883 E_md4hash(newpswd
, new_nt_hash
);
1885 /* E_deshash returns false for 'long'
1886 passwords (> 14 DOS chars).
1888 Therefore, don't send a buffer
1889 encrypted with the truncated hash
1890 (it could allow an even easier
1891 attack on the password)
1893 Likewise, obey the admin's restriction
1896 if (lp_client_lanman_auth() &&
1897 E_deshash(newpswd
, new_lm_hash
) &&
1898 E_deshash(oldpswd
, old_lm_hash
)) {
1899 new_lm_pswd
= data_blob(NULL
, 516);
1900 old_lm_hash_enc
= data_blob(NULL
, 16);
1901 encode_pw_buffer(new_lm_pswd
.data
, newpswd
,
1904 arcfour_crypt(new_lm_pswd
.data
, old_nt_hash
, 516);
1905 E_old_pw_hash(new_nt_hash
, old_lm_hash
,
1906 old_lm_hash_enc
.data
);
1908 new_lm_pswd
.data
= NULL
;
1909 new_lm_pswd
.length
= 0;
1910 old_lm_hash_enc
.data
= NULL
;
1911 old_lm_hash_enc
.length
= 0;
1914 encode_pw_buffer(new_nt_pswd
.data
, newpswd
,
1917 arcfour_crypt(new_nt_pswd
.data
, old_nt_hash
, 516);
1918 E_old_pw_hash(new_nt_hash
, old_nt_hash
,
1919 old_nt_hash_enc
.data
);
1922 if (!full_username
&& !username
) {
1923 x_fprintf(x_stdout
, "Error: No username supplied!\n");
1924 } else if ((!new_nt_pswd
.data
|| !old_nt_hash_enc
.data
) &&
1925 (!new_lm_pswd
.data
|| old_lm_hash_enc
.data
) ) {
1926 x_fprintf(x_stdout
, "Error: No NT or LM password "
1927 "blobs supplied!\n");
1929 char *error_string
= NULL
;
1931 if (full_username
&& !username
) {
1933 fstring fstr_domain
;
1935 if (!parse_ntlm_auth_domain_user(full_username
,
1938 /* username might be 'tainted', don't
1939 * print into our new-line
1940 * deleimianted stream */
1941 x_fprintf(x_stdout
, "Error: Could not "
1942 "parse into domain and "
1944 SAFE_FREE(username
);
1945 username
= smb_xstrdup(full_username
);
1947 SAFE_FREE(username
);
1949 username
= smb_xstrdup(fstr_user
);
1950 domain
= smb_xstrdup(fstr_domain
);
1955 if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
1962 x_fprintf(x_stdout
, "Password-Change: No\n");
1963 x_fprintf(x_stdout
, "Password-Change-Error: "
1964 "%s\n.\n", error_string
);
1966 x_fprintf(x_stdout
, "Password-Change: Yes\n");
1969 SAFE_FREE(error_string
);
1971 /* clear out the state */
1972 new_nt_pswd
= data_blob_null
;
1973 old_nt_hash_enc
= data_blob_null
;
1974 new_lm_pswd
= data_blob_null
;
1975 old_nt_hash_enc
= data_blob_null
;
1976 SAFE_FREE(full_username
);
1977 SAFE_FREE(username
);
1981 x_fprintf(x_stdout
, ".\n");
1988 /* Indicates a base64 encoded structure */
1989 parameter
= strstr_m(request
, ":: ");
1991 parameter
= strstr_m(request
, ": ");
1994 DEBUG(0, ("Parameter not found!\n"));
1995 x_fprintf(x_stdout
, "Error: Parameter not found!\n.\n");
2011 base64_decode_inplace(parameter
);
2014 if (strequal(request
, "new-nt-password-blob")) {
2015 new_nt_pswd
= strhex_to_data_blob(NULL
, parameter
);
2016 if (new_nt_pswd
.length
!= 516) {
2017 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2018 "(got %d bytes, expected 516)\n.\n",
2020 (int)new_nt_pswd
.length
);
2021 new_nt_pswd
= data_blob_null
;
2023 } else if (strequal(request
, "old-nt-hash-blob")) {
2024 old_nt_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2025 if (old_nt_hash_enc
.length
!= 16) {
2026 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2027 "(got %d bytes, expected 16)\n.\n",
2029 (int)old_nt_hash_enc
.length
);
2030 old_nt_hash_enc
= data_blob_null
;
2032 } else if (strequal(request
, "new-lm-password-blob")) {
2033 new_lm_pswd
= strhex_to_data_blob(NULL
, parameter
);
2034 if (new_lm_pswd
.length
!= 516) {
2035 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2036 "(got %d bytes, expected 516)\n.\n",
2038 (int)new_lm_pswd
.length
);
2039 new_lm_pswd
= data_blob_null
;
2042 else if (strequal(request
, "old-lm-hash-blob")) {
2043 old_lm_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2044 if (old_lm_hash_enc
.length
!= 16)
2046 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2047 "(got %d bytes, expected 16)\n.\n",
2049 (int)old_lm_hash_enc
.length
);
2050 old_lm_hash_enc
= data_blob_null
;
2052 } else if (strequal(request
, "nt-domain")) {
2053 domain
= smb_xstrdup(parameter
);
2054 } else if(strequal(request
, "username")) {
2055 username
= smb_xstrdup(parameter
);
2056 } else if(strequal(request
, "full-username")) {
2057 username
= smb_xstrdup(parameter
);
2058 } else if(strequal(request
, "new-password")) {
2059 newpswd
= smb_xstrdup(parameter
);
2060 } else if (strequal(request
, "old-password")) {
2061 oldpswd
= smb_xstrdup(parameter
);
2063 x_fprintf(x_stdout
, "Error: Unknown request %s\n.\n", request
);
2067 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode
,
2068 struct loadparm_context
*lp_ctx
,
2069 struct ntlm_auth_state
*state
,
2070 stdio_helper_function fn
, void **private2
)
2073 char tmp
[INITIAL_BUFFER_SIZE
+1];
2074 int length
, buf_size
= 0;
2077 buf
= talloc_strdup(state
->mem_ctx
, "");
2079 DEBUG(0, ("Failed to allocate input buffer.\n"));
2080 x_fprintf(x_stderr
, "ERR\n");
2086 /* this is not a typo - x_fgets doesn't work too well under
2088 if (fgets(tmp
, sizeof(tmp
)-1, stdin
) == NULL
) {
2089 if (ferror(stdin
)) {
2090 DEBUG(1, ("fgets() failed! dying..... errno=%d "
2091 "(%s)\n", ferror(stdin
),
2092 strerror(ferror(stdin
))));
2099 buf
= talloc_strdup_append_buffer(buf
, tmp
);
2100 buf_size
+= INITIAL_BUFFER_SIZE
;
2102 if (buf_size
> MAX_BUFFER_SIZE
) {
2103 DEBUG(2, ("Oversized message\n"));
2104 x_fprintf(x_stderr
, "ERR\n");
2109 c
= strchr(buf
, '\n');
2110 } while (c
== NULL
);
2115 DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf
,length
));
2117 if (buf
[0] == '\0') {
2118 DEBUG(2, ("Invalid Request\n"));
2119 x_fprintf(x_stderr
, "ERR\n");
2124 fn(stdio_helper_mode
, lp_ctx
, state
, buf
, length
, private2
);
2129 static void squid_stream(enum stdio_helper_mode stdio_mode
,
2130 struct loadparm_context
*lp_ctx
,
2131 stdio_helper_function fn
) {
2132 TALLOC_CTX
*mem_ctx
;
2133 struct ntlm_auth_state
*state
;
2135 /* initialize FDescs */
2136 x_setbuf(x_stdout
, NULL
);
2137 x_setbuf(x_stderr
, NULL
);
2139 mem_ctx
= talloc_init("ntlm_auth");
2141 DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
2142 x_fprintf(x_stderr
, "ERR\n");
2146 state
= talloc_zero(mem_ctx
, struct ntlm_auth_state
);
2148 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
2149 x_fprintf(x_stderr
, "ERR\n");
2153 state
->mem_ctx
= mem_ctx
;
2154 state
->helper_mode
= stdio_mode
;
2157 TALLOC_CTX
*frame
= talloc_stackframe();
2158 manage_squid_request(stdio_mode
, lp_ctx
, state
, fn
, NULL
);
2164 /* Authenticate a user with a challenge/response */
2166 static bool check_auth_crap(void)
2171 char user_session_key
[16];
2173 char *hex_user_session_key
;
2175 static uint8_t zeros
[16];
2177 x_setbuf(x_stdout
, NULL
);
2180 flags
|= WBFLAG_PAM_LMKEY
;
2182 if (request_user_session_key
)
2183 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
2185 flags
|= WBFLAG_PAM_NT_STATUS_SQUASH
;
2187 nt_status
= contact_winbind_auth_crap(opt_username
, opt_domain
,
2193 (unsigned char *)lm_key
,
2194 (unsigned char *)user_session_key
,
2195 &error_string
, NULL
);
2197 if (!NT_STATUS_IS_OK(nt_status
)) {
2198 x_fprintf(x_stdout
, "%s (0x%x)\n",
2200 NT_STATUS_V(nt_status
));
2201 SAFE_FREE(error_string
);
2206 && (memcmp(zeros
, lm_key
,
2207 sizeof(lm_key
)) != 0)) {
2208 hex_lm_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)lm_key
,
2210 x_fprintf(x_stdout
, "LM_KEY: %s\n", hex_lm_key
);
2211 TALLOC_FREE(hex_lm_key
);
2213 if (request_user_session_key
2214 && (memcmp(zeros
, user_session_key
,
2215 sizeof(user_session_key
)) != 0)) {
2216 hex_user_session_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)user_session_key
,
2217 sizeof(user_session_key
));
2218 x_fprintf(x_stdout
, "NT_KEY: %s\n", hex_user_session_key
);
2219 TALLOC_FREE(hex_user_session_key
);
2228 OPT_USERNAME
= 1000,
2237 OPT_USER_SESSION_KEY
,
2239 OPT_REQUIRE_MEMBERSHIP
,
2240 OPT_USE_CACHED_CREDS
,
2241 OPT_PAM_WINBIND_CONF
,
2243 OPT_TARGET_HOSTNAME
,
2247 int main(int argc
, const char **argv
)
2249 TALLOC_CTX
*frame
= talloc_stackframe();
2251 static const char *helper_protocol
;
2252 static int diagnostics
;
2254 static const char *hex_challenge
;
2255 static const char *hex_lm_response
;
2256 static const char *hex_nt_response
;
2257 struct loadparm_context
*lp_ctx
;
2260 /* NOTE: DO NOT change this interface without considering the implications!
2261 This is an external interface, which other programs will use to interact
2265 /* We do not use single-letter command abbreviations, because they harm future
2266 interface stability. */
2268 struct poptOption long_options
[] = {
2270 { "helper-protocol", 0, POPT_ARG_STRING
, &helper_protocol
, OPT_DOMAIN
, "operate as a stdio-based helper", "helper protocol to use"},
2271 { "username", 0, POPT_ARG_STRING
, &opt_username
, OPT_USERNAME
, "username"},
2272 { "domain", 0, POPT_ARG_STRING
, &opt_domain
, OPT_DOMAIN
, "domain name"},
2273 { "workstation", 0, POPT_ARG_STRING
, &opt_workstation
, OPT_WORKSTATION
, "workstation"},
2274 { "challenge", 0, POPT_ARG_STRING
, &hex_challenge
, OPT_CHALLENGE
, "challenge (HEX encoded)"},
2275 { "lm-response", 0, POPT_ARG_STRING
, &hex_lm_response
, OPT_LM
, "LM Response to the challenge (HEX encoded)"},
2276 { "nt-response", 0, POPT_ARG_STRING
, &hex_nt_response
, OPT_NT
, "NT or NTLMv2 Response to the challenge (HEX encoded)"},
2277 { "password", 0, POPT_ARG_STRING
, &opt_password
, OPT_PASSWORD
, "User's plaintext password"},
2278 { "request-lm-key", 0, POPT_ARG_NONE
, &request_lm_key
, OPT_LM_KEY
, "Retrieve LM session key"},
2279 { "request-nt-key", 0, POPT_ARG_NONE
, &request_user_session_key
, OPT_USER_SESSION_KEY
, "Retrieve User (NT) session key"},
2280 { "use-cached-creds", 0, POPT_ARG_NONE
, &use_cached_creds
, OPT_USE_CACHED_CREDS
, "Use cached credentials if no password is given"},
2281 { "offline-logon", 0, POPT_ARG_NONE
, &offline_logon
,
2283 "Use cached passwords when DC is offline"},
2284 { "diagnostics", 0, POPT_ARG_NONE
, &diagnostics
,
2286 "Perform diagnostics on the authentication chain"},
2287 { "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" },
2288 { "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" },
2289 { "target-service", 0, POPT_ARG_STRING
, &opt_target_service
, OPT_TARGET_SERVICE
, "Target service (eg http)" },
2290 { "target-hostname", 0, POPT_ARG_STRING
, &opt_target_hostname
, OPT_TARGET_HOSTNAME
, "Target hostname" },
2291 POPT_COMMON_CONFIGFILE
2297 /* Samba client initialisation */
2300 setup_logging("ntlm_auth", DEBUG_STDERR
);
2304 pc
= poptGetContext("ntlm_auth", argc
, argv
, long_options
, 0);
2306 /* Parse command line options */
2309 poptPrintHelp(pc
, stderr
, 0);
2313 while((opt
= poptGetNextOpt(pc
)) != -1) {
2314 /* Get generic config options like --configfile */
2317 poptFreeContext(pc
);
2319 if (!lp_load_global(get_dyn_CONFIGFILE())) {
2320 d_fprintf(stderr
, "ntlm_auth: error opening config file %s. Error was %s\n",
2321 get_dyn_CONFIGFILE(), strerror(errno
));
2325 pc
= poptGetContext(NULL
, argc
, (const char **)argv
, long_options
,
2326 POPT_CONTEXT_KEEP_FIRST
);
2328 while((opt
= poptGetNextOpt(pc
)) != -1) {
2331 opt_challenge
= strhex_to_data_blob(NULL
, hex_challenge
);
2332 if (opt_challenge
.length
!= 8) {
2333 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2335 (int)opt_challenge
.length
);
2340 opt_lm_response
= strhex_to_data_blob(NULL
, hex_lm_response
);
2341 if (opt_lm_response
.length
!= 24) {
2342 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2344 (int)opt_lm_response
.length
);
2350 opt_nt_response
= strhex_to_data_blob(NULL
, hex_nt_response
);
2351 if (opt_nt_response
.length
< 24) {
2352 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2354 (int)opt_nt_response
.length
);
2359 case OPT_REQUIRE_MEMBERSHIP
:
2360 if (strncasecmp_m("S-", require_membership_of
, 2) == 0) {
2361 require_membership_of_sid
= require_membership_of
;
2368 char *domain
= SMB_STRDUP(opt_username
);
2369 char *p
= strchr_m(domain
, *lp_winbind_separator());
2373 if (opt_domain
&& !strequal(opt_domain
, domain
)) {
2374 x_fprintf(x_stderr
, "Domain specified in username (%s) "
2375 "doesn't match specified domain (%s)!\n\n",
2376 domain
, opt_domain
);
2377 poptPrintHelp(pc
, stderr
, 0);
2380 opt_domain
= domain
;
2386 /* Note: if opt_domain is "" then send no domain */
2387 if (opt_domain
== NULL
) {
2388 opt_domain
= get_winbind_domain();
2391 if (opt_workstation
== NULL
) {
2392 opt_workstation
= "";
2395 lp_ctx
= loadparm_init_s3(NULL
, loadparm_s3_helpers());
2396 if (lp_ctx
== NULL
) {
2397 x_fprintf(x_stderr
, "loadparm_init_s3() failed!\n");
2401 if (helper_protocol
) {
2403 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2404 if (strcmp(helper_protocol
, stdio_helper_protocols
[i
].name
) == 0) {
2405 squid_stream(stdio_helper_protocols
[i
].mode
, lp_ctx
, stdio_helper_protocols
[i
].fn
);
2409 x_fprintf(x_stderr
, "unknown helper protocol [%s]\n\nValid helper protools:\n\n", helper_protocol
);
2411 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2412 x_fprintf(x_stderr
, "%s\n", stdio_helper_protocols
[i
].name
);
2418 if (!opt_username
|| !*opt_username
) {
2419 x_fprintf(x_stderr
, "username must be specified!\n\n");
2420 poptPrintHelp(pc
, stderr
, 0);
2424 if (opt_challenge
.length
) {
2425 if (!check_auth_crap()) {
2431 if (!opt_password
) {
2432 char pwd
[256] = {0};
2435 rc
= samba_getpass("Password: ", pwd
, sizeof(pwd
), false, false);
2437 opt_password
= SMB_STRDUP(pwd
);
2442 if (!diagnose_ntlm_auth()) {
2448 fstr_sprintf(user
, "%s%c%s", opt_domain
, winbind_separator(), opt_username
);
2449 if (!check_plaintext_auth(user
, opt_password
, True
)) {
2456 poptFreeContext(pc
);