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
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 3 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include "lib/param/param.h"
28 #include "popt_common.h"
29 #include "utils/ntlm_auth.h"
30 #include "../libcli/auth/libcli_auth.h"
31 #include "../libcli/auth/spnego.h"
32 #include "auth/ntlmssp/ntlmssp.h"
33 #include "auth/gensec/gensec.h"
34 #include "auth/credentials/credentials.h"
35 #include "librpc/crypto/gse.h"
37 #include <iniparser.h>
38 #include "../lib/crypto/arcfour.h"
39 #include "libads/kerberos_proto.h"
40 #include "nsswitch/winbind_client.h"
41 #include "librpc/gen_ndr/krb5pac.h"
42 #include "../lib/util/asn1.h"
43 #include "auth/common_auth.h"
45 #ifndef PAM_WINBIND_CONFIG_FILE
46 #define PAM_WINBIND_CONFIG_FILE "/etc/security/pam_winbind.conf"
49 #define WINBIND_KRB5_AUTH 0x00000080
52 #define DBGC_CLASS DBGC_WINBIND
54 #define INITIAL_BUFFER_SIZE 300
55 #define MAX_BUFFER_SIZE 630000
57 enum stdio_helper_mode {
65 NTLM_CHANGE_PASSWORD_1,
69 enum ntlm_auth_cli_state {
76 enum ntlm_auth_svr_state {
83 struct ntlm_auth_state {
85 enum stdio_helper_mode helper_mode;
86 enum ntlm_auth_cli_state cli_state;
87 enum ntlm_auth_svr_state svr_state;
88 struct ntlmssp_state *ntlmssp_state;
89 struct gensec_security *gensec_security;
91 char *want_feature_list;
93 char *spnego_mech_oid;
94 bool have_session_key;
95 DATA_BLOB session_key;
96 DATA_BLOB initial_message;
99 typedef void (*stdio_helper_function)(struct ntlm_auth_state *state, char *buf,
102 static void manage_squid_basic_request (struct ntlm_auth_state *state,
103 char *buf, int length);
105 static void manage_squid_ntlmssp_request (struct ntlm_auth_state *state,
106 char *buf, int length);
108 static void manage_client_ntlmssp_request (struct ntlm_auth_state *state,
109 char *buf, int length);
111 static void manage_gss_spnego_request (struct ntlm_auth_state *state,
112 char *buf, int length);
114 static void manage_gss_spnego_client_request (struct ntlm_auth_state *state,
115 char *buf, int length);
117 static void manage_ntlm_server_1_request (struct ntlm_auth_state *state,
118 char *buf, int length);
120 static void manage_ntlm_change_password_1_request(struct ntlm_auth_state *state,
121 char *buf, int length);
123 static const struct {
124 enum stdio_helper_mode mode;
126 stdio_helper_function fn;
127 } stdio_helper_protocols[] = {
128 { SQUID_2_4_BASIC, "squid-2.4-basic", manage_squid_basic_request},
129 { SQUID_2_5_BASIC, "squid-2.5-basic", manage_squid_basic_request},
130 { SQUID_2_5_NTLMSSP, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request},
131 { NTLMSSP_CLIENT_1, "ntlmssp-client-1", manage_client_ntlmssp_request},
132 { GSS_SPNEGO, "gss-spnego", manage_gss_spnego_request},
133 { GSS_SPNEGO_CLIENT, "gss-spnego-client", manage_gss_spnego_client_request},
134 { NTLM_SERVER_1, "ntlm-server-1", manage_ntlm_server_1_request},
135 { NTLM_CHANGE_PASSWORD_1, "ntlm-change-password-1", manage_ntlm_change_password_1_request},
136 { NUM_HELPER_MODES, NULL, NULL}
139 const char *opt_username;
140 const char *opt_domain;
141 const char *opt_workstation;
142 const char *opt_password;
143 static DATA_BLOB opt_challenge;
144 static DATA_BLOB opt_lm_response;
145 static DATA_BLOB opt_nt_response;
146 static int request_lm_key;
147 static int request_user_session_key;
148 static int use_cached_creds;
150 static const char *require_membership_of;
151 static const char *require_membership_of_sid;
152 static const char *opt_pam_winbind_conf;
154 const char *opt_target_service;
155 const char *opt_target_hostname;
158 * A limited set of features are defined with text strings as needed
162 static void gensec_want_feature_list(struct gensec_security *state, char* feature_list)
164 if (in_list("NTLMSSP_FEATURE_SESSION_KEY", feature_list, true)) {
165 DEBUG(10, ("want GENSEC_FEATURE_SESSION_KEY\n"));
166 gensec_want_feature(state, GENSEC_FEATURE_SESSION_KEY);
168 if (in_list("NTLMSSP_FEATURE_SIGN", feature_list, true)) {
169 DEBUG(10, ("want GENSEC_FEATURE_SIGN\n"));
170 gensec_want_feature(state, GENSEC_FEATURE_SIGN);
172 if (in_list("NTLMSSP_FEATURE_SEAL", feature_list, true)) {
173 DEBUG(10, ("want GENSEC_FEATURE_SEAL\n"));
174 gensec_want_feature(state, GENSEC_FEATURE_SEAL);
178 static char winbind_separator(void)
180 struct winbindd_response response;
187 ZERO_STRUCT(response);
189 /* Send off request */
191 if (winbindd_request_response(WINBINDD_INFO, NULL, &response) !=
192 NSS_STATUS_SUCCESS) {
193 d_printf("could not obtain winbind separator!\n");
194 return *lp_winbind_separator();
197 sep = response.data.info.winbind_separator;
201 d_printf("winbind separator was NULL!\n");
202 return *lp_winbind_separator();
208 const char *get_winbind_domain(void)
210 struct winbindd_response response;
212 static fstring winbind_domain;
213 if (*winbind_domain) {
214 return winbind_domain;
217 ZERO_STRUCT(response);
219 /* Send off request */
221 if (winbindd_request_response(WINBINDD_DOMAIN_NAME, NULL, &response) !=
222 NSS_STATUS_SUCCESS) {
223 DEBUG(0, ("could not obtain winbind domain name!\n"));
224 return lp_workgroup();
227 fstrcpy(winbind_domain, response.data.domain_name);
229 return winbind_domain;
233 const char *get_winbind_netbios_name(void)
235 struct winbindd_response response;
237 static fstring winbind_netbios_name;
239 if (*winbind_netbios_name) {
240 return winbind_netbios_name;
243 ZERO_STRUCT(response);
245 /* Send off request */
247 if (winbindd_request_response(WINBINDD_NETBIOS_NAME, NULL, &response) !=
248 NSS_STATUS_SUCCESS) {
249 DEBUG(0, ("could not obtain winbind netbios name!\n"));
250 return lp_netbios_name();
253 fstrcpy(winbind_netbios_name, response.data.netbios_name);
255 return winbind_netbios_name;
259 DATA_BLOB get_challenge(void)
261 static DATA_BLOB chal;
262 if (opt_challenge.length)
263 return opt_challenge;
265 chal = data_blob(NULL, 8);
267 generate_random_buffer(chal.data, chal.length);
271 /* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
272 form DOMAIN/user into a domain and a user */
274 static bool parse_ntlm_auth_domain_user(const char *domuser, fstring domain,
278 char *p = strchr(domuser,winbind_separator());
285 fstrcpy(domain, domuser);
286 domain[PTR_DIFF(p, domuser)] = 0;
292 static bool get_require_membership_sid(void) {
293 struct winbindd_request request;
294 struct winbindd_response response;
296 if (!require_membership_of) {
300 if (require_membership_of_sid) {
304 /* Otherwise, ask winbindd for the name->sid request */
306 ZERO_STRUCT(request);
307 ZERO_STRUCT(response);
309 if (!parse_ntlm_auth_domain_user(require_membership_of,
310 request.data.name.dom_name,
311 request.data.name.name)) {
312 DEBUG(0, ("Could not parse %s into seperate domain/name parts!\n",
313 require_membership_of));
317 if (winbindd_request_response(WINBINDD_LOOKUPNAME, &request, &response) !=
318 NSS_STATUS_SUCCESS) {
319 DEBUG(0, ("Winbindd lookupname failed to resolve %s into a SID!\n",
320 require_membership_of));
324 require_membership_of_sid = SMB_STRDUP(response.data.sid.sid);
326 if (require_membership_of_sid)
333 * Get some configuration from pam_winbind.conf to see if we
334 * need to contact trusted domain
337 int get_pam_winbind_config()
340 dictionary *d = NULL;
342 if (!opt_pam_winbind_conf || !*opt_pam_winbind_conf) {
343 opt_pam_winbind_conf = PAM_WINBIND_CONFIG_FILE;
346 d = iniparser_load(discard_const_p(char, opt_pam_winbind_conf));
352 if (iniparser_getboolean(d, discard_const_p(char, "global:krb5_auth"), false)) {
353 ctrl |= WINBIND_KRB5_AUTH;
356 iniparser_freedict(d);
361 /* Authenticate a user with a plaintext password */
363 static bool check_plaintext_auth(const char *user, const char *pass,
364 bool stdout_diagnostics)
366 struct winbindd_request request;
367 struct winbindd_response response;
370 if (!get_require_membership_sid()) {
374 /* Send off request */
376 ZERO_STRUCT(request);
377 ZERO_STRUCT(response);
379 fstrcpy(request.data.auth.user, user);
380 fstrcpy(request.data.auth.pass, pass);
381 if (require_membership_of_sid) {
382 strlcpy(request.data.auth.require_membership_of_sid,
383 require_membership_of_sid,
384 sizeof(request.data.auth.require_membership_of_sid));
387 result = winbindd_request_response(WINBINDD_PAM_AUTH, &request, &response);
389 /* Display response */
391 if (stdout_diagnostics) {
392 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
393 d_printf("Reading winbind reply failed! (0x01)\n");
396 d_printf("%s: %s (0x%x)\n",
397 response.data.auth.nt_status_string,
398 response.data.auth.error_string,
399 response.data.auth.nt_status);
401 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
402 DEBUG(1, ("Reading winbind reply failed! (0x01)\n"));
405 DEBUG(3, ("%s: %s (0x%x)\n",
406 response.data.auth.nt_status_string,
407 response.data.auth.error_string,
408 response.data.auth.nt_status));
411 return (result == NSS_STATUS_SUCCESS);
414 /* authenticate a user with an encrypted username/password */
416 NTSTATUS contact_winbind_auth_crap(const char *username,
418 const char *workstation,
419 const DATA_BLOB *challenge,
420 const DATA_BLOB *lm_response,
421 const DATA_BLOB *nt_response,
423 uint32 extra_logon_parameters,
425 uint8 user_session_key[16],
431 struct winbindd_request request;
432 struct winbindd_response response;
434 if (!get_require_membership_sid()) {
435 return NT_STATUS_INVALID_PARAMETER;
438 ZERO_STRUCT(request);
439 ZERO_STRUCT(response);
441 request.flags = flags;
443 request.data.auth_crap.logon_parameters = extra_logon_parameters
444 | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT | MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT;
446 if (require_membership_of_sid)
447 fstrcpy(request.data.auth_crap.require_membership_of_sid, require_membership_of_sid);
449 fstrcpy(request.data.auth_crap.user, username);
450 fstrcpy(request.data.auth_crap.domain, domain);
452 fstrcpy(request.data.auth_crap.workstation,
455 memcpy(request.data.auth_crap.chal, challenge->data, MIN(challenge->length, 8));
457 if (lm_response && lm_response->length) {
458 memcpy(request.data.auth_crap.lm_resp,
460 MIN(lm_response->length, sizeof(request.data.auth_crap.lm_resp)));
461 request.data.auth_crap.lm_resp_len = lm_response->length;
464 if (nt_response && nt_response->length) {
465 if (nt_response->length > sizeof(request.data.auth_crap.nt_resp)) {
466 request.flags = request.flags | WBFLAG_BIG_NTLMV2_BLOB;
467 request.extra_len = nt_response->length;
468 request.extra_data.data = SMB_MALLOC_ARRAY(char, request.extra_len);
469 if (request.extra_data.data == NULL) {
470 return NT_STATUS_NO_MEMORY;
472 memcpy(request.extra_data.data, nt_response->data,
473 nt_response->length);
476 memcpy(request.data.auth_crap.nt_resp,
477 nt_response->data, nt_response->length);
479 request.data.auth_crap.nt_resp_len = nt_response->length;
482 result = winbindd_request_response(WINBINDD_PAM_AUTH_CRAP, &request, &response);
483 SAFE_FREE(request.extra_data.data);
485 /* Display response */
487 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
488 nt_status = NT_STATUS_UNSUCCESSFUL;
490 *error_string = smb_xstrdup("Reading winbind reply failed!");
491 winbindd_free_response(&response);
495 nt_status = (NT_STATUS(response.data.auth.nt_status));
496 if (!NT_STATUS_IS_OK(nt_status)) {
498 *error_string = smb_xstrdup(response.data.auth.error_string);
499 winbindd_free_response(&response);
503 if ((flags & WBFLAG_PAM_LMKEY) && lm_key) {
504 memcpy(lm_key, response.data.auth.first_8_lm_hash,
505 sizeof(response.data.auth.first_8_lm_hash));
507 if ((flags & WBFLAG_PAM_USER_SESSION_KEY) && user_session_key) {
508 memcpy(user_session_key, response.data.auth.user_session_key,
509 sizeof(response.data.auth.user_session_key));
512 if (flags & WBFLAG_PAM_UNIX_NAME) {
513 *unix_name = SMB_STRDUP(response.data.auth.unix_username);
515 winbindd_free_response(&response);
516 return NT_STATUS_NO_MEMORY;
520 winbindd_free_response(&response);
524 /* contact server to change user password using auth crap */
525 static NTSTATUS contact_winbind_change_pswd_auth_crap(const char *username,
527 const DATA_BLOB new_nt_pswd,
528 const DATA_BLOB old_nt_hash_enc,
529 const DATA_BLOB new_lm_pswd,
530 const DATA_BLOB old_lm_hash_enc,
535 struct winbindd_request request;
536 struct winbindd_response response;
538 if (!get_require_membership_sid())
541 *error_string = smb_xstrdup("Can't get membership sid.");
542 return NT_STATUS_INVALID_PARAMETER;
545 ZERO_STRUCT(request);
546 ZERO_STRUCT(response);
549 fstrcpy(request.data.chng_pswd_auth_crap.user, username);
551 fstrcpy(request.data.chng_pswd_auth_crap.domain,domain);
553 if(new_nt_pswd.length)
555 memcpy(request.data.chng_pswd_auth_crap.new_nt_pswd, new_nt_pswd.data, sizeof(request.data.chng_pswd_auth_crap.new_nt_pswd));
556 request.data.chng_pswd_auth_crap.new_nt_pswd_len = new_nt_pswd.length;
559 if(old_nt_hash_enc.length)
561 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));
562 request.data.chng_pswd_auth_crap.old_nt_hash_enc_len = old_nt_hash_enc.length;
565 if(new_lm_pswd.length)
567 memcpy(request.data.chng_pswd_auth_crap.new_lm_pswd, new_lm_pswd.data, sizeof(request.data.chng_pswd_auth_crap.new_lm_pswd));
568 request.data.chng_pswd_auth_crap.new_lm_pswd_len = new_lm_pswd.length;
571 if(old_lm_hash_enc.length)
573 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));
574 request.data.chng_pswd_auth_crap.old_lm_hash_enc_len = old_lm_hash_enc.length;
577 result = winbindd_request_response(WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP, &request, &response);
579 /* Display response */
581 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0))
583 nt_status = NT_STATUS_UNSUCCESSFUL;
585 *error_string = smb_xstrdup("Reading winbind reply failed!");
586 winbindd_free_response(&response);
590 nt_status = (NT_STATUS(response.data.auth.nt_status));
591 if (!NT_STATUS_IS_OK(nt_status))
594 *error_string = smb_xstrdup(response.data.auth.error_string);
595 winbindd_free_response(&response);
599 winbindd_free_response(&response);
604 static NTSTATUS ntlm_auth_generate_session_info(struct auth4_context *auth_context,
606 void *server_returned_info,
607 const char *original_user_name,
608 uint32_t session_info_flags,
609 struct auth_session_info **session_info_out)
611 char *unix_username = (char *)server_returned_info;
612 struct auth_session_info *session_info = talloc_zero(mem_ctx, struct auth_session_info);
614 return NT_STATUS_NO_MEMORY;
617 session_info->unix_info = talloc_zero(session_info, struct auth_user_info_unix);
618 if (!session_info->unix_info) {
619 TALLOC_FREE(session_info);
620 return NT_STATUS_NO_MEMORY;
622 session_info->unix_info->unix_name = talloc_steal(session_info->unix_info, unix_username);
624 *session_info_out = session_info;
630 * Return the challenge as determined by the authentication subsystem
631 * @return an 8 byte random challenge
634 static NTSTATUS ntlm_auth_get_challenge(struct auth4_context *auth_ctx,
637 if (auth_ctx->challenge.data.length == 8) {
638 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
639 auth_ctx->challenge.set_by));
640 memcpy(chal, auth_ctx->challenge.data.data, 8);
644 if (!auth_ctx->challenge.set_by) {
645 generate_random_buffer(chal, 8);
647 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
648 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
649 auth_ctx->challenge.set_by = "random";
651 auth_ctx->challenge.may_be_modified = true;
654 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
655 auth_ctx->challenge.set_by));
661 * Some authentication methods 'fix' the challenge, so we may not be able to set it
663 * @return If the effective challenge used by the auth subsystem may be modified
665 static bool ntlm_auth_may_set_challenge(struct auth4_context *auth_ctx)
667 return auth_ctx->challenge.may_be_modified;
671 * NTLM2 authentication modifies the effective challenge,
672 * @param challenge The new challenge value
674 static NTSTATUS ntlm_auth_set_challenge(struct auth4_context *auth_ctx, const uint8_t chal[8], const char *set_by)
676 auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
677 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
679 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
680 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
686 * Check the password on an NTLMSSP login.
688 * Return the session keys used on the connection.
691 static NTSTATUS winbind_pw_check(struct auth4_context *auth4_context,
693 const struct auth_usersupplied_info *user_info,
694 void **server_returned_info,
695 DATA_BLOB *session_key, DATA_BLOB *lm_session_key)
697 static const char zeros[16] = { 0, };
699 char *error_string = NULL;
701 uint8 user_sess_key[16];
702 char *unix_name = NULL;
704 nt_status = contact_winbind_auth_crap(user_info->client.account_name, user_info->client.domain_name,
705 user_info->workstation_name,
706 &auth4_context->challenge.data,
707 &user_info->password.response.lanman,
708 &user_info->password.response.nt,
709 WBFLAG_PAM_LMKEY | WBFLAG_PAM_USER_SESSION_KEY | WBFLAG_PAM_UNIX_NAME,
711 lm_key, user_sess_key,
712 &error_string, &unix_name);
714 if (NT_STATUS_IS_OK(nt_status)) {
715 if (memcmp(lm_key, zeros, 8) != 0) {
716 *lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
717 memcpy(lm_session_key->data, lm_key, 8);
718 memset(lm_session_key->data+8, '\0', 8);
721 if (memcmp(user_sess_key, zeros, 16) != 0) {
722 *session_key = data_blob_talloc(mem_ctx, user_sess_key, 16);
724 *server_returned_info = talloc_strdup(mem_ctx,
727 DEBUG(NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED) ? 0 : 3,
728 ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
729 user_info->client.domain_name, user_info->client.account_name,
730 user_info->workstation_name,
731 error_string ? error_string : "unknown error (NULL)"));
734 SAFE_FREE(error_string);
735 SAFE_FREE(unix_name);
739 static NTSTATUS local_pw_check(struct auth4_context *auth4_context,
741 const struct auth_usersupplied_info *user_info,
742 void **server_returned_info,
743 DATA_BLOB *session_key, DATA_BLOB *lm_session_key)
746 struct samr_Password lm_pw, nt_pw;
748 nt_lm_owf_gen (opt_password, nt_pw.hash, lm_pw.hash);
750 nt_status = ntlm_password_check(mem_ctx,
752 &auth4_context->challenge.data,
753 &user_info->password.response.lanman,
754 &user_info->password.response.nt,
755 user_info->client.account_name,
756 user_info->client.account_name,
757 user_info->client.domain_name,
758 &lm_pw, &nt_pw, session_key, lm_session_key);
760 if (NT_STATUS_IS_OK(nt_status)) {
761 *server_returned_info = talloc_asprintf(mem_ctx,
762 "%s%c%s", user_info->client.domain_name,
763 *lp_winbind_separator(),
764 user_info->client.account_name);
766 DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
767 user_info->client.domain_name, user_info->client.account_name,
768 user_info->workstation_name,
769 nt_errstr(nt_status)));
774 static NTSTATUS ntlm_auth_start_ntlmssp_client(struct ntlmssp_state **client_ntlmssp_state)
777 if ( (opt_username == NULL) || (opt_domain == NULL) ) {
778 status = NT_STATUS_UNSUCCESSFUL;
779 DEBUG(1, ("Need username and domain for NTLMSSP\n"));
780 return NT_STATUS_INVALID_PARAMETER;
783 status = ntlmssp_client_start(NULL,
786 lp_client_ntlmv2_auth(),
787 client_ntlmssp_state);
789 if (!NT_STATUS_IS_OK(status)) {
790 DEBUG(1, ("Could not start NTLMSSP client: %s\n",
792 TALLOC_FREE(*client_ntlmssp_state);
796 status = ntlmssp_set_username(*client_ntlmssp_state, opt_username);
798 if (!NT_STATUS_IS_OK(status)) {
799 DEBUG(1, ("Could not set username: %s\n",
801 TALLOC_FREE(*client_ntlmssp_state);
805 status = ntlmssp_set_domain(*client_ntlmssp_state, opt_domain);
807 if (!NT_STATUS_IS_OK(status)) {
808 DEBUG(1, ("Could not set domain: %s\n",
810 TALLOC_FREE(*client_ntlmssp_state);
815 status = ntlmssp_set_password(*client_ntlmssp_state, opt_password);
817 if (!NT_STATUS_IS_OK(status)) {
818 DEBUG(1, ("Could not set password: %s\n",
820 TALLOC_FREE(*client_ntlmssp_state);
828 static struct auth4_context *make_auth4_context_ntlm_auth(TALLOC_CTX *mem_ctx, bool local_pw)
830 struct auth4_context *auth4_context = talloc_zero(mem_ctx, struct auth4_context);
831 if (auth4_context == NULL) {
832 DEBUG(10, ("failed to allocate auth4_context failed\n"));
835 auth4_context->generate_session_info = ntlm_auth_generate_session_info;
836 auth4_context->get_ntlm_challenge = ntlm_auth_get_challenge;
837 auth4_context->set_ntlm_challenge = ntlm_auth_set_challenge;
838 auth4_context->challenge_may_be_modified = ntlm_auth_may_set_challenge;
840 auth4_context->check_ntlm_password = local_pw_check;
842 auth4_context->check_ntlm_password = winbind_pw_check;
844 auth4_context->private_data = NULL;
845 return auth4_context;
848 static NTSTATUS ntlm_auth_start_ntlmssp_server(TALLOC_CTX *mem_ctx,
849 struct gensec_security **gensec_security_out)
851 struct gensec_security *gensec_security;
854 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
855 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
857 struct gensec_settings *gensec_settings;
858 struct loadparm_context *lp_ctx;
860 struct cli_credentials *server_credentials;
862 struct auth4_context *auth4_context = make_auth4_context_ntlm_auth(tmp_ctx, opt_password);
863 if (auth4_context == NULL) {
864 TALLOC_FREE(tmp_ctx);
865 return NT_STATUS_NO_MEMORY;
868 lp_ctx = loadparm_init_s3(tmp_ctx, loadparm_s3_context());
869 if (lp_ctx == NULL) {
870 DEBUG(10, ("loadparm_init_s3 failed\n"));
871 TALLOC_FREE(tmp_ctx);
872 return NT_STATUS_INVALID_SERVER_STATE;
875 gensec_settings = lpcfg_gensec_settings(tmp_ctx, lp_ctx);
876 if (lp_ctx == NULL) {
877 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
878 TALLOC_FREE(tmp_ctx);
879 return NT_STATUS_NO_MEMORY;
883 * This should be a 'netbios domain -> DNS domain'
884 * mapping, and can currently validly return NULL on
885 * poorly configured systems.
887 * This is used for the NTLMSSP server
891 gensec_settings->server_netbios_name = lp_netbios_name();
892 gensec_settings->server_netbios_domain = lp_workgroup();
894 gensec_settings->server_netbios_name = get_winbind_netbios_name();
895 gensec_settings->server_netbios_domain = get_winbind_domain();
898 gensec_settings->server_dns_domain = strlower_talloc(gensec_settings,
899 get_mydnsdomname(talloc_tos()));
900 gensec_settings->server_dns_name = strlower_talloc(gensec_settings,
901 get_mydnsfullname());
903 gensec_settings->backends = talloc_zero_array(gensec_settings,
904 struct gensec_security_ops *, 4);
906 if (gensec_settings->backends == NULL) {
907 TALLOC_FREE(tmp_ctx);
908 return NT_STATUS_NO_MEMORY;
913 gensec_settings->backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_NTLMSSP);
915 #if defined(HAVE_KRB5) && defined(HAVE_GSS_WRAP_IOV)
916 gensec_settings->backends[idx++] = &gensec_gse_krb5_security_ops;
919 gensec_settings->backends[idx++] = gensec_security_by_oid(NULL,
923 * This is anonymous for now, because we just use it
924 * to set the kerberos state at the moment
926 server_credentials = cli_credentials_init_anon(tmp_ctx);
927 if (!server_credentials) {
928 DEBUG(0, ("auth_generic_prepare: Failed to init server credentials\n"));
929 return NT_STATUS_NO_MEMORY;
932 cli_credentials_set_conf(server_credentials, lp_ctx);
934 if (lp_security() == SEC_ADS || USE_KERBEROS_KEYTAB) {
935 cli_credentials_set_kerberos_state(server_credentials, CRED_AUTO_USE_KERBEROS);
937 cli_credentials_set_kerberos_state(server_credentials, CRED_DONT_USE_KERBEROS);
940 nt_status = gensec_server_start(tmp_ctx, gensec_settings,
941 auth4_context, &gensec_security);
943 if (!NT_STATUS_IS_OK(nt_status)) {
944 TALLOC_FREE(tmp_ctx);
948 gensec_set_credentials(gensec_security, server_credentials);
950 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
951 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
953 talloc_unlink(tmp_ctx, lp_ctx);
954 talloc_unlink(tmp_ctx, server_credentials);
955 talloc_unlink(tmp_ctx, gensec_settings);
956 talloc_unlink(tmp_ctx, auth4_context);
958 nt_status = gensec_start_mech_by_oid(gensec_security, GENSEC_OID_NTLMSSP);
959 if (!NT_STATUS_IS_OK(nt_status)) {
960 TALLOC_FREE(tmp_ctx);
964 *gensec_security_out = talloc_steal(mem_ctx, gensec_security);
965 TALLOC_FREE(tmp_ctx);
969 /*******************************************************************
970 Used by firefox to drive NTLM auth to IIS servers.
971 *******************************************************************/
973 static NTSTATUS do_ccache_ntlm_auth(DATA_BLOB initial_msg, DATA_BLOB challenge_msg,
976 struct winbindd_request wb_request;
977 struct winbindd_response wb_response;
981 /* get winbindd to do the ntlmssp step on our behalf */
982 ZERO_STRUCT(wb_request);
983 ZERO_STRUCT(wb_response);
986 * This is tricky here. If we set krb5_auth in pam_winbind.conf
987 * creds for users in trusted domain will be stored the winbindd
988 * child of the trusted domain. If we ask the primary domain for
989 * ntlm_ccache_auth, it will fail. So, we have to ask the trusted
990 * domain's child for ccache_ntlm_auth. that is to say, we have to
991 * set WBFLAG_PAM_CONTACT_TRUSTDOM in request.flags.
993 ctrl = get_pam_winbind_config();
995 if (ctrl & WINBIND_KRB5_AUTH) {
996 wb_request.flags |= WBFLAG_PAM_CONTACT_TRUSTDOM;
999 fstr_sprintf(wb_request.data.ccache_ntlm_auth.user,
1000 "%s%c%s", opt_domain, winbind_separator(), opt_username);
1001 wb_request.data.ccache_ntlm_auth.uid = geteuid();
1002 wb_request.data.ccache_ntlm_auth.initial_blob_len = initial_msg.length;
1003 wb_request.data.ccache_ntlm_auth.challenge_blob_len = challenge_msg.length;
1004 wb_request.extra_len = initial_msg.length + challenge_msg.length;
1006 if (wb_request.extra_len > 0) {
1007 wb_request.extra_data.data = SMB_MALLOC_ARRAY(char, wb_request.extra_len);
1008 if (wb_request.extra_data.data == NULL) {
1009 return NT_STATUS_NO_MEMORY;
1012 memcpy(wb_request.extra_data.data, initial_msg.data, initial_msg.length);
1013 memcpy(wb_request.extra_data.data + initial_msg.length,
1014 challenge_msg.data, challenge_msg.length);
1017 result = winbindd_request_response(WINBINDD_CCACHE_NTLMAUTH, &wb_request, &wb_response);
1018 SAFE_FREE(wb_request.extra_data.data);
1020 if (result != NSS_STATUS_SUCCESS) {
1021 winbindd_free_response(&wb_response);
1022 return NT_STATUS_UNSUCCESSFUL;
1026 *reply = data_blob(wb_response.extra_data.data,
1027 wb_response.data.ccache_ntlm_auth.auth_blob_len);
1028 if (wb_response.data.ccache_ntlm_auth.auth_blob_len > 0 &&
1029 reply->data == NULL) {
1030 winbindd_free_response(&wb_response);
1031 return NT_STATUS_NO_MEMORY;
1035 winbindd_free_response(&wb_response);
1036 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1039 static void manage_squid_ntlmssp_request_int(struct ntlm_auth_state *state,
1040 char *buf, int length,
1041 TALLOC_CTX *mem_ctx,
1044 DATA_BLOB request, reply;
1047 if (strlen(buf) < 2) {
1048 DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf));
1049 *response = talloc_strdup(mem_ctx, "BH NTLMSSP query invalid");
1053 if (strlen(buf) > 3) {
1054 if(strncmp(buf, "SF ", 3) == 0){
1055 DEBUG(10, ("Setting flags to negotioate\n"));
1056 TALLOC_FREE(state->want_feature_list);
1057 state->want_feature_list = talloc_strdup(state->mem_ctx,
1059 *response = talloc_strdup(mem_ctx, "OK");
1062 request = base64_decode_data_blob(buf + 3);
1064 request = data_blob_null;
1067 if ((strncmp(buf, "PW ", 3) == 0)) {
1068 /* The calling application wants us to use a local password
1069 * (rather than winbindd) */
1071 opt_password = SMB_STRNDUP((const char *)request.data,
1074 if (opt_password == NULL) {
1075 DEBUG(1, ("Out of memory\n"));
1076 *response = talloc_strdup(mem_ctx, "BH Out of memory");
1077 data_blob_free(&request);
1081 *response = talloc_strdup(mem_ctx, "OK");
1082 data_blob_free(&request);
1086 if (strncmp(buf, "YR", 2) == 0) {
1087 TALLOC_FREE(state->gensec_security);
1088 state->svr_state = SERVER_INITIAL;
1089 } else if (strncmp(buf, "KK", 2) == 0) {
1090 /* No special preprocessing required */
1091 } else if (strncmp(buf, "GF", 2) == 0) {
1092 DEBUG(10, ("Requested negotiated NTLMSSP flags\n"));
1094 if (state->svr_state == SERVER_FINISHED) {
1095 *response = talloc_asprintf(mem_ctx, "GF 0x%08x",
1096 gensec_ntlmssp_neg_flags(state->gensec_security));
1099 *response = talloc_strdup(mem_ctx, "BH\n");
1101 data_blob_free(&request);
1103 } else if (strncmp(buf, "GK", 2) == 0) {
1104 DEBUG(10, ("Requested NTLMSSP session key\n"));
1105 if(state->have_session_key) {
1106 DATA_BLOB session_key;
1108 nt_status = gensec_session_key(state->gensec_security, talloc_tos(), &session_key);
1109 if (!NT_STATUS_IS_OK(nt_status)) {
1110 *response = talloc_asprintf(
1111 mem_ctx, "BH %s", nt_errstr(nt_status));
1114 key64 = base64_encode_data_blob(state->mem_ctx, session_key);
1115 data_blob_free(&session_key);
1116 *response = talloc_asprintf(mem_ctx, "GK %s",
1117 key64 ? key64 : "<NULL>");
1120 *response = talloc_strdup(mem_ctx, "BH");
1123 data_blob_free(&request);
1126 DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf));
1127 *response = talloc_strdup(mem_ctx, "BH NTLMSSP query invalid");
1131 if (!state->gensec_security) {
1132 nt_status = ntlm_auth_start_ntlmssp_server(state,
1133 &state->gensec_security);
1134 if (!NT_STATUS_IS_OK(nt_status)) {
1135 *response = talloc_asprintf(
1136 mem_ctx, "BH %s", nt_errstr(nt_status));
1139 gensec_want_feature_list(state->gensec_security,
1140 state->want_feature_list);
1143 DEBUG(10, ("got NTLMSSP packet:\n"));
1144 dump_data(10, request.data, request.length);
1146 nt_status = gensec_update(state->gensec_security, talloc_tos(), NULL, request, &reply);
1148 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1149 char *reply_base64 = base64_encode_data_blob(state->mem_ctx,
1151 *response = talloc_asprintf(mem_ctx, "TT %s", reply_base64);
1152 TALLOC_FREE(reply_base64);
1153 data_blob_free(&reply);
1154 state->svr_state = SERVER_CHALLENGE;
1155 DEBUG(10, ("NTLMSSP challenge\n"));
1156 } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) {
1157 *response = talloc_asprintf(mem_ctx, "BH %s",
1158 nt_errstr(nt_status));
1159 DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status)));
1161 TALLOC_FREE(state->gensec_security);
1162 } else if (!NT_STATUS_IS_OK(nt_status)) {
1163 *response = talloc_asprintf(mem_ctx, "NA %s",
1164 nt_errstr(nt_status));
1165 DEBUG(10, ("NTLMSSP %s\n", nt_errstr(nt_status)));
1167 struct auth_session_info *session_info;
1168 nt_status = gensec_session_info(state->gensec_security, state->gensec_security, &session_info);
1169 if (!NT_STATUS_IS_OK(nt_status)) {
1170 DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status)));
1171 TALLOC_FREE(state->gensec_security);
1174 *response = talloc_asprintf(
1176 session_info->unix_info->unix_name);
1177 DEBUG(10, ("NTLMSSP OK!\n"));
1179 state->have_session_key = true;
1180 state->svr_state = SERVER_FINISHED;
1183 data_blob_free(&request);
1186 static void manage_squid_ntlmssp_request(struct ntlm_auth_state *state,
1187 char *buf, int length)
1191 manage_squid_ntlmssp_request_int(state, buf, length,
1192 talloc_tos(), &response);
1194 if (response == NULL) {
1195 x_fprintf(x_stdout, "BH Out of memory\n");
1198 x_fprintf(x_stdout, "%s\n", response);
1199 TALLOC_FREE(response);
1202 static void manage_client_ntlmssp_request(struct ntlm_auth_state *state,
1203 char *buf, int length)
1205 DATA_BLOB request, reply;
1208 if (!opt_username || !*opt_username) {
1209 x_fprintf(x_stderr, "username must be specified!\n\n");
1213 if (strlen(buf) < 2) {
1214 DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf));
1215 x_fprintf(x_stdout, "BH NTLMSSP query invalid\n");
1219 if (strlen(buf) > 3) {
1220 if(strncmp(buf, "SF ", 3) == 0) {
1221 DEBUG(10, ("Looking for flags to negotiate\n"));
1222 talloc_free(state->want_feature_list);
1223 state->want_feature_list = talloc_strdup(state->mem_ctx,
1225 x_fprintf(x_stdout, "OK\n");
1228 request = base64_decode_data_blob(buf + 3);
1230 request = data_blob_null;
1233 if (strncmp(buf, "PW ", 3) == 0) {
1234 /* We asked for a password and obviously got it :-) */
1236 opt_password = SMB_STRNDUP((const char *)request.data,
1239 if (opt_password == NULL) {
1240 DEBUG(1, ("Out of memory\n"));
1241 x_fprintf(x_stdout, "BH Out of memory\n");
1242 data_blob_free(&request);
1246 x_fprintf(x_stdout, "OK\n");
1247 data_blob_free(&request);
1251 if (!state->ntlmssp_state && use_cached_creds) {
1252 /* check whether cached credentials are usable. */
1253 DATA_BLOB empty_blob = data_blob_null;
1255 nt_status = do_ccache_ntlm_auth(empty_blob, empty_blob, NULL);
1256 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1257 /* failed to use cached creds */
1258 use_cached_creds = False;
1262 if (opt_password == NULL && !use_cached_creds) {
1263 /* Request a password from the calling process. After
1264 sending it, the calling process should retry asking for the
1267 DEBUG(10, ("Requesting password\n"));
1268 x_fprintf(x_stdout, "PW\n");
1272 if (strncmp(buf, "YR", 2) == 0) {
1273 TALLOC_FREE(state->ntlmssp_state);
1274 state->cli_state = CLIENT_INITIAL;
1275 } else if (strncmp(buf, "TT", 2) == 0) {
1276 /* No special preprocessing required */
1277 } else if (strncmp(buf, "GF", 2) == 0) {
1278 DEBUG(10, ("Requested negotiated NTLMSSP flags\n"));
1280 if(state->cli_state == CLIENT_FINISHED) {
1281 x_fprintf(x_stdout, "GF 0x%08x\n", state->neg_flags);
1284 x_fprintf(x_stdout, "BH\n");
1287 data_blob_free(&request);
1289 } else if (strncmp(buf, "GK", 2) == 0 ) {
1290 DEBUG(10, ("Requested session key\n"));
1292 if(state->cli_state == CLIENT_FINISHED) {
1293 char *key64 = base64_encode_data_blob(state->mem_ctx,
1294 state->session_key);
1295 x_fprintf(x_stdout, "GK %s\n", key64?key64:"<NULL>");
1299 x_fprintf(x_stdout, "BH\n");
1302 data_blob_free(&request);
1305 DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf));
1306 x_fprintf(x_stdout, "BH NTLMSSP query invalid\n");
1310 if (!state->ntlmssp_state) {
1311 nt_status = ntlm_auth_start_ntlmssp_client(
1312 &state->ntlmssp_state);
1313 if (!NT_STATUS_IS_OK(nt_status)) {
1314 x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
1317 ntlmssp_want_feature_list(state->ntlmssp_state,
1318 state->want_feature_list);
1319 state->initial_message = data_blob_null;
1322 DEBUG(10, ("got NTLMSSP packet:\n"));
1323 dump_data(10, request.data, request.length);
1325 if (use_cached_creds && !opt_password &&
1326 (state->cli_state == CLIENT_RESPONSE)) {
1327 nt_status = do_ccache_ntlm_auth(state->initial_message, request,
1330 nt_status = ntlmssp_update(state->ntlmssp_state, request,
1334 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1335 char *reply_base64 = base64_encode_data_blob(state->mem_ctx,
1337 if (state->cli_state == CLIENT_INITIAL) {
1338 x_fprintf(x_stdout, "YR %s\n", reply_base64);
1339 state->initial_message = reply;
1340 state->cli_state = CLIENT_RESPONSE;
1342 x_fprintf(x_stdout, "KK %s\n", reply_base64);
1343 data_blob_free(&reply);
1345 TALLOC_FREE(reply_base64);
1346 DEBUG(10, ("NTLMSSP challenge\n"));
1347 } else if (NT_STATUS_IS_OK(nt_status)) {
1348 char *reply_base64 = base64_encode_data_blob(talloc_tos(),
1350 x_fprintf(x_stdout, "AF %s\n", reply_base64);
1351 TALLOC_FREE(reply_base64);
1353 if(state->have_session_key)
1354 data_blob_free(&state->session_key);
1356 state->session_key = data_blob(
1357 state->ntlmssp_state->session_key.data,
1358 state->ntlmssp_state->session_key.length);
1359 state->neg_flags = state->ntlmssp_state->neg_flags;
1360 state->have_session_key = true;
1362 DEBUG(10, ("NTLMSSP OK!\n"));
1363 state->cli_state = CLIENT_FINISHED;
1364 TALLOC_FREE(state->ntlmssp_state);
1366 x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
1367 DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status)));
1368 state->cli_state = CLIENT_ERROR;
1369 TALLOC_FREE(state->ntlmssp_state);
1372 data_blob_free(&request);
1375 static void manage_squid_basic_request(struct ntlm_auth_state *state,
1376 char *buf, int length)
1381 pass=(char *)memchr(buf,' ',length);
1383 DEBUG(2, ("Password not found. Denying access\n"));
1384 x_fprintf(x_stdout, "ERR\n");
1390 if (state->helper_mode == SQUID_2_5_BASIC) {
1391 rfc1738_unescape(user);
1392 rfc1738_unescape(pass);
1395 if (check_plaintext_auth(user, pass, False)) {
1396 x_fprintf(x_stdout, "OK\n");
1398 x_fprintf(x_stdout, "ERR\n");
1402 static void offer_gss_spnego_mechs(void) {
1405 struct spnego_data spnego;
1408 TALLOC_CTX *ctx = talloc_tos();
1412 ZERO_STRUCT(spnego);
1414 myname_lower = talloc_strdup(ctx, lp_netbios_name());
1415 if (!myname_lower) {
1418 strlower_m(myname_lower);
1420 principal = talloc_asprintf(ctx, "%s$@%s", myname_lower, lp_realm());
1425 /* Server negTokenInit (mech offerings) */
1426 spnego.type = SPNEGO_NEG_TOKEN_INIT;
1427 spnego.negTokenInit.mechTypes = talloc_array(ctx, const char *, 4);
1429 spnego.negTokenInit.mechTypes[0] = talloc_strdup(ctx, OID_KERBEROS5_OLD);
1430 spnego.negTokenInit.mechTypes[1] = talloc_strdup(ctx, OID_KERBEROS5);
1431 spnego.negTokenInit.mechTypes[2] = talloc_strdup(ctx, OID_NTLMSSP);
1432 spnego.negTokenInit.mechTypes[3] = NULL;
1434 spnego.negTokenInit.mechTypes[0] = talloc_strdup(ctx, OID_NTLMSSP);
1435 spnego.negTokenInit.mechTypes[1] = NULL;
1439 spnego.negTokenInit.mechListMIC = data_blob_talloc(ctx, principal,
1442 len = spnego_write_data(ctx, &token, &spnego);
1443 spnego_free_data(&spnego);
1446 DEBUG(1, ("Could not write SPNEGO data blob\n"));
1447 x_fprintf(x_stdout, "BH Could not write SPNEGO data blob\n");
1451 reply_base64 = base64_encode_data_blob(talloc_tos(), token);
1452 x_fprintf(x_stdout, "TT %s *\n", reply_base64);
1454 TALLOC_FREE(reply_base64);
1455 data_blob_free(&token);
1456 DEBUG(10, ("sent SPNEGO negTokenInit\n"));
1460 static void manage_gss_spnego_request(struct ntlm_auth_state *state,
1461 char *buf, int length)
1463 struct spnego_data request, response;
1465 DATA_BLOB raw_in_token = data_blob_null;
1466 DATA_BLOB raw_out_token = data_blob_null;
1469 TALLOC_CTX *ctx = talloc_tos();
1471 const char *unix_username = NULL;
1473 const char *reply_code;
1475 char *reply_argument = NULL;
1476 char *supportedMech = NULL;
1478 if (strlen(buf) < 2) {
1479 DEBUG(1, ("SPENGO query [%s] invalid\n", buf));
1480 x_fprintf(x_stdout, "BH SPENGO query invalid\n");
1484 if (strncmp(buf, "YR", 2) == 0) {
1485 TALLOC_FREE(state->gensec_security);
1486 TALLOC_FREE(state->spnego_mech);
1487 TALLOC_FREE(state->spnego_mech_oid);
1488 } else if (strncmp(buf, "KK", 2) == 0) {
1491 DEBUG(1, ("SPENGO query [%s] invalid\n", buf));
1492 x_fprintf(x_stdout, "BH SPENGO query invalid\n");
1496 if ( (strlen(buf) == 2)) {
1498 /* no client data, get the negTokenInit offering
1501 offer_gss_spnego_mechs();
1505 /* All subsequent requests have a blob. This might be negTokenInit or negTokenTarg */
1507 if (strlen(buf) <= 3) {
1508 DEBUG(1, ("GSS-SPNEGO query [%s] invalid\n", buf));
1509 x_fprintf(x_stdout, "BH GSS-SPNEGO query invalid\n");
1513 token = base64_decode_data_blob(buf + 3);
1515 if ((token.length >= 7)
1516 && (strncmp((char *)token.data, "NTLMSSP", 7) == 0)) {
1519 data_blob_free(&token);
1521 DEBUG(10, ("Could not parse GSS-SPNEGO, trying raw "
1524 manage_squid_ntlmssp_request_int(state, buf, length,
1525 talloc_tos(), &reply);
1526 if (reply == NULL) {
1527 x_fprintf(x_stdout, "BH Out of memory\n");
1531 if (strncmp(reply, "AF ", 3) == 0) {
1532 x_fprintf(x_stdout, "AF * %s\n", reply+3);
1534 x_fprintf(x_stdout, "%s *\n", reply);
1541 ZERO_STRUCT(request);
1542 len = spnego_read_data(ctx, token, &request);
1543 data_blob_free(&token);
1546 DEBUG(1, ("GSS-SPNEGO query [%s] invalid\n", buf));
1547 x_fprintf(x_stdout, "BH GSS-SPNEGO query invalid\n");
1551 if (request.type == SPNEGO_NEG_TOKEN_INIT) {
1559 if (state->spnego_mech) {
1560 DEBUG(1, ("Client restarted SPNEGO with NegTokenInit "
1561 "while mech[%s] was already negotiated\n",
1562 state->spnego_mech));
1563 x_fprintf(x_stdout, "BH Client send NegTokenInit twice\n");
1567 /* Second request from Client. This is where the
1568 client offers its mechanism to use. */
1570 if ( (request.negTokenInit.mechTypes == NULL) ||
1571 (request.negTokenInit.mechTypes[0] == NULL) ) {
1572 DEBUG(1, ("Client did not offer any mechanism\n"));
1573 x_fprintf(x_stdout, "BH Client did not offer any "
1578 status = NT_STATUS_UNSUCCESSFUL;
1579 for (i = 0; request.negTokenInit.mechTypes[i] != NULL; i++) {
1580 DEBUG(10,("got mech[%d][%s]\n",
1581 i, request.negTokenInit.mechTypes[i]));
1583 if (strcmp(request.negTokenInit.mechTypes[i], OID_KERBEROS5_OLD) == 0) {
1587 if (strcmp(request.negTokenInit.mechTypes[i], OID_KERBEROS5) == 0) {
1592 if (strcmp(request.negTokenInit.mechTypes[i], OID_NTLMSSP) == 0) {
1598 used_idx = ntlm_idx;
1600 if (krb5_idx != -1) {
1602 used_idx = krb5_idx;
1605 if (ntlm_idx > -1) {
1606 state->spnego_mech = talloc_strdup(state, "ntlmssp");
1607 if (state->spnego_mech == NULL) {
1608 x_fprintf(x_stdout, "BH Out of memory\n");
1612 if (state->gensec_security) {
1613 DEBUG(1, ("Client wants a new NTLMSSP challenge, but "
1614 "already got one\n"));
1615 x_fprintf(x_stdout, "BH Client wants a new "
1616 "NTLMSSP challenge, but "
1617 "already got one\n");
1618 TALLOC_FREE(state->gensec_security);
1622 status = ntlm_auth_start_ntlmssp_server(state, &state->gensec_security);
1623 if (!NT_STATUS_IS_OK(status)) {
1624 x_fprintf(x_stdout, "BH %s\n", nt_errstr(status));
1630 if (krb5_idx > -1) {
1631 state->spnego_mech = talloc_strdup(state, "krb5");
1632 if (state->spnego_mech == NULL) {
1633 x_fprintf(x_stdout, "BH Out of memory\n");
1638 if (used_idx > -1) {
1639 state->spnego_mech_oid = talloc_strdup(state,
1640 request.negTokenInit.mechTypes[used_idx]);
1641 if (state->spnego_mech_oid == NULL) {
1642 x_fprintf(x_stdout, "BH Out of memory\n");
1645 supportedMech = talloc_strdup(ctx, state->spnego_mech_oid);
1646 if (supportedMech == NULL) {
1647 x_fprintf(x_stdout, "BH Out of memory\n");
1651 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1653 status = NT_STATUS_NOT_SUPPORTED;
1655 if (used_idx == 0) {
1656 status = NT_STATUS_OK;
1657 raw_in_token = request.negTokenInit.mechToken;
1660 if (state->spnego_mech == NULL) {
1661 DEBUG(1,("Got netTokenTarg without negTokenInit\n"));
1662 x_fprintf(x_stdout, "BH Got a negTokenTarg without "
1667 if ((request.negTokenTarg.supportedMech != NULL) &&
1668 (strcmp(request.negTokenTarg.supportedMech, state->spnego_mech_oid) != 0 ) ) {
1669 DEBUG(1, ("Got a negTokenTarg with mech[%s] while [%s] was already negotiated\n",
1670 request.negTokenTarg.supportedMech,
1671 state->spnego_mech_oid));
1672 x_fprintf(x_stdout, "BH Got a negTokenTarg with speficied mech\n");
1676 status = NT_STATUS_OK;
1677 raw_in_token = request.negTokenTarg.responseToken;
1680 if (!NT_STATUS_IS_OK(status)) {
1681 /* error or more processing */
1682 } else if (strcmp(state->spnego_mech, "ntlmssp") == 0) {
1684 DEBUG(10, ("got NTLMSSP packet:\n"));
1685 dump_data(10, raw_in_token.data, raw_in_token.length);
1687 status = gensec_update(state->gensec_security,
1691 if (NT_STATUS_IS_OK(status)) {
1692 struct auth_session_info *session_info;
1693 status = gensec_session_info(state->gensec_security, state->gensec_security, &session_info);
1694 if (!NT_STATUS_IS_OK(status)) {
1695 DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(status)));
1696 TALLOC_FREE(state->gensec_security);
1699 unix_username = session_info->unix_info->unix_name;
1700 DEBUG(10, ("NTLMSSP OK!\n"));
1702 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1703 TALLOC_FREE(state->ntlmssp_state);
1706 } else if (strcmp(state->spnego_mech, "krb5") == 0) {
1709 DATA_BLOB session_key;
1710 struct PAC_LOGON_INFO *logon_info = NULL;
1714 if (!spnego_parse_krb5_wrap(ctx, raw_in_token,
1716 DEBUG(1, ("spnego_parse_krb5_wrap failed\n"));
1717 x_fprintf(x_stdout, "BH spnego_parse_krb5_wrap failed\n");
1721 status = ads_verify_ticket(ctx, lp_realm(), 0,
1723 &principal, &logon_info, &ap_rep,
1724 &session_key, True);
1726 /* Now in "principal" we have the name we are authenticated as. */
1728 if (NT_STATUS_IS_OK(status)) {
1731 domain = strchr_m(principal, '@');
1733 if (domain == NULL) {
1734 DEBUG(1, ("Did not get a valid principal "
1735 "from ads_verify_ticket\n"));
1736 x_fprintf(x_stdout, "BH Did not get a "
1737 "valid principal from "
1738 "ads_verify_ticket\n");
1743 domain = talloc_strdup(ctx, domain);
1744 user = talloc_strdup(ctx, principal);
1747 netsamlogon_cache_store(
1748 user, &logon_info->info3);
1751 data_blob_free(&ap_rep);
1752 data_blob_free(&session_key);
1753 unix_username = talloc_asprintf(ctx, "%s\\%s", domain, user);
1755 data_blob_free(&ticket);
1759 spnego_free_data(&request);
1760 ZERO_STRUCT(response);
1761 response.type = SPNEGO_NEG_TOKEN_TARG;
1763 if (NT_STATUS_IS_OK(status)) {
1764 TALLOC_FREE(state->spnego_mech);
1765 TALLOC_FREE(state->spnego_mech_oid);
1766 response.negTokenTarg.negResult = SPNEGO_ACCEPT_COMPLETED;
1767 response.negTokenTarg.responseToken = raw_out_token;
1769 reply_argument = unix_username;
1770 } else if (NT_STATUS_EQUAL(status,
1771 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1772 response.negTokenTarg.supportedMech = supportedMech;
1773 response.negTokenTarg.responseToken = raw_out_token;
1774 response.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
1776 reply_argument = talloc_strdup(ctx, "*");
1778 TALLOC_FREE(state->spnego_mech);
1779 TALLOC_FREE(state->spnego_mech_oid);
1780 data_blob_free(&raw_out_token);
1781 response.negTokenTarg.negResult = SPNEGO_REJECT;
1783 reply_argument = talloc_strdup(ctx, nt_errstr(status));
1786 if (!reply_argument) {
1787 DEBUG(1, ("Could not write SPNEGO data blob\n"));
1788 x_fprintf(x_stdout, "BH Could not write SPNEGO data blob\n");
1789 spnego_free_data(&response);
1793 len = spnego_write_data(ctx, &token, &response);
1794 spnego_free_data(&response);
1797 DEBUG(1, ("Could not write SPNEGO data blob\n"));
1798 x_fprintf(x_stdout, "BH Could not write SPNEGO data blob\n");
1802 reply_base64 = base64_encode_data_blob(talloc_tos(), token);
1804 x_fprintf(x_stdout, "%s %s %s\n",
1805 reply_code, reply_base64, reply_argument);
1807 TALLOC_FREE(reply_base64);
1808 data_blob_free(&token);
1813 static struct ntlmssp_state *client_ntlmssp_state = NULL;
1815 static bool manage_client_ntlmssp_init(struct spnego_data spnego)
1818 DATA_BLOB null_blob = data_blob_null;
1819 DATA_BLOB to_server;
1820 char *to_server_base64;
1821 const char *my_mechs[] = {OID_NTLMSSP, NULL};
1822 TALLOC_CTX *ctx = talloc_tos();
1824 DEBUG(10, ("Got spnego negTokenInit with NTLMSSP\n"));
1826 if (client_ntlmssp_state != NULL) {
1827 DEBUG(1, ("Request for initial SPNEGO request where "
1828 "we already have a state\n"));
1832 if (!client_ntlmssp_state) {
1833 if (!NT_STATUS_IS_OK(status = ntlm_auth_start_ntlmssp_client(&client_ntlmssp_state))) {
1834 x_fprintf(x_stdout, "BH %s\n", nt_errstr(status));
1840 if (opt_password == NULL) {
1842 /* Request a password from the calling process. After
1843 sending it, the calling process should retry with
1844 the negTokenInit. */
1846 DEBUG(10, ("Requesting password\n"));
1847 x_fprintf(x_stdout, "PW\n");
1851 spnego.type = SPNEGO_NEG_TOKEN_INIT;
1852 spnego.negTokenInit.mechTypes = my_mechs;
1853 spnego.negTokenInit.reqFlags = data_blob_null;
1854 spnego.negTokenInit.reqFlagsPadding = 0;
1855 spnego.negTokenInit.mechListMIC = null_blob;
1857 status = ntlmssp_update(client_ntlmssp_state, null_blob,
1858 &spnego.negTokenInit.mechToken);
1860 if ( !(NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) ||
1861 NT_STATUS_IS_OK(status)) ) {
1862 DEBUG(1, ("Expected OK or MORE_PROCESSING_REQUIRED, got: %s\n",
1863 nt_errstr(status)));
1864 TALLOC_FREE(client_ntlmssp_state);
1868 spnego_write_data(ctx, &to_server, &spnego);
1869 data_blob_free(&spnego.negTokenInit.mechToken);
1871 to_server_base64 = base64_encode_data_blob(talloc_tos(), to_server);
1872 data_blob_free(&to_server);
1873 x_fprintf(x_stdout, "KK %s\n", to_server_base64);
1874 TALLOC_FREE(to_server_base64);
1878 static void manage_client_ntlmssp_targ(struct spnego_data spnego)
1881 DATA_BLOB null_blob = data_blob_null;
1883 DATA_BLOB to_server;
1884 char *to_server_base64;
1885 TALLOC_CTX *ctx = talloc_tos();
1887 DEBUG(10, ("Got spnego negTokenTarg with NTLMSSP\n"));
1889 if (client_ntlmssp_state == NULL) {
1890 DEBUG(1, ("Got NTLMSSP tArg without a client state\n"));
1891 x_fprintf(x_stdout, "BH Got NTLMSSP tArg without a client state\n");
1895 if (spnego.negTokenTarg.negResult == SPNEGO_REJECT) {
1896 x_fprintf(x_stdout, "NA\n");
1897 TALLOC_FREE(client_ntlmssp_state);
1901 if (spnego.negTokenTarg.negResult == SPNEGO_ACCEPT_COMPLETED) {
1902 x_fprintf(x_stdout, "AF\n");
1903 TALLOC_FREE(client_ntlmssp_state);
1907 status = ntlmssp_update(client_ntlmssp_state,
1908 spnego.negTokenTarg.responseToken,
1911 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1912 DEBUG(1, ("Expected MORE_PROCESSING_REQUIRED from "
1913 "ntlmssp_client_update, got: %s\n",
1914 nt_errstr(status)));
1915 x_fprintf(x_stdout, "BH Expected MORE_PROCESSING_REQUIRED from "
1916 "ntlmssp_client_update\n");
1917 data_blob_free(&request);
1918 TALLOC_FREE(client_ntlmssp_state);
1922 spnego.type = SPNEGO_NEG_TOKEN_TARG;
1923 spnego.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
1924 spnego.negTokenTarg.supportedMech = (const char *)OID_NTLMSSP;
1925 spnego.negTokenTarg.responseToken = request;
1926 spnego.negTokenTarg.mechListMIC = null_blob;
1928 spnego_write_data(ctx, &to_server, &spnego);
1929 data_blob_free(&request);
1931 to_server_base64 = base64_encode_data_blob(talloc_tos(), to_server);
1932 data_blob_free(&to_server);
1933 x_fprintf(x_stdout, "KK %s\n", to_server_base64);
1934 TALLOC_FREE(to_server_base64);
1940 static bool manage_client_krb5_init(struct spnego_data spnego)
1943 DATA_BLOB tkt, tkt_wrapped, to_server;
1944 DATA_BLOB session_key_krb5 = data_blob_null;
1945 struct spnego_data reply;
1949 const char *my_mechs[] = {OID_KERBEROS5_OLD, NULL};
1951 TALLOC_CTX *ctx = talloc_tos();
1953 if ( (spnego.negTokenInit.mechListMIC.data == NULL) ||
1954 (spnego.negTokenInit.mechListMIC.length == 0) ) {
1955 DEBUG(1, ("Did not get a principal for krb5\n"));
1959 principal = talloc_strndup(ctx, (char *)spnego.negTokenInit.mechListMIC.data,
1960 spnego.negTokenInit.mechListMIC.length);
1966 /* We may not be allowed to use the server-supplied SPNEGO principal, or it may not have been supplied to us
1968 if (!lp_client_use_spnego_principal() || strequal(principal, ADS_IGNORE_PRINCIPAL)) {
1969 TALLOC_FREE(principal);
1972 if (principal == NULL &&
1973 !is_ipaddress(opt_target_hostname)) {
1974 DEBUG(3,("manage_client_krb5_init: using target "
1975 "hostname not SPNEGO principal\n"));
1977 principal = kerberos_get_principal_from_service_hostname(talloc_tos(),
1979 opt_target_hostname);
1985 DEBUG(3,("manage_client_krb5_init: guessed "
1986 "server principal=%s\n",
1987 principal ? principal : "<null>"));
1990 if (principal == NULL) {
1991 DEBUG(3,("manage_client_krb5_init: could not guess server principal\n"));
1995 retval = cli_krb5_get_ticket(ctx, principal, 0,
1996 &tkt, &session_key_krb5,
1997 0, NULL, NULL, NULL);
2001 /* Let's try to first get the TGT, for that we need a
2004 if (opt_password == NULL) {
2005 DEBUG(10, ("Requesting password\n"));
2006 x_fprintf(x_stdout, "PW\n");
2010 user = talloc_asprintf(talloc_tos(), "%s@%s", opt_username, opt_domain);
2015 if ((retval = kerberos_kinit_password(user, opt_password, 0, NULL))) {
2016 DEBUG(10, ("Requesting TGT failed: %s\n", error_message(retval)));
2020 retval = cli_krb5_get_ticket(ctx, principal, 0,
2021 &tkt, &session_key_krb5,
2022 0, NULL, NULL, NULL);
2024 DEBUG(10, ("Kinit suceeded, but getting a ticket failed: %s\n", error_message(retval)));
2030 /* wrap that up in a nice GSS-API wrapping */
2031 tkt_wrapped = spnego_gen_krb5_wrap(ctx, tkt, TOK_ID_KRB_AP_REQ);
2033 data_blob_free(&session_key_krb5);
2037 reply.type = SPNEGO_NEG_TOKEN_INIT;
2038 reply.negTokenInit.mechTypes = my_mechs;
2039 reply.negTokenInit.reqFlags = data_blob_null;
2040 reply.negTokenInit.reqFlagsPadding = 0;
2041 reply.negTokenInit.mechToken = tkt_wrapped;
2042 reply.negTokenInit.mechListMIC = data_blob_null;
2044 len = spnego_write_data(ctx, &to_server, &reply);
2045 data_blob_free(&tkt);
2048 DEBUG(1, ("Could not write SPNEGO data blob\n"));
2052 reply_base64 = base64_encode_data_blob(talloc_tos(), to_server);
2053 x_fprintf(x_stdout, "KK %s *\n", reply_base64);
2055 TALLOC_FREE(reply_base64);
2056 data_blob_free(&to_server);
2057 DEBUG(10, ("sent GSS-SPNEGO KERBEROS5 negTokenInit\n"));
2061 static void manage_client_krb5_targ(struct spnego_data spnego)
2063 switch (spnego.negTokenTarg.negResult) {
2064 case SPNEGO_ACCEPT_INCOMPLETE:
2065 DEBUG(1, ("Got a Kerberos negTokenTarg with ACCEPT_INCOMPLETE\n"));
2066 x_fprintf(x_stdout, "BH Got a Kerberos negTokenTarg with "
2067 "ACCEPT_INCOMPLETE\n");
2069 case SPNEGO_ACCEPT_COMPLETED:
2070 DEBUG(10, ("Accept completed\n"));
2071 x_fprintf(x_stdout, "AF\n");
2074 DEBUG(10, ("Rejected\n"));
2075 x_fprintf(x_stdout, "NA\n");
2078 DEBUG(1, ("Got an invalid negTokenTarg\n"));
2079 x_fprintf(x_stdout, "AF\n");
2085 static void manage_gss_spnego_client_request(struct ntlm_auth_state *state,
2086 char *buf, int length)
2089 struct spnego_data spnego;
2091 TALLOC_CTX *ctx = talloc_tos();
2093 if (!opt_username || !*opt_username) {
2094 x_fprintf(x_stderr, "username must be specified!\n\n");
2098 if (strlen(buf) <= 3) {
2099 DEBUG(1, ("SPNEGO query [%s] too short\n", buf));
2100 x_fprintf(x_stdout, "BH SPNEGO query too short\n");
2104 request = base64_decode_data_blob(buf+3);
2106 if (strncmp(buf, "PW ", 3) == 0) {
2108 /* We asked for a password and obviously got it :-) */
2110 opt_password = SMB_STRNDUP((const char *)request.data, request.length);
2112 if (opt_password == NULL) {
2113 DEBUG(1, ("Out of memory\n"));
2114 x_fprintf(x_stdout, "BH Out of memory\n");
2115 data_blob_free(&request);
2119 x_fprintf(x_stdout, "OK\n");
2120 data_blob_free(&request);
2124 if ( (strncmp(buf, "TT ", 3) != 0) &&
2125 (strncmp(buf, "AF ", 3) != 0) &&
2126 (strncmp(buf, "NA ", 3) != 0) ) {
2127 DEBUG(1, ("SPNEGO request [%s] invalid\n", buf));
2128 x_fprintf(x_stdout, "BH SPNEGO request invalid\n");
2129 data_blob_free(&request);
2133 /* So we got a server challenge to generate a SPNEGO
2134 client-to-server request... */
2136 len = spnego_read_data(ctx, request, &spnego);
2137 data_blob_free(&request);
2140 DEBUG(1, ("Could not read SPNEGO data for [%s]\n", buf));
2141 x_fprintf(x_stdout, "BH Could not read SPNEGO data\n");
2145 if (spnego.type == SPNEGO_NEG_TOKEN_INIT) {
2147 /* The server offers a list of mechanisms */
2149 const char **mechType = (const char **)spnego.negTokenInit.mechTypes;
2151 while (*mechType != NULL) {
2154 if ( (strcmp(*mechType, OID_KERBEROS5_OLD) == 0) ||
2155 (strcmp(*mechType, OID_KERBEROS5) == 0) ) {
2156 if (manage_client_krb5_init(spnego))
2161 if (strcmp(*mechType, OID_NTLMSSP) == 0) {
2162 if (manage_client_ntlmssp_init(spnego))
2169 DEBUG(1, ("Server offered no compatible mechanism\n"));
2170 x_fprintf(x_stdout, "BH Server offered no compatible mechanism\n");
2174 if (spnego.type == SPNEGO_NEG_TOKEN_TARG) {
2176 if (spnego.negTokenTarg.supportedMech == NULL) {
2177 /* On accept/reject Windows does not send the
2178 mechanism anymore. Handle that here and
2179 shut down the mechanisms. */
2181 switch (spnego.negTokenTarg.negResult) {
2182 case SPNEGO_ACCEPT_COMPLETED:
2183 x_fprintf(x_stdout, "AF\n");
2186 x_fprintf(x_stdout, "NA\n");
2189 DEBUG(1, ("Got a negTokenTarg with no mech and an "
2190 "unknown negResult: %d\n",
2191 spnego.negTokenTarg.negResult));
2192 x_fprintf(x_stdout, "BH Got a negTokenTarg with"
2193 " no mech and an unknown "
2197 TALLOC_FREE(client_ntlmssp_state);
2201 if (strcmp(spnego.negTokenTarg.supportedMech,
2202 OID_NTLMSSP) == 0) {
2203 manage_client_ntlmssp_targ(spnego);
2208 if (strcmp(spnego.negTokenTarg.supportedMech,
2209 OID_KERBEROS5_OLD) == 0) {
2210 manage_client_krb5_targ(spnego);
2217 DEBUG(1, ("Got an SPNEGO token I could not handle [%s]!\n", buf));
2218 x_fprintf(x_stdout, "BH Got an SPNEGO token I could not handle\n");
2222 spnego_free_data(&spnego);
2226 static void manage_ntlm_server_1_request(struct ntlm_auth_state *state,
2227 char *buf, int length)
2229 char *request, *parameter;
2230 static DATA_BLOB challenge;
2231 static DATA_BLOB lm_response;
2232 static DATA_BLOB nt_response;
2233 static char *full_username;
2234 static char *username;
2235 static char *domain;
2236 static char *plaintext_password;
2237 static bool ntlm_server_1_user_session_key;
2238 static bool ntlm_server_1_lm_session_key;
2240 if (strequal(buf, ".")) {
2241 if (!full_username && !username) {
2242 x_fprintf(x_stdout, "Error: No username supplied!\n");
2243 } else if (plaintext_password) {
2244 /* handle this request as plaintext */
2245 if (!full_username) {
2246 if (asprintf(&full_username, "%s%c%s", domain, winbind_separator(), username) == -1) {
2247 x_fprintf(x_stdout, "Error: Out of memory in asprintf!\n.\n");
2251 if (check_plaintext_auth(full_username, plaintext_password, False)) {
2252 x_fprintf(x_stdout, "Authenticated: Yes\n");
2254 x_fprintf(x_stdout, "Authenticated: No\n");
2256 } else if (!lm_response.data && !nt_response.data) {
2257 x_fprintf(x_stdout, "Error: No password supplied!\n");
2258 } else if (!challenge.data) {
2259 x_fprintf(x_stdout, "Error: No lanman-challenge supplied!\n");
2261 char *error_string = NULL;
2263 uchar user_session_key[16];
2266 if (full_username && !username) {
2268 fstring fstr_domain;
2270 if (!parse_ntlm_auth_domain_user(full_username, fstr_user, fstr_domain)) {
2271 /* username might be 'tainted', don't print into our new-line deleimianted stream */
2272 x_fprintf(x_stdout, "Error: Could not parse into domain and username\n");
2274 SAFE_FREE(username);
2276 username = smb_xstrdup(fstr_user);
2277 domain = smb_xstrdup(fstr_domain);
2281 domain = smb_xstrdup(get_winbind_domain());
2284 if (ntlm_server_1_lm_session_key)
2285 flags |= WBFLAG_PAM_LMKEY;
2287 if (ntlm_server_1_user_session_key)
2288 flags |= WBFLAG_PAM_USER_SESSION_KEY;
2290 if (!NT_STATUS_IS_OK(
2291 contact_winbind_auth_crap(username,
2303 x_fprintf(x_stdout, "Authenticated: No\n");
2304 x_fprintf(x_stdout, "Authentication-Error: %s\n.\n", error_string);
2306 static char zeros[16];
2308 char *hex_user_session_key;
2310 x_fprintf(x_stdout, "Authenticated: Yes\n");
2312 if (ntlm_server_1_lm_session_key
2313 && (memcmp(zeros, lm_key,
2314 sizeof(lm_key)) != 0)) {
2315 hex_lm_key = hex_encode_talloc(NULL,
2316 (const unsigned char *)lm_key,
2318 x_fprintf(x_stdout, "LANMAN-Session-Key: %s\n", hex_lm_key);
2319 TALLOC_FREE(hex_lm_key);
2322 if (ntlm_server_1_user_session_key
2323 && (memcmp(zeros, user_session_key,
2324 sizeof(user_session_key)) != 0)) {
2325 hex_user_session_key = hex_encode_talloc(NULL,
2326 (const unsigned char *)user_session_key,
2327 sizeof(user_session_key));
2328 x_fprintf(x_stdout, "User-Session-Key: %s\n", hex_user_session_key);
2329 TALLOC_FREE(hex_user_session_key);
2332 SAFE_FREE(error_string);
2334 /* clear out the state */
2335 challenge = data_blob_null;
2336 nt_response = data_blob_null;
2337 lm_response = data_blob_null;
2338 SAFE_FREE(full_username);
2339 SAFE_FREE(username);
2341 SAFE_FREE(plaintext_password);
2342 ntlm_server_1_user_session_key = False;
2343 ntlm_server_1_lm_session_key = False;
2344 x_fprintf(x_stdout, ".\n");
2351 /* Indicates a base64 encoded structure */
2352 parameter = strstr_m(request, ":: ");
2354 parameter = strstr_m(request, ": ");
2357 DEBUG(0, ("Parameter not found!\n"));
2358 x_fprintf(x_stdout, "Error: Parameter not found!\n.\n");
2375 base64_decode_inplace(parameter);
2378 if (strequal(request, "LANMAN-Challenge")) {
2379 challenge = strhex_to_data_blob(NULL, parameter);
2380 if (challenge.length != 8) {
2381 x_fprintf(x_stdout, "Error: hex decode of %s failed! (got %d bytes, expected 8)\n.\n",
2383 (int)challenge.length);
2384 challenge = data_blob_null;
2386 } else if (strequal(request, "NT-Response")) {
2387 nt_response = strhex_to_data_blob(NULL, parameter);
2388 if (nt_response.length < 24) {
2389 x_fprintf(x_stdout, "Error: hex decode of %s failed! (only got %d bytes, needed at least 24)\n.\n",
2391 (int)nt_response.length);
2392 nt_response = data_blob_null;
2394 } else if (strequal(request, "LANMAN-Response")) {
2395 lm_response = strhex_to_data_blob(NULL, parameter);
2396 if (lm_response.length != 24) {
2397 x_fprintf(x_stdout, "Error: hex decode of %s failed! (got %d bytes, expected 24)\n.\n",
2399 (int)lm_response.length);
2400 lm_response = data_blob_null;
2402 } else if (strequal(request, "Password")) {
2403 plaintext_password = smb_xstrdup(parameter);
2404 } else if (strequal(request, "NT-Domain")) {
2405 domain = smb_xstrdup(parameter);
2406 } else if (strequal(request, "Username")) {
2407 username = smb_xstrdup(parameter);
2408 } else if (strequal(request, "Full-Username")) {
2409 full_username = smb_xstrdup(parameter);
2410 } else if (strequal(request, "Request-User-Session-Key")) {
2411 ntlm_server_1_user_session_key = strequal(parameter, "Yes");
2412 } else if (strequal(request, "Request-LanMan-Session-Key")) {
2413 ntlm_server_1_lm_session_key = strequal(parameter, "Yes");
2415 x_fprintf(x_stdout, "Error: Unknown request %s\n.\n", request);
2419 static void manage_ntlm_change_password_1_request(struct ntlm_auth_state *state,
2420 char *buf, int length)
2422 char *request, *parameter;
2423 static DATA_BLOB new_nt_pswd;
2424 static DATA_BLOB old_nt_hash_enc;
2425 static DATA_BLOB new_lm_pswd;
2426 static DATA_BLOB old_lm_hash_enc;
2427 static char *full_username = NULL;
2428 static char *username = NULL;
2429 static char *domain = NULL;
2430 static char *newpswd = NULL;
2431 static char *oldpswd = NULL;
2433 if (strequal(buf, ".")) {
2434 if(newpswd && oldpswd) {
2435 uchar old_nt_hash[16];
2436 uchar old_lm_hash[16];
2437 uchar new_nt_hash[16];
2438 uchar new_lm_hash[16];
2440 new_nt_pswd = data_blob(NULL, 516);
2441 old_nt_hash_enc = data_blob(NULL, 16);
2443 /* Calculate the MD4 hash (NT compatible) of the
2445 E_md4hash(oldpswd, old_nt_hash);
2446 E_md4hash(newpswd, new_nt_hash);
2448 /* E_deshash returns false for 'long'
2449 passwords (> 14 DOS chars).
2451 Therefore, don't send a buffer
2452 encrypted with the truncated hash
2453 (it could allow an even easier
2454 attack on the password)
2456 Likewise, obey the admin's restriction
2459 if (lp_client_lanman_auth() &&
2460 E_deshash(newpswd, new_lm_hash) &&
2461 E_deshash(oldpswd, old_lm_hash)) {
2462 new_lm_pswd = data_blob(NULL, 516);
2463 old_lm_hash_enc = data_blob(NULL, 16);
2464 encode_pw_buffer(new_lm_pswd.data, newpswd,
2467 arcfour_crypt(new_lm_pswd.data, old_nt_hash, 516);
2468 E_old_pw_hash(new_nt_hash, old_lm_hash,
2469 old_lm_hash_enc.data);
2471 new_lm_pswd.data = NULL;
2472 new_lm_pswd.length = 0;
2473 old_lm_hash_enc.data = NULL;
2474 old_lm_hash_enc.length = 0;
2477 encode_pw_buffer(new_nt_pswd.data, newpswd,
2480 arcfour_crypt(new_nt_pswd.data, old_nt_hash, 516);
2481 E_old_pw_hash(new_nt_hash, old_nt_hash,
2482 old_nt_hash_enc.data);
2485 if (!full_username && !username) {
2486 x_fprintf(x_stdout, "Error: No username supplied!\n");
2487 } else if ((!new_nt_pswd.data || !old_nt_hash_enc.data) &&
2488 (!new_lm_pswd.data || old_lm_hash_enc.data) ) {
2489 x_fprintf(x_stdout, "Error: No NT or LM password "
2490 "blobs supplied!\n");
2492 char *error_string = NULL;
2494 if (full_username && !username) {
2496 fstring fstr_domain;
2498 if (!parse_ntlm_auth_domain_user(full_username,
2501 /* username might be 'tainted', don't
2502 * print into our new-line
2503 * deleimianted stream */
2504 x_fprintf(x_stdout, "Error: Could not "
2505 "parse into domain and "
2507 SAFE_FREE(username);
2508 username = smb_xstrdup(full_username);
2510 SAFE_FREE(username);
2512 username = smb_xstrdup(fstr_user);
2513 domain = smb_xstrdup(fstr_domain);
2518 if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
2525 x_fprintf(x_stdout, "Password-Change: No\n");
2526 x_fprintf(x_stdout, "Password-Change-Error: "
2527 "%s\n.\n", error_string);
2529 x_fprintf(x_stdout, "Password-Change: Yes\n");
2532 SAFE_FREE(error_string);
2534 /* clear out the state */
2535 new_nt_pswd = data_blob_null;
2536 old_nt_hash_enc = data_blob_null;
2537 new_lm_pswd = data_blob_null;
2538 old_nt_hash_enc = data_blob_null;
2539 SAFE_FREE(full_username);
2540 SAFE_FREE(username);
2544 x_fprintf(x_stdout, ".\n");
2551 /* Indicates a base64 encoded structure */
2552 parameter = strstr_m(request, ":: ");
2554 parameter = strstr_m(request, ": ");
2557 DEBUG(0, ("Parameter not found!\n"));
2558 x_fprintf(x_stdout, "Error: Parameter not found!\n.\n");
2574 base64_decode_inplace(parameter);
2577 if (strequal(request, "new-nt-password-blob")) {
2578 new_nt_pswd = strhex_to_data_blob(NULL, parameter);
2579 if (new_nt_pswd.length != 516) {
2580 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2581 "(got %d bytes, expected 516)\n.\n",
2583 (int)new_nt_pswd.length);
2584 new_nt_pswd = data_blob_null;
2586 } else if (strequal(request, "old-nt-hash-blob")) {
2587 old_nt_hash_enc = strhex_to_data_blob(NULL, parameter);
2588 if (old_nt_hash_enc.length != 16) {
2589 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2590 "(got %d bytes, expected 16)\n.\n",
2592 (int)old_nt_hash_enc.length);
2593 old_nt_hash_enc = data_blob_null;
2595 } else if (strequal(request, "new-lm-password-blob")) {
2596 new_lm_pswd = strhex_to_data_blob(NULL, parameter);
2597 if (new_lm_pswd.length != 516) {
2598 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2599 "(got %d bytes, expected 516)\n.\n",
2601 (int)new_lm_pswd.length);
2602 new_lm_pswd = data_blob_null;
2605 else if (strequal(request, "old-lm-hash-blob")) {
2606 old_lm_hash_enc = strhex_to_data_blob(NULL, parameter);
2607 if (old_lm_hash_enc.length != 16)
2609 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2610 "(got %d bytes, expected 16)\n.\n",
2612 (int)old_lm_hash_enc.length);
2613 old_lm_hash_enc = data_blob_null;
2615 } else if (strequal(request, "nt-domain")) {
2616 domain = smb_xstrdup(parameter);
2617 } else if(strequal(request, "username")) {
2618 username = smb_xstrdup(parameter);
2619 } else if(strequal(request, "full-username")) {
2620 username = smb_xstrdup(parameter);
2621 } else if(strequal(request, "new-password")) {
2622 newpswd = smb_xstrdup(parameter);
2623 } else if (strequal(request, "old-password")) {
2624 oldpswd = smb_xstrdup(parameter);
2626 x_fprintf(x_stdout, "Error: Unknown request %s\n.\n", request);
2630 static void manage_squid_request(struct ntlm_auth_state *state,
2631 stdio_helper_function fn)
2634 char tmp[INITIAL_BUFFER_SIZE+1];
2635 int length, buf_size = 0;
2638 buf = talloc_strdup(state->mem_ctx, "");
2640 DEBUG(0, ("Failed to allocate input buffer.\n"));
2641 x_fprintf(x_stderr, "ERR\n");
2647 /* this is not a typo - x_fgets doesn't work too well under
2649 if (fgets(tmp, sizeof(tmp)-1, stdin) == NULL) {
2650 if (ferror(stdin)) {
2651 DEBUG(1, ("fgets() failed! dying..... errno=%d "
2652 "(%s)\n", ferror(stdin),
2653 strerror(ferror(stdin))));
2660 buf = talloc_strdup_append_buffer(buf, tmp);
2661 buf_size += INITIAL_BUFFER_SIZE;
2663 if (buf_size > MAX_BUFFER_SIZE) {
2664 DEBUG(2, ("Oversized message\n"));
2665 x_fprintf(x_stderr, "ERR\n");
2670 c = strchr(buf, '\n');
2671 } while (c == NULL);
2676 DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf,length));
2678 if (buf[0] == '\0') {
2679 DEBUG(2, ("Invalid Request\n"));
2680 x_fprintf(x_stderr, "ERR\n");
2685 fn(state, buf, length);
2690 static void squid_stream(enum stdio_helper_mode stdio_mode, stdio_helper_function fn) {
2691 TALLOC_CTX *mem_ctx;
2692 struct ntlm_auth_state *state;
2694 /* initialize FDescs */
2695 x_setbuf(x_stdout, NULL);
2696 x_setbuf(x_stderr, NULL);
2698 mem_ctx = talloc_init("ntlm_auth");
2700 DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
2701 x_fprintf(x_stderr, "ERR\n");
2705 state = talloc_zero(mem_ctx, struct ntlm_auth_state);
2707 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
2708 x_fprintf(x_stderr, "ERR\n");
2712 state->mem_ctx = mem_ctx;
2713 state->helper_mode = stdio_mode;
2716 TALLOC_CTX *frame = talloc_stackframe();
2717 manage_squid_request(state, fn);
2723 /* Authenticate a user with a challenge/response */
2725 static bool check_auth_crap(void)
2730 char user_session_key[16];
2732 char *hex_user_session_key;
2734 static uint8 zeros[16];
2736 x_setbuf(x_stdout, NULL);
2739 flags |= WBFLAG_PAM_LMKEY;
2741 if (request_user_session_key)
2742 flags |= WBFLAG_PAM_USER_SESSION_KEY;
2744 flags |= WBFLAG_PAM_NT_STATUS_SQUASH;
2746 nt_status = contact_winbind_auth_crap(opt_username, opt_domain,
2752 (unsigned char *)lm_key,
2753 (unsigned char *)user_session_key,
2754 &error_string, NULL);
2756 if (!NT_STATUS_IS_OK(nt_status)) {
2757 x_fprintf(x_stdout, "%s (0x%x)\n",
2759 NT_STATUS_V(nt_status));
2760 SAFE_FREE(error_string);
2765 && (memcmp(zeros, lm_key,
2766 sizeof(lm_key)) != 0)) {
2767 hex_lm_key = hex_encode_talloc(talloc_tos(), (const unsigned char *)lm_key,
2769 x_fprintf(x_stdout, "LM_KEY: %s\n", hex_lm_key);
2770 TALLOC_FREE(hex_lm_key);
2772 if (request_user_session_key
2773 && (memcmp(zeros, user_session_key,
2774 sizeof(user_session_key)) != 0)) {
2775 hex_user_session_key = hex_encode_talloc(talloc_tos(), (const unsigned char *)user_session_key,
2776 sizeof(user_session_key));
2777 x_fprintf(x_stdout, "NT_KEY: %s\n", hex_user_session_key);
2778 TALLOC_FREE(hex_user_session_key);
2787 OPT_USERNAME = 1000,
2796 OPT_USER_SESSION_KEY,
2798 OPT_REQUIRE_MEMBERSHIP,
2799 OPT_USE_CACHED_CREDS,
2800 OPT_PAM_WINBIND_CONF,
2805 int main(int argc, const char **argv)
2807 TALLOC_CTX *frame = talloc_stackframe();
2809 static const char *helper_protocol;
2810 static int diagnostics;
2812 static const char *hex_challenge;
2813 static const char *hex_lm_response;
2814 static const char *hex_nt_response;
2818 /* NOTE: DO NOT change this interface without considering the implications!
2819 This is an external interface, which other programs will use to interact
2823 /* We do not use single-letter command abbreviations, because they harm future
2824 interface stability. */
2826 struct poptOption long_options[] = {
2828 { "helper-protocol", 0, POPT_ARG_STRING, &helper_protocol, OPT_DOMAIN, "operate as a stdio-based helper", "helper protocol to use"},
2829 { "username", 0, POPT_ARG_STRING, &opt_username, OPT_USERNAME, "username"},
2830 { "domain", 0, POPT_ARG_STRING, &opt_domain, OPT_DOMAIN, "domain name"},
2831 { "workstation", 0, POPT_ARG_STRING, &opt_workstation, OPT_WORKSTATION, "workstation"},
2832 { "challenge", 0, POPT_ARG_STRING, &hex_challenge, OPT_CHALLENGE, "challenge (HEX encoded)"},
2833 { "lm-response", 0, POPT_ARG_STRING, &hex_lm_response, OPT_LM, "LM Response to the challenge (HEX encoded)"},
2834 { "nt-response", 0, POPT_ARG_STRING, &hex_nt_response, OPT_NT, "NT or NTLMv2 Response to the challenge (HEX encoded)"},
2835 { "password", 0, POPT_ARG_STRING, &opt_password, OPT_PASSWORD, "User's plaintext password"},
2836 { "request-lm-key", 0, POPT_ARG_NONE, &request_lm_key, OPT_LM_KEY, "Retrieve LM session key"},
2837 { "request-nt-key", 0, POPT_ARG_NONE, &request_user_session_key, OPT_USER_SESSION_KEY, "Retrieve User (NT) session key"},
2838 { "use-cached-creds", 0, POPT_ARG_NONE, &use_cached_creds, OPT_USE_CACHED_CREDS, "Use cached credentials if no password is given"},
2839 { "diagnostics", 0, POPT_ARG_NONE, &diagnostics,
2841 "Perform diagnostics on the authentication chain"},
2842 { "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" },
2843 { "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" },
2844 { "target-service", 0, POPT_ARG_STRING, &opt_target_service, OPT_TARGET_SERVICE, "Target service (eg http)" },
2845 { "target-hostname", 0, POPT_ARG_STRING, &opt_target_hostname, OPT_TARGET_HOSTNAME, "Target hostname" },
2846 POPT_COMMON_CONFIGFILE
2851 /* Samba client initialisation */
2854 setup_logging("ntlm_auth", DEBUG_STDERR);
2858 pc = poptGetContext("ntlm_auth", argc, argv, long_options, 0);
2860 /* Parse command line options */
2863 poptPrintHelp(pc, stderr, 0);
2867 while((opt = poptGetNextOpt(pc)) != -1) {
2868 /* Get generic config options like --configfile */
2871 poptFreeContext(pc);
2873 if (!lp_load_global(get_dyn_CONFIGFILE())) {
2874 d_fprintf(stderr, "ntlm_auth: error opening config file %s. Error was %s\n",
2875 get_dyn_CONFIGFILE(), strerror(errno));
2879 pc = poptGetContext(NULL, argc, (const char **)argv, long_options,
2880 POPT_CONTEXT_KEEP_FIRST);
2882 while((opt = poptGetNextOpt(pc)) != -1) {
2885 opt_challenge = strhex_to_data_blob(NULL, hex_challenge);
2886 if (opt_challenge.length != 8) {
2887 x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n",
2889 (int)opt_challenge.length);
2894 opt_lm_response = strhex_to_data_blob(NULL, hex_lm_response);
2895 if (opt_lm_response.length != 24) {
2896 x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n",
2898 (int)opt_lm_response.length);
2904 opt_nt_response = strhex_to_data_blob(NULL, hex_nt_response);
2905 if (opt_nt_response.length < 24) {
2906 x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n",
2908 (int)opt_nt_response.length);
2913 case OPT_REQUIRE_MEMBERSHIP:
2914 if (strncasecmp_m("S-", require_membership_of, 2) == 0) {
2915 require_membership_of_sid = require_membership_of;
2922 char *domain = SMB_STRDUP(opt_username);
2923 char *p = strchr_m(domain, *lp_winbind_separator());
2927 if (opt_domain && !strequal(opt_domain, domain)) {
2928 x_fprintf(x_stderr, "Domain specified in username (%s) "
2929 "doesn't match specified domain (%s)!\n\n",
2930 domain, opt_domain);
2931 poptPrintHelp(pc, stderr, 0);
2934 opt_domain = domain;
2940 /* Note: if opt_domain is "" then send no domain */
2941 if (opt_domain == NULL) {
2942 opt_domain = get_winbind_domain();
2945 if (opt_workstation == NULL) {
2946 opt_workstation = "";
2949 if (helper_protocol) {
2951 for (i=0; i<NUM_HELPER_MODES; i++) {
2952 if (strcmp(helper_protocol, stdio_helper_protocols[i].name) == 0) {
2953 squid_stream(stdio_helper_protocols[i].mode, stdio_helper_protocols[i].fn);
2957 x_fprintf(x_stderr, "unknown helper protocol [%s]\n\nValid helper protools:\n\n", helper_protocol);
2959 for (i=0; i<NUM_HELPER_MODES; i++) {
2960 x_fprintf(x_stderr, "%s\n", stdio_helper_protocols[i].name);
2966 if (!opt_username || !*opt_username) {
2967 x_fprintf(x_stderr, "username must be specified!\n\n");
2968 poptPrintHelp(pc, stderr, 0);
2972 if (opt_challenge.length) {
2973 if (!check_auth_crap()) {
2979 if (!opt_password) {
2980 opt_password = getpass("password: ");
2984 if (!diagnose_ntlm_auth()) {
2990 fstr_sprintf(user, "%s%c%s", opt_domain, winbind_separator(), opt_username);
2991 if (!check_plaintext_auth(user, opt_password, True)) {
2998 poptFreeContext(pc);