2 Unix SMB/CIFS implementation.
4 Winbind status program.
6 Copyright (C) Tim Potter 2000-2003
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003-2004
8 Copyright (C) Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it> 2000
9 Copyright (C) Robert O'Callahan 2006 (added cached credential code).
10 Copyright (C) Kai Blin <kai@samba.org> 2008
11 Copyright (C) Simo Sorce 2010
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 3 of the License, or
16 (at your option) any later version.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 #include "lib/param/param.h"
29 #include "popt_common.h"
30 #include "libcli/security/security.h"
31 #include "utils/ntlm_auth.h"
32 #include "../libcli/auth/libcli_auth.h"
33 #include "auth/ntlmssp/ntlmssp.h"
34 #include "auth/gensec/gensec.h"
35 #include "auth/gensec/gensec_internal.h"
36 #include "auth/credentials/credentials.h"
37 #include "librpc/crypto/gse.h"
39 #include "lib/util/tiniparser.h"
40 #include "../lib/crypto/arcfour.h"
41 #include "nsswitch/winbind_client.h"
42 #include "librpc/gen_ndr/krb5pac.h"
43 #include "../lib/util/asn1.h"
44 #include "auth/common_auth.h"
45 #include "source3/include/auth.h"
46 #include "source3/auth/proto.h"
47 #include "nsswitch/libwbclient/wbclient.h"
48 #include "lib/param/loadparm.h"
49 #include "lib/util/base64.h"
52 #include "auth/kerberos/pac_utils.h"
55 #ifndef PAM_WINBIND_CONFIG_FILE
56 #define PAM_WINBIND_CONFIG_FILE "/etc/security/pam_winbind.conf"
59 #define WINBIND_KRB5_AUTH 0x00000080
62 #define DBGC_CLASS DBGC_WINBIND
64 #define INITIAL_BUFFER_SIZE 300
65 #define MAX_BUFFER_SIZE 630000
67 enum stdio_helper_mode {
75 NTLM_CHANGE_PASSWORD_1,
79 enum ntlm_auth_cli_state {
86 struct ntlm_auth_state {
88 enum stdio_helper_mode helper_mode;
89 enum ntlm_auth_cli_state cli_state;
90 struct ntlmssp_state *ntlmssp_state;
92 char *want_feature_list;
93 bool have_session_key;
94 DATA_BLOB session_key;
95 DATA_BLOB initial_message;
96 void *gensec_private_1;
98 typedef void (*stdio_helper_function)(enum stdio_helper_mode stdio_helper_mode,
99 struct loadparm_context *lp_ctx,
100 struct ntlm_auth_state *state, char *buf,
101 int length, void **private2);
103 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
104 struct loadparm_context *lp_ctx,
105 char *buf, int length, void **private1);
107 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode,
108 struct loadparm_context *lp_ctx,
109 struct ntlm_auth_state *state,
110 stdio_helper_function fn, void **private2);
112 static void manage_squid_basic_request (enum stdio_helper_mode stdio_helper_mode,
113 struct loadparm_context *lp_ctx,
114 struct ntlm_auth_state *state,
115 char *buf, int length, void **private2);
117 static void manage_squid_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode,
118 struct loadparm_context *lp_ctx,
119 struct ntlm_auth_state *state,
120 char *buf, int length, void **private2);
122 static void manage_client_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode,
123 struct loadparm_context *lp_ctx,
124 struct ntlm_auth_state *state,
125 char *buf, int length, void **private2);
127 static void manage_gss_spnego_request (enum stdio_helper_mode stdio_helper_mode,
128 struct loadparm_context *lp_ctx,
129 struct ntlm_auth_state *state,
130 char *buf, int length, void **private2);
132 static void manage_gss_spnego_client_request (enum stdio_helper_mode stdio_helper_mode,
133 struct loadparm_context *lp_ctx,
134 struct ntlm_auth_state *state,
135 char *buf, int length, void **private2);
137 static void manage_ntlm_server_1_request (enum stdio_helper_mode stdio_helper_mode,
138 struct loadparm_context *lp_ctx,
139 struct ntlm_auth_state *state,
140 char *buf, int length, void **private2);
142 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode,
143 struct loadparm_context *lp_ctx,
144 struct ntlm_auth_state *state,
145 char *buf, int length, void **private2);
147 static const struct {
148 enum stdio_helper_mode mode;
150 stdio_helper_function fn;
151 } stdio_helper_protocols[] = {
152 { SQUID_2_4_BASIC, "squid-2.4-basic", manage_squid_basic_request},
153 { SQUID_2_5_BASIC, "squid-2.5-basic", manage_squid_basic_request},
154 { SQUID_2_5_NTLMSSP, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request},
155 { NTLMSSP_CLIENT_1, "ntlmssp-client-1", manage_client_ntlmssp_request},
156 { GSS_SPNEGO_SERVER, "gss-spnego", manage_gss_spnego_request},
157 { GSS_SPNEGO_CLIENT, "gss-spnego-client", manage_gss_spnego_client_request},
158 { NTLM_SERVER_1, "ntlm-server-1", manage_ntlm_server_1_request},
159 { NTLM_CHANGE_PASSWORD_1, "ntlm-change-password-1", manage_ntlm_change_password_1_request},
160 { NUM_HELPER_MODES, NULL, NULL}
163 const char *opt_username;
164 const char *opt_domain;
165 const char *opt_workstation;
166 const char *opt_password;
167 static DATA_BLOB opt_challenge;
168 static DATA_BLOB opt_lm_response;
169 static DATA_BLOB opt_nt_response;
170 static int request_lm_key;
171 static int request_user_session_key;
172 static int use_cached_creds;
173 static int offline_logon;
174 static int opt_allow_mschapv2;
176 static const char *require_membership_of;
177 static const char *require_membership_of_sid;
178 static const char *opt_pam_winbind_conf;
180 const char *opt_target_service;
181 const char *opt_target_hostname;
184 /* This is a bit hairy, but the basic idea is to do a password callback
185 to the calling application. The callback comes from within gensec */
187 static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mode,
188 struct loadparm_context *lp_ctx,
189 struct ntlm_auth_state *state, char *buf, int length,
193 if (strlen(buf) < 2) {
194 DEBUG(1, ("query [%s] invalid", buf));
195 printf("BH Query invalid\n");
199 if (strlen(buf) > 3) {
200 in = base64_decode_data_blob(buf + 3);
202 in = data_blob(NULL, 0);
205 if (strncmp(buf, "PW ", 3) == 0) {
207 *password = talloc_strndup(NULL,
208 (const char *)in.data, in.length);
210 if (*password == NULL) {
211 DEBUG(1, ("Out of memory\n"));
212 printf("BH Out of memory\n");
221 DEBUG(1, ("Asked for (and expected) a password\n"));
222 printf("BH Expected a password\n");
227 * Callback for password credentials. This is not async, and when
228 * GENSEC and the credentials code is made async, it will look rather
232 static const char *get_password(struct cli_credentials *credentials)
234 TALLOC_CTX *frame = talloc_stackframe();
235 char *password = NULL;
236 struct ntlm_auth_state *state;
238 state = talloc_zero(frame, struct ntlm_auth_state);
240 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
241 fprintf(stderr, "ERR\n");
245 state->mem_ctx = state;
247 /* Ask for a password */
250 manage_squid_request(NUM_HELPER_MODES /* bogus */, NULL, state, manage_gensec_get_pw_request, (void **)&password);
251 talloc_steal(credentials, password);
257 * A limited set of features are defined with text strings as needed
261 static void gensec_want_feature_list(struct gensec_security *state, char* feature_list)
263 if (in_list("NTLMSSP_FEATURE_SESSION_KEY", feature_list, true)) {
264 DEBUG(10, ("want GENSEC_FEATURE_SESSION_KEY\n"));
265 gensec_want_feature(state, GENSEC_FEATURE_SESSION_KEY);
267 if (in_list("NTLMSSP_FEATURE_SIGN", feature_list, true)) {
268 DEBUG(10, ("want GENSEC_FEATURE_SIGN\n"));
269 gensec_want_feature(state, GENSEC_FEATURE_SIGN);
271 if (in_list("NTLMSSP_FEATURE_SEAL", feature_list, true)) {
272 DEBUG(10, ("want GENSEC_FEATURE_SEAL\n"));
273 gensec_want_feature(state, GENSEC_FEATURE_SEAL);
275 if (in_list("NTLMSSP_FEATURE_CCACHE", feature_list, true)) {
276 DEBUG(10, ("want GENSEC_FEATURE_NTLM_CCACHE\n"));
277 gensec_want_feature(state, GENSEC_FEATURE_NTLM_CCACHE);
281 static char winbind_separator(void)
283 struct wbcInterfaceDetails *details;
291 ret = wbcInterfaceDetails(&details);
292 if (!WBC_ERROR_IS_OK(ret)) {
293 d_fprintf(stderr, "could not obtain winbind separator!\n");
294 return *lp_winbind_separator();
297 sep = details->winbind_separator;
299 wbcFreeMemory(details);
304 d_fprintf(stderr, "winbind separator was NULL!\n");
305 return *lp_winbind_separator();
311 const char *get_winbind_domain(void)
313 struct wbcInterfaceDetails *details;
316 static fstring winbind_domain;
317 if (*winbind_domain) {
318 return winbind_domain;
321 /* Send off request */
323 ret = wbcInterfaceDetails(&details);
324 if (!WBC_ERROR_IS_OK(ret)) {
325 DEBUG(1, ("could not obtain winbind domain name!\n"));
326 return lp_workgroup();
329 fstrcpy(winbind_domain, details->netbios_domain);
331 wbcFreeMemory(details);
333 return winbind_domain;
337 const char *get_winbind_netbios_name(void)
339 struct winbindd_response response;
341 static fstring winbind_netbios_name;
343 if (*winbind_netbios_name) {
344 return winbind_netbios_name;
347 ZERO_STRUCT(response);
349 /* Send off request */
351 if (winbindd_request_response(NULL, WINBINDD_NETBIOS_NAME, NULL, &response) !=
352 NSS_STATUS_SUCCESS) {
353 DEBUG(1, ("could not obtain winbind netbios name!\n"));
354 return lp_netbios_name();
357 fstrcpy(winbind_netbios_name, response.data.netbios_name);
359 return winbind_netbios_name;
363 DATA_BLOB get_challenge(void)
365 static DATA_BLOB chal;
366 if (opt_challenge.length)
367 return opt_challenge;
369 chal = data_blob(NULL, 8);
371 generate_random_buffer(chal.data, chal.length);
375 /* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
376 form DOMAIN/user into a domain and a user */
378 static bool parse_ntlm_auth_domain_user(const char *domuser, fstring domain,
382 char *p = strchr(domuser,winbind_separator());
389 fstrcpy(domain, domuser);
390 domain[PTR_DIFF(p, domuser)] = 0;
391 return strupper_m(domain);
394 static bool get_require_membership_sid(void) {
395 fstring domain, name, sidbuf;
396 struct wbcDomainSid sid;
397 enum wbcSidType type;
400 if (!require_membership_of) {
404 if (require_membership_of_sid) {
408 /* Otherwise, ask winbindd for the name->sid request */
410 if (!parse_ntlm_auth_domain_user(require_membership_of,
412 DEBUG(0, ("Could not parse %s into separate domain/name parts!\n",
413 require_membership_of));
417 ret = wbcLookupName(domain, name, &sid, &type);
418 if (!WBC_ERROR_IS_OK(ret)) {
419 DEBUG(0, ("Winbindd lookupname failed to resolve %s into a SID!\n",
420 require_membership_of));
424 wbcSidToStringBuf(&sid, sidbuf, sizeof(sidbuf));
426 require_membership_of_sid = SMB_STRDUP(sidbuf);
428 if (require_membership_of_sid)
435 * Get some configuration from pam_winbind.conf to see if we
436 * need to contact trusted domain
439 int get_pam_winbind_config()
442 struct tiniparser_dictionary *d = NULL;
444 if (!opt_pam_winbind_conf || !*opt_pam_winbind_conf) {
445 opt_pam_winbind_conf = PAM_WINBIND_CONFIG_FILE;
448 d = tiniparser_load(opt_pam_winbind_conf);
454 if (tiniparser_getboolean(d, "global:krb5_auth", false)) {
455 ctrl |= WINBIND_KRB5_AUTH;
458 tiniparser_freedict(d);
463 /* Authenticate a user with a plaintext password */
465 static bool check_plaintext_auth(const char *user, const char *pass,
466 bool stdout_diagnostics)
468 struct winbindd_request request;
469 struct winbindd_response response;
472 if (!get_require_membership_sid()) {
476 /* Send off request */
478 ZERO_STRUCT(request);
479 ZERO_STRUCT(response);
481 fstrcpy(request.data.auth.user, user);
482 fstrcpy(request.data.auth.pass, pass);
483 if (require_membership_of_sid) {
484 strlcpy(request.data.auth.require_membership_of_sid,
485 require_membership_of_sid,
486 sizeof(request.data.auth.require_membership_of_sid));
490 request.flags |= WBFLAG_PAM_CACHED_LOGIN;
493 result = winbindd_request_response(NULL, WINBINDD_PAM_AUTH, &request, &response);
495 /* Display response */
497 if (stdout_diagnostics) {
498 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
499 d_fprintf(stderr, "Reading winbind reply failed! (0x01)\n");
502 d_printf("%s: %s (0x%x)\n",
503 response.data.auth.nt_status_string,
504 response.data.auth.error_string,
505 response.data.auth.nt_status);
507 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
508 DEBUG(1, ("Reading winbind reply failed! (0x01)\n"));
511 DEBUG(3, ("%s: %s (0x%x)\n",
512 response.data.auth.nt_status_string,
513 response.data.auth.error_string,
514 response.data.auth.nt_status));
517 return (result == NSS_STATUS_SUCCESS);
520 /* authenticate a user with an encrypted username/password */
522 NTSTATUS contact_winbind_auth_crap(const char *username,
524 const char *workstation,
525 const DATA_BLOB *challenge,
526 const DATA_BLOB *lm_response,
527 const DATA_BLOB *nt_response,
529 uint32_t extra_logon_parameters,
531 uint8_t user_session_key[16],
532 uint8_t *pauthoritative,
538 struct winbindd_request request;
539 struct winbindd_response response;
543 if (!get_require_membership_sid()) {
544 return NT_STATUS_INVALID_PARAMETER;
547 ZERO_STRUCT(request);
548 ZERO_STRUCT(response);
550 request.flags = flags;
552 request.data.auth_crap.logon_parameters = extra_logon_parameters
553 | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT | MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT;
555 if (opt_allow_mschapv2) {
556 request.data.auth_crap.logon_parameters |= MSV1_0_ALLOW_MSVCHAPV2;
559 if (require_membership_of_sid)
560 fstrcpy(request.data.auth_crap.require_membership_of_sid, require_membership_of_sid);
562 fstrcpy(request.data.auth_crap.user, username);
563 fstrcpy(request.data.auth_crap.domain, domain);
565 fstrcpy(request.data.auth_crap.workstation,
568 memcpy(request.data.auth_crap.chal, challenge->data, MIN(challenge->length, 8));
570 if (lm_response && lm_response->length) {
571 memcpy(request.data.auth_crap.lm_resp,
573 MIN(lm_response->length, sizeof(request.data.auth_crap.lm_resp)));
574 request.data.auth_crap.lm_resp_len = lm_response->length;
577 if (nt_response && nt_response->length) {
578 if (nt_response->length > sizeof(request.data.auth_crap.nt_resp)) {
579 request.flags = request.flags | WBFLAG_BIG_NTLMV2_BLOB;
580 request.extra_len = nt_response->length;
581 request.extra_data.data = SMB_MALLOC_ARRAY(char, request.extra_len);
582 if (request.extra_data.data == NULL) {
583 return NT_STATUS_NO_MEMORY;
585 memcpy(request.extra_data.data, nt_response->data,
586 nt_response->length);
589 memcpy(request.data.auth_crap.nt_resp,
590 nt_response->data, nt_response->length);
592 request.data.auth_crap.nt_resp_len = nt_response->length;
595 result = winbindd_request_response(NULL, WINBINDD_PAM_AUTH_CRAP, &request, &response);
596 SAFE_FREE(request.extra_data.data);
598 /* Display response */
600 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
601 nt_status = NT_STATUS_UNSUCCESSFUL;
603 *error_string = smb_xstrdup("Reading winbind reply failed!");
604 winbindd_free_response(&response);
608 nt_status = (NT_STATUS(response.data.auth.nt_status));
609 if (!NT_STATUS_IS_OK(nt_status)) {
611 *error_string = smb_xstrdup(response.data.auth.error_string);
612 *pauthoritative = response.data.auth.authoritative;
613 winbindd_free_response(&response);
617 if ((flags & WBFLAG_PAM_LMKEY) && lm_key) {
618 memcpy(lm_key, response.data.auth.first_8_lm_hash,
619 sizeof(response.data.auth.first_8_lm_hash));
621 if ((flags & WBFLAG_PAM_USER_SESSION_KEY) && user_session_key) {
622 memcpy(user_session_key, response.data.auth.user_session_key,
623 sizeof(response.data.auth.user_session_key));
626 if (flags & WBFLAG_PAM_UNIX_NAME) {
627 *unix_name = SMB_STRDUP(response.data.auth.unix_username);
629 winbindd_free_response(&response);
630 return NT_STATUS_NO_MEMORY;
634 winbindd_free_response(&response);
638 /* contact server to change user password using auth crap */
639 static NTSTATUS contact_winbind_change_pswd_auth_crap(const char *username,
641 const DATA_BLOB new_nt_pswd,
642 const DATA_BLOB old_nt_hash_enc,
643 const DATA_BLOB new_lm_pswd,
644 const DATA_BLOB old_lm_hash_enc,
649 struct winbindd_request request;
650 struct winbindd_response response;
652 if (!get_require_membership_sid())
655 *error_string = smb_xstrdup("Can't get membership sid.");
656 return NT_STATUS_INVALID_PARAMETER;
659 ZERO_STRUCT(request);
660 ZERO_STRUCT(response);
663 fstrcpy(request.data.chng_pswd_auth_crap.user, username);
665 fstrcpy(request.data.chng_pswd_auth_crap.domain,domain);
667 if(new_nt_pswd.length)
669 memcpy(request.data.chng_pswd_auth_crap.new_nt_pswd, new_nt_pswd.data, sizeof(request.data.chng_pswd_auth_crap.new_nt_pswd));
670 request.data.chng_pswd_auth_crap.new_nt_pswd_len = new_nt_pswd.length;
673 if(old_nt_hash_enc.length)
675 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));
676 request.data.chng_pswd_auth_crap.old_nt_hash_enc_len = old_nt_hash_enc.length;
679 if(new_lm_pswd.length)
681 memcpy(request.data.chng_pswd_auth_crap.new_lm_pswd, new_lm_pswd.data, sizeof(request.data.chng_pswd_auth_crap.new_lm_pswd));
682 request.data.chng_pswd_auth_crap.new_lm_pswd_len = new_lm_pswd.length;
685 if(old_lm_hash_enc.length)
687 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));
688 request.data.chng_pswd_auth_crap.old_lm_hash_enc_len = old_lm_hash_enc.length;
691 result = winbindd_request_response(NULL, WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP, &request, &response);
693 /* Display response */
695 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0))
697 nt_status = NT_STATUS_UNSUCCESSFUL;
699 *error_string = smb_xstrdup("Reading winbind reply failed!");
700 winbindd_free_response(&response);
704 nt_status = (NT_STATUS(response.data.auth.nt_status));
705 if (!NT_STATUS_IS_OK(nt_status))
708 *error_string = smb_xstrdup(response.data.auth.error_string);
709 winbindd_free_response(&response);
713 winbindd_free_response(&response);
718 static NTSTATUS ntlm_auth_generate_session_info(struct auth4_context *auth_context,
720 void *server_returned_info,
721 const char *original_user_name,
722 uint32_t session_info_flags,
723 struct auth_session_info **session_info_out)
725 const char *unix_username = (const char *)server_returned_info;
727 struct dom_sid *sids = NULL;
728 struct auth_session_info *session_info = NULL;
730 session_info = talloc_zero(mem_ctx, struct auth_session_info);
731 if (session_info == NULL) {
732 return NT_STATUS_NO_MEMORY;
735 session_info->unix_info = talloc_zero(session_info, struct auth_user_info_unix);
736 if (session_info->unix_info == NULL) {
737 TALLOC_FREE(session_info);
738 return NT_STATUS_NO_MEMORY;
740 session_info->unix_info->unix_name = talloc_strdup(session_info->unix_info,
742 if (session_info->unix_info->unix_name == NULL) {
743 TALLOC_FREE(session_info);
744 return NT_STATUS_NO_MEMORY;
747 session_info->security_token = talloc_zero(session_info, struct security_token);
748 if (session_info->security_token == NULL) {
749 TALLOC_FREE(session_info);
750 return NT_STATUS_NO_MEMORY;
753 sids = talloc_zero_array(session_info->security_token,
756 TALLOC_FREE(session_info);
757 return NT_STATUS_NO_MEMORY;
759 ok = dom_sid_parse(SID_WORLD, &sids[0]);
761 TALLOC_FREE(session_info);
762 return NT_STATUS_INTERNAL_ERROR;
764 ok = dom_sid_parse(SID_NT_NETWORK, &sids[1]);
766 TALLOC_FREE(session_info);
767 return NT_STATUS_INTERNAL_ERROR;
769 ok = dom_sid_parse(SID_NT_AUTHENTICATED_USERS, &sids[2]);
771 TALLOC_FREE(session_info);
772 return NT_STATUS_INTERNAL_ERROR;
775 session_info->security_token->num_sids = talloc_array_length(sids);
776 session_info->security_token->sids = sids;
778 *session_info_out = session_info;
783 static NTSTATUS ntlm_auth_generate_session_info_pac(struct auth4_context *auth_ctx,
785 struct smb_krb5_context *smb_krb5_context,
787 const char *princ_name,
788 const struct tsocket_address *remote_address,
789 uint32_t session_info_flags,
790 struct auth_session_info **session_info)
793 struct PAC_LOGON_INFO *logon_info = NULL;
801 tmp_ctx = talloc_new(mem_ctx);
803 return NT_STATUS_NO_MEMORY;
808 status = kerberos_pac_logon_info(tmp_ctx, *pac_blob, NULL, NULL,
809 NULL, NULL, 0, &logon_info);
811 status = NT_STATUS_ACCESS_DENIED;
813 if (!NT_STATUS_IS_OK(status)) {
818 DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name));
820 p = strchr_m(princ_name, '@');
822 DEBUG(3, ("[%s] Doesn't look like a valid principal\n",
824 return NT_STATUS_LOGON_FAILURE;
827 user = talloc_strndup(mem_ctx, princ_name, p - princ_name);
829 return NT_STATUS_NO_MEMORY;
832 realm = talloc_strdup(talloc_tos(), p + 1);
834 return NT_STATUS_NO_MEMORY;
837 if (!strequal(realm, lp_realm())) {
838 DEBUG(3, ("Ticket for foreign realm %s@%s\n", user, realm));
839 if (!lp_allow_trusted_domains()) {
840 return NT_STATUS_LOGON_FAILURE;
844 if (logon_info && logon_info->info3.base.logon_domain.string) {
845 domain = talloc_strdup(mem_ctx,
846 logon_info->info3.base.logon_domain.string);
848 return NT_STATUS_NO_MEMORY;
850 DEBUG(10, ("Domain is [%s] (using PAC)\n", domain));
853 /* If we have winbind running, we can (and must) shorten the
854 username by using the short netbios name. Otherwise we will
855 have inconsistent user names. With Kerberos, we get the
856 fully qualified realm, with ntlmssp we get the short
857 name. And even w2k3 does use ntlmssp if you for example
858 connect to an ip address. */
861 struct wbcDomainInfo *info = NULL;
863 DEBUG(10, ("Mapping [%s] to short name using winbindd\n",
866 wbc_status = wbcDomainInfo(realm, &info);
868 if (WBC_ERROR_IS_OK(wbc_status)) {
869 domain = talloc_strdup(mem_ctx,
873 DEBUG(3, ("Could not find short name: %s\n",
874 wbcErrorString(wbc_status)));
875 domain = talloc_strdup(mem_ctx, realm);
878 return NT_STATUS_NO_MEMORY;
880 DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain));
883 unixuser = talloc_asprintf(tmp_ctx, "%s%c%s", domain, winbind_separator(), user);
885 status = NT_STATUS_NO_MEMORY;
889 status = ntlm_auth_generate_session_info(auth_ctx, mem_ctx, unixuser, NULL, session_info_flags, session_info);
892 TALLOC_FREE(tmp_ctx);
899 * Return the challenge as determined by the authentication subsystem
900 * @return an 8 byte random challenge
903 static NTSTATUS ntlm_auth_get_challenge(struct auth4_context *auth_ctx,
906 if (auth_ctx->challenge.data.length == 8) {
907 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
908 auth_ctx->challenge.set_by));
909 memcpy(chal, auth_ctx->challenge.data.data, 8);
913 if (!auth_ctx->challenge.set_by) {
914 generate_random_buffer(chal, 8);
916 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
917 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
918 auth_ctx->challenge.set_by = "random";
921 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
922 auth_ctx->challenge.set_by));
928 * NTLM2 authentication modifies the effective challenge,
929 * @param challenge The new challenge value
931 static NTSTATUS ntlm_auth_set_challenge(struct auth4_context *auth_ctx, const uint8_t chal[8], const char *set_by)
933 auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
934 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
936 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
937 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
943 * Check the password on an NTLMSSP login.
945 * Return the session keys used on the connection.
948 static NTSTATUS winbind_pw_check(struct auth4_context *auth4_context,
950 const struct auth_usersupplied_info *user_info,
951 uint8_t *pauthoritative,
952 void **server_returned_info,
953 DATA_BLOB *session_key, DATA_BLOB *lm_session_key)
956 char *error_string = NULL;
958 uint8_t user_sess_key[16];
959 char *unix_name = NULL;
961 nt_status = contact_winbind_auth_crap(user_info->client.account_name, user_info->client.domain_name,
962 user_info->workstation_name,
963 &auth4_context->challenge.data,
964 &user_info->password.response.lanman,
965 &user_info->password.response.nt,
966 WBFLAG_PAM_LMKEY | WBFLAG_PAM_USER_SESSION_KEY | WBFLAG_PAM_UNIX_NAME,
968 lm_key, user_sess_key,
970 &error_string, &unix_name);
972 if (NT_STATUS_IS_OK(nt_status)) {
973 if (!all_zero(lm_key, 8)) {
974 *lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
975 memcpy(lm_session_key->data, lm_key, 8);
976 memset(lm_session_key->data+8, '\0', 8);
979 if (!all_zero(user_sess_key, 16)) {
980 *session_key = data_blob_talloc(mem_ctx, user_sess_key, 16);
982 *server_returned_info = talloc_strdup(mem_ctx,
985 DEBUG(NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED) ? 0 : 3,
986 ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
987 user_info->client.domain_name, user_info->client.account_name,
988 user_info->workstation_name,
989 error_string ? error_string : "unknown error (NULL)"));
992 SAFE_FREE(error_string);
993 SAFE_FREE(unix_name);
997 static NTSTATUS local_pw_check(struct auth4_context *auth4_context,
999 const struct auth_usersupplied_info *user_info,
1000 uint8_t *pauthoritative,
1001 void **server_returned_info,
1002 DATA_BLOB *session_key, DATA_BLOB *lm_session_key)
1005 struct samr_Password lm_pw, nt_pw;
1007 nt_lm_owf_gen (opt_password, nt_pw.hash, lm_pw.hash);
1009 *pauthoritative = 1;
1011 nt_status = ntlm_password_check(mem_ctx,
1013 &auth4_context->challenge.data,
1014 &user_info->password.response.lanman,
1015 &user_info->password.response.nt,
1016 user_info->client.account_name,
1017 user_info->client.account_name,
1018 user_info->client.domain_name,
1019 &lm_pw, &nt_pw, session_key, lm_session_key);
1021 if (NT_STATUS_IS_OK(nt_status)) {
1022 *server_returned_info = talloc_asprintf(mem_ctx,
1023 "%s%c%s", user_info->client.domain_name,
1024 *lp_winbind_separator(),
1025 user_info->client.account_name);
1027 DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
1028 user_info->client.domain_name, user_info->client.account_name,
1029 user_info->workstation_name,
1030 nt_errstr(nt_status)));
1035 static NTSTATUS ntlm_auth_prepare_gensec_client(TALLOC_CTX *mem_ctx,
1036 struct loadparm_context *lp_ctx,
1037 struct gensec_security **gensec_security_out)
1039 struct gensec_security *gensec_security = NULL;
1041 TALLOC_CTX *tmp_ctx;
1042 const struct gensec_security_ops **backends = NULL;
1043 struct gensec_settings *gensec_settings = NULL;
1046 tmp_ctx = talloc_new(mem_ctx);
1047 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
1049 gensec_settings = lpcfg_gensec_settings(tmp_ctx, lp_ctx);
1050 if (gensec_settings == NULL) {
1051 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1052 TALLOC_FREE(tmp_ctx);
1053 return NT_STATUS_NO_MEMORY;
1056 backends = talloc_zero_array(gensec_settings,
1057 const struct gensec_security_ops *, 4);
1058 if (backends == NULL) {
1059 TALLOC_FREE(tmp_ctx);
1060 return NT_STATUS_NO_MEMORY;
1062 gensec_settings->backends = backends;
1066 /* These need to be in priority order, krb5 before NTLMSSP */
1067 #if defined(HAVE_KRB5)
1068 backends[idx++] = &gensec_gse_krb5_security_ops;
1071 backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_NTLMSSP);
1073 backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_SPNEGO);
1075 nt_status = gensec_client_start(NULL, &gensec_security,
1077 if (!NT_STATUS_IS_OK(nt_status)) {
1078 TALLOC_FREE(tmp_ctx);
1082 talloc_unlink(tmp_ctx, gensec_settings);
1084 if (opt_target_service != NULL) {
1085 nt_status = gensec_set_target_service(gensec_security,
1086 opt_target_service);
1087 if (!NT_STATUS_IS_OK(nt_status)) {
1088 TALLOC_FREE(tmp_ctx);
1093 if (opt_target_hostname != NULL) {
1094 nt_status = gensec_set_target_hostname(gensec_security,
1095 opt_target_hostname);
1096 if (!NT_STATUS_IS_OK(nt_status)) {
1097 TALLOC_FREE(tmp_ctx);
1102 *gensec_security_out = talloc_steal(mem_ctx, gensec_security);
1103 TALLOC_FREE(tmp_ctx);
1104 return NT_STATUS_OK;
1107 static struct auth4_context *make_auth4_context_ntlm_auth(TALLOC_CTX *mem_ctx, bool local_pw)
1109 struct auth4_context *auth4_context = talloc_zero(mem_ctx, struct auth4_context);
1110 if (auth4_context == NULL) {
1111 DEBUG(10, ("failed to allocate auth4_context failed\n"));
1114 auth4_context->generate_session_info = ntlm_auth_generate_session_info;
1115 auth4_context->generate_session_info_pac = ntlm_auth_generate_session_info_pac;
1116 auth4_context->get_ntlm_challenge = ntlm_auth_get_challenge;
1117 auth4_context->set_ntlm_challenge = ntlm_auth_set_challenge;
1119 auth4_context->check_ntlm_password = local_pw_check;
1121 auth4_context->check_ntlm_password = winbind_pw_check;
1123 auth4_context->private_data = NULL;
1124 return auth4_context;
1127 static NTSTATUS ntlm_auth_prepare_gensec_server(TALLOC_CTX *mem_ctx,
1128 struct loadparm_context *lp_ctx,
1129 struct gensec_security **gensec_security_out)
1131 struct gensec_security *gensec_security;
1134 TALLOC_CTX *tmp_ctx;
1135 const struct gensec_security_ops **backends;
1136 struct gensec_settings *gensec_settings;
1138 struct cli_credentials *server_credentials;
1140 struct auth4_context *auth4_context;
1142 tmp_ctx = talloc_new(mem_ctx);
1143 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
1145 auth4_context = make_auth4_context_ntlm_auth(tmp_ctx, opt_password);
1146 if (auth4_context == NULL) {
1147 TALLOC_FREE(tmp_ctx);
1148 return NT_STATUS_NO_MEMORY;
1151 gensec_settings = lpcfg_gensec_settings(tmp_ctx, lp_ctx);
1152 if (lp_ctx == NULL) {
1153 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1154 TALLOC_FREE(tmp_ctx);
1155 return NT_STATUS_NO_MEMORY;
1159 * This should be a 'netbios domain -> DNS domain'
1160 * mapping, and can currently validly return NULL on
1161 * poorly configured systems.
1163 * This is used for the NTLMSSP server
1167 gensec_settings->server_netbios_name = lp_netbios_name();
1168 gensec_settings->server_netbios_domain = lp_workgroup();
1170 gensec_settings->server_netbios_name = get_winbind_netbios_name();
1171 gensec_settings->server_netbios_domain = get_winbind_domain();
1174 gensec_settings->server_dns_domain = strlower_talloc(gensec_settings,
1175 get_mydnsdomname(talloc_tos()));
1176 gensec_settings->server_dns_name = strlower_talloc(gensec_settings,
1177 get_mydnsfullname());
1179 backends = talloc_zero_array(gensec_settings,
1180 const struct gensec_security_ops *, 4);
1182 if (backends == NULL) {
1183 TALLOC_FREE(tmp_ctx);
1184 return NT_STATUS_NO_MEMORY;
1186 gensec_settings->backends = backends;
1190 /* These need to be in priority order, krb5 before NTLMSSP */
1191 #if defined(HAVE_KRB5)
1192 backends[idx++] = &gensec_gse_krb5_security_ops;
1195 backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_NTLMSSP);
1197 backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_SPNEGO);
1200 * This is anonymous for now, because we just use it
1201 * to set the kerberos state at the moment
1203 server_credentials = cli_credentials_init_anon(tmp_ctx);
1204 if (!server_credentials) {
1205 DEBUG(0, ("auth_generic_prepare: Failed to init server credentials\n"));
1206 return NT_STATUS_NO_MEMORY;
1209 cli_credentials_set_conf(server_credentials, lp_ctx);
1211 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC || lp_security() == SEC_ADS || USE_KERBEROS_KEYTAB) {
1212 cli_credentials_set_kerberos_state(server_credentials, CRED_AUTO_USE_KERBEROS);
1214 cli_credentials_set_kerberos_state(server_credentials, CRED_DONT_USE_KERBEROS);
1217 nt_status = gensec_server_start(tmp_ctx, gensec_settings,
1218 auth4_context, &gensec_security);
1220 if (!NT_STATUS_IS_OK(nt_status)) {
1221 TALLOC_FREE(tmp_ctx);
1225 gensec_set_credentials(gensec_security, server_credentials);
1228 * TODO: Allow the caller to pass their own description here
1229 * via a command-line option
1231 nt_status = gensec_set_target_service_description(gensec_security,
1233 if (!NT_STATUS_IS_OK(nt_status)) {
1234 TALLOC_FREE(tmp_ctx);
1238 talloc_unlink(tmp_ctx, lp_ctx);
1239 talloc_unlink(tmp_ctx, server_credentials);
1240 talloc_unlink(tmp_ctx, gensec_settings);
1241 talloc_unlink(tmp_ctx, auth4_context);
1243 *gensec_security_out = talloc_steal(mem_ctx, gensec_security);
1244 TALLOC_FREE(tmp_ctx);
1245 return NT_STATUS_OK;
1248 static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode,
1249 struct loadparm_context *lp_ctx,
1250 struct ntlm_auth_state *state,
1251 char *buf, int length, void **private2)
1253 manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
1257 static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode,
1258 struct loadparm_context *lp_ctx,
1259 struct ntlm_auth_state *state,
1260 char *buf, int length, void **private2)
1265 pass=(char *)memchr(buf,' ',length);
1267 DEBUG(2, ("Password not found. Denying access\n"));
1274 if (state->helper_mode == SQUID_2_5_BASIC) {
1275 rfc1738_unescape(user);
1276 rfc1738_unescape(pass);
1279 if (check_plaintext_auth(user, pass, False)) {
1286 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
1287 struct loadparm_context *lp_ctx,
1288 char *buf, int length, void **private1)
1291 DATA_BLOB out = data_blob(NULL, 0);
1292 char *out_base64 = NULL;
1293 const char *reply_arg = NULL;
1294 struct gensec_ntlm_state {
1295 struct gensec_security *gensec_state;
1296 const char *set_password;
1298 struct gensec_ntlm_state *state;
1302 const char *reply_code;
1303 struct cli_credentials *creds;
1305 static char *want_feature_list = NULL;
1306 static DATA_BLOB session_key;
1308 TALLOC_CTX *mem_ctx;
1310 mem_ctx = talloc_named(NULL, 0, "manage_gensec_request internal mem_ctx");
1313 state = (struct gensec_ntlm_state *)*private1;
1315 state = talloc_zero(NULL, struct gensec_ntlm_state);
1317 printf("BH No Memory\n");
1322 state->set_password = opt_password;
1326 if (strlen(buf) < 2) {
1327 DEBUG(1, ("query [%s] invalid", buf));
1328 printf("BH Query invalid\n");
1329 talloc_free(mem_ctx);
1333 if (strlen(buf) > 3) {
1334 if(strncmp(buf, "SF ", 3) == 0) {
1335 DEBUG(10, ("Setting flags to negotiate\n"));
1336 talloc_free(want_feature_list);
1337 want_feature_list = talloc_strndup(state, buf+3, strlen(buf)-3);
1339 talloc_free(mem_ctx);
1342 in = base64_decode_data_blob_talloc(mem_ctx, buf + 3);
1344 in = data_blob(NULL, 0);
1347 if (strncmp(buf, "YR", 2) == 0) {
1348 if (state->gensec_state) {
1349 talloc_free(state->gensec_state);
1350 state->gensec_state = NULL;
1352 } else if ( (strncmp(buf, "OK", 2) == 0)) {
1353 /* Just return BH, like ntlm_auth from Samba 3 does. */
1354 printf("BH Command expected\n");
1355 talloc_free(mem_ctx);
1357 } else if ( (strncmp(buf, "TT ", 3) != 0) &&
1358 (strncmp(buf, "KK ", 3) != 0) &&
1359 (strncmp(buf, "AF ", 3) != 0) &&
1360 (strncmp(buf, "NA ", 3) != 0) &&
1361 (strncmp(buf, "UG", 2) != 0) &&
1362 (strncmp(buf, "PW ", 3) != 0) &&
1363 (strncmp(buf, "GK", 2) != 0) &&
1364 (strncmp(buf, "GF", 2) != 0)) {
1365 DEBUG(1, ("SPNEGO request [%s] invalid prefix\n", buf));
1366 printf("BH SPNEGO request invalid prefix\n");
1367 talloc_free(mem_ctx);
1372 if (!(state->gensec_state)) {
1373 switch (stdio_helper_mode) {
1374 case GSS_SPNEGO_CLIENT:
1376 * cached credentials are only supported by
1377 * NTLMSSP_CLIENT_1 for now.
1379 use_cached_creds = false;
1381 case NTLMSSP_CLIENT_1:
1382 /* setup the client side */
1384 if (state->set_password != NULL) {
1385 use_cached_creds = false;
1388 if (use_cached_creds) {
1389 struct wbcCredentialCacheParams params;
1390 struct wbcCredentialCacheInfo *info = NULL;
1391 struct wbcAuthErrorInfo *error = NULL;
1394 params.account_name = opt_username;
1395 params.domain_name = opt_domain;
1396 params.level = WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP;
1397 params.num_blobs = 0;
1398 params.blobs = NULL;
1400 wbc_status = wbcCredentialCache(¶ms, &info,
1402 wbcFreeMemory(error);
1403 if (!WBC_ERROR_IS_OK(wbc_status)) {
1404 use_cached_creds = false;
1406 wbcFreeMemory(info);
1409 nt_status = ntlm_auth_prepare_gensec_client(state, lp_ctx,
1410 &state->gensec_state);
1411 if (!NT_STATUS_IS_OK(nt_status)) {
1412 printf("BH GENSEC mech failed to start: %s\n",
1413 nt_errstr(nt_status));
1414 talloc_free(mem_ctx);
1418 creds = cli_credentials_init(state->gensec_state);
1419 cli_credentials_set_conf(creds, lp_ctx);
1421 cli_credentials_set_username(creds, opt_username, CRED_SPECIFIED);
1424 cli_credentials_set_domain(creds, opt_domain, CRED_SPECIFIED);
1426 if (use_cached_creds) {
1427 gensec_want_feature(state->gensec_state,
1428 GENSEC_FEATURE_NTLM_CCACHE);
1429 } else if (state->set_password) {
1430 cli_credentials_set_password(creds, state->set_password, CRED_SPECIFIED);
1432 cli_credentials_set_password_callback(creds, get_password);
1434 if (opt_workstation) {
1435 cli_credentials_set_workstation(creds, opt_workstation, CRED_SPECIFIED);
1438 gensec_set_credentials(state->gensec_state, creds);
1441 case GSS_SPNEGO_SERVER:
1442 case SQUID_2_5_NTLMSSP:
1444 nt_status = ntlm_auth_prepare_gensec_server(state, lp_ctx,
1445 &state->gensec_state);
1446 if (!NT_STATUS_IS_OK(nt_status)) {
1447 printf("BH GENSEC mech failed to start: %s\n",
1448 nt_errstr(nt_status));
1449 talloc_free(mem_ctx);
1455 talloc_free(mem_ctx);
1459 gensec_want_feature_list(state->gensec_state, want_feature_list);
1461 /* Session info is not complete, do not pass to auth log */
1462 gensec_want_feature(state->gensec_state, GENSEC_FEATURE_NO_AUTHZ_LOG);
1464 switch (stdio_helper_mode) {
1465 case GSS_SPNEGO_CLIENT:
1466 case GSS_SPNEGO_SERVER:
1467 nt_status = gensec_start_mech_by_oid(state->gensec_state, GENSEC_OID_SPNEGO);
1472 case NTLMSSP_CLIENT_1:
1477 case SQUID_2_5_NTLMSSP:
1478 nt_status = gensec_start_mech_by_oid(state->gensec_state, GENSEC_OID_NTLMSSP);
1481 talloc_free(mem_ctx);
1485 if (!NT_STATUS_IS_OK(nt_status)) {
1486 DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status)));
1487 printf("BH GENSEC mech failed to start\n");
1488 talloc_free(mem_ctx);
1496 if (strncmp(buf, "PW ", 3) == 0) {
1497 state->set_password = talloc_strndup(state,
1498 (const char *)in.data,
1501 cli_credentials_set_password(gensec_get_credentials(state->gensec_state),
1502 state->set_password,
1505 talloc_free(mem_ctx);
1509 if (strncmp(buf, "GK", 2) == 0) {
1511 DEBUG(10, ("Requested session key\n"));
1512 nt_status = gensec_session_key(state->gensec_state, mem_ctx, &session_key);
1513 if(!NT_STATUS_IS_OK(nt_status)) {
1514 DEBUG(1, ("gensec_session_key failed: %s\n", nt_errstr(nt_status)));
1515 printf("BH No session key\n");
1516 talloc_free(mem_ctx);
1519 base64_key = base64_encode_data_blob(state, session_key);
1520 SMB_ASSERT(base64_key != NULL);
1521 printf("GK %s\n", base64_key);
1522 talloc_free(base64_key);
1524 talloc_free(mem_ctx);
1528 if (strncmp(buf, "GF", 2) == 0) {
1531 DEBUG(10, ("Requested negotiated NTLMSSP feature flags\n"));
1533 neg_flags = gensec_ntlmssp_neg_flags(state->gensec_state);
1534 if (neg_flags == 0) {
1536 talloc_free(mem_ctx);
1540 printf("GF 0x%08x\n", neg_flags);
1541 talloc_free(mem_ctx);
1545 nt_status = gensec_update(state->gensec_state, mem_ctx, in, &out);
1547 /* don't leak 'bad password'/'no such user' info to the network client */
1548 nt_status = nt_status_squash(nt_status);
1551 out_base64 = base64_encode_data_blob(mem_ctx, out);
1552 SMB_ASSERT(out_base64 != NULL);
1557 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1559 if (first && state->gensec_state->gensec_role == GENSEC_CLIENT) {
1561 } else if (state->gensec_state->gensec_role == GENSEC_CLIENT) {
1563 } else if (state->gensec_state->gensec_role == GENSEC_SERVER) {
1570 } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) {
1571 reply_code = "BH NT_STATUS_ACCESS_DENIED";
1572 reply_arg = nt_errstr(nt_status);
1573 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
1574 } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_UNSUCCESSFUL)) {
1575 reply_code = "BH NT_STATUS_UNSUCCESSFUL";
1576 reply_arg = nt_errstr(nt_status);
1577 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
1578 } else if (!NT_STATUS_IS_OK(nt_status)) {
1580 reply_arg = nt_errstr(nt_status);
1581 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
1582 } else if /* OK */ (state->gensec_state->gensec_role == GENSEC_SERVER) {
1583 struct auth_session_info *session_info;
1585 nt_status = gensec_session_info(state->gensec_state, mem_ctx, &session_info);
1586 if (!NT_STATUS_IS_OK(nt_status)) {
1587 reply_code = "BH Failed to retrive session info";
1588 reply_arg = nt_errstr(nt_status);
1589 DEBUG(1, ("GENSEC failed to retrieve the session info: %s\n", nt_errstr(nt_status)));
1593 reply_arg = talloc_strdup(state->gensec_state, session_info->unix_info->unix_name);
1594 if (reply_arg == NULL) {
1595 reply_code = "BH out of memory";
1596 reply_arg = nt_errstr(NT_STATUS_NO_MEMORY);
1598 talloc_free(session_info);
1600 } else if (state->gensec_state->gensec_role == GENSEC_CLIENT) {
1602 reply_arg = out_base64;
1607 switch (stdio_helper_mode) {
1608 case GSS_SPNEGO_SERVER:
1609 printf("%s %s %s\n", reply_code,
1610 out_base64 ? out_base64 : "*",
1611 reply_arg ? reply_arg : "*");
1615 printf("%s %s\n", reply_code, out_base64);
1616 } else if (reply_arg) {
1617 printf("%s %s\n", reply_code, reply_arg);
1619 printf("%s\n", reply_code);
1623 talloc_free(mem_ctx);
1627 static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode,
1628 struct loadparm_context *lp_ctx,
1629 struct ntlm_auth_state *state,
1630 char *buf, int length, void **private2)
1632 manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
1636 static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode,
1637 struct loadparm_context *lp_ctx,
1638 struct ntlm_auth_state *state,
1639 char *buf, int length, void **private2)
1641 manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
1645 static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode,
1646 struct loadparm_context *lp_ctx,
1647 struct ntlm_auth_state *state,
1648 char *buf, int length, void **private2)
1650 manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
1654 static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode,
1655 struct loadparm_context *lp_ctx,
1656 struct ntlm_auth_state *state,
1657 char *buf, int length, void **private2)
1659 char *request, *parameter;
1660 static DATA_BLOB challenge;
1661 static DATA_BLOB lm_response;
1662 static DATA_BLOB nt_response;
1663 static char *full_username;
1664 static char *username;
1665 static char *domain;
1666 static char *plaintext_password;
1667 static bool ntlm_server_1_user_session_key;
1668 static bool ntlm_server_1_lm_session_key;
1670 if (strequal(buf, ".")) {
1671 if (!full_username && !username) {
1672 printf("Error: No username supplied!\n");
1673 } else if (plaintext_password) {
1674 /* handle this request as plaintext */
1675 if (!full_username) {
1676 if (asprintf(&full_username, "%s%c%s", domain, winbind_separator(), username) == -1) {
1677 printf("Error: Out of memory in "
1682 if (check_plaintext_auth(full_username, plaintext_password, False)) {
1683 printf("Authenticated: Yes\n");
1685 printf("Authenticated: No\n");
1687 } else if (!lm_response.data && !nt_response.data) {
1688 printf("Error: No password supplied!\n");
1689 } else if (!challenge.data) {
1690 printf("Error: No lanman-challenge supplied!\n");
1692 char *error_string = NULL;
1694 uchar user_session_key[16];
1697 if (full_username && !username) {
1699 fstring fstr_domain;
1701 if (!parse_ntlm_auth_domain_user(full_username, fstr_user, fstr_domain)) {
1702 /* username might be 'tainted', don't print into our new-line deleimianted stream */
1703 printf("Error: Could not parse into "
1704 "domain and username\n");
1706 SAFE_FREE(username);
1708 username = smb_xstrdup(fstr_user);
1709 domain = smb_xstrdup(fstr_domain);
1713 DATA_BLOB nt_session_key, lm_session_key;
1714 struct samr_Password lm_pw, nt_pw;
1715 TALLOC_CTX *mem_ctx = talloc_new(NULL);
1716 ZERO_STRUCT(user_session_key);
1717 ZERO_STRUCT(lm_key);
1719 nt_lm_owf_gen (opt_password, nt_pw.hash, lm_pw.hash);
1720 nt_status = ntlm_password_check(mem_ctx,
1731 error_string = smb_xstrdup(get_friendly_nt_error_msg(nt_status));
1732 if (ntlm_server_1_user_session_key) {
1733 if (nt_session_key.length == sizeof(user_session_key)) {
1734 memcpy(user_session_key,
1735 nt_session_key.data,
1736 sizeof(user_session_key));
1739 if (ntlm_server_1_lm_session_key) {
1740 if (lm_session_key.length == sizeof(lm_key)) {
1742 lm_session_key.data,
1746 TALLOC_FREE(mem_ctx);
1749 uint8_t authoritative = 0;
1752 domain = smb_xstrdup(get_winbind_domain());
1755 if (ntlm_server_1_lm_session_key)
1756 flags |= WBFLAG_PAM_LMKEY;
1758 if (ntlm_server_1_user_session_key)
1759 flags |= WBFLAG_PAM_USER_SESSION_KEY;
1761 nt_status = contact_winbind_auth_crap(username,
1775 if (!NT_STATUS_IS_OK(nt_status)) {
1776 printf("Authenticated: No\n");
1777 printf("Authentication-Error: %s\n.\n",
1781 char *hex_user_session_key;
1783 printf("Authenticated: Yes\n");
1785 if (ntlm_server_1_lm_session_key
1786 && (!all_zero(lm_key,
1788 hex_lm_key = hex_encode_talloc(NULL,
1789 (const unsigned char *)lm_key,
1791 printf("LANMAN-Session-Key: %s\n",
1793 TALLOC_FREE(hex_lm_key);
1796 if (ntlm_server_1_user_session_key
1797 && (!all_zero(user_session_key,
1798 sizeof(user_session_key)))) {
1799 hex_user_session_key = hex_encode_talloc(NULL,
1800 (const unsigned char *)user_session_key,
1801 sizeof(user_session_key));
1802 printf("User-Session-Key: %s\n",
1803 hex_user_session_key);
1804 TALLOC_FREE(hex_user_session_key);
1807 SAFE_FREE(error_string);
1809 /* clear out the state */
1810 challenge = data_blob_null;
1811 nt_response = data_blob_null;
1812 lm_response = data_blob_null;
1813 SAFE_FREE(full_username);
1814 SAFE_FREE(username);
1816 SAFE_FREE(plaintext_password);
1817 ntlm_server_1_user_session_key = False;
1818 ntlm_server_1_lm_session_key = False;
1826 /* Indicates a base64 encoded structure */
1827 parameter = strstr_m(request, ":: ");
1829 parameter = strstr_m(request, ": ");
1832 DEBUG(0, ("Parameter not found!\n"));
1833 printf("Error: Parameter not found!\n.\n");
1850 base64_decode_inplace(parameter);
1853 if (strequal(request, "LANMAN-Challenge")) {
1854 challenge = strhex_to_data_blob(NULL, parameter);
1855 if (challenge.length != 8) {
1856 printf("Error: hex decode of %s failed! "
1857 "(got %d bytes, expected 8)\n.\n",
1859 (int)challenge.length);
1860 challenge = data_blob_null;
1862 } else if (strequal(request, "NT-Response")) {
1863 nt_response = strhex_to_data_blob(NULL, parameter);
1864 if (nt_response.length < 24) {
1865 printf("Error: hex decode of %s failed! "
1866 "(only got %d bytes, needed at least 24)\n.\n",
1868 (int)nt_response.length);
1869 nt_response = data_blob_null;
1871 } else if (strequal(request, "LANMAN-Response")) {
1872 lm_response = strhex_to_data_blob(NULL, parameter);
1873 if (lm_response.length != 24) {
1874 printf("Error: hex decode of %s failed! "
1875 "(got %d bytes, expected 24)\n.\n",
1877 (int)lm_response.length);
1878 lm_response = data_blob_null;
1880 } else if (strequal(request, "Password")) {
1881 plaintext_password = smb_xstrdup(parameter);
1882 } else if (strequal(request, "NT-Domain")) {
1883 domain = smb_xstrdup(parameter);
1884 } else if (strequal(request, "Username")) {
1885 username = smb_xstrdup(parameter);
1886 } else if (strequal(request, "Full-Username")) {
1887 full_username = smb_xstrdup(parameter);
1888 } else if (strequal(request, "Request-User-Session-Key")) {
1889 ntlm_server_1_user_session_key = strequal(parameter, "Yes");
1890 } else if (strequal(request, "Request-LanMan-Session-Key")) {
1891 ntlm_server_1_lm_session_key = strequal(parameter, "Yes");
1893 printf("Error: Unknown request %s\n.\n", request);
1897 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode,
1898 struct loadparm_context *lp_ctx,
1899 struct ntlm_auth_state *state,
1900 char *buf, int length, void **private2)
1902 char *request, *parameter;
1903 static DATA_BLOB new_nt_pswd;
1904 static DATA_BLOB old_nt_hash_enc;
1905 static DATA_BLOB new_lm_pswd;
1906 static DATA_BLOB old_lm_hash_enc;
1907 static char *full_username = NULL;
1908 static char *username = NULL;
1909 static char *domain = NULL;
1910 static char *newpswd = NULL;
1911 static char *oldpswd = NULL;
1913 if (strequal(buf, ".")) {
1914 if(newpswd && oldpswd) {
1915 uchar old_nt_hash[16];
1916 uchar old_lm_hash[16];
1917 uchar new_nt_hash[16];
1918 uchar new_lm_hash[16];
1920 new_nt_pswd = data_blob(NULL, 516);
1921 old_nt_hash_enc = data_blob(NULL, 16);
1923 /* Calculate the MD4 hash (NT compatible) of the
1925 E_md4hash(oldpswd, old_nt_hash);
1926 E_md4hash(newpswd, new_nt_hash);
1928 /* E_deshash returns false for 'long'
1929 passwords (> 14 DOS chars).
1931 Therefore, don't send a buffer
1932 encrypted with the truncated hash
1933 (it could allow an even easier
1934 attack on the password)
1936 Likewise, obey the admin's restriction
1939 if (lp_client_lanman_auth() &&
1940 E_deshash(newpswd, new_lm_hash) &&
1941 E_deshash(oldpswd, old_lm_hash)) {
1942 new_lm_pswd = data_blob(NULL, 516);
1943 old_lm_hash_enc = data_blob(NULL, 16);
1944 encode_pw_buffer(new_lm_pswd.data, newpswd,
1947 arcfour_crypt(new_lm_pswd.data, old_nt_hash, 516);
1948 E_old_pw_hash(new_nt_hash, old_lm_hash,
1949 old_lm_hash_enc.data);
1951 new_lm_pswd.data = NULL;
1952 new_lm_pswd.length = 0;
1953 old_lm_hash_enc.data = NULL;
1954 old_lm_hash_enc.length = 0;
1957 encode_pw_buffer(new_nt_pswd.data, newpswd,
1960 arcfour_crypt(new_nt_pswd.data, old_nt_hash, 516);
1961 E_old_pw_hash(new_nt_hash, old_nt_hash,
1962 old_nt_hash_enc.data);
1965 if (!full_username && !username) {
1966 printf("Error: No username supplied!\n");
1967 } else if ((!new_nt_pswd.data || !old_nt_hash_enc.data) &&
1968 (!new_lm_pswd.data || old_lm_hash_enc.data) ) {
1969 printf("Error: No NT or LM password "
1970 "blobs supplied!\n");
1972 char *error_string = NULL;
1974 if (full_username && !username) {
1976 fstring fstr_domain;
1978 if (!parse_ntlm_auth_domain_user(full_username,
1981 /* username might be 'tainted', don't
1982 * print into our new-line
1983 * deleimianted stream */
1984 printf("Error: Could not "
1985 "parse into domain and "
1987 SAFE_FREE(username);
1988 username = smb_xstrdup(full_username);
1990 SAFE_FREE(username);
1992 username = smb_xstrdup(fstr_user);
1993 domain = smb_xstrdup(fstr_domain);
1998 if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
2005 printf("Password-Change: No\n");
2006 printf("Password-Change-Error: %s\n.\n",
2009 printf("Password-Change: Yes\n");
2012 SAFE_FREE(error_string);
2014 /* clear out the state */
2015 new_nt_pswd = data_blob_null;
2016 old_nt_hash_enc = data_blob_null;
2017 new_lm_pswd = data_blob_null;
2018 old_nt_hash_enc = data_blob_null;
2019 SAFE_FREE(full_username);
2020 SAFE_FREE(username);
2031 /* Indicates a base64 encoded structure */
2032 parameter = strstr_m(request, ":: ");
2034 parameter = strstr_m(request, ": ");
2037 DEBUG(0, ("Parameter not found!\n"));
2038 printf("Error: Parameter not found!\n.\n");
2054 base64_decode_inplace(parameter);
2057 if (strequal(request, "new-nt-password-blob")) {
2058 new_nt_pswd = strhex_to_data_blob(NULL, parameter);
2059 if (new_nt_pswd.length != 516) {
2060 printf("Error: hex decode of %s failed! "
2061 "(got %d bytes, expected 516)\n.\n",
2063 (int)new_nt_pswd.length);
2064 new_nt_pswd = data_blob_null;
2066 } else if (strequal(request, "old-nt-hash-blob")) {
2067 old_nt_hash_enc = strhex_to_data_blob(NULL, parameter);
2068 if (old_nt_hash_enc.length != 16) {
2069 printf("Error: hex decode of %s failed! "
2070 "(got %d bytes, expected 16)\n.\n",
2072 (int)old_nt_hash_enc.length);
2073 old_nt_hash_enc = data_blob_null;
2075 } else if (strequal(request, "new-lm-password-blob")) {
2076 new_lm_pswd = strhex_to_data_blob(NULL, parameter);
2077 if (new_lm_pswd.length != 516) {
2078 printf("Error: hex decode of %s failed! "
2079 "(got %d bytes, expected 516)\n.\n",
2081 (int)new_lm_pswd.length);
2082 new_lm_pswd = data_blob_null;
2085 else if (strequal(request, "old-lm-hash-blob")) {
2086 old_lm_hash_enc = strhex_to_data_blob(NULL, parameter);
2087 if (old_lm_hash_enc.length != 16)
2089 printf("Error: hex decode of %s failed! "
2090 "(got %d bytes, expected 16)\n.\n",
2092 (int)old_lm_hash_enc.length);
2093 old_lm_hash_enc = data_blob_null;
2095 } else if (strequal(request, "nt-domain")) {
2096 domain = smb_xstrdup(parameter);
2097 } else if(strequal(request, "username")) {
2098 username = smb_xstrdup(parameter);
2099 } else if(strequal(request, "full-username")) {
2100 username = smb_xstrdup(parameter);
2101 } else if(strequal(request, "new-password")) {
2102 newpswd = smb_xstrdup(parameter);
2103 } else if (strequal(request, "old-password")) {
2104 oldpswd = smb_xstrdup(parameter);
2106 printf("Error: Unknown request %s\n.\n", request);
2110 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode,
2111 struct loadparm_context *lp_ctx,
2112 struct ntlm_auth_state *state,
2113 stdio_helper_function fn, void **private2)
2116 char tmp[INITIAL_BUFFER_SIZE+1];
2117 int length, buf_size = 0;
2120 buf = talloc_strdup(state->mem_ctx, "");
2122 DEBUG(0, ("Failed to allocate input buffer.\n"));
2123 fprintf(stderr, "ERR\n");
2129 /* this is not a typo - x_fgets doesn't work too well under
2131 if (fgets(tmp, sizeof(tmp)-1, stdin) == NULL) {
2132 if (ferror(stdin)) {
2133 DEBUG(1, ("fgets() failed! dying..... errno=%d "
2134 "(%s)\n", ferror(stdin),
2135 strerror(ferror(stdin))));
2142 buf = talloc_strdup_append_buffer(buf, tmp);
2143 buf_size += INITIAL_BUFFER_SIZE;
2145 if (buf_size > MAX_BUFFER_SIZE) {
2146 DEBUG(2, ("Oversized message\n"));
2147 fprintf(stderr, "ERR\n");
2152 c = strchr(buf, '\n');
2153 } while (c == NULL);
2158 DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf,length));
2160 if (buf[0] == '\0') {
2161 DEBUG(2, ("Invalid Request\n"));
2162 fprintf(stderr, "ERR\n");
2167 fn(stdio_helper_mode, lp_ctx, state, buf, length, private2);
2172 static void squid_stream(enum stdio_helper_mode stdio_mode,
2173 struct loadparm_context *lp_ctx,
2174 stdio_helper_function fn) {
2175 TALLOC_CTX *mem_ctx;
2176 struct ntlm_auth_state *state;
2178 /* initialize FDescs */
2179 setbuf(stdout, NULL);
2180 setbuf(stderr, NULL);
2182 mem_ctx = talloc_init("ntlm_auth");
2184 DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
2185 fprintf(stderr, "ERR\n");
2189 state = talloc_zero(mem_ctx, struct ntlm_auth_state);
2191 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
2192 fprintf(stderr, "ERR\n");
2196 state->mem_ctx = mem_ctx;
2197 state->helper_mode = stdio_mode;
2200 TALLOC_CTX *frame = talloc_stackframe();
2201 manage_squid_request(stdio_mode, lp_ctx, state, fn, NULL);
2207 /* Authenticate a user with a challenge/response */
2209 static bool check_auth_crap(void)
2214 char user_session_key[16];
2216 char *hex_user_session_key;
2218 uint8_t authoritative = 0;
2220 setbuf(stdout, NULL);
2223 flags |= WBFLAG_PAM_LMKEY;
2225 if (request_user_session_key)
2226 flags |= WBFLAG_PAM_USER_SESSION_KEY;
2228 flags |= WBFLAG_PAM_NT_STATUS_SQUASH;
2230 nt_status = contact_winbind_auth_crap(opt_username, opt_domain,
2236 (unsigned char *)lm_key,
2237 (unsigned char *)user_session_key,
2239 &error_string, NULL);
2241 if (!NT_STATUS_IS_OK(nt_status)) {
2242 printf("%s (0x%x)\n", error_string,
2243 NT_STATUS_V(nt_status));
2244 SAFE_FREE(error_string);
2249 && (!all_zero((uint8_t *)lm_key, sizeof(lm_key)))) {
2250 hex_lm_key = hex_encode_talloc(talloc_tos(), (const unsigned char *)lm_key,
2252 printf("LM_KEY: %s\n", hex_lm_key);
2253 TALLOC_FREE(hex_lm_key);
2255 if (request_user_session_key
2256 && (!all_zero((uint8_t *)user_session_key,
2257 sizeof(user_session_key)))) {
2258 hex_user_session_key = hex_encode_talloc(talloc_tos(), (const unsigned char *)user_session_key,
2259 sizeof(user_session_key));
2260 printf("NT_KEY: %s\n", hex_user_session_key);
2261 TALLOC_FREE(hex_user_session_key);
2270 OPT_USERNAME = 1000,
2279 OPT_USER_SESSION_KEY,
2281 OPT_REQUIRE_MEMBERSHIP,
2282 OPT_USE_CACHED_CREDS,
2284 OPT_PAM_WINBIND_CONF,
2286 OPT_TARGET_HOSTNAME,
2290 int main(int argc, const char **argv)
2292 TALLOC_CTX *frame = talloc_stackframe();
2294 const char *helper_protocol = NULL;
2295 int diagnostics = 0;
2297 const char *hex_challenge = NULL;
2298 const char *hex_lm_response = NULL;
2299 const char *hex_nt_response = NULL;
2300 struct loadparm_context *lp_ctx;
2303 /* NOTE: DO NOT change this interface without considering the implications!
2304 This is an external interface, which other programs will use to interact
2308 /* We do not use single-letter command abbreviations, because they harm future
2309 interface stability. */
2311 struct poptOption long_options[] = {
2313 { "helper-protocol", 0, POPT_ARG_STRING, &helper_protocol, OPT_DOMAIN, "operate as a stdio-based helper", "helper protocol to use"},
2314 { "username", 0, POPT_ARG_STRING, &opt_username, OPT_USERNAME, "username"},
2315 { "domain", 0, POPT_ARG_STRING, &opt_domain, OPT_DOMAIN, "domain name"},
2316 { "workstation", 0, POPT_ARG_STRING, &opt_workstation, OPT_WORKSTATION, "workstation"},
2317 { "challenge", 0, POPT_ARG_STRING, &hex_challenge, OPT_CHALLENGE, "challenge (HEX encoded)"},
2318 { "lm-response", 0, POPT_ARG_STRING, &hex_lm_response, OPT_LM, "LM Response to the challenge (HEX encoded)"},
2319 { "nt-response", 0, POPT_ARG_STRING, &hex_nt_response, OPT_NT, "NT or NTLMv2 Response to the challenge (HEX encoded)"},
2320 { "password", 0, POPT_ARG_STRING, &opt_password, OPT_PASSWORD, "User's plaintext password"},
2321 { "request-lm-key", 0, POPT_ARG_NONE, &request_lm_key, OPT_LM_KEY, "Retrieve LM session key"},
2322 { "request-nt-key", 0, POPT_ARG_NONE, &request_user_session_key, OPT_USER_SESSION_KEY, "Retrieve User (NT) session key"},
2323 { "use-cached-creds", 0, POPT_ARG_NONE, &use_cached_creds, OPT_USE_CACHED_CREDS, "Use cached credentials if no password is given"},
2324 { "allow-mschapv2", 0, POPT_ARG_NONE, &opt_allow_mschapv2, OPT_ALLOW_MSCHAPV2, "Explicitly allow MSCHAPv2" },
2325 { "offline-logon", 0, POPT_ARG_NONE, &offline_logon,
2327 "Use cached passwords when DC is offline"},
2328 { "diagnostics", 0, POPT_ARG_NONE, &diagnostics,
2330 "Perform diagnostics on the authentication chain"},
2331 { "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" },
2332 { "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" },
2333 { "target-service", 0, POPT_ARG_STRING, &opt_target_service, OPT_TARGET_SERVICE, "Target service (eg http)" },
2334 { "target-hostname", 0, POPT_ARG_STRING, &opt_target_hostname, OPT_TARGET_HOSTNAME, "Target hostname" },
2335 POPT_COMMON_CONFIGFILE
2341 /* Samba client initialisation */
2344 setup_logging("ntlm_auth", DEBUG_STDERR);
2349 pc = poptGetContext("ntlm_auth", argc, argv, long_options, 0);
2351 /* Parse command line options */
2354 poptPrintHelp(pc, stderr, 0);
2358 while((opt = poptGetNextOpt(pc)) != -1) {
2359 /* Get generic config options like --configfile */
2362 poptFreeContext(pc);
2364 if (!lp_load_global(get_dyn_CONFIGFILE())) {
2365 d_fprintf(stderr, "ntlm_auth: error opening config file %s. Error was %s\n",
2366 get_dyn_CONFIGFILE(), strerror(errno));
2370 pc = poptGetContext(NULL, argc, (const char **)argv, long_options,
2371 POPT_CONTEXT_KEEP_FIRST);
2373 while((opt = poptGetNextOpt(pc)) != -1) {
2376 opt_challenge = strhex_to_data_blob(NULL, hex_challenge);
2377 if (opt_challenge.length != 8) {
2378 fprintf(stderr, "hex decode of %s failed! "
2379 "(only got %d bytes)\n",
2381 (int)opt_challenge.length);
2386 opt_lm_response = strhex_to_data_blob(NULL, hex_lm_response);
2387 if (opt_lm_response.length != 24) {
2388 fprintf(stderr, "hex decode of %s failed! "
2389 "(only got %d bytes)\n",
2391 (int)opt_lm_response.length);
2397 opt_nt_response = strhex_to_data_blob(NULL, hex_nt_response);
2398 if (opt_nt_response.length < 24) {
2399 fprintf(stderr, "hex decode of %s failed! "
2400 "(only got %d bytes)\n",
2402 (int)opt_nt_response.length);
2407 case OPT_REQUIRE_MEMBERSHIP:
2408 if (strncasecmp_m("S-", require_membership_of, 2) == 0) {
2409 require_membership_of_sid = require_membership_of;
2416 char *domain = SMB_STRDUP(opt_username);
2417 char *p = strchr_m(domain, *lp_winbind_separator());
2421 if (opt_domain && !strequal(opt_domain, domain)) {
2422 fprintf(stderr, "Domain specified in username (%s) "
2423 "doesn't match specified domain (%s)!\n\n",
2424 domain, opt_domain);
2425 poptPrintHelp(pc, stderr, 0);
2428 opt_domain = domain;
2434 /* Note: if opt_domain is "" then send no domain */
2435 if (opt_domain == NULL) {
2436 opt_domain = get_winbind_domain();
2439 if (opt_workstation == NULL) {
2440 opt_workstation = "";
2443 lp_ctx = loadparm_init_s3(NULL, loadparm_s3_helpers());
2444 if (lp_ctx == NULL) {
2445 fprintf(stderr, "loadparm_init_s3() failed!\n");
2449 if (helper_protocol) {
2451 for (i=0; i<NUM_HELPER_MODES; i++) {
2452 if (strcmp(helper_protocol, stdio_helper_protocols[i].name) == 0) {
2453 squid_stream(stdio_helper_protocols[i].mode, lp_ctx, stdio_helper_protocols[i].fn);
2457 fprintf(stderr, "unknown helper protocol [%s]\n\n"
2458 "Valid helper protools:\n\n", helper_protocol);
2460 for (i=0; i<NUM_HELPER_MODES; i++) {
2461 fprintf(stderr, "%s\n",
2462 stdio_helper_protocols[i].name);
2468 if (!opt_username || !*opt_username) {
2469 fprintf(stderr, "username must be specified!\n\n");
2470 poptPrintHelp(pc, stderr, 0);
2474 if (opt_challenge.length) {
2475 if (!check_auth_crap()) {
2481 if (!opt_password) {
2482 char pwd[256] = {0};
2485 rc = samba_getpass("Password: ", pwd, sizeof(pwd), false, false);
2487 opt_password = SMB_STRDUP(pwd);
2492 if (!diagnose_ntlm_auth()) {
2498 fstr_sprintf(user, "%s%c%s", opt_domain, winbind_separator(), opt_username);
2499 if (!check_plaintext_auth(user, opt_password, True)) {
2506 poptFreeContext(pc);