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"
50 #include "cmdline_contexts.h"
53 #include "auth/kerberos/pac_utils.h"
56 #ifndef PAM_WINBIND_CONFIG_FILE
57 #define PAM_WINBIND_CONFIG_FILE "/etc/security/pam_winbind.conf"
60 #define WINBIND_KRB5_AUTH 0x00000080
63 #define DBGC_CLASS DBGC_WINBIND
65 #define INITIAL_BUFFER_SIZE 300
66 #define MAX_BUFFER_SIZE 630000
68 enum stdio_helper_mode {
76 NTLM_CHANGE_PASSWORD_1,
80 enum ntlm_auth_cli_state {
87 struct ntlm_auth_state {
89 enum stdio_helper_mode helper_mode;
90 enum ntlm_auth_cli_state cli_state;
91 struct ntlmssp_state *ntlmssp_state;
93 char *want_feature_list;
94 bool have_session_key;
95 DATA_BLOB session_key;
96 DATA_BLOB initial_message;
97 void *gensec_private_1;
99 typedef void (*stdio_helper_function)(enum stdio_helper_mode stdio_helper_mode,
100 struct loadparm_context *lp_ctx,
101 struct ntlm_auth_state *state, char *buf,
102 int length, void **private2);
104 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
105 struct loadparm_context *lp_ctx,
106 char *buf, int length, void **private1);
108 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode,
109 struct loadparm_context *lp_ctx,
110 struct ntlm_auth_state *state,
111 stdio_helper_function fn, void **private2);
113 static void manage_squid_basic_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_squid_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_client_ntlmssp_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_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_gss_spnego_client_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_server_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 void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode,
144 struct loadparm_context *lp_ctx,
145 struct ntlm_auth_state *state,
146 char *buf, int length, void **private2);
148 static const struct {
149 enum stdio_helper_mode mode;
151 stdio_helper_function fn;
152 } stdio_helper_protocols[] = {
153 { SQUID_2_4_BASIC, "squid-2.4-basic", manage_squid_basic_request},
154 { SQUID_2_5_BASIC, "squid-2.5-basic", manage_squid_basic_request},
155 { SQUID_2_5_NTLMSSP, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request},
156 { NTLMSSP_CLIENT_1, "ntlmssp-client-1", manage_client_ntlmssp_request},
157 { GSS_SPNEGO_SERVER, "gss-spnego", manage_gss_spnego_request},
158 { GSS_SPNEGO_CLIENT, "gss-spnego-client", manage_gss_spnego_client_request},
159 { NTLM_SERVER_1, "ntlm-server-1", manage_ntlm_server_1_request},
160 { NTLM_CHANGE_PASSWORD_1, "ntlm-change-password-1", manage_ntlm_change_password_1_request},
161 { NUM_HELPER_MODES, NULL, NULL}
164 const char *opt_username;
165 const char *opt_domain;
166 const char *opt_workstation;
167 const char *opt_password;
168 static DATA_BLOB opt_challenge;
169 static DATA_BLOB opt_lm_response;
170 static DATA_BLOB opt_nt_response;
171 static int request_lm_key;
172 static int request_user_session_key;
173 static int use_cached_creds;
174 static int offline_logon;
175 static int opt_allow_mschapv2;
177 static const char *require_membership_of;
178 static const char *require_membership_of_sid;
179 static const char *opt_pam_winbind_conf;
181 const char *opt_target_service;
182 const char *opt_target_hostname;
185 /* This is a bit hairy, but the basic idea is to do a password callback
186 to the calling application. The callback comes from within gensec */
188 static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mode,
189 struct loadparm_context *lp_ctx,
190 struct ntlm_auth_state *state, char *buf, int length,
194 if (strlen(buf) < 2) {
195 DEBUG(1, ("query [%s] invalid", buf));
196 printf("BH Query invalid\n");
200 if (strlen(buf) > 3) {
201 in = base64_decode_data_blob(buf + 3);
203 in = data_blob(NULL, 0);
206 if (strncmp(buf, "PW ", 3) == 0) {
208 *password = talloc_strndup(NULL,
209 (const char *)in.data, in.length);
211 if (*password == NULL) {
212 DEBUG(1, ("Out of memory\n"));
213 printf("BH Out of memory\n");
222 DEBUG(1, ("Asked for (and expected) a password\n"));
223 printf("BH Expected a password\n");
228 * Callback for password credentials. This is not async, and when
229 * GENSEC and the credentials code is made async, it will look rather
233 static const char *get_password(struct cli_credentials *credentials)
235 TALLOC_CTX *frame = talloc_stackframe();
236 char *password = NULL;
237 struct ntlm_auth_state *state;
239 state = talloc_zero(frame, struct ntlm_auth_state);
241 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
242 fprintf(stderr, "ERR\n");
246 state->mem_ctx = state;
248 /* Ask for a password */
251 manage_squid_request(NUM_HELPER_MODES /* bogus */, NULL, state, manage_gensec_get_pw_request, (void **)&password);
252 talloc_steal(credentials, password);
258 * A limited set of features are defined with text strings as needed
262 static void gensec_want_feature_list(struct gensec_security *state, char* feature_list)
264 if (in_list("NTLMSSP_FEATURE_SESSION_KEY", feature_list, true)) {
265 DEBUG(10, ("want GENSEC_FEATURE_SESSION_KEY\n"));
266 gensec_want_feature(state, GENSEC_FEATURE_SESSION_KEY);
268 if (in_list("NTLMSSP_FEATURE_SIGN", feature_list, true)) {
269 DEBUG(10, ("want GENSEC_FEATURE_SIGN\n"));
270 gensec_want_feature(state, GENSEC_FEATURE_SIGN);
272 if (in_list("NTLMSSP_FEATURE_SEAL", feature_list, true)) {
273 DEBUG(10, ("want GENSEC_FEATURE_SEAL\n"));
274 gensec_want_feature(state, GENSEC_FEATURE_SEAL);
276 if (in_list("NTLMSSP_FEATURE_CCACHE", feature_list, true)) {
277 DEBUG(10, ("want GENSEC_FEATURE_NTLM_CCACHE\n"));
278 gensec_want_feature(state, GENSEC_FEATURE_NTLM_CCACHE);
282 static char winbind_separator(void)
284 struct wbcInterfaceDetails *details;
292 ret = wbcInterfaceDetails(&details);
293 if (!WBC_ERROR_IS_OK(ret)) {
294 d_fprintf(stderr, "could not obtain winbind separator!\n");
295 return *lp_winbind_separator();
298 sep = details->winbind_separator;
300 wbcFreeMemory(details);
305 d_fprintf(stderr, "winbind separator was NULL!\n");
306 return *lp_winbind_separator();
312 const char *get_winbind_domain(void)
314 struct wbcInterfaceDetails *details;
317 static fstring winbind_domain;
318 if (*winbind_domain) {
319 return winbind_domain;
322 /* Send off request */
324 ret = wbcInterfaceDetails(&details);
325 if (!WBC_ERROR_IS_OK(ret)) {
326 DEBUG(1, ("could not obtain winbind domain name!\n"));
327 return lp_workgroup();
330 fstrcpy(winbind_domain, details->netbios_domain);
332 wbcFreeMemory(details);
334 return winbind_domain;
338 const char *get_winbind_netbios_name(void)
340 struct wbcInterfaceDetails *details;
343 static fstring winbind_netbios_name;
345 if (*winbind_netbios_name) {
346 return winbind_netbios_name;
349 /* Send off request */
351 ret = wbcInterfaceDetails(&details);
352 if (!WBC_ERROR_IS_OK(ret)) {
353 DEBUG(1, ("could not obtain winbind netbios name!\n"));
354 return lp_netbios_name();
357 fstrcpy(winbind_netbios_name, details->netbios_name);
359 wbcFreeMemory(details);
361 return winbind_netbios_name;
365 DATA_BLOB get_challenge(void)
367 static DATA_BLOB chal;
368 if (opt_challenge.length)
369 return opt_challenge;
371 chal = data_blob(NULL, 8);
373 generate_random_buffer(chal.data, chal.length);
377 /* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
378 form DOMAIN/user into a domain and a user */
380 static bool parse_ntlm_auth_domain_user(const char *domuser, fstring domain,
384 char *p = strchr(domuser,winbind_separator());
391 fstrcpy(domain, domuser);
392 domain[PTR_DIFF(p, domuser)] = 0;
393 return strupper_m(domain);
396 static bool get_require_membership_sid(void) {
397 fstring domain, name, sidbuf;
398 struct wbcDomainSid sid;
399 enum wbcSidType type;
402 if (!require_membership_of) {
406 if (require_membership_of_sid) {
410 /* Otherwise, ask winbindd for the name->sid request */
412 if (!parse_ntlm_auth_domain_user(require_membership_of,
414 DEBUG(0, ("Could not parse %s into separate domain/name parts!\n",
415 require_membership_of));
419 ret = wbcLookupName(domain, name, &sid, &type);
420 if (!WBC_ERROR_IS_OK(ret)) {
421 DEBUG(0, ("Winbindd lookupname failed to resolve %s into a SID!\n",
422 require_membership_of));
426 wbcSidToStringBuf(&sid, sidbuf, sizeof(sidbuf));
428 require_membership_of_sid = SMB_STRDUP(sidbuf);
430 if (require_membership_of_sid)
437 * Get some configuration from pam_winbind.conf to see if we
438 * need to contact trusted domain
441 int get_pam_winbind_config()
444 struct tiniparser_dictionary *d = NULL;
446 if (!opt_pam_winbind_conf || !*opt_pam_winbind_conf) {
447 opt_pam_winbind_conf = PAM_WINBIND_CONFIG_FILE;
450 d = tiniparser_load(opt_pam_winbind_conf);
456 if (tiniparser_getboolean(d, "global:krb5_auth", false)) {
457 ctrl |= WINBIND_KRB5_AUTH;
460 tiniparser_freedict(d);
465 /* Authenticate a user with a plaintext password */
467 static bool check_plaintext_auth(const char *user, const char *pass,
468 bool stdout_diagnostics)
470 struct winbindd_request request;
471 struct winbindd_response response;
474 if (!get_require_membership_sid()) {
478 /* Send off request */
480 ZERO_STRUCT(request);
481 ZERO_STRUCT(response);
483 fstrcpy(request.data.auth.user, user);
484 fstrcpy(request.data.auth.pass, pass);
485 if (require_membership_of_sid) {
486 strlcpy(request.data.auth.require_membership_of_sid,
487 require_membership_of_sid,
488 sizeof(request.data.auth.require_membership_of_sid));
492 request.flags |= WBFLAG_PAM_CACHED_LOGIN;
495 result = winbindd_request_response(NULL, WINBINDD_PAM_AUTH, &request, &response);
497 /* Display response */
499 if (stdout_diagnostics) {
500 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
501 d_fprintf(stderr, "Reading winbind reply failed! (0x01)\n");
504 d_printf("%s: %s (0x%x)\n",
505 response.data.auth.nt_status_string,
506 response.data.auth.error_string,
507 response.data.auth.nt_status);
509 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
510 DEBUG(1, ("Reading winbind reply failed! (0x01)\n"));
513 DEBUG(3, ("%s: %s (0x%x)\n",
514 response.data.auth.nt_status_string,
515 response.data.auth.error_string,
516 response.data.auth.nt_status));
519 return (result == NSS_STATUS_SUCCESS);
522 /* authenticate a user with an encrypted username/password */
524 NTSTATUS contact_winbind_auth_crap(const char *username,
526 const char *workstation,
527 const DATA_BLOB *challenge,
528 const DATA_BLOB *lm_response,
529 const DATA_BLOB *nt_response,
531 uint32_t extra_logon_parameters,
533 uint8_t user_session_key[16],
534 uint8_t *pauthoritative,
540 struct winbindd_request request;
541 struct winbindd_response response;
545 if (!get_require_membership_sid()) {
546 return NT_STATUS_INVALID_PARAMETER;
549 ZERO_STRUCT(request);
550 ZERO_STRUCT(response);
552 request.flags = flags;
554 request.data.auth_crap.logon_parameters = extra_logon_parameters
555 | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT | MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT;
557 if (opt_allow_mschapv2) {
558 request.data.auth_crap.logon_parameters |= MSV1_0_ALLOW_MSVCHAPV2;
561 if (require_membership_of_sid)
562 fstrcpy(request.data.auth_crap.require_membership_of_sid, require_membership_of_sid);
564 fstrcpy(request.data.auth_crap.user, username);
565 fstrcpy(request.data.auth_crap.domain, domain);
567 fstrcpy(request.data.auth_crap.workstation,
570 memcpy(request.data.auth_crap.chal, challenge->data, MIN(challenge->length, 8));
572 if (lm_response && lm_response->length) {
573 memcpy(request.data.auth_crap.lm_resp,
575 MIN(lm_response->length, sizeof(request.data.auth_crap.lm_resp)));
576 request.data.auth_crap.lm_resp_len = lm_response->length;
579 if (nt_response && nt_response->length) {
580 if (nt_response->length > sizeof(request.data.auth_crap.nt_resp)) {
581 request.flags = request.flags | WBFLAG_BIG_NTLMV2_BLOB;
582 request.extra_len = nt_response->length;
583 request.extra_data.data = SMB_MALLOC_ARRAY(char, request.extra_len);
584 if (request.extra_data.data == NULL) {
585 return NT_STATUS_NO_MEMORY;
587 memcpy(request.extra_data.data, nt_response->data,
588 nt_response->length);
591 memcpy(request.data.auth_crap.nt_resp,
592 nt_response->data, nt_response->length);
594 request.data.auth_crap.nt_resp_len = nt_response->length;
597 result = winbindd_priv_request_response(
599 WINBINDD_PAM_AUTH_CRAP,
602 SAFE_FREE(request.extra_data.data);
604 /* Display response */
606 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
607 nt_status = NT_STATUS_UNSUCCESSFUL;
609 *error_string = smb_xstrdup("Reading winbind reply failed!");
610 winbindd_free_response(&response);
614 nt_status = (NT_STATUS(response.data.auth.nt_status));
615 if (!NT_STATUS_IS_OK(nt_status)) {
617 *error_string = smb_xstrdup(response.data.auth.error_string);
618 *pauthoritative = response.data.auth.authoritative;
619 winbindd_free_response(&response);
623 if ((flags & WBFLAG_PAM_LMKEY) && lm_key) {
624 memcpy(lm_key, response.data.auth.first_8_lm_hash,
625 sizeof(response.data.auth.first_8_lm_hash));
627 if ((flags & WBFLAG_PAM_USER_SESSION_KEY) && user_session_key) {
628 memcpy(user_session_key, response.data.auth.user_session_key,
629 sizeof(response.data.auth.user_session_key));
632 if (flags & WBFLAG_PAM_UNIX_NAME) {
633 *unix_name = SMB_STRDUP(response.data.auth.unix_username);
635 winbindd_free_response(&response);
636 return NT_STATUS_NO_MEMORY;
640 winbindd_free_response(&response);
644 /* contact server to change user password using auth crap */
645 static NTSTATUS contact_winbind_change_pswd_auth_crap(const char *username,
647 const DATA_BLOB new_nt_pswd,
648 const DATA_BLOB old_nt_hash_enc,
649 const DATA_BLOB new_lm_pswd,
650 const DATA_BLOB old_lm_hash_enc,
655 struct winbindd_request request;
656 struct winbindd_response response;
658 if (!get_require_membership_sid())
661 *error_string = smb_xstrdup("Can't get membership sid.");
662 return NT_STATUS_INVALID_PARAMETER;
665 ZERO_STRUCT(request);
666 ZERO_STRUCT(response);
669 fstrcpy(request.data.chng_pswd_auth_crap.user, username);
671 fstrcpy(request.data.chng_pswd_auth_crap.domain,domain);
673 if(new_nt_pswd.length)
675 memcpy(request.data.chng_pswd_auth_crap.new_nt_pswd, new_nt_pswd.data, sizeof(request.data.chng_pswd_auth_crap.new_nt_pswd));
676 request.data.chng_pswd_auth_crap.new_nt_pswd_len = new_nt_pswd.length;
679 if(old_nt_hash_enc.length)
681 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));
682 request.data.chng_pswd_auth_crap.old_nt_hash_enc_len = old_nt_hash_enc.length;
685 if(new_lm_pswd.length)
687 memcpy(request.data.chng_pswd_auth_crap.new_lm_pswd, new_lm_pswd.data, sizeof(request.data.chng_pswd_auth_crap.new_lm_pswd));
688 request.data.chng_pswd_auth_crap.new_lm_pswd_len = new_lm_pswd.length;
691 if(old_lm_hash_enc.length)
693 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));
694 request.data.chng_pswd_auth_crap.old_lm_hash_enc_len = old_lm_hash_enc.length;
697 result = winbindd_request_response(NULL, WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP, &request, &response);
699 /* Display response */
701 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0))
703 nt_status = NT_STATUS_UNSUCCESSFUL;
705 *error_string = smb_xstrdup("Reading winbind reply failed!");
706 winbindd_free_response(&response);
710 nt_status = (NT_STATUS(response.data.auth.nt_status));
711 if (!NT_STATUS_IS_OK(nt_status))
714 *error_string = smb_xstrdup(response.data.auth.error_string);
715 winbindd_free_response(&response);
719 winbindd_free_response(&response);
724 static NTSTATUS ntlm_auth_generate_session_info(struct auth4_context *auth_context,
726 void *server_returned_info,
727 const char *original_user_name,
728 uint32_t session_info_flags,
729 struct auth_session_info **session_info_out)
731 const char *unix_username = (const char *)server_returned_info;
733 struct dom_sid *sids = NULL;
734 struct auth_session_info *session_info = NULL;
736 session_info = talloc_zero(mem_ctx, struct auth_session_info);
737 if (session_info == NULL) {
738 return NT_STATUS_NO_MEMORY;
741 session_info->unix_info = talloc_zero(session_info, struct auth_user_info_unix);
742 if (session_info->unix_info == NULL) {
743 TALLOC_FREE(session_info);
744 return NT_STATUS_NO_MEMORY;
746 session_info->unix_info->unix_name = talloc_strdup(session_info->unix_info,
748 if (session_info->unix_info->unix_name == NULL) {
749 TALLOC_FREE(session_info);
750 return NT_STATUS_NO_MEMORY;
753 session_info->security_token = talloc_zero(session_info, struct security_token);
754 if (session_info->security_token == NULL) {
755 TALLOC_FREE(session_info);
756 return NT_STATUS_NO_MEMORY;
759 sids = talloc_zero_array(session_info->security_token,
762 TALLOC_FREE(session_info);
763 return NT_STATUS_NO_MEMORY;
765 ok = dom_sid_parse(SID_WORLD, &sids[0]);
767 TALLOC_FREE(session_info);
768 return NT_STATUS_INTERNAL_ERROR;
770 ok = dom_sid_parse(SID_NT_NETWORK, &sids[1]);
772 TALLOC_FREE(session_info);
773 return NT_STATUS_INTERNAL_ERROR;
775 ok = dom_sid_parse(SID_NT_AUTHENTICATED_USERS, &sids[2]);
777 TALLOC_FREE(session_info);
778 return NT_STATUS_INTERNAL_ERROR;
781 session_info->security_token->num_sids = talloc_array_length(sids);
782 session_info->security_token->sids = sids;
784 *session_info_out = session_info;
789 static NTSTATUS ntlm_auth_generate_session_info_pac(struct auth4_context *auth_ctx,
791 struct smb_krb5_context *smb_krb5_context,
793 const char *princ_name,
794 const struct tsocket_address *remote_address,
795 uint32_t session_info_flags,
796 struct auth_session_info **session_info)
799 struct PAC_LOGON_INFO *logon_info = NULL;
807 tmp_ctx = talloc_new(mem_ctx);
809 return NT_STATUS_NO_MEMORY;
814 status = kerberos_pac_logon_info(tmp_ctx, *pac_blob, NULL, NULL,
815 NULL, NULL, 0, &logon_info);
817 status = NT_STATUS_ACCESS_DENIED;
819 if (!NT_STATUS_IS_OK(status)) {
824 DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name));
826 p = strchr_m(princ_name, '@');
828 DEBUG(3, ("[%s] Doesn't look like a valid principal\n",
830 return NT_STATUS_LOGON_FAILURE;
833 user = talloc_strndup(mem_ctx, princ_name, p - princ_name);
835 return NT_STATUS_NO_MEMORY;
838 realm = talloc_strdup(talloc_tos(), p + 1);
840 return NT_STATUS_NO_MEMORY;
843 if (!strequal(realm, lp_realm())) {
844 DEBUG(3, ("Ticket for foreign realm %s@%s\n", user, realm));
845 if (!lp_allow_trusted_domains()) {
846 return NT_STATUS_LOGON_FAILURE;
850 if (logon_info && logon_info->info3.base.logon_domain.string) {
851 domain = talloc_strdup(mem_ctx,
852 logon_info->info3.base.logon_domain.string);
854 return NT_STATUS_NO_MEMORY;
856 DEBUG(10, ("Domain is [%s] (using PAC)\n", domain));
859 /* If we have winbind running, we can (and must) shorten the
860 username by using the short netbios name. Otherwise we will
861 have inconsistent user names. With Kerberos, we get the
862 fully qualified realm, with ntlmssp we get the short
863 name. And even w2k3 does use ntlmssp if you for example
864 connect to an ip address. */
867 struct wbcDomainInfo *info = NULL;
869 DEBUG(10, ("Mapping [%s] to short name using winbindd\n",
872 wbc_status = wbcDomainInfo(realm, &info);
874 if (WBC_ERROR_IS_OK(wbc_status)) {
875 domain = talloc_strdup(mem_ctx,
879 DEBUG(3, ("Could not find short name: %s\n",
880 wbcErrorString(wbc_status)));
881 domain = talloc_strdup(mem_ctx, realm);
884 return NT_STATUS_NO_MEMORY;
886 DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain));
889 unixuser = talloc_asprintf(tmp_ctx, "%s%c%s", domain, winbind_separator(), user);
891 status = NT_STATUS_NO_MEMORY;
895 status = ntlm_auth_generate_session_info(auth_ctx, mem_ctx, unixuser, NULL, session_info_flags, session_info);
898 TALLOC_FREE(tmp_ctx);
905 * Return the challenge as determined by the authentication subsystem
906 * @return an 8 byte random challenge
909 static NTSTATUS ntlm_auth_get_challenge(struct auth4_context *auth_ctx,
912 if (auth_ctx->challenge.data.length == 8) {
913 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
914 auth_ctx->challenge.set_by));
915 memcpy(chal, auth_ctx->challenge.data.data, 8);
919 if (!auth_ctx->challenge.set_by) {
920 generate_random_buffer(chal, 8);
922 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
923 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
924 auth_ctx->challenge.set_by = "random";
927 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
928 auth_ctx->challenge.set_by));
934 * NTLM2 authentication modifies the effective challenge,
935 * @param challenge The new challenge value
937 static NTSTATUS ntlm_auth_set_challenge(struct auth4_context *auth_ctx, const uint8_t chal[8], const char *set_by)
939 auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
940 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
942 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
943 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
949 * Check the password on an NTLMSSP login.
951 * Return the session keys used on the connection.
954 static NTSTATUS winbind_pw_check(struct auth4_context *auth4_context,
956 const struct auth_usersupplied_info *user_info,
957 uint8_t *pauthoritative,
958 void **server_returned_info,
959 DATA_BLOB *session_key, DATA_BLOB *lm_session_key)
962 char *error_string = NULL;
964 uint8_t user_sess_key[16];
965 char *unix_name = NULL;
967 nt_status = contact_winbind_auth_crap(user_info->client.account_name, user_info->client.domain_name,
968 user_info->workstation_name,
969 &auth4_context->challenge.data,
970 &user_info->password.response.lanman,
971 &user_info->password.response.nt,
972 WBFLAG_PAM_LMKEY | WBFLAG_PAM_USER_SESSION_KEY | WBFLAG_PAM_UNIX_NAME,
974 lm_key, user_sess_key,
976 &error_string, &unix_name);
978 if (NT_STATUS_IS_OK(nt_status)) {
979 if (!all_zero(lm_key, 8)) {
980 *lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
981 memcpy(lm_session_key->data, lm_key, 8);
982 memset(lm_session_key->data+8, '\0', 8);
985 if (!all_zero(user_sess_key, 16)) {
986 *session_key = data_blob_talloc(mem_ctx, user_sess_key, 16);
988 *server_returned_info = talloc_strdup(mem_ctx,
991 DEBUG(NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED) ? 0 : 3,
992 ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
993 user_info->client.domain_name, user_info->client.account_name,
994 user_info->workstation_name,
995 error_string ? error_string : "unknown error (NULL)"));
998 SAFE_FREE(error_string);
999 SAFE_FREE(unix_name);
1003 static NTSTATUS local_pw_check(struct auth4_context *auth4_context,
1004 TALLOC_CTX *mem_ctx,
1005 const struct auth_usersupplied_info *user_info,
1006 uint8_t *pauthoritative,
1007 void **server_returned_info,
1008 DATA_BLOB *session_key, DATA_BLOB *lm_session_key)
1011 struct samr_Password lm_pw, nt_pw;
1013 nt_lm_owf_gen (opt_password, nt_pw.hash, lm_pw.hash);
1015 *pauthoritative = 1;
1017 nt_status = ntlm_password_check(mem_ctx,
1018 true, NTLM_AUTH_ON, 0,
1019 &auth4_context->challenge.data,
1020 &user_info->password.response.lanman,
1021 &user_info->password.response.nt,
1022 user_info->client.account_name,
1023 user_info->client.account_name,
1024 user_info->client.domain_name,
1025 &lm_pw, &nt_pw, session_key, lm_session_key);
1027 if (NT_STATUS_IS_OK(nt_status)) {
1028 *server_returned_info = talloc_asprintf(mem_ctx,
1029 "%s%c%s", user_info->client.domain_name,
1030 *lp_winbind_separator(),
1031 user_info->client.account_name);
1033 DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
1034 user_info->client.domain_name, user_info->client.account_name,
1035 user_info->workstation_name,
1036 nt_errstr(nt_status)));
1041 static NTSTATUS ntlm_auth_prepare_gensec_client(TALLOC_CTX *mem_ctx,
1042 struct loadparm_context *lp_ctx,
1043 struct gensec_security **gensec_security_out)
1045 struct gensec_security *gensec_security = NULL;
1047 TALLOC_CTX *tmp_ctx;
1048 const struct gensec_security_ops **backends = NULL;
1049 struct gensec_settings *gensec_settings = NULL;
1052 tmp_ctx = talloc_new(mem_ctx);
1053 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
1055 gensec_settings = lpcfg_gensec_settings(tmp_ctx, lp_ctx);
1056 if (gensec_settings == NULL) {
1057 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1058 TALLOC_FREE(tmp_ctx);
1059 return NT_STATUS_NO_MEMORY;
1062 backends = talloc_zero_array(gensec_settings,
1063 const struct gensec_security_ops *, 4);
1064 if (backends == NULL) {
1065 TALLOC_FREE(tmp_ctx);
1066 return NT_STATUS_NO_MEMORY;
1068 gensec_settings->backends = backends;
1072 /* These need to be in priority order, krb5 before NTLMSSP */
1073 #if defined(HAVE_KRB5)
1074 backends[idx++] = &gensec_gse_krb5_security_ops;
1077 backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_NTLMSSP);
1079 backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_SPNEGO);
1081 nt_status = gensec_client_start(NULL, &gensec_security,
1083 if (!NT_STATUS_IS_OK(nt_status)) {
1084 TALLOC_FREE(tmp_ctx);
1088 talloc_unlink(tmp_ctx, gensec_settings);
1090 if (opt_target_service != NULL) {
1091 nt_status = gensec_set_target_service(gensec_security,
1092 opt_target_service);
1093 if (!NT_STATUS_IS_OK(nt_status)) {
1094 TALLOC_FREE(tmp_ctx);
1099 if (opt_target_hostname != NULL) {
1100 nt_status = gensec_set_target_hostname(gensec_security,
1101 opt_target_hostname);
1102 if (!NT_STATUS_IS_OK(nt_status)) {
1103 TALLOC_FREE(tmp_ctx);
1108 *gensec_security_out = talloc_steal(mem_ctx, gensec_security);
1109 TALLOC_FREE(tmp_ctx);
1110 return NT_STATUS_OK;
1113 static struct auth4_context *make_auth4_context_ntlm_auth(TALLOC_CTX *mem_ctx, bool local_pw)
1115 struct auth4_context *auth4_context = talloc_zero(mem_ctx, struct auth4_context);
1116 if (auth4_context == NULL) {
1117 DEBUG(10, ("failed to allocate auth4_context failed\n"));
1120 auth4_context->generate_session_info = ntlm_auth_generate_session_info;
1121 auth4_context->generate_session_info_pac = ntlm_auth_generate_session_info_pac;
1122 auth4_context->get_ntlm_challenge = ntlm_auth_get_challenge;
1123 auth4_context->set_ntlm_challenge = ntlm_auth_set_challenge;
1125 auth4_context->check_ntlm_password = local_pw_check;
1127 auth4_context->check_ntlm_password = winbind_pw_check;
1129 auth4_context->private_data = NULL;
1130 return auth4_context;
1133 static NTSTATUS ntlm_auth_prepare_gensec_server(TALLOC_CTX *mem_ctx,
1134 struct loadparm_context *lp_ctx,
1135 struct gensec_security **gensec_security_out)
1137 struct gensec_security *gensec_security;
1140 TALLOC_CTX *tmp_ctx;
1141 const struct gensec_security_ops **backends;
1142 struct gensec_settings *gensec_settings;
1144 struct cli_credentials *server_credentials;
1146 struct auth4_context *auth4_context;
1148 tmp_ctx = talloc_new(mem_ctx);
1149 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
1151 auth4_context = make_auth4_context_ntlm_auth(tmp_ctx, opt_password);
1152 if (auth4_context == NULL) {
1153 TALLOC_FREE(tmp_ctx);
1154 return NT_STATUS_NO_MEMORY;
1157 gensec_settings = lpcfg_gensec_settings(tmp_ctx, lp_ctx);
1158 if (lp_ctx == NULL) {
1159 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1160 TALLOC_FREE(tmp_ctx);
1161 return NT_STATUS_NO_MEMORY;
1165 * This should be a 'netbios domain -> DNS domain'
1166 * mapping, and can currently validly return NULL on
1167 * poorly configured systems.
1169 * This is used for the NTLMSSP server
1173 gensec_settings->server_netbios_name = lp_netbios_name();
1174 gensec_settings->server_netbios_domain = lp_workgroup();
1176 gensec_settings->server_netbios_name = get_winbind_netbios_name();
1177 gensec_settings->server_netbios_domain = get_winbind_domain();
1180 gensec_settings->server_dns_domain = strlower_talloc(gensec_settings,
1181 get_mydnsdomname(talloc_tos()));
1182 gensec_settings->server_dns_name = strlower_talloc(gensec_settings,
1183 get_mydnsfullname());
1185 backends = talloc_zero_array(gensec_settings,
1186 const struct gensec_security_ops *, 4);
1188 if (backends == NULL) {
1189 TALLOC_FREE(tmp_ctx);
1190 return NT_STATUS_NO_MEMORY;
1192 gensec_settings->backends = backends;
1196 /* These need to be in priority order, krb5 before NTLMSSP */
1197 #if defined(HAVE_KRB5)
1198 backends[idx++] = &gensec_gse_krb5_security_ops;
1201 backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_NTLMSSP);
1203 backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_SPNEGO);
1206 * This is anonymous for now, because we just use it
1207 * to set the kerberos state at the moment
1209 server_credentials = cli_credentials_init_anon(tmp_ctx);
1210 if (!server_credentials) {
1211 DEBUG(0, ("auth_generic_prepare: Failed to init server credentials\n"));
1212 return NT_STATUS_NO_MEMORY;
1215 cli_credentials_set_conf(server_credentials, lp_ctx);
1217 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC || lp_security() == SEC_ADS || USE_KERBEROS_KEYTAB) {
1218 cli_credentials_set_kerberos_state(server_credentials, CRED_AUTO_USE_KERBEROS);
1220 cli_credentials_set_kerberos_state(server_credentials, CRED_DONT_USE_KERBEROS);
1223 nt_status = gensec_server_start(tmp_ctx, gensec_settings,
1224 auth4_context, &gensec_security);
1226 if (!NT_STATUS_IS_OK(nt_status)) {
1227 TALLOC_FREE(tmp_ctx);
1231 gensec_set_credentials(gensec_security, server_credentials);
1234 * TODO: Allow the caller to pass their own description here
1235 * via a command-line option
1237 nt_status = gensec_set_target_service_description(gensec_security,
1239 if (!NT_STATUS_IS_OK(nt_status)) {
1240 TALLOC_FREE(tmp_ctx);
1244 talloc_unlink(tmp_ctx, lp_ctx);
1245 talloc_unlink(tmp_ctx, server_credentials);
1246 talloc_unlink(tmp_ctx, gensec_settings);
1247 talloc_unlink(tmp_ctx, auth4_context);
1249 *gensec_security_out = talloc_steal(mem_ctx, gensec_security);
1250 TALLOC_FREE(tmp_ctx);
1251 return NT_STATUS_OK;
1254 static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode,
1255 struct loadparm_context *lp_ctx,
1256 struct ntlm_auth_state *state,
1257 char *buf, int length, void **private2)
1259 manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
1263 static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode,
1264 struct loadparm_context *lp_ctx,
1265 struct ntlm_auth_state *state,
1266 char *buf, int length, void **private2)
1271 pass=(char *)memchr(buf,' ',length);
1273 DEBUG(2, ("Password not found. Denying access\n"));
1280 if (state->helper_mode == SQUID_2_5_BASIC) {
1281 char *end = rfc1738_unescape(user);
1282 if (end == NULL || (end - user) != strlen(user)) {
1283 DEBUG(2, ("Badly rfc1738 encoded username: %s; "
1284 "denying access\n", user));
1288 end = rfc1738_unescape(pass);
1289 if (end == NULL || (end - pass) != strlen(pass)) {
1290 DEBUG(2, ("Badly encoded password for %s; "
1291 "denying access\n", user));
1297 if (check_plaintext_auth(user, pass, False)) {
1304 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
1305 struct loadparm_context *lp_ctx,
1306 char *buf, int length, void **private1)
1309 DATA_BLOB out = data_blob(NULL, 0);
1310 char *out_base64 = NULL;
1311 const char *reply_arg = NULL;
1312 struct gensec_ntlm_state {
1313 struct gensec_security *gensec_state;
1314 const char *set_password;
1316 struct gensec_ntlm_state *state;
1320 const char *reply_code;
1321 struct cli_credentials *creds;
1323 static char *want_feature_list = NULL;
1324 static DATA_BLOB session_key;
1326 TALLOC_CTX *mem_ctx;
1328 mem_ctx = talloc_named(NULL, 0, "manage_gensec_request internal mem_ctx");
1331 state = (struct gensec_ntlm_state *)*private1;
1333 state = talloc_zero(NULL, struct gensec_ntlm_state);
1335 printf("BH No Memory\n");
1340 state->set_password = opt_password;
1344 if (strlen(buf) < 2) {
1345 DEBUG(1, ("query [%s] invalid", buf));
1346 printf("BH Query invalid\n");
1347 talloc_free(mem_ctx);
1351 if (strlen(buf) > 3) {
1352 if(strncmp(buf, "SF ", 3) == 0) {
1353 DEBUG(10, ("Setting flags to negotiate\n"));
1354 talloc_free(want_feature_list);
1355 want_feature_list = talloc_strndup(state, buf+3, strlen(buf)-3);
1357 talloc_free(mem_ctx);
1360 in = base64_decode_data_blob_talloc(mem_ctx, buf + 3);
1362 in = data_blob(NULL, 0);
1365 if (strncmp(buf, "YR", 2) == 0) {
1366 if (state->gensec_state) {
1367 talloc_free(state->gensec_state);
1368 state->gensec_state = NULL;
1370 } else if ( (strncmp(buf, "OK", 2) == 0)) {
1371 /* Just return BH, like ntlm_auth from Samba 3 does. */
1372 printf("BH Command expected\n");
1373 talloc_free(mem_ctx);
1375 } else if ( (strncmp(buf, "TT ", 3) != 0) &&
1376 (strncmp(buf, "KK ", 3) != 0) &&
1377 (strncmp(buf, "AF ", 3) != 0) &&
1378 (strncmp(buf, "NA ", 3) != 0) &&
1379 (strncmp(buf, "UG", 2) != 0) &&
1380 (strncmp(buf, "PW ", 3) != 0) &&
1381 (strncmp(buf, "GK", 2) != 0) &&
1382 (strncmp(buf, "GF", 2) != 0)) {
1383 DEBUG(1, ("SPNEGO request [%s] invalid prefix\n", buf));
1384 printf("BH SPNEGO request invalid prefix\n");
1385 talloc_free(mem_ctx);
1390 if (!(state->gensec_state)) {
1391 switch (stdio_helper_mode) {
1392 case GSS_SPNEGO_CLIENT:
1394 * cached credentials are only supported by
1395 * NTLMSSP_CLIENT_1 for now.
1397 use_cached_creds = false;
1399 case NTLMSSP_CLIENT_1:
1400 /* setup the client side */
1402 if (state->set_password != NULL) {
1403 use_cached_creds = false;
1406 if (use_cached_creds) {
1407 struct wbcCredentialCacheParams params;
1408 struct wbcCredentialCacheInfo *info = NULL;
1409 struct wbcAuthErrorInfo *error = NULL;
1412 params.account_name = opt_username;
1413 params.domain_name = opt_domain;
1414 params.level = WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP;
1415 params.num_blobs = 0;
1416 params.blobs = NULL;
1418 wbc_status = wbcCredentialCache(¶ms, &info,
1420 wbcFreeMemory(error);
1421 if (!WBC_ERROR_IS_OK(wbc_status)) {
1422 use_cached_creds = false;
1424 wbcFreeMemory(info);
1427 nt_status = ntlm_auth_prepare_gensec_client(state, lp_ctx,
1428 &state->gensec_state);
1429 if (!NT_STATUS_IS_OK(nt_status)) {
1430 printf("BH GENSEC mech failed to start: %s\n",
1431 nt_errstr(nt_status));
1432 talloc_free(mem_ctx);
1436 creds = cli_credentials_init(state->gensec_state);
1437 cli_credentials_set_conf(creds, lp_ctx);
1439 cli_credentials_set_username(creds, opt_username, CRED_SPECIFIED);
1442 cli_credentials_set_domain(creds, opt_domain, CRED_SPECIFIED);
1444 if (use_cached_creds) {
1445 gensec_want_feature(state->gensec_state,
1446 GENSEC_FEATURE_NTLM_CCACHE);
1447 } else if (state->set_password) {
1448 cli_credentials_set_password(creds, state->set_password, CRED_SPECIFIED);
1450 cli_credentials_set_password_callback(creds, get_password);
1452 if (opt_workstation) {
1453 cli_credentials_set_workstation(creds, opt_workstation, CRED_SPECIFIED);
1456 gensec_set_credentials(state->gensec_state, creds);
1459 case GSS_SPNEGO_SERVER:
1460 case SQUID_2_5_NTLMSSP:
1462 nt_status = ntlm_auth_prepare_gensec_server(state, lp_ctx,
1463 &state->gensec_state);
1464 if (!NT_STATUS_IS_OK(nt_status)) {
1465 printf("BH GENSEC mech failed to start: %s\n",
1466 nt_errstr(nt_status));
1467 talloc_free(mem_ctx);
1473 talloc_free(mem_ctx);
1477 gensec_want_feature_list(state->gensec_state, want_feature_list);
1479 /* Session info is not complete, do not pass to auth log */
1480 gensec_want_feature(state->gensec_state, GENSEC_FEATURE_NO_AUTHZ_LOG);
1482 switch (stdio_helper_mode) {
1483 case GSS_SPNEGO_CLIENT:
1484 case GSS_SPNEGO_SERVER:
1485 nt_status = gensec_start_mech_by_oid(state->gensec_state, GENSEC_OID_SPNEGO);
1490 case NTLMSSP_CLIENT_1:
1495 case SQUID_2_5_NTLMSSP:
1496 nt_status = gensec_start_mech_by_oid(state->gensec_state, GENSEC_OID_NTLMSSP);
1499 talloc_free(mem_ctx);
1503 if (!NT_STATUS_IS_OK(nt_status)) {
1504 DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status)));
1505 printf("BH GENSEC mech failed to start\n");
1506 talloc_free(mem_ctx);
1514 if (strncmp(buf, "PW ", 3) == 0) {
1515 state->set_password = talloc_strndup(state,
1516 (const char *)in.data,
1519 cli_credentials_set_password(gensec_get_credentials(state->gensec_state),
1520 state->set_password,
1523 talloc_free(mem_ctx);
1527 if (strncmp(buf, "GK", 2) == 0) {
1529 DEBUG(10, ("Requested session key\n"));
1530 nt_status = gensec_session_key(state->gensec_state, mem_ctx, &session_key);
1531 if(!NT_STATUS_IS_OK(nt_status)) {
1532 DEBUG(1, ("gensec_session_key failed: %s\n", nt_errstr(nt_status)));
1533 printf("BH No session key\n");
1534 talloc_free(mem_ctx);
1537 base64_key = base64_encode_data_blob(state, session_key);
1538 SMB_ASSERT(base64_key != NULL);
1539 printf("GK %s\n", base64_key);
1540 talloc_free(base64_key);
1542 talloc_free(mem_ctx);
1546 if (strncmp(buf, "GF", 2) == 0) {
1549 DEBUG(10, ("Requested negotiated NTLMSSP feature flags\n"));
1551 neg_flags = gensec_ntlmssp_neg_flags(state->gensec_state);
1552 if (neg_flags == 0) {
1554 talloc_free(mem_ctx);
1558 printf("GF 0x%08x\n", neg_flags);
1559 talloc_free(mem_ctx);
1563 nt_status = gensec_update(state->gensec_state, mem_ctx, in, &out);
1565 /* don't leak 'bad password'/'no such user' info to the network client */
1566 nt_status = nt_status_squash(nt_status);
1569 out_base64 = base64_encode_data_blob(mem_ctx, out);
1570 SMB_ASSERT(out_base64 != NULL);
1575 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1577 if (first && state->gensec_state->gensec_role == GENSEC_CLIENT) {
1579 } else if (state->gensec_state->gensec_role == GENSEC_CLIENT) {
1581 } else if (state->gensec_state->gensec_role == GENSEC_SERVER) {
1588 } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) {
1589 reply_code = "BH NT_STATUS_ACCESS_DENIED";
1590 reply_arg = nt_errstr(nt_status);
1591 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
1592 } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_UNSUCCESSFUL)) {
1593 reply_code = "BH NT_STATUS_UNSUCCESSFUL";
1594 reply_arg = nt_errstr(nt_status);
1595 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
1596 } else if (!NT_STATUS_IS_OK(nt_status)) {
1598 reply_arg = nt_errstr(nt_status);
1599 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
1600 } else if /* OK */ (state->gensec_state->gensec_role == GENSEC_SERVER) {
1601 struct auth_session_info *session_info;
1603 nt_status = gensec_session_info(state->gensec_state, mem_ctx, &session_info);
1604 if (!NT_STATUS_IS_OK(nt_status)) {
1605 reply_code = "BH Failed to retrieve session info";
1606 reply_arg = nt_errstr(nt_status);
1607 DEBUG(1, ("GENSEC failed to retrieve the session info: %s\n", nt_errstr(nt_status)));
1611 reply_arg = talloc_strdup(state->gensec_state, session_info->unix_info->unix_name);
1612 if (reply_arg == NULL) {
1613 reply_code = "BH out of memory";
1614 reply_arg = nt_errstr(NT_STATUS_NO_MEMORY);
1616 talloc_free(session_info);
1618 } else if (state->gensec_state->gensec_role == GENSEC_CLIENT) {
1620 reply_arg = out_base64;
1625 switch (stdio_helper_mode) {
1626 case GSS_SPNEGO_SERVER:
1627 printf("%s %s %s\n", reply_code,
1628 out_base64 ? out_base64 : "*",
1629 reply_arg ? reply_arg : "*");
1633 printf("%s %s\n", reply_code, out_base64);
1634 } else if (reply_arg) {
1635 printf("%s %s\n", reply_code, reply_arg);
1637 printf("%s\n", reply_code);
1641 talloc_free(mem_ctx);
1645 static void manage_gss_spnego_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_squid_ntlmssp_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 manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
1663 static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode,
1664 struct loadparm_context *lp_ctx,
1665 struct ntlm_auth_state *state,
1666 char *buf, int length, void **private2)
1668 manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
1672 static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode,
1673 struct loadparm_context *lp_ctx,
1674 struct ntlm_auth_state *state,
1675 char *buf, int length, void **private2)
1677 char *request, *parameter;
1678 static DATA_BLOB challenge;
1679 static DATA_BLOB lm_response;
1680 static DATA_BLOB nt_response;
1681 static char *full_username;
1682 static char *username;
1683 static char *domain;
1684 static char *plaintext_password;
1685 static bool ntlm_server_1_user_session_key;
1686 static bool ntlm_server_1_lm_session_key;
1688 if (strequal(buf, ".")) {
1689 if (!full_username && !username) {
1690 printf("Error: No username supplied!\n");
1691 } else if (plaintext_password) {
1692 /* handle this request as plaintext */
1693 if (!full_username) {
1694 if (asprintf(&full_username, "%s%c%s", domain, winbind_separator(), username) == -1) {
1695 printf("Error: Out of memory in "
1700 if (check_plaintext_auth(full_username, plaintext_password, False)) {
1701 printf("Authenticated: Yes\n");
1703 printf("Authenticated: No\n");
1705 } else if (!lm_response.data && !nt_response.data) {
1706 printf("Error: No password supplied!\n");
1707 } else if (!challenge.data) {
1708 printf("Error: No lanman-challenge supplied!\n");
1710 char *error_string = NULL;
1712 uchar user_session_key[16];
1715 if (full_username && !username) {
1717 fstring fstr_domain;
1719 if (!parse_ntlm_auth_domain_user(full_username, fstr_user, fstr_domain)) {
1720 /* username might be 'tainted', don't print into our new-line deleimianted stream */
1721 printf("Error: Could not parse into "
1722 "domain and username\n");
1724 SAFE_FREE(username);
1726 username = smb_xstrdup(fstr_user);
1727 domain = smb_xstrdup(fstr_domain);
1731 DATA_BLOB nt_session_key, lm_session_key;
1732 struct samr_Password lm_pw, nt_pw;
1733 TALLOC_CTX *mem_ctx = talloc_new(NULL);
1734 ZERO_STRUCT(user_session_key);
1735 ZERO_STRUCT(lm_key);
1737 nt_lm_owf_gen (opt_password, nt_pw.hash, lm_pw.hash);
1738 nt_status = ntlm_password_check(mem_ctx,
1751 error_string = smb_xstrdup(get_friendly_nt_error_msg(nt_status));
1752 if (ntlm_server_1_user_session_key) {
1753 if (nt_session_key.length == sizeof(user_session_key)) {
1754 memcpy(user_session_key,
1755 nt_session_key.data,
1756 sizeof(user_session_key));
1759 if (ntlm_server_1_lm_session_key) {
1760 if (lm_session_key.length == sizeof(lm_key)) {
1762 lm_session_key.data,
1766 TALLOC_FREE(mem_ctx);
1769 uint8_t authoritative = 0;
1772 domain = smb_xstrdup(get_winbind_domain());
1775 if (ntlm_server_1_lm_session_key)
1776 flags |= WBFLAG_PAM_LMKEY;
1778 if (ntlm_server_1_user_session_key)
1779 flags |= WBFLAG_PAM_USER_SESSION_KEY;
1781 nt_status = contact_winbind_auth_crap(username,
1795 if (!NT_STATUS_IS_OK(nt_status)) {
1796 printf("Authenticated: No\n");
1797 printf("Authentication-Error: %s\n.\n",
1801 char *hex_user_session_key;
1803 printf("Authenticated: Yes\n");
1805 if (ntlm_server_1_lm_session_key
1806 && (!all_zero(lm_key,
1808 hex_lm_key = hex_encode_talloc(NULL,
1809 (const unsigned char *)lm_key,
1811 printf("LANMAN-Session-Key: %s\n",
1813 TALLOC_FREE(hex_lm_key);
1816 if (ntlm_server_1_user_session_key
1817 && (!all_zero(user_session_key,
1818 sizeof(user_session_key)))) {
1819 hex_user_session_key = hex_encode_talloc(NULL,
1820 (const unsigned char *)user_session_key,
1821 sizeof(user_session_key));
1822 printf("User-Session-Key: %s\n",
1823 hex_user_session_key);
1824 TALLOC_FREE(hex_user_session_key);
1827 SAFE_FREE(error_string);
1829 /* clear out the state */
1830 challenge = data_blob_null;
1831 nt_response = data_blob_null;
1832 lm_response = data_blob_null;
1833 SAFE_FREE(full_username);
1834 SAFE_FREE(username);
1836 SAFE_FREE(plaintext_password);
1837 ntlm_server_1_user_session_key = False;
1838 ntlm_server_1_lm_session_key = False;
1846 /* Indicates a base64 encoded structure */
1847 parameter = strstr_m(request, ":: ");
1849 parameter = strstr_m(request, ": ");
1852 DEBUG(0, ("Parameter not found!\n"));
1853 printf("Error: Parameter not found!\n.\n");
1870 base64_decode_inplace(parameter);
1873 if (strequal(request, "LANMAN-Challenge")) {
1874 challenge = strhex_to_data_blob(NULL, parameter);
1875 if (challenge.length != 8) {
1876 printf("Error: hex decode of %s failed! "
1877 "(got %d bytes, expected 8)\n.\n",
1879 (int)challenge.length);
1880 challenge = data_blob_null;
1882 } else if (strequal(request, "NT-Response")) {
1883 nt_response = strhex_to_data_blob(NULL, parameter);
1884 if (nt_response.length < 24) {
1885 printf("Error: hex decode of %s failed! "
1886 "(only got %d bytes, needed at least 24)\n.\n",
1888 (int)nt_response.length);
1889 nt_response = data_blob_null;
1891 } else if (strequal(request, "LANMAN-Response")) {
1892 lm_response = strhex_to_data_blob(NULL, parameter);
1893 if (lm_response.length != 24) {
1894 printf("Error: hex decode of %s failed! "
1895 "(got %d bytes, expected 24)\n.\n",
1897 (int)lm_response.length);
1898 lm_response = data_blob_null;
1900 } else if (strequal(request, "Password")) {
1901 plaintext_password = smb_xstrdup(parameter);
1902 } else if (strequal(request, "NT-Domain")) {
1903 domain = smb_xstrdup(parameter);
1904 } else if (strequal(request, "Username")) {
1905 username = smb_xstrdup(parameter);
1906 } else if (strequal(request, "Full-Username")) {
1907 full_username = smb_xstrdup(parameter);
1908 } else if (strequal(request, "Request-User-Session-Key")) {
1909 ntlm_server_1_user_session_key = strequal(parameter, "Yes");
1910 } else if (strequal(request, "Request-LanMan-Session-Key")) {
1911 ntlm_server_1_lm_session_key = strequal(parameter, "Yes");
1913 printf("Error: Unknown request %s\n.\n", request);
1917 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode,
1918 struct loadparm_context *lp_ctx,
1919 struct ntlm_auth_state *state,
1920 char *buf, int length, void **private2)
1922 char *request, *parameter;
1923 static DATA_BLOB new_nt_pswd;
1924 static DATA_BLOB old_nt_hash_enc;
1925 static DATA_BLOB new_lm_pswd;
1926 static DATA_BLOB old_lm_hash_enc;
1927 static char *full_username = NULL;
1928 static char *username = NULL;
1929 static char *domain = NULL;
1930 static char *newpswd = NULL;
1931 static char *oldpswd = NULL;
1933 if (strequal(buf, ".")) {
1934 if(newpswd && oldpswd) {
1935 uchar old_nt_hash[16];
1936 uchar old_lm_hash[16];
1937 uchar new_nt_hash[16];
1938 uchar new_lm_hash[16];
1940 new_nt_pswd = data_blob(NULL, 516);
1941 old_nt_hash_enc = data_blob(NULL, 16);
1943 /* Calculate the MD4 hash (NT compatible) of the
1945 E_md4hash(oldpswd, old_nt_hash);
1946 E_md4hash(newpswd, new_nt_hash);
1948 /* E_deshash returns false for 'long'
1949 passwords (> 14 DOS chars).
1951 Therefore, don't send a buffer
1952 encrypted with the truncated hash
1953 (it could allow an even easier
1954 attack on the password)
1956 Likewise, obey the admin's restriction
1959 if (lp_client_lanman_auth() &&
1960 E_deshash(newpswd, new_lm_hash) &&
1961 E_deshash(oldpswd, old_lm_hash)) {
1962 new_lm_pswd = data_blob(NULL, 516);
1963 old_lm_hash_enc = data_blob(NULL, 16);
1964 encode_pw_buffer(new_lm_pswd.data, newpswd,
1967 arcfour_crypt(new_lm_pswd.data, old_nt_hash, 516);
1968 E_old_pw_hash(new_nt_hash, old_lm_hash,
1969 old_lm_hash_enc.data);
1971 new_lm_pswd.data = NULL;
1972 new_lm_pswd.length = 0;
1973 old_lm_hash_enc.data = NULL;
1974 old_lm_hash_enc.length = 0;
1977 encode_pw_buffer(new_nt_pswd.data, newpswd,
1980 arcfour_crypt(new_nt_pswd.data, old_nt_hash, 516);
1981 E_old_pw_hash(new_nt_hash, old_nt_hash,
1982 old_nt_hash_enc.data);
1985 if (!full_username && !username) {
1986 printf("Error: No username supplied!\n");
1987 } else if ((!new_nt_pswd.data || !old_nt_hash_enc.data) &&
1988 (!new_lm_pswd.data || old_lm_hash_enc.data) ) {
1989 printf("Error: No NT or LM password "
1990 "blobs supplied!\n");
1992 char *error_string = NULL;
1994 if (full_username && !username) {
1996 fstring fstr_domain;
1998 if (!parse_ntlm_auth_domain_user(full_username,
2001 /* username might be 'tainted', don't
2002 * print into our new-line
2003 * deleimianted stream */
2004 printf("Error: Could not "
2005 "parse into domain and "
2007 SAFE_FREE(username);
2008 username = smb_xstrdup(full_username);
2010 SAFE_FREE(username);
2012 username = smb_xstrdup(fstr_user);
2013 domain = smb_xstrdup(fstr_domain);
2018 if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
2025 printf("Password-Change: No\n");
2026 printf("Password-Change-Error: %s\n.\n",
2029 printf("Password-Change: Yes\n");
2032 SAFE_FREE(error_string);
2034 /* clear out the state */
2035 new_nt_pswd = data_blob_null;
2036 old_nt_hash_enc = data_blob_null;
2037 new_lm_pswd = data_blob_null;
2038 old_nt_hash_enc = data_blob_null;
2039 SAFE_FREE(full_username);
2040 SAFE_FREE(username);
2051 /* Indicates a base64 encoded structure */
2052 parameter = strstr_m(request, ":: ");
2054 parameter = strstr_m(request, ": ");
2057 DEBUG(0, ("Parameter not found!\n"));
2058 printf("Error: Parameter not found!\n.\n");
2074 base64_decode_inplace(parameter);
2077 if (strequal(request, "new-nt-password-blob")) {
2078 new_nt_pswd = strhex_to_data_blob(NULL, parameter);
2079 if (new_nt_pswd.length != 516) {
2080 printf("Error: hex decode of %s failed! "
2081 "(got %d bytes, expected 516)\n.\n",
2083 (int)new_nt_pswd.length);
2084 new_nt_pswd = data_blob_null;
2086 } else if (strequal(request, "old-nt-hash-blob")) {
2087 old_nt_hash_enc = strhex_to_data_blob(NULL, parameter);
2088 if (old_nt_hash_enc.length != 16) {
2089 printf("Error: hex decode of %s failed! "
2090 "(got %d bytes, expected 16)\n.\n",
2092 (int)old_nt_hash_enc.length);
2093 old_nt_hash_enc = data_blob_null;
2095 } else if (strequal(request, "new-lm-password-blob")) {
2096 new_lm_pswd = strhex_to_data_blob(NULL, parameter);
2097 if (new_lm_pswd.length != 516) {
2098 printf("Error: hex decode of %s failed! "
2099 "(got %d bytes, expected 516)\n.\n",
2101 (int)new_lm_pswd.length);
2102 new_lm_pswd = data_blob_null;
2105 else if (strequal(request, "old-lm-hash-blob")) {
2106 old_lm_hash_enc = strhex_to_data_blob(NULL, parameter);
2107 if (old_lm_hash_enc.length != 16)
2109 printf("Error: hex decode of %s failed! "
2110 "(got %d bytes, expected 16)\n.\n",
2112 (int)old_lm_hash_enc.length);
2113 old_lm_hash_enc = data_blob_null;
2115 } else if (strequal(request, "nt-domain")) {
2116 domain = smb_xstrdup(parameter);
2117 } else if(strequal(request, "username")) {
2118 username = smb_xstrdup(parameter);
2119 } else if(strequal(request, "full-username")) {
2120 username = smb_xstrdup(parameter);
2121 } else if(strequal(request, "new-password")) {
2122 newpswd = smb_xstrdup(parameter);
2123 } else if (strequal(request, "old-password")) {
2124 oldpswd = smb_xstrdup(parameter);
2126 printf("Error: Unknown request %s\n.\n", request);
2130 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode,
2131 struct loadparm_context *lp_ctx,
2132 struct ntlm_auth_state *state,
2133 stdio_helper_function fn, void **private2)
2136 char tmp[INITIAL_BUFFER_SIZE+1];
2137 int length, buf_size = 0;
2140 buf = talloc_strdup(state->mem_ctx, "");
2142 DEBUG(0, ("Failed to allocate input buffer.\n"));
2143 fprintf(stderr, "ERR\n");
2149 /* this is not a typo - x_fgets doesn't work too well under
2151 if (fgets(tmp, sizeof(tmp)-1, stdin) == NULL) {
2152 if (ferror(stdin)) {
2153 DEBUG(1, ("fgets() failed! dying..... errno=%d "
2154 "(%s)\n", ferror(stdin),
2155 strerror(ferror(stdin))));
2162 buf = talloc_strdup_append_buffer(buf, tmp);
2163 buf_size += INITIAL_BUFFER_SIZE;
2165 if (buf_size > MAX_BUFFER_SIZE) {
2166 DEBUG(2, ("Oversized message\n"));
2167 fprintf(stderr, "ERR\n");
2172 c = strchr(buf, '\n');
2173 } while (c == NULL);
2178 DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf,length));
2180 if (buf[0] == '\0') {
2181 DEBUG(2, ("Invalid Request\n"));
2182 fprintf(stderr, "ERR\n");
2187 fn(stdio_helper_mode, lp_ctx, state, buf, length, private2);
2192 static void squid_stream(enum stdio_helper_mode stdio_mode,
2193 struct loadparm_context *lp_ctx,
2194 stdio_helper_function fn) {
2195 TALLOC_CTX *mem_ctx;
2196 struct ntlm_auth_state *state;
2198 /* initialize FDescs */
2199 setbuf(stdout, NULL);
2200 setbuf(stderr, NULL);
2202 mem_ctx = talloc_init("ntlm_auth");
2204 DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
2205 fprintf(stderr, "ERR\n");
2209 state = talloc_zero(mem_ctx, struct ntlm_auth_state);
2211 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
2212 fprintf(stderr, "ERR\n");
2216 state->mem_ctx = mem_ctx;
2217 state->helper_mode = stdio_mode;
2220 TALLOC_CTX *frame = talloc_stackframe();
2221 manage_squid_request(stdio_mode, lp_ctx, state, fn, NULL);
2227 /* Authenticate a user with a challenge/response */
2229 static bool check_auth_crap(void)
2234 char user_session_key[16];
2236 char *hex_user_session_key;
2238 uint8_t authoritative = 0;
2240 setbuf(stdout, NULL);
2243 flags |= WBFLAG_PAM_LMKEY;
2245 if (request_user_session_key)
2246 flags |= WBFLAG_PAM_USER_SESSION_KEY;
2248 flags |= WBFLAG_PAM_NT_STATUS_SQUASH;
2250 nt_status = contact_winbind_auth_crap(opt_username, opt_domain,
2256 (unsigned char *)lm_key,
2257 (unsigned char *)user_session_key,
2259 &error_string, NULL);
2261 if (!NT_STATUS_IS_OK(nt_status)) {
2262 printf("%s (0x%x)\n", error_string,
2263 NT_STATUS_V(nt_status));
2264 SAFE_FREE(error_string);
2269 && (!all_zero((uint8_t *)lm_key, sizeof(lm_key)))) {
2270 hex_lm_key = hex_encode_talloc(talloc_tos(), (const unsigned char *)lm_key,
2272 printf("LM_KEY: %s\n", hex_lm_key);
2273 TALLOC_FREE(hex_lm_key);
2275 if (request_user_session_key
2276 && (!all_zero((uint8_t *)user_session_key,
2277 sizeof(user_session_key)))) {
2278 hex_user_session_key = hex_encode_talloc(talloc_tos(), (const unsigned char *)user_session_key,
2279 sizeof(user_session_key));
2280 printf("NT_KEY: %s\n", hex_user_session_key);
2281 TALLOC_FREE(hex_user_session_key);
2290 OPT_USERNAME = 1000,
2299 OPT_USER_SESSION_KEY,
2301 OPT_REQUIRE_MEMBERSHIP,
2302 OPT_USE_CACHED_CREDS,
2304 OPT_PAM_WINBIND_CONF,
2306 OPT_TARGET_HOSTNAME,
2310 int main(int argc, const char **argv)
2312 TALLOC_CTX *frame = talloc_stackframe();
2314 const char *helper_protocol = NULL;
2315 int diagnostics = 0;
2317 const char *hex_challenge = NULL;
2318 const char *hex_lm_response = NULL;
2319 const char *hex_nt_response = NULL;
2320 struct loadparm_context *lp_ctx;
2323 /* NOTE: DO NOT change this interface without considering the implications!
2324 This is an external interface, which other programs will use to interact
2328 /* We do not use single-letter command abbreviations, because they harm future
2329 interface stability. */
2331 struct poptOption long_options[] = {
2333 { "helper-protocol", 0, POPT_ARG_STRING, &helper_protocol, OPT_DOMAIN, "operate as a stdio-based helper", "helper protocol to use"},
2334 { "username", 0, POPT_ARG_STRING, &opt_username, OPT_USERNAME, "username"},
2335 { "domain", 0, POPT_ARG_STRING, &opt_domain, OPT_DOMAIN, "domain name"},
2336 { "workstation", 0, POPT_ARG_STRING, &opt_workstation, OPT_WORKSTATION, "workstation"},
2337 { "challenge", 0, POPT_ARG_STRING, &hex_challenge, OPT_CHALLENGE, "challenge (HEX encoded)"},
2338 { "lm-response", 0, POPT_ARG_STRING, &hex_lm_response, OPT_LM, "LM Response to the challenge (HEX encoded)"},
2339 { "nt-response", 0, POPT_ARG_STRING, &hex_nt_response, OPT_NT, "NT or NTLMv2 Response to the challenge (HEX encoded)"},
2340 { "password", 0, POPT_ARG_STRING, &opt_password, OPT_PASSWORD, "User's plaintext password"},
2341 { "request-lm-key", 0, POPT_ARG_NONE, &request_lm_key, OPT_LM_KEY, "Retrieve LM session key"},
2342 { "request-nt-key", 0, POPT_ARG_NONE, &request_user_session_key, OPT_USER_SESSION_KEY, "Retrieve User (NT) session key"},
2343 { "use-cached-creds", 0, POPT_ARG_NONE, &use_cached_creds, OPT_USE_CACHED_CREDS, "Use cached credentials if no password is given"},
2344 { "allow-mschapv2", 0, POPT_ARG_NONE, &opt_allow_mschapv2, OPT_ALLOW_MSCHAPV2, "Explicitly allow MSCHAPv2" },
2345 { "offline-logon", 0, POPT_ARG_NONE, &offline_logon,
2347 "Use cached passwords when DC is offline"},
2348 { "diagnostics", 0, POPT_ARG_NONE, &diagnostics,
2350 "Perform diagnostics on the authentication chain"},
2351 { "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" },
2352 { "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" },
2353 { "target-service", 0, POPT_ARG_STRING, &opt_target_service, OPT_TARGET_SERVICE, "Target service (eg http)" },
2354 { "target-hostname", 0, POPT_ARG_STRING, &opt_target_hostname, OPT_TARGET_HOSTNAME, "Target hostname" },
2355 POPT_COMMON_CONFIGFILE
2361 /* Samba client initialisation */
2364 setup_logging("ntlm_auth", DEBUG_STDERR);
2369 pc = poptGetContext("ntlm_auth", argc, argv, long_options, 0);
2371 /* Parse command line options */
2374 poptPrintHelp(pc, stderr, 0);
2378 while((opt = poptGetNextOpt(pc)) != -1) {
2379 /* Get generic config options like --configfile */
2382 poptFreeContext(pc);
2384 cmdline_messaging_context(get_dyn_CONFIGFILE());
2386 if (!lp_load_global(get_dyn_CONFIGFILE())) {
2387 d_fprintf(stderr, "ntlm_auth: error opening config file %s. Error was %s\n",
2388 get_dyn_CONFIGFILE(), strerror(errno));
2392 pc = poptGetContext(NULL, argc, (const char **)argv, long_options,
2393 POPT_CONTEXT_KEEP_FIRST);
2395 while((opt = poptGetNextOpt(pc)) != -1) {
2398 opt_challenge = strhex_to_data_blob(NULL, hex_challenge);
2399 if (opt_challenge.length != 8) {
2400 fprintf(stderr, "hex decode of %s failed! "
2401 "(only got %d bytes)\n",
2403 (int)opt_challenge.length);
2408 opt_lm_response = strhex_to_data_blob(NULL, hex_lm_response);
2409 if (opt_lm_response.length != 24) {
2410 fprintf(stderr, "hex decode of %s failed! "
2411 "(only got %d bytes)\n",
2413 (int)opt_lm_response.length);
2419 opt_nt_response = strhex_to_data_blob(NULL, hex_nt_response);
2420 if (opt_nt_response.length < 24) {
2421 fprintf(stderr, "hex decode of %s failed! "
2422 "(only got %d bytes)\n",
2424 (int)opt_nt_response.length);
2429 case OPT_REQUIRE_MEMBERSHIP:
2430 if (strncasecmp_m("S-", require_membership_of, 2) == 0) {
2431 require_membership_of_sid = require_membership_of;
2438 char *domain = SMB_STRDUP(opt_username);
2439 char *p = strchr_m(domain, *lp_winbind_separator());
2443 if (opt_domain && !strequal(opt_domain, domain)) {
2444 fprintf(stderr, "Domain specified in username (%s) "
2445 "doesn't match specified domain (%s)!\n\n",
2446 domain, opt_domain);
2447 poptPrintHelp(pc, stderr, 0);
2450 opt_domain = domain;
2456 /* Note: if opt_domain is "" then send no domain */
2457 if (opt_domain == NULL) {
2458 opt_domain = get_winbind_domain();
2461 if (opt_workstation == NULL) {
2462 opt_workstation = "";
2465 lp_ctx = loadparm_init_s3(NULL, loadparm_s3_helpers());
2466 if (lp_ctx == NULL) {
2467 fprintf(stderr, "loadparm_init_s3() failed!\n");
2471 if (helper_protocol) {
2473 for (i=0; i<NUM_HELPER_MODES; i++) {
2474 if (strcmp(helper_protocol, stdio_helper_protocols[i].name) == 0) {
2475 squid_stream(stdio_helper_protocols[i].mode, lp_ctx, stdio_helper_protocols[i].fn);
2479 fprintf(stderr, "unknown helper protocol [%s]\n\n"
2480 "Valid helper protools:\n\n", helper_protocol);
2482 for (i=0; i<NUM_HELPER_MODES; i++) {
2483 fprintf(stderr, "%s\n",
2484 stdio_helper_protocols[i].name);
2490 if (!opt_username || !*opt_username) {
2491 fprintf(stderr, "username must be specified!\n\n");
2492 poptPrintHelp(pc, stderr, 0);
2496 if (opt_challenge.length) {
2497 if (!check_auth_crap()) {
2503 if (!opt_password) {
2504 char pwd[256] = {0};
2507 rc = samba_getpass("Password: ", pwd, sizeof(pwd), false, false);
2509 opt_password = SMB_STRDUP(pwd);
2514 if (!diagnose_ntlm_auth()) {
2520 fstr_sprintf(user, "%s%c%s", opt_domain, winbind_separator(), opt_username);
2521 if (!check_plaintext_auth(user, opt_password, True)) {
2528 poptFreeContext(pc);