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 "utils/ntlm_auth.h"
31 #include "../libcli/auth/libcli_auth.h"
32 #include "../libcli/auth/spnego.h"
33 #include "auth/ntlmssp/ntlmssp.h"
34 #include "auth/gensec/gensec.h"
35 #include "auth/credentials/credentials.h"
36 #include "librpc/crypto/gse.h"
38 #include <iniparser.h>
39 #include "../lib/crypto/arcfour.h"
40 #include "libads/kerberos_proto.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_squid_request(enum stdio_helper_mode stdio_helper_mode,
103 struct loadparm_context *lp_ctx,
104 struct ntlm_auth_state *state,
105 stdio_helper_function fn, void **private2);
107 static void manage_squid_basic_request (enum stdio_helper_mode stdio_helper_mode,
108 struct loadparm_context *lp_ctx,
109 struct ntlm_auth_state *state,
110 char *buf, int length, void **private2);
112 static void manage_squid_ntlmssp_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_client_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_gss_spnego_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_client_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_ntlm_server_1_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_change_password_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 const struct {
143 enum stdio_helper_mode mode;
145 stdio_helper_function fn;
146 } stdio_helper_protocols[] = {
147 { SQUID_2_4_BASIC, "squid-2.4-basic", manage_squid_basic_request},
148 { SQUID_2_5_BASIC, "squid-2.5-basic", manage_squid_basic_request},
149 { SQUID_2_5_NTLMSSP, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request},
150 { NTLMSSP_CLIENT_1, "ntlmssp-client-1", manage_client_ntlmssp_request},
151 { GSS_SPNEGO_SERVER, "gss-spnego", manage_gss_spnego_request},
152 { GSS_SPNEGO_CLIENT, "gss-spnego-client", manage_gss_spnego_client_request},
153 { NTLM_SERVER_1, "ntlm-server-1", manage_ntlm_server_1_request},
154 { NTLM_CHANGE_PASSWORD_1, "ntlm-change-password-1", manage_ntlm_change_password_1_request},
155 { NUM_HELPER_MODES, NULL, NULL}
158 const char *opt_username;
159 const char *opt_domain;
160 const char *opt_workstation;
161 const char *opt_password;
162 static DATA_BLOB opt_challenge;
163 static DATA_BLOB opt_lm_response;
164 static DATA_BLOB opt_nt_response;
165 static int request_lm_key;
166 static int request_user_session_key;
167 static int use_cached_creds;
169 static const char *require_membership_of;
170 static const char *require_membership_of_sid;
171 static const char *opt_pam_winbind_conf;
173 const char *opt_target_service;
174 const char *opt_target_hostname;
177 /* This is a bit hairy, but the basic idea is to do a password callback
178 to the calling application. The callback comes from within gensec */
180 static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mode,
181 struct loadparm_context *lp_ctx,
182 struct ntlm_auth_state *state, char *buf, int length,
186 if (strlen(buf) < 2) {
187 DEBUG(1, ("query [%s] invalid", buf));
188 x_fprintf(x_stdout, "BH Query invalid\n");
192 if (strlen(buf) > 3) {
193 in = base64_decode_data_blob(buf + 3);
195 in = data_blob(NULL, 0);
198 if (strncmp(buf, "PW ", 3) == 0) {
200 *password = talloc_strndup(NULL,
201 (const char *)in.data, in.length);
203 if (*password == NULL) {
204 DEBUG(1, ("Out of memory\n"));
205 x_fprintf(x_stdout, "BH Out of memory\n");
210 x_fprintf(x_stdout, "OK\n");
214 DEBUG(1, ("Asked for (and expected) a password\n"));
215 x_fprintf(x_stdout, "BH Expected a password\n");
220 * Callback for password credentials. This is not async, and when
221 * GENSEC and the credentials code is made async, it will look rather
225 static const char *get_password(struct cli_credentials *credentials)
227 char *password = NULL;
229 /* Ask for a password */
230 x_fprintf(x_stdout, "PW\n");
231 credentials->priv_data = NULL;
233 manage_squid_request(NUM_HELPER_MODES /* bogus */, NULL, NULL, manage_gensec_get_pw_request, (void **)&password);
234 talloc_steal(credentials, password);
239 * A limited set of features are defined with text strings as needed
243 static void gensec_want_feature_list(struct gensec_security *state, char* feature_list)
245 if (in_list("NTLMSSP_FEATURE_SESSION_KEY", feature_list, true)) {
246 DEBUG(10, ("want GENSEC_FEATURE_SESSION_KEY\n"));
247 gensec_want_feature(state, GENSEC_FEATURE_SESSION_KEY);
249 if (in_list("NTLMSSP_FEATURE_SIGN", feature_list, true)) {
250 DEBUG(10, ("want GENSEC_FEATURE_SIGN\n"));
251 gensec_want_feature(state, GENSEC_FEATURE_SIGN);
253 if (in_list("NTLMSSP_FEATURE_SEAL", feature_list, true)) {
254 DEBUG(10, ("want GENSEC_FEATURE_SEAL\n"));
255 gensec_want_feature(state, GENSEC_FEATURE_SEAL);
259 static char winbind_separator(void)
261 struct winbindd_response response;
268 ZERO_STRUCT(response);
270 /* Send off request */
272 if (winbindd_request_response(WINBINDD_INFO, NULL, &response) !=
273 NSS_STATUS_SUCCESS) {
274 d_printf("could not obtain winbind separator!\n");
275 return *lp_winbind_separator();
278 sep = response.data.info.winbind_separator;
282 d_printf("winbind separator was NULL!\n");
283 return *lp_winbind_separator();
289 const char *get_winbind_domain(void)
291 struct winbindd_response response;
293 static fstring winbind_domain;
294 if (*winbind_domain) {
295 return winbind_domain;
298 ZERO_STRUCT(response);
300 /* Send off request */
302 if (winbindd_request_response(WINBINDD_DOMAIN_NAME, NULL, &response) !=
303 NSS_STATUS_SUCCESS) {
304 DEBUG(0, ("could not obtain winbind domain name!\n"));
305 return lp_workgroup();
308 fstrcpy(winbind_domain, response.data.domain_name);
310 return winbind_domain;
314 const char *get_winbind_netbios_name(void)
316 struct winbindd_response response;
318 static fstring winbind_netbios_name;
320 if (*winbind_netbios_name) {
321 return winbind_netbios_name;
324 ZERO_STRUCT(response);
326 /* Send off request */
328 if (winbindd_request_response(WINBINDD_NETBIOS_NAME, NULL, &response) !=
329 NSS_STATUS_SUCCESS) {
330 DEBUG(0, ("could not obtain winbind netbios name!\n"));
331 return lp_netbios_name();
334 fstrcpy(winbind_netbios_name, response.data.netbios_name);
336 return winbind_netbios_name;
340 DATA_BLOB get_challenge(void)
342 static DATA_BLOB chal;
343 if (opt_challenge.length)
344 return opt_challenge;
346 chal = data_blob(NULL, 8);
348 generate_random_buffer(chal.data, chal.length);
352 /* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
353 form DOMAIN/user into a domain and a user */
355 static bool parse_ntlm_auth_domain_user(const char *domuser, fstring domain,
359 char *p = strchr(domuser,winbind_separator());
366 fstrcpy(domain, domuser);
367 domain[PTR_DIFF(p, domuser)] = 0;
373 static bool get_require_membership_sid(void) {
374 struct winbindd_request request;
375 struct winbindd_response response;
377 if (!require_membership_of) {
381 if (require_membership_of_sid) {
385 /* Otherwise, ask winbindd for the name->sid request */
387 ZERO_STRUCT(request);
388 ZERO_STRUCT(response);
390 if (!parse_ntlm_auth_domain_user(require_membership_of,
391 request.data.name.dom_name,
392 request.data.name.name)) {
393 DEBUG(0, ("Could not parse %s into seperate domain/name parts!\n",
394 require_membership_of));
398 if (winbindd_request_response(WINBINDD_LOOKUPNAME, &request, &response) !=
399 NSS_STATUS_SUCCESS) {
400 DEBUG(0, ("Winbindd lookupname failed to resolve %s into a SID!\n",
401 require_membership_of));
405 require_membership_of_sid = SMB_STRDUP(response.data.sid.sid);
407 if (require_membership_of_sid)
414 * Get some configuration from pam_winbind.conf to see if we
415 * need to contact trusted domain
418 int get_pam_winbind_config()
421 dictionary *d = NULL;
423 if (!opt_pam_winbind_conf || !*opt_pam_winbind_conf) {
424 opt_pam_winbind_conf = PAM_WINBIND_CONFIG_FILE;
427 d = iniparser_load(discard_const_p(char, opt_pam_winbind_conf));
433 if (iniparser_getboolean(d, discard_const_p(char, "global:krb5_auth"), false)) {
434 ctrl |= WINBIND_KRB5_AUTH;
437 iniparser_freedict(d);
442 /* Authenticate a user with a plaintext password */
444 static bool check_plaintext_auth(const char *user, const char *pass,
445 bool stdout_diagnostics)
447 struct winbindd_request request;
448 struct winbindd_response response;
451 if (!get_require_membership_sid()) {
455 /* Send off request */
457 ZERO_STRUCT(request);
458 ZERO_STRUCT(response);
460 fstrcpy(request.data.auth.user, user);
461 fstrcpy(request.data.auth.pass, pass);
462 if (require_membership_of_sid) {
463 strlcpy(request.data.auth.require_membership_of_sid,
464 require_membership_of_sid,
465 sizeof(request.data.auth.require_membership_of_sid));
468 result = winbindd_request_response(WINBINDD_PAM_AUTH, &request, &response);
470 /* Display response */
472 if (stdout_diagnostics) {
473 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
474 d_printf("Reading winbind reply failed! (0x01)\n");
477 d_printf("%s: %s (0x%x)\n",
478 response.data.auth.nt_status_string,
479 response.data.auth.error_string,
480 response.data.auth.nt_status);
482 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
483 DEBUG(1, ("Reading winbind reply failed! (0x01)\n"));
486 DEBUG(3, ("%s: %s (0x%x)\n",
487 response.data.auth.nt_status_string,
488 response.data.auth.error_string,
489 response.data.auth.nt_status));
492 return (result == NSS_STATUS_SUCCESS);
495 /* authenticate a user with an encrypted username/password */
497 NTSTATUS contact_winbind_auth_crap(const char *username,
499 const char *workstation,
500 const DATA_BLOB *challenge,
501 const DATA_BLOB *lm_response,
502 const DATA_BLOB *nt_response,
504 uint32 extra_logon_parameters,
506 uint8 user_session_key[16],
512 struct winbindd_request request;
513 struct winbindd_response response;
515 if (!get_require_membership_sid()) {
516 return NT_STATUS_INVALID_PARAMETER;
519 ZERO_STRUCT(request);
520 ZERO_STRUCT(response);
522 request.flags = flags;
524 request.data.auth_crap.logon_parameters = extra_logon_parameters
525 | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT | MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT;
527 if (require_membership_of_sid)
528 fstrcpy(request.data.auth_crap.require_membership_of_sid, require_membership_of_sid);
530 fstrcpy(request.data.auth_crap.user, username);
531 fstrcpy(request.data.auth_crap.domain, domain);
533 fstrcpy(request.data.auth_crap.workstation,
536 memcpy(request.data.auth_crap.chal, challenge->data, MIN(challenge->length, 8));
538 if (lm_response && lm_response->length) {
539 memcpy(request.data.auth_crap.lm_resp,
541 MIN(lm_response->length, sizeof(request.data.auth_crap.lm_resp)));
542 request.data.auth_crap.lm_resp_len = lm_response->length;
545 if (nt_response && nt_response->length) {
546 if (nt_response->length > sizeof(request.data.auth_crap.nt_resp)) {
547 request.flags = request.flags | WBFLAG_BIG_NTLMV2_BLOB;
548 request.extra_len = nt_response->length;
549 request.extra_data.data = SMB_MALLOC_ARRAY(char, request.extra_len);
550 if (request.extra_data.data == NULL) {
551 return NT_STATUS_NO_MEMORY;
553 memcpy(request.extra_data.data, nt_response->data,
554 nt_response->length);
557 memcpy(request.data.auth_crap.nt_resp,
558 nt_response->data, nt_response->length);
560 request.data.auth_crap.nt_resp_len = nt_response->length;
563 result = winbindd_request_response(WINBINDD_PAM_AUTH_CRAP, &request, &response);
564 SAFE_FREE(request.extra_data.data);
566 /* Display response */
568 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
569 nt_status = NT_STATUS_UNSUCCESSFUL;
571 *error_string = smb_xstrdup("Reading winbind reply failed!");
572 winbindd_free_response(&response);
576 nt_status = (NT_STATUS(response.data.auth.nt_status));
577 if (!NT_STATUS_IS_OK(nt_status)) {
579 *error_string = smb_xstrdup(response.data.auth.error_string);
580 winbindd_free_response(&response);
584 if ((flags & WBFLAG_PAM_LMKEY) && lm_key) {
585 memcpy(lm_key, response.data.auth.first_8_lm_hash,
586 sizeof(response.data.auth.first_8_lm_hash));
588 if ((flags & WBFLAG_PAM_USER_SESSION_KEY) && user_session_key) {
589 memcpy(user_session_key, response.data.auth.user_session_key,
590 sizeof(response.data.auth.user_session_key));
593 if (flags & WBFLAG_PAM_UNIX_NAME) {
594 *unix_name = SMB_STRDUP(response.data.auth.unix_username);
596 winbindd_free_response(&response);
597 return NT_STATUS_NO_MEMORY;
601 winbindd_free_response(&response);
605 /* contact server to change user password using auth crap */
606 static NTSTATUS contact_winbind_change_pswd_auth_crap(const char *username,
608 const DATA_BLOB new_nt_pswd,
609 const DATA_BLOB old_nt_hash_enc,
610 const DATA_BLOB new_lm_pswd,
611 const DATA_BLOB old_lm_hash_enc,
616 struct winbindd_request request;
617 struct winbindd_response response;
619 if (!get_require_membership_sid())
622 *error_string = smb_xstrdup("Can't get membership sid.");
623 return NT_STATUS_INVALID_PARAMETER;
626 ZERO_STRUCT(request);
627 ZERO_STRUCT(response);
630 fstrcpy(request.data.chng_pswd_auth_crap.user, username);
632 fstrcpy(request.data.chng_pswd_auth_crap.domain,domain);
634 if(new_nt_pswd.length)
636 memcpy(request.data.chng_pswd_auth_crap.new_nt_pswd, new_nt_pswd.data, sizeof(request.data.chng_pswd_auth_crap.new_nt_pswd));
637 request.data.chng_pswd_auth_crap.new_nt_pswd_len = new_nt_pswd.length;
640 if(old_nt_hash_enc.length)
642 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));
643 request.data.chng_pswd_auth_crap.old_nt_hash_enc_len = old_nt_hash_enc.length;
646 if(new_lm_pswd.length)
648 memcpy(request.data.chng_pswd_auth_crap.new_lm_pswd, new_lm_pswd.data, sizeof(request.data.chng_pswd_auth_crap.new_lm_pswd));
649 request.data.chng_pswd_auth_crap.new_lm_pswd_len = new_lm_pswd.length;
652 if(old_lm_hash_enc.length)
654 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));
655 request.data.chng_pswd_auth_crap.old_lm_hash_enc_len = old_lm_hash_enc.length;
658 result = winbindd_request_response(WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP, &request, &response);
660 /* Display response */
662 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0))
664 nt_status = NT_STATUS_UNSUCCESSFUL;
666 *error_string = smb_xstrdup("Reading winbind reply failed!");
667 winbindd_free_response(&response);
671 nt_status = (NT_STATUS(response.data.auth.nt_status));
672 if (!NT_STATUS_IS_OK(nt_status))
675 *error_string = smb_xstrdup(response.data.auth.error_string);
676 winbindd_free_response(&response);
680 winbindd_free_response(&response);
685 static NTSTATUS ntlm_auth_generate_session_info(struct auth4_context *auth_context,
687 void *server_returned_info,
688 const char *original_user_name,
689 uint32_t session_info_flags,
690 struct auth_session_info **session_info_out)
692 char *unix_username = (char *)server_returned_info;
693 struct auth_session_info *session_info = talloc_zero(mem_ctx, struct auth_session_info);
695 return NT_STATUS_NO_MEMORY;
698 session_info->unix_info = talloc_zero(session_info, struct auth_user_info_unix);
699 if (!session_info->unix_info) {
700 TALLOC_FREE(session_info);
701 return NT_STATUS_NO_MEMORY;
703 session_info->unix_info->unix_name = talloc_steal(session_info->unix_info, unix_username);
705 *session_info_out = session_info;
710 static NTSTATUS ntlm_auth_generate_session_info_pac(struct auth4_context *auth_ctx,
712 struct smb_krb5_context *smb_krb5_context,
714 const char *princ_name,
715 const struct tsocket_address *remote_address,
716 uint32_t session_info_flags,
717 struct auth_session_info **session_info)
720 struct PAC_LOGON_INFO *logon_info = NULL;
728 tmp_ctx = talloc_new(mem_ctx);
730 return NT_STATUS_NO_MEMORY;
735 status = kerberos_pac_logon_info(tmp_ctx, *pac_blob, NULL, NULL,
736 NULL, NULL, 0, &logon_info);
738 status = NT_STATUS_ACCESS_DENIED;
740 if (!NT_STATUS_IS_OK(status)) {
745 DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name));
747 p = strchr_m(princ_name, '@');
749 DEBUG(3, ("[%s] Doesn't look like a valid principal\n",
751 return NT_STATUS_LOGON_FAILURE;
754 user = talloc_strndup(mem_ctx, princ_name, p - princ_name);
756 return NT_STATUS_NO_MEMORY;
759 realm = talloc_strdup(talloc_tos(), p + 1);
761 return NT_STATUS_NO_MEMORY;
764 if (!strequal(realm, lp_realm())) {
765 DEBUG(3, ("Ticket for foreign realm %s@%s\n", user, realm));
766 if (!lp_allow_trusted_domains()) {
767 return NT_STATUS_LOGON_FAILURE;
771 if (logon_info && logon_info->info3.base.logon_domain.string) {
772 domain = talloc_strdup(mem_ctx,
773 logon_info->info3.base.logon_domain.string);
775 return NT_STATUS_NO_MEMORY;
777 DEBUG(10, ("Domain is [%s] (using PAC)\n", domain));
780 /* If we have winbind running, we can (and must) shorten the
781 username by using the short netbios name. Otherwise we will
782 have inconsistent user names. With Kerberos, we get the
783 fully qualified realm, with ntlmssp we get the short
784 name. And even w2k3 does use ntlmssp if you for example
785 connect to an ip address. */
788 struct wbcDomainInfo *info = NULL;
790 DEBUG(10, ("Mapping [%s] to short name using winbindd\n",
793 wbc_status = wbcDomainInfo(realm, &info);
795 if (WBC_ERROR_IS_OK(wbc_status)) {
796 domain = talloc_strdup(mem_ctx,
800 DEBUG(3, ("Could not find short name: %s\n",
801 wbcErrorString(wbc_status)));
802 domain = talloc_strdup(mem_ctx, realm);
805 return NT_STATUS_NO_MEMORY;
807 DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain));
810 unixuser = talloc_asprintf(tmp_ctx, "%s%c%s", domain, winbind_separator(), user);
812 status = NT_STATUS_NO_MEMORY;
816 status = ntlm_auth_generate_session_info(auth_ctx, mem_ctx, unixuser, NULL, session_info_flags, session_info);
819 TALLOC_FREE(tmp_ctx);
826 * Return the challenge as determined by the authentication subsystem
827 * @return an 8 byte random challenge
830 static NTSTATUS ntlm_auth_get_challenge(struct auth4_context *auth_ctx,
833 if (auth_ctx->challenge.data.length == 8) {
834 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
835 auth_ctx->challenge.set_by));
836 memcpy(chal, auth_ctx->challenge.data.data, 8);
840 if (!auth_ctx->challenge.set_by) {
841 generate_random_buffer(chal, 8);
843 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
844 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
845 auth_ctx->challenge.set_by = "random";
848 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
849 auth_ctx->challenge.set_by));
855 * NTLM2 authentication modifies the effective challenge,
856 * @param challenge The new challenge value
858 static NTSTATUS ntlm_auth_set_challenge(struct auth4_context *auth_ctx, const uint8_t chal[8], const char *set_by)
860 auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
861 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
863 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
864 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
870 * Check the password on an NTLMSSP login.
872 * Return the session keys used on the connection.
875 static NTSTATUS winbind_pw_check(struct auth4_context *auth4_context,
877 const struct auth_usersupplied_info *user_info,
878 void **server_returned_info,
879 DATA_BLOB *session_key, DATA_BLOB *lm_session_key)
881 static const char zeros[16] = { 0, };
883 char *error_string = NULL;
885 uint8 user_sess_key[16];
886 char *unix_name = NULL;
888 nt_status = contact_winbind_auth_crap(user_info->client.account_name, user_info->client.domain_name,
889 user_info->workstation_name,
890 &auth4_context->challenge.data,
891 &user_info->password.response.lanman,
892 &user_info->password.response.nt,
893 WBFLAG_PAM_LMKEY | WBFLAG_PAM_USER_SESSION_KEY | WBFLAG_PAM_UNIX_NAME,
895 lm_key, user_sess_key,
896 &error_string, &unix_name);
898 if (NT_STATUS_IS_OK(nt_status)) {
899 if (memcmp(lm_key, zeros, 8) != 0) {
900 *lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
901 memcpy(lm_session_key->data, lm_key, 8);
902 memset(lm_session_key->data+8, '\0', 8);
905 if (memcmp(user_sess_key, zeros, 16) != 0) {
906 *session_key = data_blob_talloc(mem_ctx, user_sess_key, 16);
908 *server_returned_info = talloc_strdup(mem_ctx,
911 DEBUG(NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED) ? 0 : 3,
912 ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
913 user_info->client.domain_name, user_info->client.account_name,
914 user_info->workstation_name,
915 error_string ? error_string : "unknown error (NULL)"));
918 SAFE_FREE(error_string);
919 SAFE_FREE(unix_name);
923 static NTSTATUS local_pw_check(struct auth4_context *auth4_context,
925 const struct auth_usersupplied_info *user_info,
926 void **server_returned_info,
927 DATA_BLOB *session_key, DATA_BLOB *lm_session_key)
930 struct samr_Password lm_pw, nt_pw;
932 nt_lm_owf_gen (opt_password, nt_pw.hash, lm_pw.hash);
934 nt_status = ntlm_password_check(mem_ctx,
936 &auth4_context->challenge.data,
937 &user_info->password.response.lanman,
938 &user_info->password.response.nt,
939 user_info->client.account_name,
940 user_info->client.account_name,
941 user_info->client.domain_name,
942 &lm_pw, &nt_pw, session_key, lm_session_key);
944 if (NT_STATUS_IS_OK(nt_status)) {
945 *server_returned_info = talloc_asprintf(mem_ctx,
946 "%s%c%s", user_info->client.domain_name,
947 *lp_winbind_separator(),
948 user_info->client.account_name);
950 DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
951 user_info->client.domain_name, user_info->client.account_name,
952 user_info->workstation_name,
953 nt_errstr(nt_status)));
958 static NTSTATUS ntlm_auth_start_ntlmssp_client(struct ntlmssp_state **client_ntlmssp_state)
961 if ( (opt_username == NULL) || (opt_domain == NULL) ) {
962 status = NT_STATUS_UNSUCCESSFUL;
963 DEBUG(1, ("Need username and domain for NTLMSSP\n"));
964 return NT_STATUS_INVALID_PARAMETER;
967 status = ntlmssp_client_start(NULL,
970 lp_client_ntlmv2_auth(),
971 client_ntlmssp_state);
973 if (!NT_STATUS_IS_OK(status)) {
974 DEBUG(1, ("Could not start NTLMSSP client: %s\n",
976 TALLOC_FREE(*client_ntlmssp_state);
980 status = ntlmssp_set_username(*client_ntlmssp_state, opt_username);
982 if (!NT_STATUS_IS_OK(status)) {
983 DEBUG(1, ("Could not set username: %s\n",
985 TALLOC_FREE(*client_ntlmssp_state);
989 status = ntlmssp_set_domain(*client_ntlmssp_state, opt_domain);
991 if (!NT_STATUS_IS_OK(status)) {
992 DEBUG(1, ("Could not set domain: %s\n",
994 TALLOC_FREE(*client_ntlmssp_state);
999 status = ntlmssp_set_password(*client_ntlmssp_state, opt_password);
1001 if (!NT_STATUS_IS_OK(status)) {
1002 DEBUG(1, ("Could not set password: %s\n",
1003 nt_errstr(status)));
1004 TALLOC_FREE(*client_ntlmssp_state);
1009 return NT_STATUS_OK;
1012 static struct auth4_context *make_auth4_context_ntlm_auth(TALLOC_CTX *mem_ctx, bool local_pw)
1014 struct auth4_context *auth4_context = talloc_zero(mem_ctx, struct auth4_context);
1015 if (auth4_context == NULL) {
1016 DEBUG(10, ("failed to allocate auth4_context failed\n"));
1019 auth4_context->generate_session_info = ntlm_auth_generate_session_info;
1020 auth4_context->generate_session_info_pac = ntlm_auth_generate_session_info_pac;
1021 auth4_context->get_ntlm_challenge = ntlm_auth_get_challenge;
1022 auth4_context->set_ntlm_challenge = ntlm_auth_set_challenge;
1024 auth4_context->check_ntlm_password = local_pw_check;
1026 auth4_context->check_ntlm_password = winbind_pw_check;
1028 auth4_context->private_data = NULL;
1029 return auth4_context;
1032 static NTSTATUS ntlm_auth_start_ntlmssp_server(TALLOC_CTX *mem_ctx,
1033 struct loadparm_context *lp_ctx,
1034 struct gensec_security **gensec_security_out)
1036 struct gensec_security *gensec_security;
1039 TALLOC_CTX *tmp_ctx;
1041 struct gensec_settings *gensec_settings;
1043 struct cli_credentials *server_credentials;
1045 struct auth4_context *auth4_context;
1047 tmp_ctx = talloc_new(mem_ctx);
1048 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
1050 auth4_context = make_auth4_context_ntlm_auth(tmp_ctx, opt_password);
1051 if (auth4_context == NULL) {
1052 TALLOC_FREE(tmp_ctx);
1053 return NT_STATUS_NO_MEMORY;
1056 gensec_settings = lpcfg_gensec_settings(tmp_ctx, lp_ctx);
1057 if (lp_ctx == NULL) {
1058 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1059 TALLOC_FREE(tmp_ctx);
1060 return NT_STATUS_NO_MEMORY;
1064 * This should be a 'netbios domain -> DNS domain'
1065 * mapping, and can currently validly return NULL on
1066 * poorly configured systems.
1068 * This is used for the NTLMSSP server
1072 gensec_settings->server_netbios_name = lp_netbios_name();
1073 gensec_settings->server_netbios_domain = lp_workgroup();
1075 gensec_settings->server_netbios_name = get_winbind_netbios_name();
1076 gensec_settings->server_netbios_domain = get_winbind_domain();
1079 gensec_settings->server_dns_domain = strlower_talloc(gensec_settings,
1080 get_mydnsdomname(talloc_tos()));
1081 gensec_settings->server_dns_name = strlower_talloc(gensec_settings,
1082 get_mydnsfullname());
1084 gensec_settings->backends = talloc_zero_array(gensec_settings,
1085 struct gensec_security_ops *, 4);
1087 if (gensec_settings->backends == NULL) {
1088 TALLOC_FREE(tmp_ctx);
1089 return NT_STATUS_NO_MEMORY;
1094 /* These need to be in priority order, krb5 before NTLMSSP */
1095 #if defined(HAVE_KRB5)
1096 gensec_settings->backends[idx++] = &gensec_gse_krb5_security_ops;
1099 gensec_settings->backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_NTLMSSP);
1101 gensec_settings->backends[idx++] = gensec_security_by_oid(NULL,
1105 * This is anonymous for now, because we just use it
1106 * to set the kerberos state at the moment
1108 server_credentials = cli_credentials_init_anon(tmp_ctx);
1109 if (!server_credentials) {
1110 DEBUG(0, ("auth_generic_prepare: Failed to init server credentials\n"));
1111 return NT_STATUS_NO_MEMORY;
1114 cli_credentials_set_conf(server_credentials, lp_ctx);
1116 if (lp_security() == SEC_ADS || USE_KERBEROS_KEYTAB) {
1117 cli_credentials_set_kerberos_state(server_credentials, CRED_AUTO_USE_KERBEROS);
1119 cli_credentials_set_kerberos_state(server_credentials, CRED_DONT_USE_KERBEROS);
1122 nt_status = gensec_server_start(tmp_ctx, gensec_settings,
1123 auth4_context, &gensec_security);
1125 if (!NT_STATUS_IS_OK(nt_status)) {
1126 TALLOC_FREE(tmp_ctx);
1130 gensec_set_credentials(gensec_security, server_credentials);
1132 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
1133 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
1135 talloc_unlink(tmp_ctx, lp_ctx);
1136 talloc_unlink(tmp_ctx, server_credentials);
1137 talloc_unlink(tmp_ctx, gensec_settings);
1138 talloc_unlink(tmp_ctx, auth4_context);
1140 nt_status = gensec_start_mech_by_oid(gensec_security, GENSEC_OID_NTLMSSP);
1141 if (!NT_STATUS_IS_OK(nt_status)) {
1142 TALLOC_FREE(tmp_ctx);
1146 *gensec_security_out = talloc_steal(mem_ctx, gensec_security);
1147 TALLOC_FREE(tmp_ctx);
1148 return NT_STATUS_OK;
1151 /*******************************************************************
1152 Used by firefox to drive NTLM auth to IIS servers.
1153 *******************************************************************/
1155 static NTSTATUS do_ccache_ntlm_auth(DATA_BLOB initial_msg, DATA_BLOB challenge_msg,
1158 struct winbindd_request wb_request;
1159 struct winbindd_response wb_response;
1163 /* get winbindd to do the ntlmssp step on our behalf */
1164 ZERO_STRUCT(wb_request);
1165 ZERO_STRUCT(wb_response);
1168 * This is tricky here. If we set krb5_auth in pam_winbind.conf
1169 * creds for users in trusted domain will be stored the winbindd
1170 * child of the trusted domain. If we ask the primary domain for
1171 * ntlm_ccache_auth, it will fail. So, we have to ask the trusted
1172 * domain's child for ccache_ntlm_auth. that is to say, we have to
1173 * set WBFLAG_PAM_CONTACT_TRUSTDOM in request.flags.
1175 ctrl = get_pam_winbind_config();
1177 if (ctrl & WINBIND_KRB5_AUTH) {
1178 wb_request.flags |= WBFLAG_PAM_CONTACT_TRUSTDOM;
1181 fstr_sprintf(wb_request.data.ccache_ntlm_auth.user,
1182 "%s%c%s", opt_domain, winbind_separator(), opt_username);
1183 wb_request.data.ccache_ntlm_auth.uid = geteuid();
1184 wb_request.data.ccache_ntlm_auth.initial_blob_len = initial_msg.length;
1185 wb_request.data.ccache_ntlm_auth.challenge_blob_len = challenge_msg.length;
1186 wb_request.extra_len = initial_msg.length + challenge_msg.length;
1188 if (wb_request.extra_len > 0) {
1189 wb_request.extra_data.data = SMB_MALLOC_ARRAY(char, wb_request.extra_len);
1190 if (wb_request.extra_data.data == NULL) {
1191 return NT_STATUS_NO_MEMORY;
1194 memcpy(wb_request.extra_data.data, initial_msg.data, initial_msg.length);
1195 memcpy(wb_request.extra_data.data + initial_msg.length,
1196 challenge_msg.data, challenge_msg.length);
1199 result = winbindd_request_response(WINBINDD_CCACHE_NTLMAUTH, &wb_request, &wb_response);
1200 SAFE_FREE(wb_request.extra_data.data);
1202 if (result != NSS_STATUS_SUCCESS) {
1203 winbindd_free_response(&wb_response);
1204 return NT_STATUS_UNSUCCESSFUL;
1208 *reply = data_blob(wb_response.extra_data.data,
1209 wb_response.data.ccache_ntlm_auth.auth_blob_len);
1210 if (wb_response.data.ccache_ntlm_auth.auth_blob_len > 0 &&
1211 reply->data == NULL) {
1212 winbindd_free_response(&wb_response);
1213 return NT_STATUS_NO_MEMORY;
1217 winbindd_free_response(&wb_response);
1218 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1221 static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode,
1222 struct loadparm_context *lp_ctx,
1223 struct ntlm_auth_state *state,
1224 char *buf, int length, void **private2)
1226 DATA_BLOB request, reply;
1229 if (!opt_username || !*opt_username) {
1230 x_fprintf(x_stderr, "username must be specified!\n\n");
1234 if (strlen(buf) < 2) {
1235 DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf));
1236 x_fprintf(x_stdout, "BH NTLMSSP query invalid\n");
1240 if (strlen(buf) > 3) {
1241 if(strncmp(buf, "SF ", 3) == 0) {
1242 DEBUG(10, ("Looking for flags to negotiate\n"));
1243 talloc_free(state->want_feature_list);
1244 state->want_feature_list = talloc_strdup(state->mem_ctx,
1246 x_fprintf(x_stdout, "OK\n");
1249 request = base64_decode_data_blob(buf + 3);
1251 request = data_blob_null;
1254 if (strncmp(buf, "PW ", 3) == 0) {
1255 /* We asked for a password and obviously got it :-) */
1257 opt_password = SMB_STRNDUP((const char *)request.data,
1260 if (opt_password == NULL) {
1261 DEBUG(1, ("Out of memory\n"));
1262 x_fprintf(x_stdout, "BH Out of memory\n");
1263 data_blob_free(&request);
1267 x_fprintf(x_stdout, "OK\n");
1268 data_blob_free(&request);
1272 if (!state->ntlmssp_state && use_cached_creds) {
1273 /* check whether cached credentials are usable. */
1274 DATA_BLOB empty_blob = data_blob_null;
1276 nt_status = do_ccache_ntlm_auth(empty_blob, empty_blob, NULL);
1277 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1278 /* failed to use cached creds */
1279 use_cached_creds = False;
1283 if (opt_password == NULL && !use_cached_creds) {
1284 /* Request a password from the calling process. After
1285 sending it, the calling process should retry asking for the
1288 DEBUG(10, ("Requesting password\n"));
1289 x_fprintf(x_stdout, "PW\n");
1293 if (strncmp(buf, "YR", 2) == 0) {
1294 TALLOC_FREE(state->ntlmssp_state);
1295 state->cli_state = CLIENT_INITIAL;
1296 } else if (strncmp(buf, "TT", 2) == 0) {
1297 /* No special preprocessing required */
1298 } else if (strncmp(buf, "GF", 2) == 0) {
1299 DEBUG(10, ("Requested negotiated NTLMSSP flags\n"));
1301 if(state->cli_state == CLIENT_FINISHED) {
1302 x_fprintf(x_stdout, "GF 0x%08x\n", state->neg_flags);
1305 x_fprintf(x_stdout, "BH\n");
1308 data_blob_free(&request);
1310 } else if (strncmp(buf, "GK", 2) == 0 ) {
1311 DEBUG(10, ("Requested session key\n"));
1313 if(state->cli_state == CLIENT_FINISHED) {
1314 char *key64 = base64_encode_data_blob(state->mem_ctx,
1315 state->session_key);
1316 x_fprintf(x_stdout, "GK %s\n", key64?key64:"<NULL>");
1320 x_fprintf(x_stdout, "BH\n");
1323 data_blob_free(&request);
1326 DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf));
1327 x_fprintf(x_stdout, "BH NTLMSSP query invalid\n");
1331 if (!state->ntlmssp_state) {
1332 nt_status = ntlm_auth_start_ntlmssp_client(
1333 &state->ntlmssp_state);
1334 if (!NT_STATUS_IS_OK(nt_status)) {
1335 x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
1338 ntlmssp_want_feature_list(state->ntlmssp_state,
1339 state->want_feature_list);
1340 state->initial_message = data_blob_null;
1343 DEBUG(10, ("got NTLMSSP packet:\n"));
1344 dump_data(10, request.data, request.length);
1346 if (use_cached_creds && !opt_password &&
1347 (state->cli_state == CLIENT_RESPONSE)) {
1348 nt_status = do_ccache_ntlm_auth(state->initial_message, request,
1351 nt_status = ntlmssp_update(state->ntlmssp_state, request,
1355 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1356 char *reply_base64 = base64_encode_data_blob(state->mem_ctx,
1358 if (state->cli_state == CLIENT_INITIAL) {
1359 x_fprintf(x_stdout, "YR %s\n", reply_base64);
1360 state->initial_message = reply;
1361 state->cli_state = CLIENT_RESPONSE;
1363 x_fprintf(x_stdout, "KK %s\n", reply_base64);
1364 data_blob_free(&reply);
1366 TALLOC_FREE(reply_base64);
1367 DEBUG(10, ("NTLMSSP challenge\n"));
1368 } else if (NT_STATUS_IS_OK(nt_status)) {
1369 char *reply_base64 = base64_encode_data_blob(talloc_tos(),
1371 x_fprintf(x_stdout, "AF %s\n", reply_base64);
1372 TALLOC_FREE(reply_base64);
1374 if(state->have_session_key)
1375 data_blob_free(&state->session_key);
1377 state->session_key = data_blob(
1378 state->ntlmssp_state->session_key.data,
1379 state->ntlmssp_state->session_key.length);
1380 state->neg_flags = state->ntlmssp_state->neg_flags;
1381 state->have_session_key = true;
1383 DEBUG(10, ("NTLMSSP OK!\n"));
1384 state->cli_state = CLIENT_FINISHED;
1385 TALLOC_FREE(state->ntlmssp_state);
1387 x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
1388 DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status)));
1389 state->cli_state = CLIENT_ERROR;
1390 TALLOC_FREE(state->ntlmssp_state);
1393 data_blob_free(&request);
1396 static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode,
1397 struct loadparm_context *lp_ctx,
1398 struct ntlm_auth_state *state,
1399 char *buf, int length, void **private2)
1404 pass=(char *)memchr(buf,' ',length);
1406 DEBUG(2, ("Password not found. Denying access\n"));
1407 x_fprintf(x_stdout, "ERR\n");
1413 if (state->helper_mode == SQUID_2_5_BASIC) {
1414 rfc1738_unescape(user);
1415 rfc1738_unescape(pass);
1418 if (check_plaintext_auth(user, pass, False)) {
1419 x_fprintf(x_stdout, "OK\n");
1421 x_fprintf(x_stdout, "ERR\n");
1425 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
1426 struct loadparm_context *lp_ctx,
1427 char *buf, int length, void **private1)
1430 DATA_BLOB out = data_blob(NULL, 0);
1431 char *out_base64 = NULL;
1432 const char *reply_arg = NULL;
1433 struct gensec_ntlm_state {
1434 struct gensec_security *gensec_state;
1435 const char *set_password;
1437 struct gensec_ntlm_state *state;
1441 const char *reply_code;
1442 struct cli_credentials *creds;
1444 static char *want_feature_list = NULL;
1445 static DATA_BLOB session_key;
1447 TALLOC_CTX *mem_ctx;
1450 state = (struct gensec_ntlm_state *)*private1;
1452 state = talloc_zero(NULL, struct gensec_ntlm_state);
1454 x_fprintf(x_stdout, "BH No Memory\n");
1459 state->set_password = opt_password;
1463 if (strlen(buf) < 2) {
1464 DEBUG(1, ("query [%s] invalid", buf));
1465 x_fprintf(x_stdout, "BH Query invalid\n");
1469 if (strlen(buf) > 3) {
1470 if(strncmp(buf, "SF ", 3) == 0) {
1471 DEBUG(10, ("Setting flags to negotiate\n"));
1472 talloc_free(want_feature_list);
1473 want_feature_list = talloc_strndup(state, buf+3, strlen(buf)-3);
1474 x_fprintf(x_stdout, "OK\n");
1477 in = base64_decode_data_blob(buf + 3);
1479 in = data_blob(NULL, 0);
1482 if (strncmp(buf, "YR", 2) == 0) {
1483 if (state->gensec_state) {
1484 talloc_free(state->gensec_state);
1485 state->gensec_state = NULL;
1487 } else if ( (strncmp(buf, "OK", 2) == 0)) {
1488 /* Just return BH, like ntlm_auth from Samba 3 does. */
1489 x_fprintf(x_stdout, "BH Command expected\n");
1490 data_blob_free(&in);
1492 } else if ( (strncmp(buf, "TT ", 3) != 0) &&
1493 (strncmp(buf, "KK ", 3) != 0) &&
1494 (strncmp(buf, "AF ", 3) != 0) &&
1495 (strncmp(buf, "NA ", 3) != 0) &&
1496 (strncmp(buf, "UG", 2) != 0) &&
1497 (strncmp(buf, "PW ", 3) != 0) &&
1498 (strncmp(buf, "GK", 2) != 0) &&
1499 (strncmp(buf, "GF", 2) != 0)) {
1500 DEBUG(1, ("SPNEGO request [%s] invalid prefix\n", buf));
1501 x_fprintf(x_stdout, "BH SPNEGO request invalid prefix\n");
1502 data_blob_free(&in);
1506 mem_ctx = talloc_named(NULL, 0, "manage_gensec_request internal mem_ctx");
1509 if (!(state->gensec_state)) {
1510 switch (stdio_helper_mode) {
1511 case GSS_SPNEGO_CLIENT:
1512 case NTLMSSP_CLIENT_1:
1513 /* setup the client side */
1515 nt_status = gensec_client_start(NULL, &state->gensec_state,
1516 lpcfg_gensec_settings(NULL, lp_ctx));
1517 if (!NT_STATUS_IS_OK(nt_status)) {
1518 x_fprintf(x_stdout, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status));
1519 talloc_free(mem_ctx);
1523 creds = cli_credentials_init(state->gensec_state);
1524 cli_credentials_set_conf(creds, lp_ctx);
1526 cli_credentials_set_username(creds, opt_username, CRED_SPECIFIED);
1529 cli_credentials_set_domain(creds, opt_domain, CRED_SPECIFIED);
1531 if (state->set_password) {
1532 cli_credentials_set_password(creds, state->set_password, CRED_SPECIFIED);
1534 cli_credentials_set_password_callback(creds, get_password);
1536 if (opt_workstation) {
1537 cli_credentials_set_workstation(creds, opt_workstation, CRED_SPECIFIED);
1540 gensec_set_credentials(state->gensec_state, creds);
1543 case GSS_SPNEGO_SERVER:
1544 case SQUID_2_5_NTLMSSP:
1546 nt_status = ntlm_auth_start_ntlmssp_server(state, lp_ctx,
1547 &state->gensec_state);
1548 if (!NT_STATUS_IS_OK(nt_status)) {
1549 x_fprintf(x_stdout, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status));
1550 talloc_free(mem_ctx);
1556 talloc_free(mem_ctx);
1560 gensec_want_feature_list(state->gensec_state, want_feature_list);
1562 switch (stdio_helper_mode) {
1563 case GSS_SPNEGO_CLIENT:
1564 case GSS_SPNEGO_SERVER:
1565 nt_status = gensec_start_mech_by_oid(state->gensec_state, GENSEC_OID_SPNEGO);
1570 case NTLMSSP_CLIENT_1:
1575 case SQUID_2_5_NTLMSSP:
1576 nt_status = gensec_start_mech_by_oid(state->gensec_state, GENSEC_OID_NTLMSSP);
1579 talloc_free(mem_ctx);
1583 if (!NT_STATUS_IS_OK(nt_status)) {
1584 DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status)));
1585 x_fprintf(x_stdout, "BH GENSEC mech failed to start\n");
1586 talloc_free(mem_ctx);
1594 if (strncmp(buf, "PW ", 3) == 0) {
1595 state->set_password = talloc_strndup(state,
1596 (const char *)in.data,
1599 cli_credentials_set_password(gensec_get_credentials(state->gensec_state),
1600 state->set_password,
1602 x_fprintf(x_stdout, "OK\n");
1603 data_blob_free(&in);
1604 talloc_free(mem_ctx);
1608 if (strncmp(buf, "GK", 2) == 0) {
1610 DEBUG(10, ("Requested session key\n"));
1611 nt_status = gensec_session_key(state->gensec_state, mem_ctx, &session_key);
1612 if(!NT_STATUS_IS_OK(nt_status)) {
1613 DEBUG(1, ("gensec_session_key failed: %s\n", nt_errstr(nt_status)));
1614 x_fprintf(x_stdout, "BH No session key\n");
1615 talloc_free(mem_ctx);
1618 base64_key = base64_encode_data_blob(state, session_key);
1619 x_fprintf(x_stdout, "GK %s\n", base64_key);
1620 talloc_free(base64_key);
1622 talloc_free(mem_ctx);
1626 if (stdio_helper_mode == SQUID_2_5_NTLMSSP && strncmp(buf, "GF", 2) == 0) {
1629 neg_flags = gensec_ntlmssp_neg_flags(state->gensec_state);
1631 DEBUG(10, ("Requested negotiated feature flags\n"));
1632 x_fprintf(x_stdout, "GF 0x%08x\n", neg_flags);
1636 nt_status = gensec_update(state->gensec_state, mem_ctx, NULL, in, &out);
1638 /* don't leak 'bad password'/'no such user' info to the network client */
1639 nt_status = nt_status_squash(nt_status);
1642 out_base64 = base64_encode_data_blob(mem_ctx, out);
1647 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1649 if (first && state->gensec_state->gensec_role == GENSEC_CLIENT) {
1651 } else if (state->gensec_state->gensec_role == GENSEC_CLIENT) {
1653 } else if (state->gensec_state->gensec_role == GENSEC_SERVER) {
1660 } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) {
1661 reply_code = "BH NT_STATUS_ACCESS_DENIED";
1662 reply_arg = nt_errstr(nt_status);
1663 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
1664 } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_UNSUCCESSFUL)) {
1665 reply_code = "BH NT_STATUS_UNSUCCESSFUL";
1666 reply_arg = nt_errstr(nt_status);
1667 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
1668 } else if (!NT_STATUS_IS_OK(nt_status)) {
1670 reply_arg = nt_errstr(nt_status);
1671 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
1672 } else if /* OK */ (state->gensec_state->gensec_role == GENSEC_SERVER) {
1673 struct auth_session_info *session_info;
1675 nt_status = gensec_session_info(state->gensec_state, mem_ctx, &session_info);
1676 if (!NT_STATUS_IS_OK(nt_status)) {
1677 reply_code = "BH Failed to retrive session info";
1678 reply_arg = nt_errstr(nt_status);
1679 DEBUG(1, ("GENSEC failed to retrieve the session info: %s\n", nt_errstr(nt_status)));
1683 reply_arg = session_info->unix_info->unix_name;
1684 talloc_free(session_info);
1686 } else if (state->gensec_state->gensec_role == GENSEC_CLIENT) {
1688 reply_arg = out_base64;
1693 switch (stdio_helper_mode) {
1694 case GSS_SPNEGO_SERVER:
1695 x_fprintf(x_stdout, "%s %s %s\n", reply_code,
1696 out_base64 ? out_base64 : "*",
1697 reply_arg ? reply_arg : "*");
1701 x_fprintf(x_stdout, "%s %s\n", reply_code, out_base64);
1702 } else if (reply_arg) {
1703 x_fprintf(x_stdout, "%s %s\n", reply_code, reply_arg);
1705 x_fprintf(x_stdout, "%s\n", reply_code);
1709 talloc_free(mem_ctx);
1713 static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode,
1714 struct loadparm_context *lp_ctx,
1715 struct ntlm_auth_state *state,
1716 char *buf, int length, void **private2)
1718 manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
1722 static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode,
1723 struct loadparm_context *lp_ctx,
1724 struct ntlm_auth_state *state,
1725 char *buf, int length, void **private2)
1727 manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
1731 static struct ntlmssp_state *client_ntlmssp_state = NULL;
1733 static bool manage_client_ntlmssp_init(struct spnego_data spnego)
1736 DATA_BLOB null_blob = data_blob_null;
1737 DATA_BLOB to_server;
1738 char *to_server_base64;
1739 const char *my_mechs[] = {OID_NTLMSSP, NULL};
1740 TALLOC_CTX *ctx = talloc_tos();
1742 DEBUG(10, ("Got spnego negTokenInit with NTLMSSP\n"));
1744 if (client_ntlmssp_state != NULL) {
1745 DEBUG(1, ("Request for initial SPNEGO request where "
1746 "we already have a state\n"));
1750 if (!client_ntlmssp_state) {
1751 if (!NT_STATUS_IS_OK(status = ntlm_auth_start_ntlmssp_client(&client_ntlmssp_state))) {
1752 x_fprintf(x_stdout, "BH %s\n", nt_errstr(status));
1758 if (opt_password == NULL) {
1760 /* Request a password from the calling process. After
1761 sending it, the calling process should retry with
1762 the negTokenInit. */
1764 DEBUG(10, ("Requesting password\n"));
1765 x_fprintf(x_stdout, "PW\n");
1769 spnego.type = SPNEGO_NEG_TOKEN_INIT;
1770 spnego.negTokenInit.mechTypes = my_mechs;
1771 spnego.negTokenInit.reqFlags = data_blob_null;
1772 spnego.negTokenInit.reqFlagsPadding = 0;
1773 spnego.negTokenInit.mechListMIC = null_blob;
1775 status = ntlmssp_update(client_ntlmssp_state, null_blob,
1776 &spnego.negTokenInit.mechToken);
1778 if ( !(NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) ||
1779 NT_STATUS_IS_OK(status)) ) {
1780 DEBUG(1, ("Expected OK or MORE_PROCESSING_REQUIRED, got: %s\n",
1781 nt_errstr(status)));
1782 TALLOC_FREE(client_ntlmssp_state);
1786 spnego_write_data(ctx, &to_server, &spnego);
1787 data_blob_free(&spnego.negTokenInit.mechToken);
1789 to_server_base64 = base64_encode_data_blob(talloc_tos(), to_server);
1790 data_blob_free(&to_server);
1791 x_fprintf(x_stdout, "KK %s\n", to_server_base64);
1792 TALLOC_FREE(to_server_base64);
1796 static void manage_client_ntlmssp_targ(struct spnego_data spnego)
1799 DATA_BLOB null_blob = data_blob_null;
1801 DATA_BLOB to_server;
1802 char *to_server_base64;
1803 TALLOC_CTX *ctx = talloc_tos();
1805 DEBUG(10, ("Got spnego negTokenTarg with NTLMSSP\n"));
1807 if (client_ntlmssp_state == NULL) {
1808 DEBUG(1, ("Got NTLMSSP tArg without a client state\n"));
1809 x_fprintf(x_stdout, "BH Got NTLMSSP tArg without a client state\n");
1813 if (spnego.negTokenTarg.negResult == SPNEGO_REJECT) {
1814 x_fprintf(x_stdout, "NA\n");
1815 TALLOC_FREE(client_ntlmssp_state);
1819 if (spnego.negTokenTarg.negResult == SPNEGO_ACCEPT_COMPLETED) {
1820 x_fprintf(x_stdout, "AF\n");
1821 TALLOC_FREE(client_ntlmssp_state);
1825 status = ntlmssp_update(client_ntlmssp_state,
1826 spnego.negTokenTarg.responseToken,
1829 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) {
1830 DEBUG(1, ("Expected MORE_PROCESSING_REQUIRED or OK from "
1831 "ntlmssp_client_update, got: %s\n",
1832 nt_errstr(status)));
1833 x_fprintf(x_stdout, "BH Expected MORE_PROCESSING_REQUIRED from "
1834 "ntlmssp_client_update\n");
1835 data_blob_free(&request);
1836 TALLOC_FREE(client_ntlmssp_state);
1840 spnego.type = SPNEGO_NEG_TOKEN_TARG;
1841 spnego.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
1842 spnego.negTokenTarg.supportedMech = (const char *)OID_NTLMSSP;
1843 spnego.negTokenTarg.responseToken = request;
1844 spnego.negTokenTarg.mechListMIC = null_blob;
1846 spnego_write_data(ctx, &to_server, &spnego);
1847 data_blob_free(&request);
1849 to_server_base64 = base64_encode_data_blob(talloc_tos(), to_server);
1850 data_blob_free(&to_server);
1851 x_fprintf(x_stdout, "KK %s\n", to_server_base64);
1852 TALLOC_FREE(to_server_base64);
1858 static bool manage_client_krb5_init(struct spnego_data spnego)
1861 DATA_BLOB tkt, tkt_wrapped, to_server;
1862 DATA_BLOB session_key_krb5 = data_blob_null;
1863 struct spnego_data reply;
1867 const char *my_mechs[] = {OID_KERBEROS5_OLD, NULL};
1869 TALLOC_CTX *ctx = talloc_tos();
1871 principal = spnego.negTokenInit.targetPrincipal;
1873 /* We may not be allowed to use the server-supplied SPNEGO principal, or it may not have been supplied to us
1875 if (!lp_client_use_spnego_principal() || strequal(principal, ADS_IGNORE_PRINCIPAL)) {
1879 if (principal == NULL &&
1880 opt_target_service && opt_target_hostname && !is_ipaddress(opt_target_hostname)) {
1881 DEBUG(3,("manage_client_krb5_init: using target "
1882 "hostname not SPNEGO principal\n"));
1884 principal = kerberos_get_principal_from_service_hostname(talloc_tos(),
1886 opt_target_hostname,
1893 DEBUG(3,("manage_client_krb5_init: guessed "
1894 "server principal=%s\n",
1895 principal ? principal : "<null>"));
1898 if (principal == NULL) {
1899 DEBUG(3,("manage_client_krb5_init: could not guess server principal\n"));
1903 retval = cli_krb5_get_ticket(ctx, principal, 0,
1904 &tkt, &session_key_krb5,
1905 0, NULL, NULL, NULL);
1909 /* Let's try to first get the TGT, for that we need a
1912 if (opt_password == NULL) {
1913 DEBUG(10, ("Requesting password\n"));
1914 x_fprintf(x_stdout, "PW\n");
1918 user = talloc_asprintf(talloc_tos(), "%s@%s", opt_username, opt_domain);
1923 if ((retval = kerberos_kinit_password(user, opt_password, 0, NULL))) {
1924 DEBUG(10, ("Requesting TGT failed: %s\n", error_message(retval)));
1928 retval = cli_krb5_get_ticket(ctx, principal, 0,
1929 &tkt, &session_key_krb5,
1930 0, NULL, NULL, NULL);
1932 DEBUG(10, ("Kinit suceeded, but getting a ticket failed: %s\n", error_message(retval)));
1938 /* wrap that up in a nice GSS-API wrapping */
1939 tkt_wrapped = spnego_gen_krb5_wrap(ctx, tkt, TOK_ID_KRB_AP_REQ);
1941 data_blob_free(&session_key_krb5);
1945 reply.type = SPNEGO_NEG_TOKEN_INIT;
1946 reply.negTokenInit.mechTypes = my_mechs;
1947 reply.negTokenInit.reqFlags = data_blob_null;
1948 reply.negTokenInit.reqFlagsPadding = 0;
1949 reply.negTokenInit.mechToken = tkt_wrapped;
1950 reply.negTokenInit.mechListMIC = data_blob_null;
1952 len = spnego_write_data(ctx, &to_server, &reply);
1953 data_blob_free(&tkt);
1956 DEBUG(1, ("Could not write SPNEGO data blob\n"));
1960 reply_base64 = base64_encode_data_blob(talloc_tos(), to_server);
1961 x_fprintf(x_stdout, "KK %s *\n", reply_base64);
1963 TALLOC_FREE(reply_base64);
1964 data_blob_free(&to_server);
1965 DEBUG(10, ("sent GSS-SPNEGO KERBEROS5 negTokenInit\n"));
1969 static void manage_client_krb5_targ(struct spnego_data spnego)
1971 switch (spnego.negTokenTarg.negResult) {
1972 case SPNEGO_ACCEPT_INCOMPLETE:
1973 DEBUG(1, ("Got a Kerberos negTokenTarg with ACCEPT_INCOMPLETE\n"));
1974 x_fprintf(x_stdout, "BH Got a Kerberos negTokenTarg with "
1975 "ACCEPT_INCOMPLETE\n");
1977 case SPNEGO_ACCEPT_COMPLETED:
1978 DEBUG(10, ("Accept completed\n"));
1979 x_fprintf(x_stdout, "AF\n");
1982 DEBUG(10, ("Rejected\n"));
1983 x_fprintf(x_stdout, "NA\n");
1986 DEBUG(1, ("Got an invalid negTokenTarg\n"));
1987 x_fprintf(x_stdout, "AF\n");
1993 static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode,
1994 struct loadparm_context *lp_ctx,
1995 struct ntlm_auth_state *state,
1996 char *buf, int length, void **private2)
1999 struct spnego_data spnego;
2001 TALLOC_CTX *ctx = talloc_tos();
2003 if (!opt_username || !*opt_username) {
2004 x_fprintf(x_stderr, "username must be specified!\n\n");
2008 if (strlen(buf) <= 3) {
2009 DEBUG(1, ("SPNEGO query [%s] too short\n", buf));
2010 x_fprintf(x_stdout, "BH SPNEGO query too short\n");
2014 request = base64_decode_data_blob(buf+3);
2016 if (strncmp(buf, "PW ", 3) == 0) {
2018 /* We asked for a password and obviously got it :-) */
2020 opt_password = SMB_STRNDUP((const char *)request.data, request.length);
2022 if (opt_password == NULL) {
2023 DEBUG(1, ("Out of memory\n"));
2024 x_fprintf(x_stdout, "BH Out of memory\n");
2025 data_blob_free(&request);
2029 x_fprintf(x_stdout, "OK\n");
2030 data_blob_free(&request);
2034 if ( (strncmp(buf, "TT ", 3) != 0) &&
2035 (strncmp(buf, "AF ", 3) != 0) &&
2036 (strncmp(buf, "NA ", 3) != 0) ) {
2037 DEBUG(1, ("SPNEGO request [%s] invalid\n", buf));
2038 x_fprintf(x_stdout, "BH SPNEGO request invalid\n");
2039 data_blob_free(&request);
2043 /* So we got a server challenge to generate a SPNEGO
2044 client-to-server request... */
2046 len = spnego_read_data(ctx, request, &spnego);
2047 data_blob_free(&request);
2050 DEBUG(1, ("Could not read SPNEGO data for [%s]\n", buf));
2051 x_fprintf(x_stdout, "BH Could not read SPNEGO data\n");
2055 if (spnego.type == SPNEGO_NEG_TOKEN_INIT) {
2057 /* The server offers a list of mechanisms */
2059 const char **mechType = (const char **)spnego.negTokenInit.mechTypes;
2061 while (*mechType != NULL) {
2064 if ( (strcmp(*mechType, OID_KERBEROS5_OLD) == 0) ||
2065 (strcmp(*mechType, OID_KERBEROS5) == 0) ) {
2066 if (manage_client_krb5_init(spnego))
2071 if (strcmp(*mechType, OID_NTLMSSP) == 0) {
2072 if (manage_client_ntlmssp_init(spnego))
2079 DEBUG(1, ("Server offered no compatible mechanism\n"));
2080 x_fprintf(x_stdout, "BH Server offered no compatible mechanism\n");
2084 if (spnego.type == SPNEGO_NEG_TOKEN_TARG) {
2086 if (spnego.negTokenTarg.supportedMech == NULL) {
2087 /* On accept/reject Windows does not send the
2088 mechanism anymore. Handle that here and
2089 shut down the mechanisms. */
2091 switch (spnego.negTokenTarg.negResult) {
2092 case SPNEGO_ACCEPT_COMPLETED:
2093 x_fprintf(x_stdout, "AF\n");
2096 x_fprintf(x_stdout, "NA\n");
2099 DEBUG(1, ("Got a negTokenTarg with no mech and an "
2100 "unknown negResult: %d\n",
2101 spnego.negTokenTarg.negResult));
2102 x_fprintf(x_stdout, "BH Got a negTokenTarg with"
2103 " no mech and an unknown "
2107 TALLOC_FREE(client_ntlmssp_state);
2111 if (strcmp(spnego.negTokenTarg.supportedMech,
2112 OID_NTLMSSP) == 0) {
2113 manage_client_ntlmssp_targ(spnego);
2118 if (strcmp(spnego.negTokenTarg.supportedMech,
2119 OID_KERBEROS5_OLD) == 0) {
2120 manage_client_krb5_targ(spnego);
2127 DEBUG(1, ("Got an SPNEGO token I could not handle [%s]!\n", buf));
2128 x_fprintf(x_stdout, "BH Got an SPNEGO token I could not handle\n");
2132 spnego_free_data(&spnego);
2136 static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode,
2137 struct loadparm_context *lp_ctx,
2138 struct ntlm_auth_state *state,
2139 char *buf, int length, void **private2)
2141 char *request, *parameter;
2142 static DATA_BLOB challenge;
2143 static DATA_BLOB lm_response;
2144 static DATA_BLOB nt_response;
2145 static char *full_username;
2146 static char *username;
2147 static char *domain;
2148 static char *plaintext_password;
2149 static bool ntlm_server_1_user_session_key;
2150 static bool ntlm_server_1_lm_session_key;
2152 if (strequal(buf, ".")) {
2153 if (!full_username && !username) {
2154 x_fprintf(x_stdout, "Error: No username supplied!\n");
2155 } else if (plaintext_password) {
2156 /* handle this request as plaintext */
2157 if (!full_username) {
2158 if (asprintf(&full_username, "%s%c%s", domain, winbind_separator(), username) == -1) {
2159 x_fprintf(x_stdout, "Error: Out of memory in asprintf!\n.\n");
2163 if (check_plaintext_auth(full_username, plaintext_password, False)) {
2164 x_fprintf(x_stdout, "Authenticated: Yes\n");
2166 x_fprintf(x_stdout, "Authenticated: No\n");
2168 } else if (!lm_response.data && !nt_response.data) {
2169 x_fprintf(x_stdout, "Error: No password supplied!\n");
2170 } else if (!challenge.data) {
2171 x_fprintf(x_stdout, "Error: No lanman-challenge supplied!\n");
2173 char *error_string = NULL;
2175 uchar user_session_key[16];
2178 if (full_username && !username) {
2180 fstring fstr_domain;
2182 if (!parse_ntlm_auth_domain_user(full_username, fstr_user, fstr_domain)) {
2183 /* username might be 'tainted', don't print into our new-line deleimianted stream */
2184 x_fprintf(x_stdout, "Error: Could not parse into domain and username\n");
2186 SAFE_FREE(username);
2188 username = smb_xstrdup(fstr_user);
2189 domain = smb_xstrdup(fstr_domain);
2193 domain = smb_xstrdup(get_winbind_domain());
2196 if (ntlm_server_1_lm_session_key)
2197 flags |= WBFLAG_PAM_LMKEY;
2199 if (ntlm_server_1_user_session_key)
2200 flags |= WBFLAG_PAM_USER_SESSION_KEY;
2202 if (!NT_STATUS_IS_OK(
2203 contact_winbind_auth_crap(username,
2215 x_fprintf(x_stdout, "Authenticated: No\n");
2216 x_fprintf(x_stdout, "Authentication-Error: %s\n.\n", error_string);
2218 static char zeros[16];
2220 char *hex_user_session_key;
2222 x_fprintf(x_stdout, "Authenticated: Yes\n");
2224 if (ntlm_server_1_lm_session_key
2225 && (memcmp(zeros, lm_key,
2226 sizeof(lm_key)) != 0)) {
2227 hex_lm_key = hex_encode_talloc(NULL,
2228 (const unsigned char *)lm_key,
2230 x_fprintf(x_stdout, "LANMAN-Session-Key: %s\n", hex_lm_key);
2231 TALLOC_FREE(hex_lm_key);
2234 if (ntlm_server_1_user_session_key
2235 && (memcmp(zeros, user_session_key,
2236 sizeof(user_session_key)) != 0)) {
2237 hex_user_session_key = hex_encode_talloc(NULL,
2238 (const unsigned char *)user_session_key,
2239 sizeof(user_session_key));
2240 x_fprintf(x_stdout, "User-Session-Key: %s\n", hex_user_session_key);
2241 TALLOC_FREE(hex_user_session_key);
2244 SAFE_FREE(error_string);
2246 /* clear out the state */
2247 challenge = data_blob_null;
2248 nt_response = data_blob_null;
2249 lm_response = data_blob_null;
2250 SAFE_FREE(full_username);
2251 SAFE_FREE(username);
2253 SAFE_FREE(plaintext_password);
2254 ntlm_server_1_user_session_key = False;
2255 ntlm_server_1_lm_session_key = False;
2256 x_fprintf(x_stdout, ".\n");
2263 /* Indicates a base64 encoded structure */
2264 parameter = strstr_m(request, ":: ");
2266 parameter = strstr_m(request, ": ");
2269 DEBUG(0, ("Parameter not found!\n"));
2270 x_fprintf(x_stdout, "Error: Parameter not found!\n.\n");
2287 base64_decode_inplace(parameter);
2290 if (strequal(request, "LANMAN-Challenge")) {
2291 challenge = strhex_to_data_blob(NULL, parameter);
2292 if (challenge.length != 8) {
2293 x_fprintf(x_stdout, "Error: hex decode of %s failed! (got %d bytes, expected 8)\n.\n",
2295 (int)challenge.length);
2296 challenge = data_blob_null;
2298 } else if (strequal(request, "NT-Response")) {
2299 nt_response = strhex_to_data_blob(NULL, parameter);
2300 if (nt_response.length < 24) {
2301 x_fprintf(x_stdout, "Error: hex decode of %s failed! (only got %d bytes, needed at least 24)\n.\n",
2303 (int)nt_response.length);
2304 nt_response = data_blob_null;
2306 } else if (strequal(request, "LANMAN-Response")) {
2307 lm_response = strhex_to_data_blob(NULL, parameter);
2308 if (lm_response.length != 24) {
2309 x_fprintf(x_stdout, "Error: hex decode of %s failed! (got %d bytes, expected 24)\n.\n",
2311 (int)lm_response.length);
2312 lm_response = data_blob_null;
2314 } else if (strequal(request, "Password")) {
2315 plaintext_password = smb_xstrdup(parameter);
2316 } else if (strequal(request, "NT-Domain")) {
2317 domain = smb_xstrdup(parameter);
2318 } else if (strequal(request, "Username")) {
2319 username = smb_xstrdup(parameter);
2320 } else if (strequal(request, "Full-Username")) {
2321 full_username = smb_xstrdup(parameter);
2322 } else if (strequal(request, "Request-User-Session-Key")) {
2323 ntlm_server_1_user_session_key = strequal(parameter, "Yes");
2324 } else if (strequal(request, "Request-LanMan-Session-Key")) {
2325 ntlm_server_1_lm_session_key = strequal(parameter, "Yes");
2327 x_fprintf(x_stdout, "Error: Unknown request %s\n.\n", request);
2331 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode,
2332 struct loadparm_context *lp_ctx,
2333 struct ntlm_auth_state *state,
2334 char *buf, int length, void **private2)
2336 char *request, *parameter;
2337 static DATA_BLOB new_nt_pswd;
2338 static DATA_BLOB old_nt_hash_enc;
2339 static DATA_BLOB new_lm_pswd;
2340 static DATA_BLOB old_lm_hash_enc;
2341 static char *full_username = NULL;
2342 static char *username = NULL;
2343 static char *domain = NULL;
2344 static char *newpswd = NULL;
2345 static char *oldpswd = NULL;
2347 if (strequal(buf, ".")) {
2348 if(newpswd && oldpswd) {
2349 uchar old_nt_hash[16];
2350 uchar old_lm_hash[16];
2351 uchar new_nt_hash[16];
2352 uchar new_lm_hash[16];
2354 new_nt_pswd = data_blob(NULL, 516);
2355 old_nt_hash_enc = data_blob(NULL, 16);
2357 /* Calculate the MD4 hash (NT compatible) of the
2359 E_md4hash(oldpswd, old_nt_hash);
2360 E_md4hash(newpswd, new_nt_hash);
2362 /* E_deshash returns false for 'long'
2363 passwords (> 14 DOS chars).
2365 Therefore, don't send a buffer
2366 encrypted with the truncated hash
2367 (it could allow an even easier
2368 attack on the password)
2370 Likewise, obey the admin's restriction
2373 if (lp_client_lanman_auth() &&
2374 E_deshash(newpswd, new_lm_hash) &&
2375 E_deshash(oldpswd, old_lm_hash)) {
2376 new_lm_pswd = data_blob(NULL, 516);
2377 old_lm_hash_enc = data_blob(NULL, 16);
2378 encode_pw_buffer(new_lm_pswd.data, newpswd,
2381 arcfour_crypt(new_lm_pswd.data, old_nt_hash, 516);
2382 E_old_pw_hash(new_nt_hash, old_lm_hash,
2383 old_lm_hash_enc.data);
2385 new_lm_pswd.data = NULL;
2386 new_lm_pswd.length = 0;
2387 old_lm_hash_enc.data = NULL;
2388 old_lm_hash_enc.length = 0;
2391 encode_pw_buffer(new_nt_pswd.data, newpswd,
2394 arcfour_crypt(new_nt_pswd.data, old_nt_hash, 516);
2395 E_old_pw_hash(new_nt_hash, old_nt_hash,
2396 old_nt_hash_enc.data);
2399 if (!full_username && !username) {
2400 x_fprintf(x_stdout, "Error: No username supplied!\n");
2401 } else if ((!new_nt_pswd.data || !old_nt_hash_enc.data) &&
2402 (!new_lm_pswd.data || old_lm_hash_enc.data) ) {
2403 x_fprintf(x_stdout, "Error: No NT or LM password "
2404 "blobs supplied!\n");
2406 char *error_string = NULL;
2408 if (full_username && !username) {
2410 fstring fstr_domain;
2412 if (!parse_ntlm_auth_domain_user(full_username,
2415 /* username might be 'tainted', don't
2416 * print into our new-line
2417 * deleimianted stream */
2418 x_fprintf(x_stdout, "Error: Could not "
2419 "parse into domain and "
2421 SAFE_FREE(username);
2422 username = smb_xstrdup(full_username);
2424 SAFE_FREE(username);
2426 username = smb_xstrdup(fstr_user);
2427 domain = smb_xstrdup(fstr_domain);
2432 if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
2439 x_fprintf(x_stdout, "Password-Change: No\n");
2440 x_fprintf(x_stdout, "Password-Change-Error: "
2441 "%s\n.\n", error_string);
2443 x_fprintf(x_stdout, "Password-Change: Yes\n");
2446 SAFE_FREE(error_string);
2448 /* clear out the state */
2449 new_nt_pswd = data_blob_null;
2450 old_nt_hash_enc = data_blob_null;
2451 new_lm_pswd = data_blob_null;
2452 old_nt_hash_enc = data_blob_null;
2453 SAFE_FREE(full_username);
2454 SAFE_FREE(username);
2458 x_fprintf(x_stdout, ".\n");
2465 /* Indicates a base64 encoded structure */
2466 parameter = strstr_m(request, ":: ");
2468 parameter = strstr_m(request, ": ");
2471 DEBUG(0, ("Parameter not found!\n"));
2472 x_fprintf(x_stdout, "Error: Parameter not found!\n.\n");
2488 base64_decode_inplace(parameter);
2491 if (strequal(request, "new-nt-password-blob")) {
2492 new_nt_pswd = strhex_to_data_blob(NULL, parameter);
2493 if (new_nt_pswd.length != 516) {
2494 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2495 "(got %d bytes, expected 516)\n.\n",
2497 (int)new_nt_pswd.length);
2498 new_nt_pswd = data_blob_null;
2500 } else if (strequal(request, "old-nt-hash-blob")) {
2501 old_nt_hash_enc = strhex_to_data_blob(NULL, parameter);
2502 if (old_nt_hash_enc.length != 16) {
2503 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2504 "(got %d bytes, expected 16)\n.\n",
2506 (int)old_nt_hash_enc.length);
2507 old_nt_hash_enc = data_blob_null;
2509 } else if (strequal(request, "new-lm-password-blob")) {
2510 new_lm_pswd = strhex_to_data_blob(NULL, parameter);
2511 if (new_lm_pswd.length != 516) {
2512 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2513 "(got %d bytes, expected 516)\n.\n",
2515 (int)new_lm_pswd.length);
2516 new_lm_pswd = data_blob_null;
2519 else if (strequal(request, "old-lm-hash-blob")) {
2520 old_lm_hash_enc = strhex_to_data_blob(NULL, parameter);
2521 if (old_lm_hash_enc.length != 16)
2523 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2524 "(got %d bytes, expected 16)\n.\n",
2526 (int)old_lm_hash_enc.length);
2527 old_lm_hash_enc = data_blob_null;
2529 } else if (strequal(request, "nt-domain")) {
2530 domain = smb_xstrdup(parameter);
2531 } else if(strequal(request, "username")) {
2532 username = smb_xstrdup(parameter);
2533 } else if(strequal(request, "full-username")) {
2534 username = smb_xstrdup(parameter);
2535 } else if(strequal(request, "new-password")) {
2536 newpswd = smb_xstrdup(parameter);
2537 } else if (strequal(request, "old-password")) {
2538 oldpswd = smb_xstrdup(parameter);
2540 x_fprintf(x_stdout, "Error: Unknown request %s\n.\n", request);
2544 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode,
2545 struct loadparm_context *lp_ctx,
2546 struct ntlm_auth_state *state,
2547 stdio_helper_function fn, void **private2)
2550 char tmp[INITIAL_BUFFER_SIZE+1];
2551 int length, buf_size = 0;
2554 buf = talloc_strdup(state->mem_ctx, "");
2556 DEBUG(0, ("Failed to allocate input buffer.\n"));
2557 x_fprintf(x_stderr, "ERR\n");
2563 /* this is not a typo - x_fgets doesn't work too well under
2565 if (fgets(tmp, sizeof(tmp)-1, stdin) == NULL) {
2566 if (ferror(stdin)) {
2567 DEBUG(1, ("fgets() failed! dying..... errno=%d "
2568 "(%s)\n", ferror(stdin),
2569 strerror(ferror(stdin))));
2576 buf = talloc_strdup_append_buffer(buf, tmp);
2577 buf_size += INITIAL_BUFFER_SIZE;
2579 if (buf_size > MAX_BUFFER_SIZE) {
2580 DEBUG(2, ("Oversized message\n"));
2581 x_fprintf(x_stderr, "ERR\n");
2586 c = strchr(buf, '\n');
2587 } while (c == NULL);
2592 DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf,length));
2594 if (buf[0] == '\0') {
2595 DEBUG(2, ("Invalid Request\n"));
2596 x_fprintf(x_stderr, "ERR\n");
2601 fn(stdio_helper_mode, lp_ctx, state, buf, length, private2);
2606 static void squid_stream(enum stdio_helper_mode stdio_mode,
2607 struct loadparm_context *lp_ctx,
2608 stdio_helper_function fn) {
2609 TALLOC_CTX *mem_ctx;
2610 struct ntlm_auth_state *state;
2612 /* initialize FDescs */
2613 x_setbuf(x_stdout, NULL);
2614 x_setbuf(x_stderr, NULL);
2616 mem_ctx = talloc_init("ntlm_auth");
2618 DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
2619 x_fprintf(x_stderr, "ERR\n");
2623 state = talloc_zero(mem_ctx, struct ntlm_auth_state);
2625 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
2626 x_fprintf(x_stderr, "ERR\n");
2630 state->mem_ctx = mem_ctx;
2631 state->helper_mode = stdio_mode;
2634 TALLOC_CTX *frame = talloc_stackframe();
2635 manage_squid_request(stdio_mode, lp_ctx, state, fn, NULL);
2641 /* Authenticate a user with a challenge/response */
2643 static bool check_auth_crap(void)
2648 char user_session_key[16];
2650 char *hex_user_session_key;
2652 static uint8 zeros[16];
2654 x_setbuf(x_stdout, NULL);
2657 flags |= WBFLAG_PAM_LMKEY;
2659 if (request_user_session_key)
2660 flags |= WBFLAG_PAM_USER_SESSION_KEY;
2662 flags |= WBFLAG_PAM_NT_STATUS_SQUASH;
2664 nt_status = contact_winbind_auth_crap(opt_username, opt_domain,
2670 (unsigned char *)lm_key,
2671 (unsigned char *)user_session_key,
2672 &error_string, NULL);
2674 if (!NT_STATUS_IS_OK(nt_status)) {
2675 x_fprintf(x_stdout, "%s (0x%x)\n",
2677 NT_STATUS_V(nt_status));
2678 SAFE_FREE(error_string);
2683 && (memcmp(zeros, lm_key,
2684 sizeof(lm_key)) != 0)) {
2685 hex_lm_key = hex_encode_talloc(talloc_tos(), (const unsigned char *)lm_key,
2687 x_fprintf(x_stdout, "LM_KEY: %s\n", hex_lm_key);
2688 TALLOC_FREE(hex_lm_key);
2690 if (request_user_session_key
2691 && (memcmp(zeros, user_session_key,
2692 sizeof(user_session_key)) != 0)) {
2693 hex_user_session_key = hex_encode_talloc(talloc_tos(), (const unsigned char *)user_session_key,
2694 sizeof(user_session_key));
2695 x_fprintf(x_stdout, "NT_KEY: %s\n", hex_user_session_key);
2696 TALLOC_FREE(hex_user_session_key);
2705 OPT_USERNAME = 1000,
2714 OPT_USER_SESSION_KEY,
2716 OPT_REQUIRE_MEMBERSHIP,
2717 OPT_USE_CACHED_CREDS,
2718 OPT_PAM_WINBIND_CONF,
2723 int main(int argc, const char **argv)
2725 TALLOC_CTX *frame = talloc_stackframe();
2727 static const char *helper_protocol;
2728 static int diagnostics;
2730 static const char *hex_challenge;
2731 static const char *hex_lm_response;
2732 static const char *hex_nt_response;
2733 struct loadparm_context *lp_ctx;
2736 /* NOTE: DO NOT change this interface without considering the implications!
2737 This is an external interface, which other programs will use to interact
2741 /* We do not use single-letter command abbreviations, because they harm future
2742 interface stability. */
2744 struct poptOption long_options[] = {
2746 { "helper-protocol", 0, POPT_ARG_STRING, &helper_protocol, OPT_DOMAIN, "operate as a stdio-based helper", "helper protocol to use"},
2747 { "username", 0, POPT_ARG_STRING, &opt_username, OPT_USERNAME, "username"},
2748 { "domain", 0, POPT_ARG_STRING, &opt_domain, OPT_DOMAIN, "domain name"},
2749 { "workstation", 0, POPT_ARG_STRING, &opt_workstation, OPT_WORKSTATION, "workstation"},
2750 { "challenge", 0, POPT_ARG_STRING, &hex_challenge, OPT_CHALLENGE, "challenge (HEX encoded)"},
2751 { "lm-response", 0, POPT_ARG_STRING, &hex_lm_response, OPT_LM, "LM Response to the challenge (HEX encoded)"},
2752 { "nt-response", 0, POPT_ARG_STRING, &hex_nt_response, OPT_NT, "NT or NTLMv2 Response to the challenge (HEX encoded)"},
2753 { "password", 0, POPT_ARG_STRING, &opt_password, OPT_PASSWORD, "User's plaintext password"},
2754 { "request-lm-key", 0, POPT_ARG_NONE, &request_lm_key, OPT_LM_KEY, "Retrieve LM session key"},
2755 { "request-nt-key", 0, POPT_ARG_NONE, &request_user_session_key, OPT_USER_SESSION_KEY, "Retrieve User (NT) session key"},
2756 { "use-cached-creds", 0, POPT_ARG_NONE, &use_cached_creds, OPT_USE_CACHED_CREDS, "Use cached credentials if no password is given"},
2757 { "diagnostics", 0, POPT_ARG_NONE, &diagnostics,
2759 "Perform diagnostics on the authentication chain"},
2760 { "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" },
2761 { "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" },
2762 { "target-service", 0, POPT_ARG_STRING, &opt_target_service, OPT_TARGET_SERVICE, "Target service (eg http)" },
2763 { "target-hostname", 0, POPT_ARG_STRING, &opt_target_hostname, OPT_TARGET_HOSTNAME, "Target hostname" },
2764 POPT_COMMON_CONFIGFILE
2769 /* Samba client initialisation */
2772 setup_logging("ntlm_auth", DEBUG_STDERR);
2776 pc = poptGetContext("ntlm_auth", argc, argv, long_options, 0);
2778 /* Parse command line options */
2781 poptPrintHelp(pc, stderr, 0);
2785 while((opt = poptGetNextOpt(pc)) != -1) {
2786 /* Get generic config options like --configfile */
2789 poptFreeContext(pc);
2791 if (!lp_load_global(get_dyn_CONFIGFILE())) {
2792 d_fprintf(stderr, "ntlm_auth: error opening config file %s. Error was %s\n",
2793 get_dyn_CONFIGFILE(), strerror(errno));
2797 pc = poptGetContext(NULL, argc, (const char **)argv, long_options,
2798 POPT_CONTEXT_KEEP_FIRST);
2800 while((opt = poptGetNextOpt(pc)) != -1) {
2803 opt_challenge = strhex_to_data_blob(NULL, hex_challenge);
2804 if (opt_challenge.length != 8) {
2805 x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n",
2807 (int)opt_challenge.length);
2812 opt_lm_response = strhex_to_data_blob(NULL, hex_lm_response);
2813 if (opt_lm_response.length != 24) {
2814 x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n",
2816 (int)opt_lm_response.length);
2822 opt_nt_response = strhex_to_data_blob(NULL, hex_nt_response);
2823 if (opt_nt_response.length < 24) {
2824 x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n",
2826 (int)opt_nt_response.length);
2831 case OPT_REQUIRE_MEMBERSHIP:
2832 if (strncasecmp_m("S-", require_membership_of, 2) == 0) {
2833 require_membership_of_sid = require_membership_of;
2840 char *domain = SMB_STRDUP(opt_username);
2841 char *p = strchr_m(domain, *lp_winbind_separator());
2845 if (opt_domain && !strequal(opt_domain, domain)) {
2846 x_fprintf(x_stderr, "Domain specified in username (%s) "
2847 "doesn't match specified domain (%s)!\n\n",
2848 domain, opt_domain);
2849 poptPrintHelp(pc, stderr, 0);
2852 opt_domain = domain;
2858 /* Note: if opt_domain is "" then send no domain */
2859 if (opt_domain == NULL) {
2860 opt_domain = get_winbind_domain();
2863 if (opt_workstation == NULL) {
2864 opt_workstation = "";
2867 lp_ctx = loadparm_init_s3(NULL, loadparm_s3_helpers());
2868 if (lp_ctx == NULL) {
2869 x_fprintf(x_stderr, "loadparm_init_s3() failed!\n");
2873 if (helper_protocol) {
2875 for (i=0; i<NUM_HELPER_MODES; i++) {
2876 if (strcmp(helper_protocol, stdio_helper_protocols[i].name) == 0) {
2877 squid_stream(stdio_helper_protocols[i].mode, lp_ctx, stdio_helper_protocols[i].fn);
2881 x_fprintf(x_stderr, "unknown helper protocol [%s]\n\nValid helper protools:\n\n", helper_protocol);
2883 for (i=0; i<NUM_HELPER_MODES; i++) {
2884 x_fprintf(x_stderr, "%s\n", stdio_helper_protocols[i].name);
2890 if (!opt_username || !*opt_username) {
2891 x_fprintf(x_stderr, "username must be specified!\n\n");
2892 poptPrintHelp(pc, stderr, 0);
2896 if (opt_challenge.length) {
2897 if (!check_auth_crap()) {
2903 if (!opt_password) {
2904 opt_password = getpass("password: ");
2908 if (!diagnose_ntlm_auth()) {
2914 fstr_sprintf(user, "%s%c%s", opt_domain, winbind_separator(), opt_username);
2915 if (!check_plaintext_auth(user, opt_password, True)) {
2922 poptFreeContext(pc);