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/gensec/gensec_internal.h"
36 #include "auth/credentials/credentials.h"
37 #include "librpc/crypto/gse.h"
39 #include "lib/util/tiniparser.h"
40 #include "../lib/crypto/arcfour.h"
41 #include "libads/kerberos_proto.h"
42 #include "nsswitch/winbind_client.h"
43 #include "librpc/gen_ndr/krb5pac.h"
44 #include "../lib/util/asn1.h"
45 #include "auth/common_auth.h"
46 #include "source3/include/auth.h"
47 #include "source3/auth/proto.h"
48 #include "nsswitch/libwbclient/wbclient.h"
49 #include "lib/param/loadparm.h"
52 #include "auth/kerberos/pac_utils.h"
55 #ifndef PAM_WINBIND_CONFIG_FILE
56 #define PAM_WINBIND_CONFIG_FILE "/etc/security/pam_winbind.conf"
59 #define WINBIND_KRB5_AUTH 0x00000080
62 #define DBGC_CLASS DBGC_WINBIND
64 #define INITIAL_BUFFER_SIZE 300
65 #define MAX_BUFFER_SIZE 630000
67 enum stdio_helper_mode {
75 NTLM_CHANGE_PASSWORD_1,
79 enum ntlm_auth_cli_state {
86 struct ntlm_auth_state {
88 enum stdio_helper_mode helper_mode;
89 enum ntlm_auth_cli_state cli_state;
90 struct ntlmssp_state *ntlmssp_state;
92 char *want_feature_list;
93 bool have_session_key;
94 DATA_BLOB session_key;
95 DATA_BLOB initial_message;
96 void *gensec_private_1;
98 typedef void (*stdio_helper_function)(enum stdio_helper_mode stdio_helper_mode,
99 struct loadparm_context *lp_ctx,
100 struct ntlm_auth_state *state, char *buf,
101 int length, void **private2);
103 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode,
104 struct loadparm_context *lp_ctx,
105 struct ntlm_auth_state *state,
106 stdio_helper_function fn, void **private2);
108 static void manage_squid_basic_request (enum stdio_helper_mode stdio_helper_mode,
109 struct loadparm_context *lp_ctx,
110 struct ntlm_auth_state *state,
111 char *buf, int length, void **private2);
113 static void manage_squid_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode,
114 struct loadparm_context *lp_ctx,
115 struct ntlm_auth_state *state,
116 char *buf, int length, void **private2);
118 static void manage_client_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode,
119 struct loadparm_context *lp_ctx,
120 struct ntlm_auth_state *state,
121 char *buf, int length, void **private2);
123 static void manage_gss_spnego_request (enum stdio_helper_mode stdio_helper_mode,
124 struct loadparm_context *lp_ctx,
125 struct ntlm_auth_state *state,
126 char *buf, int length, void **private2);
128 static void manage_gss_spnego_client_request (enum stdio_helper_mode stdio_helper_mode,
129 struct loadparm_context *lp_ctx,
130 struct ntlm_auth_state *state,
131 char *buf, int length, void **private2);
133 static void manage_ntlm_server_1_request (enum stdio_helper_mode stdio_helper_mode,
134 struct loadparm_context *lp_ctx,
135 struct ntlm_auth_state *state,
136 char *buf, int length, void **private2);
138 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode,
139 struct loadparm_context *lp_ctx,
140 struct ntlm_auth_state *state,
141 char *buf, int length, void **private2);
143 static const struct {
144 enum stdio_helper_mode mode;
146 stdio_helper_function fn;
147 } stdio_helper_protocols[] = {
148 { SQUID_2_4_BASIC, "squid-2.4-basic", manage_squid_basic_request},
149 { SQUID_2_5_BASIC, "squid-2.5-basic", manage_squid_basic_request},
150 { SQUID_2_5_NTLMSSP, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request},
151 { NTLMSSP_CLIENT_1, "ntlmssp-client-1", manage_client_ntlmssp_request},
152 { GSS_SPNEGO_SERVER, "gss-spnego", manage_gss_spnego_request},
153 { GSS_SPNEGO_CLIENT, "gss-spnego-client", manage_gss_spnego_client_request},
154 { NTLM_SERVER_1, "ntlm-server-1", manage_ntlm_server_1_request},
155 { NTLM_CHANGE_PASSWORD_1, "ntlm-change-password-1", manage_ntlm_change_password_1_request},
156 { NUM_HELPER_MODES, NULL, NULL}
159 const char *opt_username;
160 const char *opt_domain;
161 const char *opt_workstation;
162 const char *opt_password;
163 static DATA_BLOB opt_challenge;
164 static DATA_BLOB opt_lm_response;
165 static DATA_BLOB opt_nt_response;
166 static int request_lm_key;
167 static int request_user_session_key;
168 static int use_cached_creds;
169 static int offline_logon;
171 static const char *require_membership_of;
172 static const char *require_membership_of_sid;
173 static const char *opt_pam_winbind_conf;
175 const char *opt_target_service;
176 const char *opt_target_hostname;
179 /* This is a bit hairy, but the basic idea is to do a password callback
180 to the calling application. The callback comes from within gensec */
182 static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mode,
183 struct loadparm_context *lp_ctx,
184 struct ntlm_auth_state *state, char *buf, int length,
188 if (strlen(buf) < 2) {
189 DEBUG(1, ("query [%s] invalid", buf));
190 x_fprintf(x_stdout, "BH Query invalid\n");
194 if (strlen(buf) > 3) {
195 in = base64_decode_data_blob(buf + 3);
197 in = data_blob(NULL, 0);
200 if (strncmp(buf, "PW ", 3) == 0) {
202 *password = talloc_strndup(NULL,
203 (const char *)in.data, in.length);
205 if (*password == NULL) {
206 DEBUG(1, ("Out of memory\n"));
207 x_fprintf(x_stdout, "BH Out of memory\n");
212 x_fprintf(x_stdout, "OK\n");
216 DEBUG(1, ("Asked for (and expected) a password\n"));
217 x_fprintf(x_stdout, "BH Expected a password\n");
222 * Callback for password credentials. This is not async, and when
223 * GENSEC and the credentials code is made async, it will look rather
227 static const char *get_password(struct cli_credentials *credentials)
229 char *password = NULL;
231 /* Ask for a password */
232 x_fprintf(x_stdout, "PW\n");
234 manage_squid_request(NUM_HELPER_MODES /* bogus */, NULL, NULL, manage_gensec_get_pw_request, (void **)&password);
235 talloc_steal(credentials, password);
240 * A limited set of features are defined with text strings as needed
244 static void gensec_want_feature_list(struct gensec_security *state, char* feature_list)
246 if (in_list("NTLMSSP_FEATURE_SESSION_KEY", feature_list, true)) {
247 DEBUG(10, ("want GENSEC_FEATURE_SESSION_KEY\n"));
248 gensec_want_feature(state, GENSEC_FEATURE_SESSION_KEY);
250 if (in_list("NTLMSSP_FEATURE_SIGN", feature_list, true)) {
251 DEBUG(10, ("want GENSEC_FEATURE_SIGN\n"));
252 gensec_want_feature(state, GENSEC_FEATURE_SIGN);
254 if (in_list("NTLMSSP_FEATURE_SEAL", feature_list, true)) {
255 DEBUG(10, ("want GENSEC_FEATURE_SEAL\n"));
256 gensec_want_feature(state, GENSEC_FEATURE_SEAL);
260 static char winbind_separator(void)
262 struct winbindd_response response;
269 ZERO_STRUCT(response);
271 /* Send off request */
273 if (winbindd_request_response(NULL, WINBINDD_INFO, NULL, &response) !=
274 NSS_STATUS_SUCCESS) {
275 d_printf("could not obtain winbind separator!\n");
276 return *lp_winbind_separator();
279 sep = response.data.info.winbind_separator;
283 d_printf("winbind separator was NULL!\n");
284 return *lp_winbind_separator();
290 const char *get_winbind_domain(void)
292 struct winbindd_response response;
294 static fstring winbind_domain;
295 if (*winbind_domain) {
296 return winbind_domain;
299 ZERO_STRUCT(response);
301 /* Send off request */
303 if (winbindd_request_response(NULL, WINBINDD_DOMAIN_NAME, NULL, &response) !=
304 NSS_STATUS_SUCCESS) {
305 DEBUG(1, ("could not obtain winbind domain name!\n"));
306 return lp_workgroup();
309 fstrcpy(winbind_domain, response.data.domain_name);
311 return winbind_domain;
315 const char *get_winbind_netbios_name(void)
317 struct winbindd_response response;
319 static fstring winbind_netbios_name;
321 if (*winbind_netbios_name) {
322 return winbind_netbios_name;
325 ZERO_STRUCT(response);
327 /* Send off request */
329 if (winbindd_request_response(NULL, WINBINDD_NETBIOS_NAME, NULL, &response) !=
330 NSS_STATUS_SUCCESS) {
331 DEBUG(1, ("could not obtain winbind netbios name!\n"));
332 return lp_netbios_name();
335 fstrcpy(winbind_netbios_name, response.data.netbios_name);
337 return winbind_netbios_name;
341 DATA_BLOB get_challenge(void)
343 static DATA_BLOB chal;
344 if (opt_challenge.length)
345 return opt_challenge;
347 chal = data_blob(NULL, 8);
349 generate_random_buffer(chal.data, chal.length);
353 /* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
354 form DOMAIN/user into a domain and a user */
356 static bool parse_ntlm_auth_domain_user(const char *domuser, fstring domain,
360 char *p = strchr(domuser,winbind_separator());
367 fstrcpy(domain, domuser);
368 domain[PTR_DIFF(p, domuser)] = 0;
369 return strupper_m(domain);
372 static bool get_require_membership_sid(void) {
373 struct winbindd_request request;
374 struct winbindd_response response;
376 if (!require_membership_of) {
380 if (require_membership_of_sid) {
384 /* Otherwise, ask winbindd for the name->sid request */
386 ZERO_STRUCT(request);
387 ZERO_STRUCT(response);
389 if (!parse_ntlm_auth_domain_user(require_membership_of,
390 request.data.name.dom_name,
391 request.data.name.name)) {
392 DEBUG(0, ("Could not parse %s into separate domain/name parts!\n",
393 require_membership_of));
397 if (winbindd_request_response(NULL, WINBINDD_LOOKUPNAME, &request, &response) !=
398 NSS_STATUS_SUCCESS) {
399 DEBUG(0, ("Winbindd lookupname failed to resolve %s into a SID!\n",
400 require_membership_of));
404 require_membership_of_sid = SMB_STRDUP(response.data.sid.sid);
406 if (require_membership_of_sid)
413 * Get some configuration from pam_winbind.conf to see if we
414 * need to contact trusted domain
417 int get_pam_winbind_config()
420 struct tiniparser_dictionary *d = NULL;
422 if (!opt_pam_winbind_conf || !*opt_pam_winbind_conf) {
423 opt_pam_winbind_conf = PAM_WINBIND_CONFIG_FILE;
426 d = tiniparser_load(opt_pam_winbind_conf);
432 if (tiniparser_getboolean(d, "global:krb5_auth", false)) {
433 ctrl |= WINBIND_KRB5_AUTH;
436 tiniparser_freedict(d);
441 /* Authenticate a user with a plaintext password */
443 static bool check_plaintext_auth(const char *user, const char *pass,
444 bool stdout_diagnostics)
446 struct winbindd_request request;
447 struct winbindd_response response;
450 if (!get_require_membership_sid()) {
454 /* Send off request */
456 ZERO_STRUCT(request);
457 ZERO_STRUCT(response);
459 fstrcpy(request.data.auth.user, user);
460 fstrcpy(request.data.auth.pass, pass);
461 if (require_membership_of_sid) {
462 strlcpy(request.data.auth.require_membership_of_sid,
463 require_membership_of_sid,
464 sizeof(request.data.auth.require_membership_of_sid));
468 request.flags |= WBFLAG_PAM_CACHED_LOGIN;
471 result = winbindd_request_response(NULL, WINBINDD_PAM_AUTH, &request, &response);
473 /* Display response */
475 if (stdout_diagnostics) {
476 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
477 d_printf("Reading winbind reply failed! (0x01)\n");
480 d_printf("%s: %s (0x%x)\n",
481 response.data.auth.nt_status_string,
482 response.data.auth.error_string,
483 response.data.auth.nt_status);
485 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
486 DEBUG(1, ("Reading winbind reply failed! (0x01)\n"));
489 DEBUG(3, ("%s: %s (0x%x)\n",
490 response.data.auth.nt_status_string,
491 response.data.auth.error_string,
492 response.data.auth.nt_status));
495 return (result == NSS_STATUS_SUCCESS);
498 /* authenticate a user with an encrypted username/password */
500 NTSTATUS contact_winbind_auth_crap(const char *username,
502 const char *workstation,
503 const DATA_BLOB *challenge,
504 const DATA_BLOB *lm_response,
505 const DATA_BLOB *nt_response,
507 uint32_t extra_logon_parameters,
509 uint8_t user_session_key[16],
515 struct winbindd_request request;
516 struct winbindd_response response;
518 if (!get_require_membership_sid()) {
519 return NT_STATUS_INVALID_PARAMETER;
522 ZERO_STRUCT(request);
523 ZERO_STRUCT(response);
525 request.flags = flags;
527 request.data.auth_crap.logon_parameters = extra_logon_parameters
528 | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT | MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT;
530 if (require_membership_of_sid)
531 fstrcpy(request.data.auth_crap.require_membership_of_sid, require_membership_of_sid);
533 fstrcpy(request.data.auth_crap.user, username);
534 fstrcpy(request.data.auth_crap.domain, domain);
536 fstrcpy(request.data.auth_crap.workstation,
539 memcpy(request.data.auth_crap.chal, challenge->data, MIN(challenge->length, 8));
541 if (lm_response && lm_response->length) {
542 memcpy(request.data.auth_crap.lm_resp,
544 MIN(lm_response->length, sizeof(request.data.auth_crap.lm_resp)));
545 request.data.auth_crap.lm_resp_len = lm_response->length;
548 if (nt_response && nt_response->length) {
549 if (nt_response->length > sizeof(request.data.auth_crap.nt_resp)) {
550 request.flags = request.flags | WBFLAG_BIG_NTLMV2_BLOB;
551 request.extra_len = nt_response->length;
552 request.extra_data.data = SMB_MALLOC_ARRAY(char, request.extra_len);
553 if (request.extra_data.data == NULL) {
554 return NT_STATUS_NO_MEMORY;
556 memcpy(request.extra_data.data, nt_response->data,
557 nt_response->length);
560 memcpy(request.data.auth_crap.nt_resp,
561 nt_response->data, nt_response->length);
563 request.data.auth_crap.nt_resp_len = nt_response->length;
566 result = winbindd_request_response(NULL, WINBINDD_PAM_AUTH_CRAP, &request, &response);
567 SAFE_FREE(request.extra_data.data);
569 /* Display response */
571 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
572 nt_status = NT_STATUS_UNSUCCESSFUL;
574 *error_string = smb_xstrdup("Reading winbind reply failed!");
575 winbindd_free_response(&response);
579 nt_status = (NT_STATUS(response.data.auth.nt_status));
580 if (!NT_STATUS_IS_OK(nt_status)) {
582 *error_string = smb_xstrdup(response.data.auth.error_string);
583 winbindd_free_response(&response);
587 if ((flags & WBFLAG_PAM_LMKEY) && lm_key) {
588 memcpy(lm_key, response.data.auth.first_8_lm_hash,
589 sizeof(response.data.auth.first_8_lm_hash));
591 if ((flags & WBFLAG_PAM_USER_SESSION_KEY) && user_session_key) {
592 memcpy(user_session_key, response.data.auth.user_session_key,
593 sizeof(response.data.auth.user_session_key));
596 if (flags & WBFLAG_PAM_UNIX_NAME) {
597 *unix_name = SMB_STRDUP(response.data.auth.unix_username);
599 winbindd_free_response(&response);
600 return NT_STATUS_NO_MEMORY;
604 winbindd_free_response(&response);
608 /* contact server to change user password using auth crap */
609 static NTSTATUS contact_winbind_change_pswd_auth_crap(const char *username,
611 const DATA_BLOB new_nt_pswd,
612 const DATA_BLOB old_nt_hash_enc,
613 const DATA_BLOB new_lm_pswd,
614 const DATA_BLOB old_lm_hash_enc,
619 struct winbindd_request request;
620 struct winbindd_response response;
622 if (!get_require_membership_sid())
625 *error_string = smb_xstrdup("Can't get membership sid.");
626 return NT_STATUS_INVALID_PARAMETER;
629 ZERO_STRUCT(request);
630 ZERO_STRUCT(response);
633 fstrcpy(request.data.chng_pswd_auth_crap.user, username);
635 fstrcpy(request.data.chng_pswd_auth_crap.domain,domain);
637 if(new_nt_pswd.length)
639 memcpy(request.data.chng_pswd_auth_crap.new_nt_pswd, new_nt_pswd.data, sizeof(request.data.chng_pswd_auth_crap.new_nt_pswd));
640 request.data.chng_pswd_auth_crap.new_nt_pswd_len = new_nt_pswd.length;
643 if(old_nt_hash_enc.length)
645 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));
646 request.data.chng_pswd_auth_crap.old_nt_hash_enc_len = old_nt_hash_enc.length;
649 if(new_lm_pswd.length)
651 memcpy(request.data.chng_pswd_auth_crap.new_lm_pswd, new_lm_pswd.data, sizeof(request.data.chng_pswd_auth_crap.new_lm_pswd));
652 request.data.chng_pswd_auth_crap.new_lm_pswd_len = new_lm_pswd.length;
655 if(old_lm_hash_enc.length)
657 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));
658 request.data.chng_pswd_auth_crap.old_lm_hash_enc_len = old_lm_hash_enc.length;
661 result = winbindd_request_response(NULL, WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP, &request, &response);
663 /* Display response */
665 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0))
667 nt_status = NT_STATUS_UNSUCCESSFUL;
669 *error_string = smb_xstrdup("Reading winbind reply failed!");
670 winbindd_free_response(&response);
674 nt_status = (NT_STATUS(response.data.auth.nt_status));
675 if (!NT_STATUS_IS_OK(nt_status))
678 *error_string = smb_xstrdup(response.data.auth.error_string);
679 winbindd_free_response(&response);
683 winbindd_free_response(&response);
688 static NTSTATUS ntlm_auth_generate_session_info(struct auth4_context *auth_context,
690 void *server_returned_info,
691 const char *original_user_name,
692 uint32_t session_info_flags,
693 struct auth_session_info **session_info_out)
695 char *unix_username = (char *)server_returned_info;
696 struct auth_session_info *session_info = talloc_zero(mem_ctx, struct auth_session_info);
698 return NT_STATUS_NO_MEMORY;
701 session_info->unix_info = talloc_zero(session_info, struct auth_user_info_unix);
702 if (!session_info->unix_info) {
703 TALLOC_FREE(session_info);
704 return NT_STATUS_NO_MEMORY;
706 session_info->unix_info->unix_name = talloc_steal(session_info->unix_info, unix_username);
708 *session_info_out = session_info;
713 static NTSTATUS ntlm_auth_generate_session_info_pac(struct auth4_context *auth_ctx,
715 struct smb_krb5_context *smb_krb5_context,
717 const char *princ_name,
718 const struct tsocket_address *remote_address,
719 uint32_t session_info_flags,
720 struct auth_session_info **session_info)
723 struct PAC_LOGON_INFO *logon_info = NULL;
731 tmp_ctx = talloc_new(mem_ctx);
733 return NT_STATUS_NO_MEMORY;
738 status = kerberos_pac_logon_info(tmp_ctx, *pac_blob, NULL, NULL,
739 NULL, NULL, 0, &logon_info);
741 status = NT_STATUS_ACCESS_DENIED;
743 if (!NT_STATUS_IS_OK(status)) {
748 DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name));
750 p = strchr_m(princ_name, '@');
752 DEBUG(3, ("[%s] Doesn't look like a valid principal\n",
754 return NT_STATUS_LOGON_FAILURE;
757 user = talloc_strndup(mem_ctx, princ_name, p - princ_name);
759 return NT_STATUS_NO_MEMORY;
762 realm = talloc_strdup(talloc_tos(), p + 1);
764 return NT_STATUS_NO_MEMORY;
767 if (!strequal(realm, lp_realm())) {
768 DEBUG(3, ("Ticket for foreign realm %s@%s\n", user, realm));
769 if (!lp_allow_trusted_domains()) {
770 return NT_STATUS_LOGON_FAILURE;
774 if (logon_info && logon_info->info3.base.logon_domain.string) {
775 domain = talloc_strdup(mem_ctx,
776 logon_info->info3.base.logon_domain.string);
778 return NT_STATUS_NO_MEMORY;
780 DEBUG(10, ("Domain is [%s] (using PAC)\n", domain));
783 /* If we have winbind running, we can (and must) shorten the
784 username by using the short netbios name. Otherwise we will
785 have inconsistent user names. With Kerberos, we get the
786 fully qualified realm, with ntlmssp we get the short
787 name. And even w2k3 does use ntlmssp if you for example
788 connect to an ip address. */
791 struct wbcDomainInfo *info = NULL;
793 DEBUG(10, ("Mapping [%s] to short name using winbindd\n",
796 wbc_status = wbcDomainInfo(realm, &info);
798 if (WBC_ERROR_IS_OK(wbc_status)) {
799 domain = talloc_strdup(mem_ctx,
803 DEBUG(3, ("Could not find short name: %s\n",
804 wbcErrorString(wbc_status)));
805 domain = talloc_strdup(mem_ctx, realm);
808 return NT_STATUS_NO_MEMORY;
810 DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain));
813 unixuser = talloc_asprintf(tmp_ctx, "%s%c%s", domain, winbind_separator(), user);
815 status = NT_STATUS_NO_MEMORY;
819 status = ntlm_auth_generate_session_info(auth_ctx, mem_ctx, unixuser, NULL, session_info_flags, session_info);
822 TALLOC_FREE(tmp_ctx);
829 * Return the challenge as determined by the authentication subsystem
830 * @return an 8 byte random challenge
833 static NTSTATUS ntlm_auth_get_challenge(struct auth4_context *auth_ctx,
836 if (auth_ctx->challenge.data.length == 8) {
837 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
838 auth_ctx->challenge.set_by));
839 memcpy(chal, auth_ctx->challenge.data.data, 8);
843 if (!auth_ctx->challenge.set_by) {
844 generate_random_buffer(chal, 8);
846 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
847 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
848 auth_ctx->challenge.set_by = "random";
851 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
852 auth_ctx->challenge.set_by));
858 * NTLM2 authentication modifies the effective challenge,
859 * @param challenge The new challenge value
861 static NTSTATUS ntlm_auth_set_challenge(struct auth4_context *auth_ctx, const uint8_t chal[8], const char *set_by)
863 auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
864 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
866 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
867 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
873 * Check the password on an NTLMSSP login.
875 * Return the session keys used on the connection.
878 static NTSTATUS winbind_pw_check(struct auth4_context *auth4_context,
880 const struct auth_usersupplied_info *user_info,
881 void **server_returned_info,
882 DATA_BLOB *session_key, DATA_BLOB *lm_session_key)
884 static const char zeros[16] = { 0, };
886 char *error_string = NULL;
888 uint8_t user_sess_key[16];
889 char *unix_name = NULL;
891 nt_status = contact_winbind_auth_crap(user_info->client.account_name, user_info->client.domain_name,
892 user_info->workstation_name,
893 &auth4_context->challenge.data,
894 &user_info->password.response.lanman,
895 &user_info->password.response.nt,
896 WBFLAG_PAM_LMKEY | WBFLAG_PAM_USER_SESSION_KEY | WBFLAG_PAM_UNIX_NAME,
898 lm_key, user_sess_key,
899 &error_string, &unix_name);
901 if (NT_STATUS_IS_OK(nt_status)) {
902 if (memcmp(lm_key, zeros, 8) != 0) {
903 *lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
904 memcpy(lm_session_key->data, lm_key, 8);
905 memset(lm_session_key->data+8, '\0', 8);
908 if (memcmp(user_sess_key, zeros, 16) != 0) {
909 *session_key = data_blob_talloc(mem_ctx, user_sess_key, 16);
911 *server_returned_info = talloc_strdup(mem_ctx,
914 DEBUG(NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED) ? 0 : 3,
915 ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
916 user_info->client.domain_name, user_info->client.account_name,
917 user_info->workstation_name,
918 error_string ? error_string : "unknown error (NULL)"));
921 SAFE_FREE(error_string);
922 SAFE_FREE(unix_name);
926 static NTSTATUS local_pw_check(struct auth4_context *auth4_context,
928 const struct auth_usersupplied_info *user_info,
929 void **server_returned_info,
930 DATA_BLOB *session_key, DATA_BLOB *lm_session_key)
933 struct samr_Password lm_pw, nt_pw;
935 nt_lm_owf_gen (opt_password, nt_pw.hash, lm_pw.hash);
937 nt_status = ntlm_password_check(mem_ctx,
939 &auth4_context->challenge.data,
940 &user_info->password.response.lanman,
941 &user_info->password.response.nt,
942 user_info->client.account_name,
943 user_info->client.account_name,
944 user_info->client.domain_name,
945 &lm_pw, &nt_pw, session_key, lm_session_key);
947 if (NT_STATUS_IS_OK(nt_status)) {
948 *server_returned_info = talloc_asprintf(mem_ctx,
949 "%s%c%s", user_info->client.domain_name,
950 *lp_winbind_separator(),
951 user_info->client.account_name);
953 DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
954 user_info->client.domain_name, user_info->client.account_name,
955 user_info->workstation_name,
956 nt_errstr(nt_status)));
961 static NTSTATUS ntlm_auth_start_ntlmssp_client(struct ntlmssp_state **client_ntlmssp_state)
964 if ( (opt_username == NULL) || (opt_domain == NULL) ) {
965 status = NT_STATUS_UNSUCCESSFUL;
966 DEBUG(1, ("Need username and domain for NTLMSSP\n"));
967 return NT_STATUS_INVALID_PARAMETER;
970 status = ntlmssp_client_start(NULL,
973 lp_client_ntlmv2_auth(),
974 client_ntlmssp_state);
976 if (!NT_STATUS_IS_OK(status)) {
977 DEBUG(1, ("Could not start NTLMSSP client: %s\n",
979 TALLOC_FREE(*client_ntlmssp_state);
983 status = ntlmssp_set_username(*client_ntlmssp_state, opt_username);
985 if (!NT_STATUS_IS_OK(status)) {
986 DEBUG(1, ("Could not set username: %s\n",
988 TALLOC_FREE(*client_ntlmssp_state);
992 status = ntlmssp_set_domain(*client_ntlmssp_state, opt_domain);
994 if (!NT_STATUS_IS_OK(status)) {
995 DEBUG(1, ("Could not set domain: %s\n",
997 TALLOC_FREE(*client_ntlmssp_state);
1002 status = ntlmssp_set_password(*client_ntlmssp_state, opt_password);
1004 if (!NT_STATUS_IS_OK(status)) {
1005 DEBUG(1, ("Could not set password: %s\n",
1006 nt_errstr(status)));
1007 TALLOC_FREE(*client_ntlmssp_state);
1012 return NT_STATUS_OK;
1015 static struct auth4_context *make_auth4_context_ntlm_auth(TALLOC_CTX *mem_ctx, bool local_pw)
1017 struct auth4_context *auth4_context = talloc_zero(mem_ctx, struct auth4_context);
1018 if (auth4_context == NULL) {
1019 DEBUG(10, ("failed to allocate auth4_context failed\n"));
1022 auth4_context->generate_session_info = ntlm_auth_generate_session_info;
1023 auth4_context->generate_session_info_pac = ntlm_auth_generate_session_info_pac;
1024 auth4_context->get_ntlm_challenge = ntlm_auth_get_challenge;
1025 auth4_context->set_ntlm_challenge = ntlm_auth_set_challenge;
1027 auth4_context->check_ntlm_password = local_pw_check;
1029 auth4_context->check_ntlm_password = winbind_pw_check;
1031 auth4_context->private_data = NULL;
1032 return auth4_context;
1035 static NTSTATUS ntlm_auth_prepare_gensec_server(TALLOC_CTX *mem_ctx,
1036 struct loadparm_context *lp_ctx,
1037 struct gensec_security **gensec_security_out)
1039 struct gensec_security *gensec_security;
1042 TALLOC_CTX *tmp_ctx;
1043 const struct gensec_security_ops **backends;
1044 struct gensec_settings *gensec_settings;
1046 struct cli_credentials *server_credentials;
1048 struct auth4_context *auth4_context;
1050 tmp_ctx = talloc_new(mem_ctx);
1051 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
1053 auth4_context = make_auth4_context_ntlm_auth(tmp_ctx, opt_password);
1054 if (auth4_context == NULL) {
1055 TALLOC_FREE(tmp_ctx);
1056 return NT_STATUS_NO_MEMORY;
1059 gensec_settings = lpcfg_gensec_settings(tmp_ctx, lp_ctx);
1060 if (lp_ctx == NULL) {
1061 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1062 TALLOC_FREE(tmp_ctx);
1063 return NT_STATUS_NO_MEMORY;
1067 * This should be a 'netbios domain -> DNS domain'
1068 * mapping, and can currently validly return NULL on
1069 * poorly configured systems.
1071 * This is used for the NTLMSSP server
1075 gensec_settings->server_netbios_name = lp_netbios_name();
1076 gensec_settings->server_netbios_domain = lp_workgroup();
1078 gensec_settings->server_netbios_name = get_winbind_netbios_name();
1079 gensec_settings->server_netbios_domain = get_winbind_domain();
1082 gensec_settings->server_dns_domain = strlower_talloc(gensec_settings,
1083 get_mydnsdomname(talloc_tos()));
1084 gensec_settings->server_dns_name = strlower_talloc(gensec_settings,
1085 get_mydnsfullname());
1087 backends = talloc_zero_array(gensec_settings,
1088 const struct gensec_security_ops *, 4);
1090 if (backends == NULL) {
1091 TALLOC_FREE(tmp_ctx);
1092 return NT_STATUS_NO_MEMORY;
1094 gensec_settings->backends = backends;
1098 /* These need to be in priority order, krb5 before NTLMSSP */
1099 #if defined(HAVE_KRB5)
1100 backends[idx++] = &gensec_gse_krb5_security_ops;
1103 backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_NTLMSSP);
1105 backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_SPNEGO);
1108 * This is anonymous for now, because we just use it
1109 * to set the kerberos state at the moment
1111 server_credentials = cli_credentials_init_anon(tmp_ctx);
1112 if (!server_credentials) {
1113 DEBUG(0, ("auth_generic_prepare: Failed to init server credentials\n"));
1114 return NT_STATUS_NO_MEMORY;
1117 cli_credentials_set_conf(server_credentials, lp_ctx);
1119 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC || lp_security() == SEC_ADS || USE_KERBEROS_KEYTAB) {
1120 cli_credentials_set_kerberos_state(server_credentials, CRED_AUTO_USE_KERBEROS);
1122 cli_credentials_set_kerberos_state(server_credentials, CRED_DONT_USE_KERBEROS);
1125 nt_status = gensec_server_start(tmp_ctx, gensec_settings,
1126 auth4_context, &gensec_security);
1128 if (!NT_STATUS_IS_OK(nt_status)) {
1129 TALLOC_FREE(tmp_ctx);
1133 gensec_set_credentials(gensec_security, server_credentials);
1135 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
1136 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
1138 talloc_unlink(tmp_ctx, lp_ctx);
1139 talloc_unlink(tmp_ctx, server_credentials);
1140 talloc_unlink(tmp_ctx, gensec_settings);
1141 talloc_unlink(tmp_ctx, auth4_context);
1143 *gensec_security_out = talloc_steal(mem_ctx, gensec_security);
1144 TALLOC_FREE(tmp_ctx);
1145 return NT_STATUS_OK;
1148 /*******************************************************************
1149 Used by firefox to drive NTLM auth to IIS servers.
1150 *******************************************************************/
1152 static NTSTATUS do_ccache_ntlm_auth(DATA_BLOB initial_msg, DATA_BLOB challenge_msg,
1155 struct winbindd_request wb_request;
1156 struct winbindd_response wb_response;
1160 /* get winbindd to do the ntlmssp step on our behalf */
1161 ZERO_STRUCT(wb_request);
1162 ZERO_STRUCT(wb_response);
1165 * This is tricky here. If we set krb5_auth in pam_winbind.conf
1166 * creds for users in trusted domain will be stored the winbindd
1167 * child of the trusted domain. If we ask the primary domain for
1168 * ntlm_ccache_auth, it will fail. So, we have to ask the trusted
1169 * domain's child for ccache_ntlm_auth. that is to say, we have to
1170 * set WBFLAG_PAM_CONTACT_TRUSTDOM in request.flags.
1172 ctrl = get_pam_winbind_config();
1174 if (ctrl & WINBIND_KRB5_AUTH) {
1175 wb_request.flags |= WBFLAG_PAM_CONTACT_TRUSTDOM;
1178 fstr_sprintf(wb_request.data.ccache_ntlm_auth.user,
1179 "%s%c%s", opt_domain, winbind_separator(), opt_username);
1180 wb_request.data.ccache_ntlm_auth.uid = geteuid();
1181 wb_request.data.ccache_ntlm_auth.initial_blob_len = initial_msg.length;
1182 wb_request.data.ccache_ntlm_auth.challenge_blob_len = challenge_msg.length;
1183 wb_request.extra_len = initial_msg.length + challenge_msg.length;
1185 if (wb_request.extra_len > 0) {
1186 wb_request.extra_data.data = SMB_MALLOC_ARRAY(char, wb_request.extra_len);
1187 if (wb_request.extra_data.data == NULL) {
1188 return NT_STATUS_NO_MEMORY;
1191 memcpy(wb_request.extra_data.data, initial_msg.data, initial_msg.length);
1192 memcpy(wb_request.extra_data.data + initial_msg.length,
1193 challenge_msg.data, challenge_msg.length);
1196 result = winbindd_request_response(NULL, WINBINDD_CCACHE_NTLMAUTH, &wb_request, &wb_response);
1197 SAFE_FREE(wb_request.extra_data.data);
1199 if (result != NSS_STATUS_SUCCESS) {
1200 winbindd_free_response(&wb_response);
1201 return NT_STATUS_UNSUCCESSFUL;
1205 *reply = data_blob(wb_response.extra_data.data,
1206 wb_response.data.ccache_ntlm_auth.auth_blob_len);
1207 if (wb_response.data.ccache_ntlm_auth.auth_blob_len > 0 &&
1208 reply->data == NULL) {
1209 winbindd_free_response(&wb_response);
1210 return NT_STATUS_NO_MEMORY;
1214 winbindd_free_response(&wb_response);
1215 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1218 static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode,
1219 struct loadparm_context *lp_ctx,
1220 struct ntlm_auth_state *state,
1221 char *buf, int length, void **private2)
1223 DATA_BLOB request, reply;
1226 if (!opt_username || !*opt_username) {
1227 x_fprintf(x_stderr, "username must be specified!\n\n");
1231 if (strlen(buf) < 2) {
1232 DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf));
1233 x_fprintf(x_stdout, "BH NTLMSSP query invalid\n");
1237 if (strlen(buf) > 3) {
1238 if(strncmp(buf, "SF ", 3) == 0) {
1239 DEBUG(10, ("Looking for flags to negotiate\n"));
1240 talloc_free(state->want_feature_list);
1241 state->want_feature_list = talloc_strdup(state->mem_ctx,
1243 x_fprintf(x_stdout, "OK\n");
1246 request = base64_decode_data_blob(buf + 3);
1248 request = data_blob_null;
1251 if (strncmp(buf, "PW ", 3) == 0) {
1252 /* We asked for a password and obviously got it :-) */
1254 opt_password = SMB_STRNDUP((const char *)request.data,
1257 if (opt_password == NULL) {
1258 DEBUG(1, ("Out of memory\n"));
1259 x_fprintf(x_stdout, "BH Out of memory\n");
1260 data_blob_free(&request);
1264 x_fprintf(x_stdout, "OK\n");
1265 data_blob_free(&request);
1269 if (!state->ntlmssp_state && use_cached_creds) {
1270 /* check whether cached credentials are usable. */
1271 DATA_BLOB empty_blob = data_blob_null;
1273 nt_status = do_ccache_ntlm_auth(empty_blob, empty_blob, NULL);
1274 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1275 /* failed to use cached creds */
1276 use_cached_creds = False;
1280 if (opt_password == NULL && !use_cached_creds) {
1281 /* Request a password from the calling process. After
1282 sending it, the calling process should retry asking for the
1285 DEBUG(10, ("Requesting password\n"));
1286 x_fprintf(x_stdout, "PW\n");
1290 if (strncmp(buf, "YR", 2) == 0) {
1291 TALLOC_FREE(state->ntlmssp_state);
1292 state->cli_state = CLIENT_INITIAL;
1293 } else if (strncmp(buf, "TT", 2) == 0) {
1294 /* No special preprocessing required */
1295 } else if (strncmp(buf, "GF", 2) == 0) {
1296 DEBUG(10, ("Requested negotiated NTLMSSP flags\n"));
1298 if(state->cli_state == CLIENT_FINISHED) {
1299 x_fprintf(x_stdout, "GF 0x%08x\n", state->neg_flags);
1302 x_fprintf(x_stdout, "BH\n");
1305 data_blob_free(&request);
1307 } else if (strncmp(buf, "GK", 2) == 0 ) {
1308 DEBUG(10, ("Requested session key\n"));
1310 if(state->cli_state == CLIENT_FINISHED) {
1311 char *key64 = base64_encode_data_blob(state->mem_ctx,
1312 state->session_key);
1313 x_fprintf(x_stdout, "GK %s\n", key64?key64:"<NULL>");
1317 x_fprintf(x_stdout, "BH\n");
1320 data_blob_free(&request);
1323 DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf));
1324 x_fprintf(x_stdout, "BH NTLMSSP query invalid\n");
1328 if (!state->ntlmssp_state) {
1329 nt_status = ntlm_auth_start_ntlmssp_client(
1330 &state->ntlmssp_state);
1331 if (!NT_STATUS_IS_OK(nt_status)) {
1332 x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
1335 ntlmssp_want_feature_list(state->ntlmssp_state,
1336 state->want_feature_list);
1337 state->initial_message = data_blob_null;
1340 DEBUG(10, ("got NTLMSSP packet:\n"));
1341 dump_data(10, request.data, request.length);
1343 if (use_cached_creds && !opt_password &&
1344 (state->cli_state == CLIENT_RESPONSE)) {
1345 nt_status = do_ccache_ntlm_auth(state->initial_message, request,
1348 nt_status = ntlmssp_update(state->ntlmssp_state, request,
1352 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1353 char *reply_base64 = base64_encode_data_blob(state->mem_ctx,
1355 if (state->cli_state == CLIENT_INITIAL) {
1356 x_fprintf(x_stdout, "YR %s\n", reply_base64);
1357 state->initial_message = reply;
1358 state->cli_state = CLIENT_RESPONSE;
1360 x_fprintf(x_stdout, "KK %s\n", reply_base64);
1361 data_blob_free(&reply);
1363 TALLOC_FREE(reply_base64);
1364 DEBUG(10, ("NTLMSSP challenge\n"));
1365 } else if (NT_STATUS_IS_OK(nt_status)) {
1366 char *reply_base64 = base64_encode_data_blob(talloc_tos(),
1368 x_fprintf(x_stdout, "AF %s\n", reply_base64);
1369 TALLOC_FREE(reply_base64);
1371 if(state->have_session_key)
1372 data_blob_free(&state->session_key);
1374 state->session_key = data_blob(
1375 state->ntlmssp_state->session_key.data,
1376 state->ntlmssp_state->session_key.length);
1377 state->neg_flags = state->ntlmssp_state->neg_flags;
1378 state->have_session_key = true;
1380 DEBUG(10, ("NTLMSSP OK!\n"));
1381 state->cli_state = CLIENT_FINISHED;
1382 TALLOC_FREE(state->ntlmssp_state);
1384 x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
1385 DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status)));
1386 state->cli_state = CLIENT_ERROR;
1387 TALLOC_FREE(state->ntlmssp_state);
1390 data_blob_free(&request);
1393 static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode,
1394 struct loadparm_context *lp_ctx,
1395 struct ntlm_auth_state *state,
1396 char *buf, int length, void **private2)
1401 pass=(char *)memchr(buf,' ',length);
1403 DEBUG(2, ("Password not found. Denying access\n"));
1404 x_fprintf(x_stdout, "ERR\n");
1410 if (state->helper_mode == SQUID_2_5_BASIC) {
1411 rfc1738_unescape(user);
1412 rfc1738_unescape(pass);
1415 if (check_plaintext_auth(user, pass, False)) {
1416 x_fprintf(x_stdout, "OK\n");
1418 x_fprintf(x_stdout, "ERR\n");
1422 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
1423 struct loadparm_context *lp_ctx,
1424 char *buf, int length, void **private1)
1427 DATA_BLOB out = data_blob(NULL, 0);
1428 char *out_base64 = NULL;
1429 const char *reply_arg = NULL;
1430 struct gensec_ntlm_state {
1431 struct gensec_security *gensec_state;
1432 const char *set_password;
1434 struct gensec_ntlm_state *state;
1438 const char *reply_code;
1439 struct cli_credentials *creds;
1441 static char *want_feature_list = NULL;
1442 static DATA_BLOB session_key;
1444 TALLOC_CTX *mem_ctx;
1447 state = (struct gensec_ntlm_state *)*private1;
1449 state = talloc_zero(NULL, struct gensec_ntlm_state);
1451 x_fprintf(x_stdout, "BH No Memory\n");
1456 state->set_password = opt_password;
1460 if (strlen(buf) < 2) {
1461 DEBUG(1, ("query [%s] invalid", buf));
1462 x_fprintf(x_stdout, "BH Query invalid\n");
1466 if (strlen(buf) > 3) {
1467 if(strncmp(buf, "SF ", 3) == 0) {
1468 DEBUG(10, ("Setting flags to negotiate\n"));
1469 talloc_free(want_feature_list);
1470 want_feature_list = talloc_strndup(state, buf+3, strlen(buf)-3);
1471 x_fprintf(x_stdout, "OK\n");
1474 in = base64_decode_data_blob(buf + 3);
1476 in = data_blob(NULL, 0);
1479 if (strncmp(buf, "YR", 2) == 0) {
1480 if (state->gensec_state) {
1481 talloc_free(state->gensec_state);
1482 state->gensec_state = NULL;
1484 } else if ( (strncmp(buf, "OK", 2) == 0)) {
1485 /* Just return BH, like ntlm_auth from Samba 3 does. */
1486 x_fprintf(x_stdout, "BH Command expected\n");
1487 data_blob_free(&in);
1489 } else if ( (strncmp(buf, "TT ", 3) != 0) &&
1490 (strncmp(buf, "KK ", 3) != 0) &&
1491 (strncmp(buf, "AF ", 3) != 0) &&
1492 (strncmp(buf, "NA ", 3) != 0) &&
1493 (strncmp(buf, "UG", 2) != 0) &&
1494 (strncmp(buf, "PW ", 3) != 0) &&
1495 (strncmp(buf, "GK", 2) != 0) &&
1496 (strncmp(buf, "GF", 2) != 0)) {
1497 DEBUG(1, ("SPNEGO request [%s] invalid prefix\n", buf));
1498 x_fprintf(x_stdout, "BH SPNEGO request invalid prefix\n");
1499 data_blob_free(&in);
1503 mem_ctx = talloc_named(NULL, 0, "manage_gensec_request internal mem_ctx");
1506 if (!(state->gensec_state)) {
1507 switch (stdio_helper_mode) {
1508 case GSS_SPNEGO_CLIENT:
1509 case NTLMSSP_CLIENT_1:
1510 /* setup the client side */
1512 nt_status = gensec_client_start(NULL, &state->gensec_state,
1513 lpcfg_gensec_settings(NULL, lp_ctx));
1514 if (!NT_STATUS_IS_OK(nt_status)) {
1515 x_fprintf(x_stdout, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status));
1516 talloc_free(mem_ctx);
1520 creds = cli_credentials_init(state->gensec_state);
1521 cli_credentials_set_conf(creds, lp_ctx);
1523 cli_credentials_set_username(creds, opt_username, CRED_SPECIFIED);
1526 cli_credentials_set_domain(creds, opt_domain, CRED_SPECIFIED);
1528 if (state->set_password) {
1529 cli_credentials_set_password(creds, state->set_password, CRED_SPECIFIED);
1531 cli_credentials_set_password_callback(creds, get_password);
1533 if (opt_workstation) {
1534 cli_credentials_set_workstation(creds, opt_workstation, CRED_SPECIFIED);
1537 gensec_set_credentials(state->gensec_state, creds);
1540 case GSS_SPNEGO_SERVER:
1541 case SQUID_2_5_NTLMSSP:
1543 nt_status = ntlm_auth_prepare_gensec_server(state, lp_ctx,
1544 &state->gensec_state);
1545 if (!NT_STATUS_IS_OK(nt_status)) {
1546 x_fprintf(x_stdout, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status));
1547 talloc_free(mem_ctx);
1553 talloc_free(mem_ctx);
1557 gensec_want_feature_list(state->gensec_state, want_feature_list);
1559 switch (stdio_helper_mode) {
1560 case GSS_SPNEGO_CLIENT:
1561 case GSS_SPNEGO_SERVER:
1562 nt_status = gensec_start_mech_by_oid(state->gensec_state, GENSEC_OID_SPNEGO);
1567 case NTLMSSP_CLIENT_1:
1572 case SQUID_2_5_NTLMSSP:
1573 nt_status = gensec_start_mech_by_oid(state->gensec_state, GENSEC_OID_NTLMSSP);
1576 talloc_free(mem_ctx);
1580 if (!NT_STATUS_IS_OK(nt_status)) {
1581 DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status)));
1582 x_fprintf(x_stdout, "BH GENSEC mech failed to start\n");
1583 talloc_free(mem_ctx);
1591 if (strncmp(buf, "PW ", 3) == 0) {
1592 state->set_password = talloc_strndup(state,
1593 (const char *)in.data,
1596 cli_credentials_set_password(gensec_get_credentials(state->gensec_state),
1597 state->set_password,
1599 x_fprintf(x_stdout, "OK\n");
1600 data_blob_free(&in);
1601 talloc_free(mem_ctx);
1605 if (strncmp(buf, "GK", 2) == 0) {
1607 DEBUG(10, ("Requested session key\n"));
1608 nt_status = gensec_session_key(state->gensec_state, mem_ctx, &session_key);
1609 if(!NT_STATUS_IS_OK(nt_status)) {
1610 DEBUG(1, ("gensec_session_key failed: %s\n", nt_errstr(nt_status)));
1611 x_fprintf(x_stdout, "BH No session key\n");
1612 talloc_free(mem_ctx);
1615 base64_key = base64_encode_data_blob(state, session_key);
1616 x_fprintf(x_stdout, "GK %s\n", base64_key);
1617 talloc_free(base64_key);
1619 talloc_free(mem_ctx);
1623 if (stdio_helper_mode == SQUID_2_5_NTLMSSP && strncmp(buf, "GF", 2) == 0) {
1626 neg_flags = gensec_ntlmssp_neg_flags(state->gensec_state);
1628 DEBUG(10, ("Requested negotiated feature flags\n"));
1629 x_fprintf(x_stdout, "GF 0x%08x\n", neg_flags);
1633 nt_status = gensec_update(state->gensec_state, mem_ctx, in, &out);
1635 /* don't leak 'bad password'/'no such user' info to the network client */
1636 nt_status = nt_status_squash(nt_status);
1639 out_base64 = base64_encode_data_blob(mem_ctx, out);
1644 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1646 if (first && state->gensec_state->gensec_role == GENSEC_CLIENT) {
1648 } else if (state->gensec_state->gensec_role == GENSEC_CLIENT) {
1650 } else if (state->gensec_state->gensec_role == GENSEC_SERVER) {
1657 } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) {
1658 reply_code = "BH NT_STATUS_ACCESS_DENIED";
1659 reply_arg = nt_errstr(nt_status);
1660 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
1661 } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_UNSUCCESSFUL)) {
1662 reply_code = "BH NT_STATUS_UNSUCCESSFUL";
1663 reply_arg = nt_errstr(nt_status);
1664 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
1665 } else if (!NT_STATUS_IS_OK(nt_status)) {
1667 reply_arg = nt_errstr(nt_status);
1668 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
1669 } else if /* OK */ (state->gensec_state->gensec_role == GENSEC_SERVER) {
1670 struct auth_session_info *session_info;
1672 nt_status = gensec_session_info(state->gensec_state, mem_ctx, &session_info);
1673 if (!NT_STATUS_IS_OK(nt_status)) {
1674 reply_code = "BH Failed to retrive session info";
1675 reply_arg = nt_errstr(nt_status);
1676 DEBUG(1, ("GENSEC failed to retrieve the session info: %s\n", nt_errstr(nt_status)));
1680 reply_arg = talloc_strdup(state->gensec_state, session_info->unix_info->unix_name);
1681 if (reply_arg == NULL) {
1682 reply_code = "BH out of memory";
1683 reply_arg = nt_errstr(NT_STATUS_NO_MEMORY);
1685 talloc_free(session_info);
1687 } else if (state->gensec_state->gensec_role == GENSEC_CLIENT) {
1689 reply_arg = out_base64;
1694 switch (stdio_helper_mode) {
1695 case GSS_SPNEGO_SERVER:
1696 x_fprintf(x_stdout, "%s %s %s\n", reply_code,
1697 out_base64 ? out_base64 : "*",
1698 reply_arg ? reply_arg : "*");
1702 x_fprintf(x_stdout, "%s %s\n", reply_code, out_base64);
1703 } else if (reply_arg) {
1704 x_fprintf(x_stdout, "%s %s\n", reply_code, reply_arg);
1706 x_fprintf(x_stdout, "%s\n", reply_code);
1710 talloc_free(mem_ctx);
1714 static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode,
1715 struct loadparm_context *lp_ctx,
1716 struct ntlm_auth_state *state,
1717 char *buf, int length, void **private2)
1719 manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
1723 static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode,
1724 struct loadparm_context *lp_ctx,
1725 struct ntlm_auth_state *state,
1726 char *buf, int length, void **private2)
1728 manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
1732 static struct ntlmssp_state *client_ntlmssp_state = NULL;
1734 static bool manage_client_ntlmssp_init(struct spnego_data spnego)
1737 DATA_BLOB null_blob = data_blob_null;
1738 DATA_BLOB to_server;
1739 char *to_server_base64;
1740 const char *my_mechs[] = {OID_NTLMSSP, NULL};
1741 TALLOC_CTX *ctx = talloc_tos();
1743 DEBUG(10, ("Got spnego negTokenInit with NTLMSSP\n"));
1745 if (client_ntlmssp_state != NULL) {
1746 DEBUG(1, ("Request for initial SPNEGO request where "
1747 "we already have a state\n"));
1751 if (!client_ntlmssp_state) {
1752 if (!NT_STATUS_IS_OK(status = ntlm_auth_start_ntlmssp_client(&client_ntlmssp_state))) {
1753 x_fprintf(x_stdout, "BH %s\n", nt_errstr(status));
1759 if (opt_password == NULL) {
1761 /* Request a password from the calling process. After
1762 sending it, the calling process should retry with
1763 the negTokenInit. */
1765 DEBUG(10, ("Requesting password\n"));
1766 x_fprintf(x_stdout, "PW\n");
1770 spnego.type = SPNEGO_NEG_TOKEN_INIT;
1771 spnego.negTokenInit.mechTypes = my_mechs;
1772 spnego.negTokenInit.reqFlags = data_blob_null;
1773 spnego.negTokenInit.reqFlagsPadding = 0;
1774 spnego.negTokenInit.mechListMIC = null_blob;
1776 status = ntlmssp_update(client_ntlmssp_state, null_blob,
1777 &spnego.negTokenInit.mechToken);
1779 if ( !(NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) ||
1780 NT_STATUS_IS_OK(status)) ) {
1781 DEBUG(1, ("Expected OK or MORE_PROCESSING_REQUIRED, got: %s\n",
1782 nt_errstr(status)));
1783 TALLOC_FREE(client_ntlmssp_state);
1787 spnego_write_data(ctx, &to_server, &spnego);
1788 data_blob_free(&spnego.negTokenInit.mechToken);
1790 to_server_base64 = base64_encode_data_blob(talloc_tos(), to_server);
1791 data_blob_free(&to_server);
1792 x_fprintf(x_stdout, "KK %s\n", to_server_base64);
1793 TALLOC_FREE(to_server_base64);
1797 static void manage_client_ntlmssp_targ(struct spnego_data spnego)
1800 DATA_BLOB null_blob = data_blob_null;
1802 DATA_BLOB to_server;
1803 char *to_server_base64;
1804 TALLOC_CTX *ctx = talloc_tos();
1806 DEBUG(10, ("Got spnego negTokenTarg with NTLMSSP\n"));
1808 if (client_ntlmssp_state == NULL) {
1809 DEBUG(1, ("Got NTLMSSP tArg without a client state\n"));
1810 x_fprintf(x_stdout, "BH Got NTLMSSP tArg without a client state\n");
1814 if (spnego.negTokenTarg.negResult == SPNEGO_REJECT) {
1815 x_fprintf(x_stdout, "NA\n");
1816 TALLOC_FREE(client_ntlmssp_state);
1820 if (spnego.negTokenTarg.negResult == SPNEGO_ACCEPT_COMPLETED) {
1821 x_fprintf(x_stdout, "AF\n");
1822 TALLOC_FREE(client_ntlmssp_state);
1826 status = ntlmssp_update(client_ntlmssp_state,
1827 spnego.negTokenTarg.responseToken,
1830 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) {
1831 DEBUG(1, ("Expected MORE_PROCESSING_REQUIRED or OK from "
1832 "ntlmssp_client_update, got: %s\n",
1833 nt_errstr(status)));
1834 x_fprintf(x_stdout, "BH Expected MORE_PROCESSING_REQUIRED from "
1835 "ntlmssp_client_update\n");
1836 data_blob_free(&request);
1837 TALLOC_FREE(client_ntlmssp_state);
1841 spnego.type = SPNEGO_NEG_TOKEN_TARG;
1842 spnego.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
1843 spnego.negTokenTarg.supportedMech = (const char *)OID_NTLMSSP;
1844 spnego.negTokenTarg.responseToken = request;
1845 spnego.negTokenTarg.mechListMIC = null_blob;
1847 spnego_write_data(ctx, &to_server, &spnego);
1848 data_blob_free(&request);
1850 to_server_base64 = base64_encode_data_blob(talloc_tos(), to_server);
1851 data_blob_free(&to_server);
1852 x_fprintf(x_stdout, "KK %s\n", to_server_base64);
1853 TALLOC_FREE(to_server_base64);
1859 static bool manage_client_krb5_init(struct spnego_data spnego)
1862 DATA_BLOB tkt, tkt_wrapped, to_server;
1863 DATA_BLOB session_key_krb5 = data_blob_null;
1864 struct spnego_data reply;
1868 const char *my_mechs[] = {OID_KERBEROS5_OLD, NULL};
1870 TALLOC_CTX *ctx = talloc_tos();
1872 principal = spnego.negTokenInit.targetPrincipal;
1874 /* We may not be allowed to use the server-supplied SPNEGO principal, or it may not have been supplied to us
1876 if (!lp_client_use_spnego_principal() || strequal(principal, ADS_IGNORE_PRINCIPAL)) {
1880 if (principal == NULL &&
1881 opt_target_service && opt_target_hostname && !is_ipaddress(opt_target_hostname)) {
1882 DEBUG(3,("manage_client_krb5_init: using target "
1883 "hostname not SPNEGO principal\n"));
1885 principal = kerberos_get_principal_from_service_hostname(talloc_tos(),
1887 opt_target_hostname,
1894 DEBUG(3,("manage_client_krb5_init: guessed "
1895 "server principal=%s\n",
1896 principal ? principal : "<null>"));
1899 if (principal == NULL) {
1900 DEBUG(3,("manage_client_krb5_init: could not guess server principal\n"));
1904 retval = cli_krb5_get_ticket(ctx, principal, 0,
1905 &tkt, &session_key_krb5,
1906 0, NULL, NULL, NULL);
1910 /* Let's try to first get the TGT, for that we need a
1913 if (opt_password == NULL) {
1914 DEBUG(10, ("Requesting password\n"));
1915 x_fprintf(x_stdout, "PW\n");
1919 user = talloc_asprintf(talloc_tos(), "%s@%s", opt_username, opt_domain);
1924 if ((retval = kerberos_kinit_password(user, opt_password, 0, NULL))) {
1925 DEBUG(10, ("Requesting TGT failed: %s\n", error_message(retval)));
1929 retval = cli_krb5_get_ticket(ctx, principal, 0,
1930 &tkt, &session_key_krb5,
1931 0, NULL, NULL, NULL);
1933 DEBUG(10, ("Kinit suceeded, but getting a ticket failed: %s\n", error_message(retval)));
1939 /* wrap that up in a nice GSS-API wrapping */
1940 tkt_wrapped = spnego_gen_krb5_wrap(ctx, tkt, TOK_ID_KRB_AP_REQ);
1942 data_blob_free(&session_key_krb5);
1946 reply.type = SPNEGO_NEG_TOKEN_INIT;
1947 reply.negTokenInit.mechTypes = my_mechs;
1948 reply.negTokenInit.reqFlags = data_blob_null;
1949 reply.negTokenInit.reqFlagsPadding = 0;
1950 reply.negTokenInit.mechToken = tkt_wrapped;
1951 reply.negTokenInit.mechListMIC = data_blob_null;
1953 len = spnego_write_data(ctx, &to_server, &reply);
1954 data_blob_free(&tkt);
1957 DEBUG(1, ("Could not write SPNEGO data blob\n"));
1961 reply_base64 = base64_encode_data_blob(talloc_tos(), to_server);
1962 x_fprintf(x_stdout, "KK %s *\n", reply_base64);
1964 TALLOC_FREE(reply_base64);
1965 data_blob_free(&to_server);
1966 DEBUG(10, ("sent GSS-SPNEGO KERBEROS5 negTokenInit\n"));
1970 static void manage_client_krb5_targ(struct spnego_data spnego)
1972 switch (spnego.negTokenTarg.negResult) {
1973 case SPNEGO_ACCEPT_INCOMPLETE:
1974 DEBUG(1, ("Got a Kerberos negTokenTarg with ACCEPT_INCOMPLETE\n"));
1975 x_fprintf(x_stdout, "BH Got a Kerberos negTokenTarg with "
1976 "ACCEPT_INCOMPLETE\n");
1978 case SPNEGO_ACCEPT_COMPLETED:
1979 DEBUG(10, ("Accept completed\n"));
1980 x_fprintf(x_stdout, "AF\n");
1983 DEBUG(10, ("Rejected\n"));
1984 x_fprintf(x_stdout, "NA\n");
1987 DEBUG(1, ("Got an invalid negTokenTarg\n"));
1988 x_fprintf(x_stdout, "AF\n");
1994 static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode,
1995 struct loadparm_context *lp_ctx,
1996 struct ntlm_auth_state *state,
1997 char *buf, int length, void **private2)
2000 struct spnego_data spnego;
2002 TALLOC_CTX *ctx = talloc_tos();
2004 if (!opt_username || !*opt_username) {
2005 x_fprintf(x_stderr, "username must be specified!\n\n");
2009 if (strlen(buf) <= 3) {
2010 DEBUG(1, ("SPNEGO query [%s] too short\n", buf));
2011 x_fprintf(x_stdout, "BH SPNEGO query too short\n");
2015 request = base64_decode_data_blob(buf+3);
2017 if (strncmp(buf, "PW ", 3) == 0) {
2019 /* We asked for a password and obviously got it :-) */
2021 opt_password = SMB_STRNDUP((const char *)request.data, request.length);
2023 if (opt_password == NULL) {
2024 DEBUG(1, ("Out of memory\n"));
2025 x_fprintf(x_stdout, "BH Out of memory\n");
2026 data_blob_free(&request);
2030 x_fprintf(x_stdout, "OK\n");
2031 data_blob_free(&request);
2035 if ( (strncmp(buf, "TT ", 3) != 0) &&
2036 (strncmp(buf, "AF ", 3) != 0) &&
2037 (strncmp(buf, "NA ", 3) != 0) ) {
2038 DEBUG(1, ("SPNEGO request [%s] invalid\n", buf));
2039 x_fprintf(x_stdout, "BH SPNEGO request invalid\n");
2040 data_blob_free(&request);
2044 /* So we got a server challenge to generate a SPNEGO
2045 client-to-server request... */
2047 len = spnego_read_data(ctx, request, &spnego);
2048 data_blob_free(&request);
2051 DEBUG(1, ("Could not read SPNEGO data for [%s]\n", buf));
2052 x_fprintf(x_stdout, "BH Could not read SPNEGO data\n");
2056 if (spnego.type == SPNEGO_NEG_TOKEN_INIT) {
2058 /* The server offers a list of mechanisms */
2060 const char *const *mechType = spnego.negTokenInit.mechTypes;
2062 while (*mechType != NULL) {
2065 if ( (strcmp(*mechType, OID_KERBEROS5_OLD) == 0) ||
2066 (strcmp(*mechType, OID_KERBEROS5) == 0) ) {
2067 if (manage_client_krb5_init(spnego))
2072 if (strcmp(*mechType, OID_NTLMSSP) == 0) {
2073 if (manage_client_ntlmssp_init(spnego))
2080 DEBUG(1, ("Server offered no compatible mechanism\n"));
2081 x_fprintf(x_stdout, "BH Server offered no compatible mechanism\n");
2085 if (spnego.type == SPNEGO_NEG_TOKEN_TARG) {
2087 if (spnego.negTokenTarg.supportedMech == NULL) {
2088 /* On accept/reject Windows does not send the
2089 mechanism anymore. Handle that here and
2090 shut down the mechanisms. */
2092 switch (spnego.negTokenTarg.negResult) {
2093 case SPNEGO_ACCEPT_COMPLETED:
2094 x_fprintf(x_stdout, "AF\n");
2097 x_fprintf(x_stdout, "NA\n");
2100 DEBUG(1, ("Got a negTokenTarg with no mech and an "
2101 "unknown negResult: %d\n",
2102 spnego.negTokenTarg.negResult));
2103 x_fprintf(x_stdout, "BH Got a negTokenTarg with"
2104 " no mech and an unknown "
2108 TALLOC_FREE(client_ntlmssp_state);
2112 if (strcmp(spnego.negTokenTarg.supportedMech,
2113 OID_NTLMSSP) == 0) {
2114 manage_client_ntlmssp_targ(spnego);
2119 if (strcmp(spnego.negTokenTarg.supportedMech,
2120 OID_KERBEROS5_OLD) == 0) {
2121 manage_client_krb5_targ(spnego);
2128 DEBUG(1, ("Got an SPNEGO token I could not handle [%s]!\n", buf));
2129 x_fprintf(x_stdout, "BH Got an SPNEGO token I could not handle\n");
2133 spnego_free_data(&spnego);
2137 static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode,
2138 struct loadparm_context *lp_ctx,
2139 struct ntlm_auth_state *state,
2140 char *buf, int length, void **private2)
2142 char *request, *parameter;
2143 static DATA_BLOB challenge;
2144 static DATA_BLOB lm_response;
2145 static DATA_BLOB nt_response;
2146 static char *full_username;
2147 static char *username;
2148 static char *domain;
2149 static char *plaintext_password;
2150 static bool ntlm_server_1_user_session_key;
2151 static bool ntlm_server_1_lm_session_key;
2153 if (strequal(buf, ".")) {
2154 if (!full_username && !username) {
2155 x_fprintf(x_stdout, "Error: No username supplied!\n");
2156 } else if (plaintext_password) {
2157 /* handle this request as plaintext */
2158 if (!full_username) {
2159 if (asprintf(&full_username, "%s%c%s", domain, winbind_separator(), username) == -1) {
2160 x_fprintf(x_stdout, "Error: Out of memory in asprintf!\n.\n");
2164 if (check_plaintext_auth(full_username, plaintext_password, False)) {
2165 x_fprintf(x_stdout, "Authenticated: Yes\n");
2167 x_fprintf(x_stdout, "Authenticated: No\n");
2169 } else if (!lm_response.data && !nt_response.data) {
2170 x_fprintf(x_stdout, "Error: No password supplied!\n");
2171 } else if (!challenge.data) {
2172 x_fprintf(x_stdout, "Error: No lanman-challenge supplied!\n");
2174 char *error_string = NULL;
2176 uchar user_session_key[16];
2179 if (full_username && !username) {
2181 fstring fstr_domain;
2183 if (!parse_ntlm_auth_domain_user(full_username, fstr_user, fstr_domain)) {
2184 /* username might be 'tainted', don't print into our new-line deleimianted stream */
2185 x_fprintf(x_stdout, "Error: Could not parse into domain and username\n");
2187 SAFE_FREE(username);
2189 username = smb_xstrdup(fstr_user);
2190 domain = smb_xstrdup(fstr_domain);
2194 DATA_BLOB nt_session_key, lm_session_key;
2195 struct samr_Password lm_pw, nt_pw;
2196 TALLOC_CTX *mem_ctx = talloc_new(NULL);
2197 ZERO_STRUCT(user_session_key);
2198 ZERO_STRUCT(lm_key);
2200 nt_lm_owf_gen (opt_password, nt_pw.hash, lm_pw.hash);
2201 nt_status = ntlm_password_check(mem_ctx,
2212 error_string = smb_xstrdup(get_friendly_nt_error_msg(nt_status));
2213 if (ntlm_server_1_user_session_key) {
2214 if (nt_session_key.length == sizeof(user_session_key)) {
2215 memcpy(user_session_key,
2216 nt_session_key.data,
2217 sizeof(user_session_key));
2220 if (ntlm_server_1_lm_session_key) {
2221 if (lm_session_key.length == sizeof(lm_key)) {
2223 lm_session_key.data,
2227 TALLOC_FREE(mem_ctx);
2231 domain = smb_xstrdup(get_winbind_domain());
2234 if (ntlm_server_1_lm_session_key)
2235 flags |= WBFLAG_PAM_LMKEY;
2237 if (ntlm_server_1_user_session_key)
2238 flags |= WBFLAG_PAM_USER_SESSION_KEY;
2240 nt_status = contact_winbind_auth_crap(username,
2253 if (!NT_STATUS_IS_OK(nt_status)) {
2254 x_fprintf(x_stdout, "Authenticated: No\n");
2255 x_fprintf(x_stdout, "Authentication-Error: %s\n.\n", error_string);
2257 static char zeros[16];
2259 char *hex_user_session_key;
2261 x_fprintf(x_stdout, "Authenticated: Yes\n");
2263 if (ntlm_server_1_lm_session_key
2264 && (memcmp(zeros, lm_key,
2265 sizeof(lm_key)) != 0)) {
2266 hex_lm_key = hex_encode_talloc(NULL,
2267 (const unsigned char *)lm_key,
2269 x_fprintf(x_stdout, "LANMAN-Session-Key: %s\n", hex_lm_key);
2270 TALLOC_FREE(hex_lm_key);
2273 if (ntlm_server_1_user_session_key
2274 && (memcmp(zeros, user_session_key,
2275 sizeof(user_session_key)) != 0)) {
2276 hex_user_session_key = hex_encode_talloc(NULL,
2277 (const unsigned char *)user_session_key,
2278 sizeof(user_session_key));
2279 x_fprintf(x_stdout, "User-Session-Key: %s\n", hex_user_session_key);
2280 TALLOC_FREE(hex_user_session_key);
2283 SAFE_FREE(error_string);
2285 /* clear out the state */
2286 challenge = data_blob_null;
2287 nt_response = data_blob_null;
2288 lm_response = data_blob_null;
2289 SAFE_FREE(full_username);
2290 SAFE_FREE(username);
2292 SAFE_FREE(plaintext_password);
2293 ntlm_server_1_user_session_key = False;
2294 ntlm_server_1_lm_session_key = False;
2295 x_fprintf(x_stdout, ".\n");
2302 /* Indicates a base64 encoded structure */
2303 parameter = strstr_m(request, ":: ");
2305 parameter = strstr_m(request, ": ");
2308 DEBUG(0, ("Parameter not found!\n"));
2309 x_fprintf(x_stdout, "Error: Parameter not found!\n.\n");
2326 base64_decode_inplace(parameter);
2329 if (strequal(request, "LANMAN-Challenge")) {
2330 challenge = strhex_to_data_blob(NULL, parameter);
2331 if (challenge.length != 8) {
2332 x_fprintf(x_stdout, "Error: hex decode of %s failed! (got %d bytes, expected 8)\n.\n",
2334 (int)challenge.length);
2335 challenge = data_blob_null;
2337 } else if (strequal(request, "NT-Response")) {
2338 nt_response = strhex_to_data_blob(NULL, parameter);
2339 if (nt_response.length < 24) {
2340 x_fprintf(x_stdout, "Error: hex decode of %s failed! (only got %d bytes, needed at least 24)\n.\n",
2342 (int)nt_response.length);
2343 nt_response = data_blob_null;
2345 } else if (strequal(request, "LANMAN-Response")) {
2346 lm_response = strhex_to_data_blob(NULL, parameter);
2347 if (lm_response.length != 24) {
2348 x_fprintf(x_stdout, "Error: hex decode of %s failed! (got %d bytes, expected 24)\n.\n",
2350 (int)lm_response.length);
2351 lm_response = data_blob_null;
2353 } else if (strequal(request, "Password")) {
2354 plaintext_password = smb_xstrdup(parameter);
2355 } else if (strequal(request, "NT-Domain")) {
2356 domain = smb_xstrdup(parameter);
2357 } else if (strequal(request, "Username")) {
2358 username = smb_xstrdup(parameter);
2359 } else if (strequal(request, "Full-Username")) {
2360 full_username = smb_xstrdup(parameter);
2361 } else if (strequal(request, "Request-User-Session-Key")) {
2362 ntlm_server_1_user_session_key = strequal(parameter, "Yes");
2363 } else if (strequal(request, "Request-LanMan-Session-Key")) {
2364 ntlm_server_1_lm_session_key = strequal(parameter, "Yes");
2366 x_fprintf(x_stdout, "Error: Unknown request %s\n.\n", request);
2370 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode,
2371 struct loadparm_context *lp_ctx,
2372 struct ntlm_auth_state *state,
2373 char *buf, int length, void **private2)
2375 char *request, *parameter;
2376 static DATA_BLOB new_nt_pswd;
2377 static DATA_BLOB old_nt_hash_enc;
2378 static DATA_BLOB new_lm_pswd;
2379 static DATA_BLOB old_lm_hash_enc;
2380 static char *full_username = NULL;
2381 static char *username = NULL;
2382 static char *domain = NULL;
2383 static char *newpswd = NULL;
2384 static char *oldpswd = NULL;
2386 if (strequal(buf, ".")) {
2387 if(newpswd && oldpswd) {
2388 uchar old_nt_hash[16];
2389 uchar old_lm_hash[16];
2390 uchar new_nt_hash[16];
2391 uchar new_lm_hash[16];
2393 new_nt_pswd = data_blob(NULL, 516);
2394 old_nt_hash_enc = data_blob(NULL, 16);
2396 /* Calculate the MD4 hash (NT compatible) of the
2398 E_md4hash(oldpswd, old_nt_hash);
2399 E_md4hash(newpswd, new_nt_hash);
2401 /* E_deshash returns false for 'long'
2402 passwords (> 14 DOS chars).
2404 Therefore, don't send a buffer
2405 encrypted with the truncated hash
2406 (it could allow an even easier
2407 attack on the password)
2409 Likewise, obey the admin's restriction
2412 if (lp_client_lanman_auth() &&
2413 E_deshash(newpswd, new_lm_hash) &&
2414 E_deshash(oldpswd, old_lm_hash)) {
2415 new_lm_pswd = data_blob(NULL, 516);
2416 old_lm_hash_enc = data_blob(NULL, 16);
2417 encode_pw_buffer(new_lm_pswd.data, newpswd,
2420 arcfour_crypt(new_lm_pswd.data, old_nt_hash, 516);
2421 E_old_pw_hash(new_nt_hash, old_lm_hash,
2422 old_lm_hash_enc.data);
2424 new_lm_pswd.data = NULL;
2425 new_lm_pswd.length = 0;
2426 old_lm_hash_enc.data = NULL;
2427 old_lm_hash_enc.length = 0;
2430 encode_pw_buffer(new_nt_pswd.data, newpswd,
2433 arcfour_crypt(new_nt_pswd.data, old_nt_hash, 516);
2434 E_old_pw_hash(new_nt_hash, old_nt_hash,
2435 old_nt_hash_enc.data);
2438 if (!full_username && !username) {
2439 x_fprintf(x_stdout, "Error: No username supplied!\n");
2440 } else if ((!new_nt_pswd.data || !old_nt_hash_enc.data) &&
2441 (!new_lm_pswd.data || old_lm_hash_enc.data) ) {
2442 x_fprintf(x_stdout, "Error: No NT or LM password "
2443 "blobs supplied!\n");
2445 char *error_string = NULL;
2447 if (full_username && !username) {
2449 fstring fstr_domain;
2451 if (!parse_ntlm_auth_domain_user(full_username,
2454 /* username might be 'tainted', don't
2455 * print into our new-line
2456 * deleimianted stream */
2457 x_fprintf(x_stdout, "Error: Could not "
2458 "parse into domain and "
2460 SAFE_FREE(username);
2461 username = smb_xstrdup(full_username);
2463 SAFE_FREE(username);
2465 username = smb_xstrdup(fstr_user);
2466 domain = smb_xstrdup(fstr_domain);
2471 if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
2478 x_fprintf(x_stdout, "Password-Change: No\n");
2479 x_fprintf(x_stdout, "Password-Change-Error: "
2480 "%s\n.\n", error_string);
2482 x_fprintf(x_stdout, "Password-Change: Yes\n");
2485 SAFE_FREE(error_string);
2487 /* clear out the state */
2488 new_nt_pswd = data_blob_null;
2489 old_nt_hash_enc = data_blob_null;
2490 new_lm_pswd = data_blob_null;
2491 old_nt_hash_enc = data_blob_null;
2492 SAFE_FREE(full_username);
2493 SAFE_FREE(username);
2497 x_fprintf(x_stdout, ".\n");
2504 /* Indicates a base64 encoded structure */
2505 parameter = strstr_m(request, ":: ");
2507 parameter = strstr_m(request, ": ");
2510 DEBUG(0, ("Parameter not found!\n"));
2511 x_fprintf(x_stdout, "Error: Parameter not found!\n.\n");
2527 base64_decode_inplace(parameter);
2530 if (strequal(request, "new-nt-password-blob")) {
2531 new_nt_pswd = strhex_to_data_blob(NULL, parameter);
2532 if (new_nt_pswd.length != 516) {
2533 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2534 "(got %d bytes, expected 516)\n.\n",
2536 (int)new_nt_pswd.length);
2537 new_nt_pswd = data_blob_null;
2539 } else if (strequal(request, "old-nt-hash-blob")) {
2540 old_nt_hash_enc = strhex_to_data_blob(NULL, parameter);
2541 if (old_nt_hash_enc.length != 16) {
2542 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2543 "(got %d bytes, expected 16)\n.\n",
2545 (int)old_nt_hash_enc.length);
2546 old_nt_hash_enc = data_blob_null;
2548 } else if (strequal(request, "new-lm-password-blob")) {
2549 new_lm_pswd = strhex_to_data_blob(NULL, parameter);
2550 if (new_lm_pswd.length != 516) {
2551 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2552 "(got %d bytes, expected 516)\n.\n",
2554 (int)new_lm_pswd.length);
2555 new_lm_pswd = data_blob_null;
2558 else if (strequal(request, "old-lm-hash-blob")) {
2559 old_lm_hash_enc = strhex_to_data_blob(NULL, parameter);
2560 if (old_lm_hash_enc.length != 16)
2562 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2563 "(got %d bytes, expected 16)\n.\n",
2565 (int)old_lm_hash_enc.length);
2566 old_lm_hash_enc = data_blob_null;
2568 } else if (strequal(request, "nt-domain")) {
2569 domain = smb_xstrdup(parameter);
2570 } else if(strequal(request, "username")) {
2571 username = smb_xstrdup(parameter);
2572 } else if(strequal(request, "full-username")) {
2573 username = smb_xstrdup(parameter);
2574 } else if(strequal(request, "new-password")) {
2575 newpswd = smb_xstrdup(parameter);
2576 } else if (strequal(request, "old-password")) {
2577 oldpswd = smb_xstrdup(parameter);
2579 x_fprintf(x_stdout, "Error: Unknown request %s\n.\n", request);
2583 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode,
2584 struct loadparm_context *lp_ctx,
2585 struct ntlm_auth_state *state,
2586 stdio_helper_function fn, void **private2)
2589 char tmp[INITIAL_BUFFER_SIZE+1];
2590 int length, buf_size = 0;
2593 buf = talloc_strdup(state->mem_ctx, "");
2595 DEBUG(0, ("Failed to allocate input buffer.\n"));
2596 x_fprintf(x_stderr, "ERR\n");
2602 /* this is not a typo - x_fgets doesn't work too well under
2604 if (fgets(tmp, sizeof(tmp)-1, stdin) == NULL) {
2605 if (ferror(stdin)) {
2606 DEBUG(1, ("fgets() failed! dying..... errno=%d "
2607 "(%s)\n", ferror(stdin),
2608 strerror(ferror(stdin))));
2615 buf = talloc_strdup_append_buffer(buf, tmp);
2616 buf_size += INITIAL_BUFFER_SIZE;
2618 if (buf_size > MAX_BUFFER_SIZE) {
2619 DEBUG(2, ("Oversized message\n"));
2620 x_fprintf(x_stderr, "ERR\n");
2625 c = strchr(buf, '\n');
2626 } while (c == NULL);
2631 DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf,length));
2633 if (buf[0] == '\0') {
2634 DEBUG(2, ("Invalid Request\n"));
2635 x_fprintf(x_stderr, "ERR\n");
2640 fn(stdio_helper_mode, lp_ctx, state, buf, length, private2);
2645 static void squid_stream(enum stdio_helper_mode stdio_mode,
2646 struct loadparm_context *lp_ctx,
2647 stdio_helper_function fn) {
2648 TALLOC_CTX *mem_ctx;
2649 struct ntlm_auth_state *state;
2651 /* initialize FDescs */
2652 x_setbuf(x_stdout, NULL);
2653 x_setbuf(x_stderr, NULL);
2655 mem_ctx = talloc_init("ntlm_auth");
2657 DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
2658 x_fprintf(x_stderr, "ERR\n");
2662 state = talloc_zero(mem_ctx, struct ntlm_auth_state);
2664 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
2665 x_fprintf(x_stderr, "ERR\n");
2669 state->mem_ctx = mem_ctx;
2670 state->helper_mode = stdio_mode;
2673 TALLOC_CTX *frame = talloc_stackframe();
2674 manage_squid_request(stdio_mode, lp_ctx, state, fn, NULL);
2680 /* Authenticate a user with a challenge/response */
2682 static bool check_auth_crap(void)
2687 char user_session_key[16];
2689 char *hex_user_session_key;
2691 static uint8_t zeros[16];
2693 x_setbuf(x_stdout, NULL);
2696 flags |= WBFLAG_PAM_LMKEY;
2698 if (request_user_session_key)
2699 flags |= WBFLAG_PAM_USER_SESSION_KEY;
2701 flags |= WBFLAG_PAM_NT_STATUS_SQUASH;
2703 nt_status = contact_winbind_auth_crap(opt_username, opt_domain,
2709 (unsigned char *)lm_key,
2710 (unsigned char *)user_session_key,
2711 &error_string, NULL);
2713 if (!NT_STATUS_IS_OK(nt_status)) {
2714 x_fprintf(x_stdout, "%s (0x%x)\n",
2716 NT_STATUS_V(nt_status));
2717 SAFE_FREE(error_string);
2722 && (memcmp(zeros, lm_key,
2723 sizeof(lm_key)) != 0)) {
2724 hex_lm_key = hex_encode_talloc(talloc_tos(), (const unsigned char *)lm_key,
2726 x_fprintf(x_stdout, "LM_KEY: %s\n", hex_lm_key);
2727 TALLOC_FREE(hex_lm_key);
2729 if (request_user_session_key
2730 && (memcmp(zeros, user_session_key,
2731 sizeof(user_session_key)) != 0)) {
2732 hex_user_session_key = hex_encode_talloc(talloc_tos(), (const unsigned char *)user_session_key,
2733 sizeof(user_session_key));
2734 x_fprintf(x_stdout, "NT_KEY: %s\n", hex_user_session_key);
2735 TALLOC_FREE(hex_user_session_key);
2744 OPT_USERNAME = 1000,
2753 OPT_USER_SESSION_KEY,
2755 OPT_REQUIRE_MEMBERSHIP,
2756 OPT_USE_CACHED_CREDS,
2757 OPT_PAM_WINBIND_CONF,
2759 OPT_TARGET_HOSTNAME,
2763 int main(int argc, const char **argv)
2765 TALLOC_CTX *frame = talloc_stackframe();
2767 static const char *helper_protocol;
2768 static int diagnostics;
2770 static const char *hex_challenge;
2771 static const char *hex_lm_response;
2772 static const char *hex_nt_response;
2773 struct loadparm_context *lp_ctx;
2776 /* NOTE: DO NOT change this interface without considering the implications!
2777 This is an external interface, which other programs will use to interact
2781 /* We do not use single-letter command abbreviations, because they harm future
2782 interface stability. */
2784 struct poptOption long_options[] = {
2786 { "helper-protocol", 0, POPT_ARG_STRING, &helper_protocol, OPT_DOMAIN, "operate as a stdio-based helper", "helper protocol to use"},
2787 { "username", 0, POPT_ARG_STRING, &opt_username, OPT_USERNAME, "username"},
2788 { "domain", 0, POPT_ARG_STRING, &opt_domain, OPT_DOMAIN, "domain name"},
2789 { "workstation", 0, POPT_ARG_STRING, &opt_workstation, OPT_WORKSTATION, "workstation"},
2790 { "challenge", 0, POPT_ARG_STRING, &hex_challenge, OPT_CHALLENGE, "challenge (HEX encoded)"},
2791 { "lm-response", 0, POPT_ARG_STRING, &hex_lm_response, OPT_LM, "LM Response to the challenge (HEX encoded)"},
2792 { "nt-response", 0, POPT_ARG_STRING, &hex_nt_response, OPT_NT, "NT or NTLMv2 Response to the challenge (HEX encoded)"},
2793 { "password", 0, POPT_ARG_STRING, &opt_password, OPT_PASSWORD, "User's plaintext password"},
2794 { "request-lm-key", 0, POPT_ARG_NONE, &request_lm_key, OPT_LM_KEY, "Retrieve LM session key"},
2795 { "request-nt-key", 0, POPT_ARG_NONE, &request_user_session_key, OPT_USER_SESSION_KEY, "Retrieve User (NT) session key"},
2796 { "use-cached-creds", 0, POPT_ARG_NONE, &use_cached_creds, OPT_USE_CACHED_CREDS, "Use cached credentials if no password is given"},
2797 { "offline-logon", 0, POPT_ARG_NONE, &offline_logon,
2799 "Use cached passwords when DC is offline"},
2800 { "diagnostics", 0, POPT_ARG_NONE, &diagnostics,
2802 "Perform diagnostics on the authentication chain"},
2803 { "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" },
2804 { "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" },
2805 { "target-service", 0, POPT_ARG_STRING, &opt_target_service, OPT_TARGET_SERVICE, "Target service (eg http)" },
2806 { "target-hostname", 0, POPT_ARG_STRING, &opt_target_hostname, OPT_TARGET_HOSTNAME, "Target hostname" },
2807 POPT_COMMON_CONFIGFILE
2813 /* Samba client initialisation */
2816 setup_logging("ntlm_auth", DEBUG_STDERR);
2820 pc = poptGetContext("ntlm_auth", argc, argv, long_options, 0);
2822 /* Parse command line options */
2825 poptPrintHelp(pc, stderr, 0);
2829 while((opt = poptGetNextOpt(pc)) != -1) {
2830 /* Get generic config options like --configfile */
2833 poptFreeContext(pc);
2835 if (!lp_load_global(get_dyn_CONFIGFILE())) {
2836 d_fprintf(stderr, "ntlm_auth: error opening config file %s. Error was %s\n",
2837 get_dyn_CONFIGFILE(), strerror(errno));
2841 pc = poptGetContext(NULL, argc, (const char **)argv, long_options,
2842 POPT_CONTEXT_KEEP_FIRST);
2844 while((opt = poptGetNextOpt(pc)) != -1) {
2847 opt_challenge = strhex_to_data_blob(NULL, hex_challenge);
2848 if (opt_challenge.length != 8) {
2849 x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n",
2851 (int)opt_challenge.length);
2856 opt_lm_response = strhex_to_data_blob(NULL, hex_lm_response);
2857 if (opt_lm_response.length != 24) {
2858 x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n",
2860 (int)opt_lm_response.length);
2866 opt_nt_response = strhex_to_data_blob(NULL, hex_nt_response);
2867 if (opt_nt_response.length < 24) {
2868 x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n",
2870 (int)opt_nt_response.length);
2875 case OPT_REQUIRE_MEMBERSHIP:
2876 if (strncasecmp_m("S-", require_membership_of, 2) == 0) {
2877 require_membership_of_sid = require_membership_of;
2884 char *domain = SMB_STRDUP(opt_username);
2885 char *p = strchr_m(domain, *lp_winbind_separator());
2889 if (opt_domain && !strequal(opt_domain, domain)) {
2890 x_fprintf(x_stderr, "Domain specified in username (%s) "
2891 "doesn't match specified domain (%s)!\n\n",
2892 domain, opt_domain);
2893 poptPrintHelp(pc, stderr, 0);
2896 opt_domain = domain;
2902 /* Note: if opt_domain is "" then send no domain */
2903 if (opt_domain == NULL) {
2904 opt_domain = get_winbind_domain();
2907 if (opt_workstation == NULL) {
2908 opt_workstation = "";
2911 lp_ctx = loadparm_init_s3(NULL, loadparm_s3_helpers());
2912 if (lp_ctx == NULL) {
2913 x_fprintf(x_stderr, "loadparm_init_s3() failed!\n");
2917 if (helper_protocol) {
2919 for (i=0; i<NUM_HELPER_MODES; i++) {
2920 if (strcmp(helper_protocol, stdio_helper_protocols[i].name) == 0) {
2921 squid_stream(stdio_helper_protocols[i].mode, lp_ctx, stdio_helper_protocols[i].fn);
2925 x_fprintf(x_stderr, "unknown helper protocol [%s]\n\nValid helper protools:\n\n", helper_protocol);
2927 for (i=0; i<NUM_HELPER_MODES; i++) {
2928 x_fprintf(x_stderr, "%s\n", stdio_helper_protocols[i].name);
2934 if (!opt_username || !*opt_username) {
2935 x_fprintf(x_stderr, "username must be specified!\n\n");
2936 poptPrintHelp(pc, stderr, 0);
2940 if (opt_challenge.length) {
2941 if (!check_auth_crap()) {
2947 if (!opt_password) {
2948 char pwd[256] = {0};
2951 rc = samba_getpass("Password: ", pwd, sizeof(pwd), false, false);
2953 opt_password = SMB_STRDUP(pwd);
2958 if (!diagnose_ntlm_auth()) {
2964 fstr_sprintf(user, "%s%c%s", opt_domain, winbind_separator(), opt_username);
2965 if (!check_plaintext_auth(user, opt_password, True)) {
2972 poptFreeContext(pc);