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 wbcInterfaceDetails *details;
342 static fstring winbind_netbios_name;
344 if (*winbind_netbios_name) {
345 return winbind_netbios_name;
348 /* Send off request */
350 ret = wbcInterfaceDetails(&details);
351 if (!WBC_ERROR_IS_OK(ret)) {
352 DEBUG(1, ("could not obtain winbind netbios name!\n"));
353 return lp_netbios_name();
356 fstrcpy(winbind_netbios_name, details->netbios_name);
358 wbcFreeMemory(details);
360 return winbind_netbios_name;
364 DATA_BLOB get_challenge(void)
366 static DATA_BLOB chal;
367 if (opt_challenge.length)
368 return opt_challenge;
370 chal = data_blob(NULL, 8);
372 generate_random_buffer(chal.data, chal.length);
376 /* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
377 form DOMAIN/user into a domain and a user */
379 static bool parse_ntlm_auth_domain_user(const char *domuser, fstring domain,
383 char *p = strchr(domuser,winbind_separator());
390 fstrcpy(domain, domuser);
391 domain[PTR_DIFF(p, domuser)] = 0;
392 return strupper_m(domain);
395 static bool get_require_membership_sid(void) {
396 fstring domain, name, sidbuf;
397 struct wbcDomainSid sid;
398 enum wbcSidType type;
401 if (!require_membership_of) {
405 if (require_membership_of_sid) {
409 /* Otherwise, ask winbindd for the name->sid request */
411 if (!parse_ntlm_auth_domain_user(require_membership_of,
413 DEBUG(0, ("Could not parse %s into separate domain/name parts!\n",
414 require_membership_of));
418 ret = wbcLookupName(domain, name, &sid, &type);
419 if (!WBC_ERROR_IS_OK(ret)) {
420 DEBUG(0, ("Winbindd lookupname failed to resolve %s into a SID!\n",
421 require_membership_of));
425 wbcSidToStringBuf(&sid, sidbuf, sizeof(sidbuf));
427 require_membership_of_sid = SMB_STRDUP(sidbuf);
429 if (require_membership_of_sid)
436 * Get some configuration from pam_winbind.conf to see if we
437 * need to contact trusted domain
440 int get_pam_winbind_config()
443 struct tiniparser_dictionary *d = NULL;
445 if (!opt_pam_winbind_conf || !*opt_pam_winbind_conf) {
446 opt_pam_winbind_conf = PAM_WINBIND_CONFIG_FILE;
449 d = tiniparser_load(opt_pam_winbind_conf);
455 if (tiniparser_getboolean(d, "global:krb5_auth", false)) {
456 ctrl |= WINBIND_KRB5_AUTH;
459 tiniparser_freedict(d);
464 /* Authenticate a user with a plaintext password */
466 static bool check_plaintext_auth(const char *user, const char *pass,
467 bool stdout_diagnostics)
469 struct winbindd_request request;
470 struct winbindd_response response;
473 if (!get_require_membership_sid()) {
477 /* Send off request */
479 ZERO_STRUCT(request);
480 ZERO_STRUCT(response);
482 fstrcpy(request.data.auth.user, user);
483 fstrcpy(request.data.auth.pass, pass);
484 if (require_membership_of_sid) {
485 strlcpy(request.data.auth.require_membership_of_sid,
486 require_membership_of_sid,
487 sizeof(request.data.auth.require_membership_of_sid));
491 request.flags |= WBFLAG_PAM_CACHED_LOGIN;
494 result = winbindd_request_response(NULL, WINBINDD_PAM_AUTH, &request, &response);
496 /* Display response */
498 if (stdout_diagnostics) {
499 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
500 d_fprintf(stderr, "Reading winbind reply failed! (0x01)\n");
503 d_printf("%s: %s (0x%x)\n",
504 response.data.auth.nt_status_string,
505 response.data.auth.error_string,
506 response.data.auth.nt_status);
508 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
509 DEBUG(1, ("Reading winbind reply failed! (0x01)\n"));
512 DEBUG(3, ("%s: %s (0x%x)\n",
513 response.data.auth.nt_status_string,
514 response.data.auth.error_string,
515 response.data.auth.nt_status));
518 return (result == NSS_STATUS_SUCCESS);
521 /* authenticate a user with an encrypted username/password */
523 NTSTATUS contact_winbind_auth_crap(const char *username,
525 const char *workstation,
526 const DATA_BLOB *challenge,
527 const DATA_BLOB *lm_response,
528 const DATA_BLOB *nt_response,
530 uint32_t extra_logon_parameters,
532 uint8_t user_session_key[16],
533 uint8_t *pauthoritative,
539 struct winbindd_request request;
540 struct winbindd_response response;
544 if (!get_require_membership_sid()) {
545 return NT_STATUS_INVALID_PARAMETER;
548 ZERO_STRUCT(request);
549 ZERO_STRUCT(response);
551 request.flags = flags;
553 request.data.auth_crap.logon_parameters = extra_logon_parameters
554 | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT | MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT;
556 if (opt_allow_mschapv2) {
557 request.data.auth_crap.logon_parameters |= MSV1_0_ALLOW_MSVCHAPV2;
560 if (require_membership_of_sid)
561 fstrcpy(request.data.auth_crap.require_membership_of_sid, require_membership_of_sid);
563 fstrcpy(request.data.auth_crap.user, username);
564 fstrcpy(request.data.auth_crap.domain, domain);
566 fstrcpy(request.data.auth_crap.workstation,
569 memcpy(request.data.auth_crap.chal, challenge->data, MIN(challenge->length, 8));
571 if (lm_response && lm_response->length) {
572 memcpy(request.data.auth_crap.lm_resp,
574 MIN(lm_response->length, sizeof(request.data.auth_crap.lm_resp)));
575 request.data.auth_crap.lm_resp_len = lm_response->length;
578 if (nt_response && nt_response->length) {
579 if (nt_response->length > sizeof(request.data.auth_crap.nt_resp)) {
580 request.flags = request.flags | WBFLAG_BIG_NTLMV2_BLOB;
581 request.extra_len = nt_response->length;
582 request.extra_data.data = SMB_MALLOC_ARRAY(char, request.extra_len);
583 if (request.extra_data.data == NULL) {
584 return NT_STATUS_NO_MEMORY;
586 memcpy(request.extra_data.data, nt_response->data,
587 nt_response->length);
590 memcpy(request.data.auth_crap.nt_resp,
591 nt_response->data, nt_response->length);
593 request.data.auth_crap.nt_resp_len = nt_response->length;
596 result = winbindd_priv_request_response(
598 WINBINDD_PAM_AUTH_CRAP,
601 SAFE_FREE(request.extra_data.data);
603 /* Display response */
605 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
606 nt_status = NT_STATUS_UNSUCCESSFUL;
608 *error_string = smb_xstrdup("Reading winbind reply failed!");
609 winbindd_free_response(&response);
613 nt_status = (NT_STATUS(response.data.auth.nt_status));
614 if (!NT_STATUS_IS_OK(nt_status)) {
616 *error_string = smb_xstrdup(response.data.auth.error_string);
617 *pauthoritative = response.data.auth.authoritative;
618 winbindd_free_response(&response);
622 if ((flags & WBFLAG_PAM_LMKEY) && lm_key) {
623 memcpy(lm_key, response.data.auth.first_8_lm_hash,
624 sizeof(response.data.auth.first_8_lm_hash));
626 if ((flags & WBFLAG_PAM_USER_SESSION_KEY) && user_session_key) {
627 memcpy(user_session_key, response.data.auth.user_session_key,
628 sizeof(response.data.auth.user_session_key));
631 if (flags & WBFLAG_PAM_UNIX_NAME) {
632 *unix_name = SMB_STRDUP(response.data.auth.unix_username);
634 winbindd_free_response(&response);
635 return NT_STATUS_NO_MEMORY;
639 winbindd_free_response(&response);
643 /* contact server to change user password using auth crap */
644 static NTSTATUS contact_winbind_change_pswd_auth_crap(const char *username,
646 const DATA_BLOB new_nt_pswd,
647 const DATA_BLOB old_nt_hash_enc,
648 const DATA_BLOB new_lm_pswd,
649 const DATA_BLOB old_lm_hash_enc,
654 struct winbindd_request request;
655 struct winbindd_response response;
657 if (!get_require_membership_sid())
660 *error_string = smb_xstrdup("Can't get membership sid.");
661 return NT_STATUS_INVALID_PARAMETER;
664 ZERO_STRUCT(request);
665 ZERO_STRUCT(response);
668 fstrcpy(request.data.chng_pswd_auth_crap.user, username);
670 fstrcpy(request.data.chng_pswd_auth_crap.domain,domain);
672 if(new_nt_pswd.length)
674 memcpy(request.data.chng_pswd_auth_crap.new_nt_pswd, new_nt_pswd.data, sizeof(request.data.chng_pswd_auth_crap.new_nt_pswd));
675 request.data.chng_pswd_auth_crap.new_nt_pswd_len = new_nt_pswd.length;
678 if(old_nt_hash_enc.length)
680 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));
681 request.data.chng_pswd_auth_crap.old_nt_hash_enc_len = old_nt_hash_enc.length;
684 if(new_lm_pswd.length)
686 memcpy(request.data.chng_pswd_auth_crap.new_lm_pswd, new_lm_pswd.data, sizeof(request.data.chng_pswd_auth_crap.new_lm_pswd));
687 request.data.chng_pswd_auth_crap.new_lm_pswd_len = new_lm_pswd.length;
690 if(old_lm_hash_enc.length)
692 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));
693 request.data.chng_pswd_auth_crap.old_lm_hash_enc_len = old_lm_hash_enc.length;
696 result = winbindd_request_response(NULL, WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP, &request, &response);
698 /* Display response */
700 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0))
702 nt_status = NT_STATUS_UNSUCCESSFUL;
704 *error_string = smb_xstrdup("Reading winbind reply failed!");
705 winbindd_free_response(&response);
709 nt_status = (NT_STATUS(response.data.auth.nt_status));
710 if (!NT_STATUS_IS_OK(nt_status))
713 *error_string = smb_xstrdup(response.data.auth.error_string);
714 winbindd_free_response(&response);
718 winbindd_free_response(&response);
723 static NTSTATUS ntlm_auth_generate_session_info(struct auth4_context *auth_context,
725 void *server_returned_info,
726 const char *original_user_name,
727 uint32_t session_info_flags,
728 struct auth_session_info **session_info_out)
730 const char *unix_username = (const char *)server_returned_info;
732 struct dom_sid *sids = NULL;
733 struct auth_session_info *session_info = NULL;
735 session_info = talloc_zero(mem_ctx, struct auth_session_info);
736 if (session_info == NULL) {
737 return NT_STATUS_NO_MEMORY;
740 session_info->unix_info = talloc_zero(session_info, struct auth_user_info_unix);
741 if (session_info->unix_info == NULL) {
742 TALLOC_FREE(session_info);
743 return NT_STATUS_NO_MEMORY;
745 session_info->unix_info->unix_name = talloc_strdup(session_info->unix_info,
747 if (session_info->unix_info->unix_name == NULL) {
748 TALLOC_FREE(session_info);
749 return NT_STATUS_NO_MEMORY;
752 session_info->security_token = talloc_zero(session_info, struct security_token);
753 if (session_info->security_token == NULL) {
754 TALLOC_FREE(session_info);
755 return NT_STATUS_NO_MEMORY;
758 sids = talloc_zero_array(session_info->security_token,
761 TALLOC_FREE(session_info);
762 return NT_STATUS_NO_MEMORY;
764 ok = dom_sid_parse(SID_WORLD, &sids[0]);
766 TALLOC_FREE(session_info);
767 return NT_STATUS_INTERNAL_ERROR;
769 ok = dom_sid_parse(SID_NT_NETWORK, &sids[1]);
771 TALLOC_FREE(session_info);
772 return NT_STATUS_INTERNAL_ERROR;
774 ok = dom_sid_parse(SID_NT_AUTHENTICATED_USERS, &sids[2]);
776 TALLOC_FREE(session_info);
777 return NT_STATUS_INTERNAL_ERROR;
780 session_info->security_token->num_sids = talloc_array_length(sids);
781 session_info->security_token->sids = sids;
783 *session_info_out = session_info;
788 static NTSTATUS ntlm_auth_generate_session_info_pac(struct auth4_context *auth_ctx,
790 struct smb_krb5_context *smb_krb5_context,
792 const char *princ_name,
793 const struct tsocket_address *remote_address,
794 uint32_t session_info_flags,
795 struct auth_session_info **session_info)
798 struct PAC_LOGON_INFO *logon_info = NULL;
806 tmp_ctx = talloc_new(mem_ctx);
808 return NT_STATUS_NO_MEMORY;
813 status = kerberos_pac_logon_info(tmp_ctx, *pac_blob, NULL, NULL,
814 NULL, NULL, 0, &logon_info);
816 status = NT_STATUS_ACCESS_DENIED;
818 if (!NT_STATUS_IS_OK(status)) {
823 DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name));
825 p = strchr_m(princ_name, '@');
827 DEBUG(3, ("[%s] Doesn't look like a valid principal\n",
829 return NT_STATUS_LOGON_FAILURE;
832 user = talloc_strndup(mem_ctx, princ_name, p - princ_name);
834 return NT_STATUS_NO_MEMORY;
837 realm = talloc_strdup(talloc_tos(), p + 1);
839 return NT_STATUS_NO_MEMORY;
842 if (!strequal(realm, lp_realm())) {
843 DEBUG(3, ("Ticket for foreign realm %s@%s\n", user, realm));
844 if (!lp_allow_trusted_domains()) {
845 return NT_STATUS_LOGON_FAILURE;
849 if (logon_info && logon_info->info3.base.logon_domain.string) {
850 domain = talloc_strdup(mem_ctx,
851 logon_info->info3.base.logon_domain.string);
853 return NT_STATUS_NO_MEMORY;
855 DEBUG(10, ("Domain is [%s] (using PAC)\n", domain));
858 /* If we have winbind running, we can (and must) shorten the
859 username by using the short netbios name. Otherwise we will
860 have inconsistent user names. With Kerberos, we get the
861 fully qualified realm, with ntlmssp we get the short
862 name. And even w2k3 does use ntlmssp if you for example
863 connect to an ip address. */
866 struct wbcDomainInfo *info = NULL;
868 DEBUG(10, ("Mapping [%s] to short name using winbindd\n",
871 wbc_status = wbcDomainInfo(realm, &info);
873 if (WBC_ERROR_IS_OK(wbc_status)) {
874 domain = talloc_strdup(mem_ctx,
878 DEBUG(3, ("Could not find short name: %s\n",
879 wbcErrorString(wbc_status)));
880 domain = talloc_strdup(mem_ctx, realm);
883 return NT_STATUS_NO_MEMORY;
885 DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain));
888 unixuser = talloc_asprintf(tmp_ctx, "%s%c%s", domain, winbind_separator(), user);
890 status = NT_STATUS_NO_MEMORY;
894 status = ntlm_auth_generate_session_info(auth_ctx, mem_ctx, unixuser, NULL, session_info_flags, session_info);
897 TALLOC_FREE(tmp_ctx);
904 * Return the challenge as determined by the authentication subsystem
905 * @return an 8 byte random challenge
908 static NTSTATUS ntlm_auth_get_challenge(struct auth4_context *auth_ctx,
911 if (auth_ctx->challenge.data.length == 8) {
912 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
913 auth_ctx->challenge.set_by));
914 memcpy(chal, auth_ctx->challenge.data.data, 8);
918 if (!auth_ctx->challenge.set_by) {
919 generate_random_buffer(chal, 8);
921 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
922 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
923 auth_ctx->challenge.set_by = "random";
926 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
927 auth_ctx->challenge.set_by));
933 * NTLM2 authentication modifies the effective challenge,
934 * @param challenge The new challenge value
936 static NTSTATUS ntlm_auth_set_challenge(struct auth4_context *auth_ctx, const uint8_t chal[8], const char *set_by)
938 auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
939 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
941 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
942 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
948 * Check the password on an NTLMSSP login.
950 * Return the session keys used on the connection.
953 static NTSTATUS winbind_pw_check(struct auth4_context *auth4_context,
955 const struct auth_usersupplied_info *user_info,
956 uint8_t *pauthoritative,
957 void **server_returned_info,
958 DATA_BLOB *session_key, DATA_BLOB *lm_session_key)
961 char *error_string = NULL;
963 uint8_t user_sess_key[16];
964 char *unix_name = NULL;
966 nt_status = contact_winbind_auth_crap(user_info->client.account_name, user_info->client.domain_name,
967 user_info->workstation_name,
968 &auth4_context->challenge.data,
969 &user_info->password.response.lanman,
970 &user_info->password.response.nt,
971 WBFLAG_PAM_LMKEY | WBFLAG_PAM_USER_SESSION_KEY | WBFLAG_PAM_UNIX_NAME,
973 lm_key, user_sess_key,
975 &error_string, &unix_name);
977 if (NT_STATUS_IS_OK(nt_status)) {
978 if (!all_zero(lm_key, 8)) {
979 *lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
980 memcpy(lm_session_key->data, lm_key, 8);
981 memset(lm_session_key->data+8, '\0', 8);
984 if (!all_zero(user_sess_key, 16)) {
985 *session_key = data_blob_talloc(mem_ctx, user_sess_key, 16);
987 *server_returned_info = talloc_strdup(mem_ctx,
990 DEBUG(NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED) ? 0 : 3,
991 ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
992 user_info->client.domain_name, user_info->client.account_name,
993 user_info->workstation_name,
994 error_string ? error_string : "unknown error (NULL)"));
997 SAFE_FREE(error_string);
998 SAFE_FREE(unix_name);
1002 static NTSTATUS local_pw_check(struct auth4_context *auth4_context,
1003 TALLOC_CTX *mem_ctx,
1004 const struct auth_usersupplied_info *user_info,
1005 uint8_t *pauthoritative,
1006 void **server_returned_info,
1007 DATA_BLOB *session_key, DATA_BLOB *lm_session_key)
1010 struct samr_Password lm_pw, nt_pw;
1012 nt_lm_owf_gen (opt_password, nt_pw.hash, lm_pw.hash);
1014 *pauthoritative = 1;
1016 nt_status = ntlm_password_check(mem_ctx,
1017 true, NTLM_AUTH_ON, 0,
1018 &auth4_context->challenge.data,
1019 &user_info->password.response.lanman,
1020 &user_info->password.response.nt,
1021 user_info->client.account_name,
1022 user_info->client.account_name,
1023 user_info->client.domain_name,
1024 &lm_pw, &nt_pw, session_key, lm_session_key);
1026 if (NT_STATUS_IS_OK(nt_status)) {
1027 *server_returned_info = talloc_asprintf(mem_ctx,
1028 "%s%c%s", user_info->client.domain_name,
1029 *lp_winbind_separator(),
1030 user_info->client.account_name);
1032 DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
1033 user_info->client.domain_name, user_info->client.account_name,
1034 user_info->workstation_name,
1035 nt_errstr(nt_status)));
1040 static NTSTATUS ntlm_auth_prepare_gensec_client(TALLOC_CTX *mem_ctx,
1041 struct loadparm_context *lp_ctx,
1042 struct gensec_security **gensec_security_out)
1044 struct gensec_security *gensec_security = NULL;
1046 TALLOC_CTX *tmp_ctx;
1047 const struct gensec_security_ops **backends = NULL;
1048 struct gensec_settings *gensec_settings = NULL;
1051 tmp_ctx = talloc_new(mem_ctx);
1052 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
1054 gensec_settings = lpcfg_gensec_settings(tmp_ctx, lp_ctx);
1055 if (gensec_settings == NULL) {
1056 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1057 TALLOC_FREE(tmp_ctx);
1058 return NT_STATUS_NO_MEMORY;
1061 backends = talloc_zero_array(gensec_settings,
1062 const struct gensec_security_ops *, 4);
1063 if (backends == NULL) {
1064 TALLOC_FREE(tmp_ctx);
1065 return NT_STATUS_NO_MEMORY;
1067 gensec_settings->backends = backends;
1071 /* These need to be in priority order, krb5 before NTLMSSP */
1072 #if defined(HAVE_KRB5)
1073 backends[idx++] = &gensec_gse_krb5_security_ops;
1076 backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_NTLMSSP);
1078 backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_SPNEGO);
1080 nt_status = gensec_client_start(NULL, &gensec_security,
1082 if (!NT_STATUS_IS_OK(nt_status)) {
1083 TALLOC_FREE(tmp_ctx);
1087 talloc_unlink(tmp_ctx, gensec_settings);
1089 if (opt_target_service != NULL) {
1090 nt_status = gensec_set_target_service(gensec_security,
1091 opt_target_service);
1092 if (!NT_STATUS_IS_OK(nt_status)) {
1093 TALLOC_FREE(tmp_ctx);
1098 if (opt_target_hostname != NULL) {
1099 nt_status = gensec_set_target_hostname(gensec_security,
1100 opt_target_hostname);
1101 if (!NT_STATUS_IS_OK(nt_status)) {
1102 TALLOC_FREE(tmp_ctx);
1107 *gensec_security_out = talloc_steal(mem_ctx, gensec_security);
1108 TALLOC_FREE(tmp_ctx);
1109 return NT_STATUS_OK;
1112 static struct auth4_context *make_auth4_context_ntlm_auth(TALLOC_CTX *mem_ctx, bool local_pw)
1114 struct auth4_context *auth4_context = talloc_zero(mem_ctx, struct auth4_context);
1115 if (auth4_context == NULL) {
1116 DEBUG(10, ("failed to allocate auth4_context failed\n"));
1119 auth4_context->generate_session_info = ntlm_auth_generate_session_info;
1120 auth4_context->generate_session_info_pac = ntlm_auth_generate_session_info_pac;
1121 auth4_context->get_ntlm_challenge = ntlm_auth_get_challenge;
1122 auth4_context->set_ntlm_challenge = ntlm_auth_set_challenge;
1124 auth4_context->check_ntlm_password = local_pw_check;
1126 auth4_context->check_ntlm_password = winbind_pw_check;
1128 auth4_context->private_data = NULL;
1129 return auth4_context;
1132 static NTSTATUS ntlm_auth_prepare_gensec_server(TALLOC_CTX *mem_ctx,
1133 struct loadparm_context *lp_ctx,
1134 struct gensec_security **gensec_security_out)
1136 struct gensec_security *gensec_security;
1139 TALLOC_CTX *tmp_ctx;
1140 const struct gensec_security_ops **backends;
1141 struct gensec_settings *gensec_settings;
1143 struct cli_credentials *server_credentials;
1145 struct auth4_context *auth4_context;
1147 tmp_ctx = talloc_new(mem_ctx);
1148 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
1150 auth4_context = make_auth4_context_ntlm_auth(tmp_ctx, opt_password);
1151 if (auth4_context == NULL) {
1152 TALLOC_FREE(tmp_ctx);
1153 return NT_STATUS_NO_MEMORY;
1156 gensec_settings = lpcfg_gensec_settings(tmp_ctx, lp_ctx);
1157 if (lp_ctx == NULL) {
1158 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1159 TALLOC_FREE(tmp_ctx);
1160 return NT_STATUS_NO_MEMORY;
1164 * This should be a 'netbios domain -> DNS domain'
1165 * mapping, and can currently validly return NULL on
1166 * poorly configured systems.
1168 * This is used for the NTLMSSP server
1172 gensec_settings->server_netbios_name = lp_netbios_name();
1173 gensec_settings->server_netbios_domain = lp_workgroup();
1175 gensec_settings->server_netbios_name = get_winbind_netbios_name();
1176 gensec_settings->server_netbios_domain = get_winbind_domain();
1179 gensec_settings->server_dns_domain = strlower_talloc(gensec_settings,
1180 get_mydnsdomname(talloc_tos()));
1181 gensec_settings->server_dns_name = strlower_talloc(gensec_settings,
1182 get_mydnsfullname());
1184 backends = talloc_zero_array(gensec_settings,
1185 const struct gensec_security_ops *, 4);
1187 if (backends == NULL) {
1188 TALLOC_FREE(tmp_ctx);
1189 return NT_STATUS_NO_MEMORY;
1191 gensec_settings->backends = backends;
1195 /* These need to be in priority order, krb5 before NTLMSSP */
1196 #if defined(HAVE_KRB5)
1197 backends[idx++] = &gensec_gse_krb5_security_ops;
1200 backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_NTLMSSP);
1202 backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_SPNEGO);
1205 * This is anonymous for now, because we just use it
1206 * to set the kerberos state at the moment
1208 server_credentials = cli_credentials_init_anon(tmp_ctx);
1209 if (!server_credentials) {
1210 DEBUG(0, ("auth_generic_prepare: Failed to init server credentials\n"));
1211 return NT_STATUS_NO_MEMORY;
1214 cli_credentials_set_conf(server_credentials, lp_ctx);
1216 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC || lp_security() == SEC_ADS || USE_KERBEROS_KEYTAB) {
1217 cli_credentials_set_kerberos_state(server_credentials, CRED_AUTO_USE_KERBEROS);
1219 cli_credentials_set_kerberos_state(server_credentials, CRED_DONT_USE_KERBEROS);
1222 nt_status = gensec_server_start(tmp_ctx, gensec_settings,
1223 auth4_context, &gensec_security);
1225 if (!NT_STATUS_IS_OK(nt_status)) {
1226 TALLOC_FREE(tmp_ctx);
1230 gensec_set_credentials(gensec_security, server_credentials);
1233 * TODO: Allow the caller to pass their own description here
1234 * via a command-line option
1236 nt_status = gensec_set_target_service_description(gensec_security,
1238 if (!NT_STATUS_IS_OK(nt_status)) {
1239 TALLOC_FREE(tmp_ctx);
1243 talloc_unlink(tmp_ctx, lp_ctx);
1244 talloc_unlink(tmp_ctx, server_credentials);
1245 talloc_unlink(tmp_ctx, gensec_settings);
1246 talloc_unlink(tmp_ctx, auth4_context);
1248 *gensec_security_out = talloc_steal(mem_ctx, gensec_security);
1249 TALLOC_FREE(tmp_ctx);
1250 return NT_STATUS_OK;
1253 static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode,
1254 struct loadparm_context *lp_ctx,
1255 struct ntlm_auth_state *state,
1256 char *buf, int length, void **private2)
1258 manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
1262 static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode,
1263 struct loadparm_context *lp_ctx,
1264 struct ntlm_auth_state *state,
1265 char *buf, int length, void **private2)
1270 pass=(char *)memchr(buf,' ',length);
1272 DEBUG(2, ("Password not found. Denying access\n"));
1279 if (state->helper_mode == SQUID_2_5_BASIC) {
1280 char *end = rfc1738_unescape(user);
1281 if (end == NULL || (end - user) != strlen(user)) {
1282 DEBUG(2, ("Badly rfc1738 encoded username: %s; "
1283 "denying access\n", user));
1287 end = rfc1738_unescape(pass);
1288 if (end == NULL || (end - pass) != strlen(pass)) {
1289 DEBUG(2, ("Badly encoded password for %s; "
1290 "denying access\n", user));
1296 if (check_plaintext_auth(user, pass, False)) {
1303 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
1304 struct loadparm_context *lp_ctx,
1305 char *buf, int length, void **private1)
1308 DATA_BLOB out = data_blob(NULL, 0);
1309 char *out_base64 = NULL;
1310 const char *reply_arg = NULL;
1311 struct gensec_ntlm_state {
1312 struct gensec_security *gensec_state;
1313 const char *set_password;
1315 struct gensec_ntlm_state *state;
1319 const char *reply_code;
1320 struct cli_credentials *creds;
1322 static char *want_feature_list = NULL;
1323 static DATA_BLOB session_key;
1325 TALLOC_CTX *mem_ctx;
1327 mem_ctx = talloc_named(NULL, 0, "manage_gensec_request internal mem_ctx");
1330 state = (struct gensec_ntlm_state *)*private1;
1332 state = talloc_zero(NULL, struct gensec_ntlm_state);
1334 printf("BH No Memory\n");
1339 state->set_password = opt_password;
1343 if (strlen(buf) < 2) {
1344 DEBUG(1, ("query [%s] invalid", buf));
1345 printf("BH Query invalid\n");
1346 talloc_free(mem_ctx);
1350 if (strlen(buf) > 3) {
1351 if(strncmp(buf, "SF ", 3) == 0) {
1352 DEBUG(10, ("Setting flags to negotiate\n"));
1353 talloc_free(want_feature_list);
1354 want_feature_list = talloc_strndup(state, buf+3, strlen(buf)-3);
1356 talloc_free(mem_ctx);
1359 in = base64_decode_data_blob_talloc(mem_ctx, buf + 3);
1361 in = data_blob(NULL, 0);
1364 if (strncmp(buf, "YR", 2) == 0) {
1365 if (state->gensec_state) {
1366 talloc_free(state->gensec_state);
1367 state->gensec_state = NULL;
1369 } else if ( (strncmp(buf, "OK", 2) == 0)) {
1370 /* Just return BH, like ntlm_auth from Samba 3 does. */
1371 printf("BH Command expected\n");
1372 talloc_free(mem_ctx);
1374 } else if ( (strncmp(buf, "TT ", 3) != 0) &&
1375 (strncmp(buf, "KK ", 3) != 0) &&
1376 (strncmp(buf, "AF ", 3) != 0) &&
1377 (strncmp(buf, "NA ", 3) != 0) &&
1378 (strncmp(buf, "UG", 2) != 0) &&
1379 (strncmp(buf, "PW ", 3) != 0) &&
1380 (strncmp(buf, "GK", 2) != 0) &&
1381 (strncmp(buf, "GF", 2) != 0)) {
1382 DEBUG(1, ("SPNEGO request [%s] invalid prefix\n", buf));
1383 printf("BH SPNEGO request invalid prefix\n");
1384 talloc_free(mem_ctx);
1389 if (!(state->gensec_state)) {
1390 switch (stdio_helper_mode) {
1391 case GSS_SPNEGO_CLIENT:
1393 * cached credentials are only supported by
1394 * NTLMSSP_CLIENT_1 for now.
1396 use_cached_creds = false;
1398 case NTLMSSP_CLIENT_1:
1399 /* setup the client side */
1401 if (state->set_password != NULL) {
1402 use_cached_creds = false;
1405 if (use_cached_creds) {
1406 struct wbcCredentialCacheParams params;
1407 struct wbcCredentialCacheInfo *info = NULL;
1408 struct wbcAuthErrorInfo *error = NULL;
1411 params.account_name = opt_username;
1412 params.domain_name = opt_domain;
1413 params.level = WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP;
1414 params.num_blobs = 0;
1415 params.blobs = NULL;
1417 wbc_status = wbcCredentialCache(¶ms, &info,
1419 wbcFreeMemory(error);
1420 if (!WBC_ERROR_IS_OK(wbc_status)) {
1421 use_cached_creds = false;
1423 wbcFreeMemory(info);
1426 nt_status = ntlm_auth_prepare_gensec_client(state, lp_ctx,
1427 &state->gensec_state);
1428 if (!NT_STATUS_IS_OK(nt_status)) {
1429 printf("BH GENSEC mech failed to start: %s\n",
1430 nt_errstr(nt_status));
1431 talloc_free(mem_ctx);
1435 creds = cli_credentials_init(state->gensec_state);
1436 cli_credentials_set_conf(creds, lp_ctx);
1438 cli_credentials_set_username(creds, opt_username, CRED_SPECIFIED);
1441 cli_credentials_set_domain(creds, opt_domain, CRED_SPECIFIED);
1443 if (use_cached_creds) {
1444 gensec_want_feature(state->gensec_state,
1445 GENSEC_FEATURE_NTLM_CCACHE);
1446 } else if (state->set_password) {
1447 cli_credentials_set_password(creds, state->set_password, CRED_SPECIFIED);
1449 cli_credentials_set_password_callback(creds, get_password);
1451 if (opt_workstation) {
1452 cli_credentials_set_workstation(creds, opt_workstation, CRED_SPECIFIED);
1455 gensec_set_credentials(state->gensec_state, creds);
1458 case GSS_SPNEGO_SERVER:
1459 case SQUID_2_5_NTLMSSP:
1461 nt_status = ntlm_auth_prepare_gensec_server(state, lp_ctx,
1462 &state->gensec_state);
1463 if (!NT_STATUS_IS_OK(nt_status)) {
1464 printf("BH GENSEC mech failed to start: %s\n",
1465 nt_errstr(nt_status));
1466 talloc_free(mem_ctx);
1472 talloc_free(mem_ctx);
1476 gensec_want_feature_list(state->gensec_state, want_feature_list);
1478 /* Session info is not complete, do not pass to auth log */
1479 gensec_want_feature(state->gensec_state, GENSEC_FEATURE_NO_AUTHZ_LOG);
1481 switch (stdio_helper_mode) {
1482 case GSS_SPNEGO_CLIENT:
1483 case GSS_SPNEGO_SERVER:
1484 nt_status = gensec_start_mech_by_oid(state->gensec_state, GENSEC_OID_SPNEGO);
1489 case NTLMSSP_CLIENT_1:
1494 case SQUID_2_5_NTLMSSP:
1495 nt_status = gensec_start_mech_by_oid(state->gensec_state, GENSEC_OID_NTLMSSP);
1498 talloc_free(mem_ctx);
1502 if (!NT_STATUS_IS_OK(nt_status)) {
1503 DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status)));
1504 printf("BH GENSEC mech failed to start\n");
1505 talloc_free(mem_ctx);
1513 if (strncmp(buf, "PW ", 3) == 0) {
1514 state->set_password = talloc_strndup(state,
1515 (const char *)in.data,
1518 cli_credentials_set_password(gensec_get_credentials(state->gensec_state),
1519 state->set_password,
1522 talloc_free(mem_ctx);
1526 if (strncmp(buf, "GK", 2) == 0) {
1528 DEBUG(10, ("Requested session key\n"));
1529 nt_status = gensec_session_key(state->gensec_state, mem_ctx, &session_key);
1530 if(!NT_STATUS_IS_OK(nt_status)) {
1531 DEBUG(1, ("gensec_session_key failed: %s\n", nt_errstr(nt_status)));
1532 printf("BH No session key\n");
1533 talloc_free(mem_ctx);
1536 base64_key = base64_encode_data_blob(state, session_key);
1537 SMB_ASSERT(base64_key != NULL);
1538 printf("GK %s\n", base64_key);
1539 talloc_free(base64_key);
1541 talloc_free(mem_ctx);
1545 if (strncmp(buf, "GF", 2) == 0) {
1548 DEBUG(10, ("Requested negotiated NTLMSSP feature flags\n"));
1550 neg_flags = gensec_ntlmssp_neg_flags(state->gensec_state);
1551 if (neg_flags == 0) {
1553 talloc_free(mem_ctx);
1557 printf("GF 0x%08x\n", neg_flags);
1558 talloc_free(mem_ctx);
1562 nt_status = gensec_update(state->gensec_state, mem_ctx, in, &out);
1564 /* don't leak 'bad password'/'no such user' info to the network client */
1565 nt_status = nt_status_squash(nt_status);
1568 out_base64 = base64_encode_data_blob(mem_ctx, out);
1569 SMB_ASSERT(out_base64 != NULL);
1574 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1576 if (first && state->gensec_state->gensec_role == GENSEC_CLIENT) {
1578 } else if (state->gensec_state->gensec_role == GENSEC_CLIENT) {
1580 } else if (state->gensec_state->gensec_role == GENSEC_SERVER) {
1587 } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) {
1588 reply_code = "BH NT_STATUS_ACCESS_DENIED";
1589 reply_arg = nt_errstr(nt_status);
1590 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
1591 } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_UNSUCCESSFUL)) {
1592 reply_code = "BH NT_STATUS_UNSUCCESSFUL";
1593 reply_arg = nt_errstr(nt_status);
1594 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
1595 } else if (!NT_STATUS_IS_OK(nt_status)) {
1597 reply_arg = nt_errstr(nt_status);
1598 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
1599 } else if /* OK */ (state->gensec_state->gensec_role == GENSEC_SERVER) {
1600 struct auth_session_info *session_info;
1602 nt_status = gensec_session_info(state->gensec_state, mem_ctx, &session_info);
1603 if (!NT_STATUS_IS_OK(nt_status)) {
1604 reply_code = "BH Failed to retrieve session info";
1605 reply_arg = nt_errstr(nt_status);
1606 DEBUG(1, ("GENSEC failed to retrieve the session info: %s\n", nt_errstr(nt_status)));
1610 reply_arg = talloc_strdup(state->gensec_state, session_info->unix_info->unix_name);
1611 if (reply_arg == NULL) {
1612 reply_code = "BH out of memory";
1613 reply_arg = nt_errstr(NT_STATUS_NO_MEMORY);
1615 talloc_free(session_info);
1617 } else if (state->gensec_state->gensec_role == GENSEC_CLIENT) {
1619 reply_arg = out_base64;
1624 switch (stdio_helper_mode) {
1625 case GSS_SPNEGO_SERVER:
1626 printf("%s %s %s\n", reply_code,
1627 out_base64 ? out_base64 : "*",
1628 reply_arg ? reply_arg : "*");
1632 printf("%s %s\n", reply_code, out_base64);
1633 } else if (reply_arg) {
1634 printf("%s %s\n", reply_code, reply_arg);
1636 printf("%s\n", reply_code);
1640 talloc_free(mem_ctx);
1644 static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode,
1645 struct loadparm_context *lp_ctx,
1646 struct ntlm_auth_state *state,
1647 char *buf, int length, void **private2)
1649 manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
1653 static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode,
1654 struct loadparm_context *lp_ctx,
1655 struct ntlm_auth_state *state,
1656 char *buf, int length, void **private2)
1658 manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
1662 static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode,
1663 struct loadparm_context *lp_ctx,
1664 struct ntlm_auth_state *state,
1665 char *buf, int length, void **private2)
1667 manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
1671 static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode,
1672 struct loadparm_context *lp_ctx,
1673 struct ntlm_auth_state *state,
1674 char *buf, int length, void **private2)
1676 char *request, *parameter;
1677 static DATA_BLOB challenge;
1678 static DATA_BLOB lm_response;
1679 static DATA_BLOB nt_response;
1680 static char *full_username;
1681 static char *username;
1682 static char *domain;
1683 static char *plaintext_password;
1684 static bool ntlm_server_1_user_session_key;
1685 static bool ntlm_server_1_lm_session_key;
1687 if (strequal(buf, ".")) {
1688 if (!full_username && !username) {
1689 printf("Error: No username supplied!\n");
1690 } else if (plaintext_password) {
1691 /* handle this request as plaintext */
1692 if (!full_username) {
1693 if (asprintf(&full_username, "%s%c%s", domain, winbind_separator(), username) == -1) {
1694 printf("Error: Out of memory in "
1699 if (check_plaintext_auth(full_username, plaintext_password, False)) {
1700 printf("Authenticated: Yes\n");
1702 printf("Authenticated: No\n");
1704 } else if (!lm_response.data && !nt_response.data) {
1705 printf("Error: No password supplied!\n");
1706 } else if (!challenge.data) {
1707 printf("Error: No lanman-challenge supplied!\n");
1709 char *error_string = NULL;
1711 uchar user_session_key[16];
1714 if (full_username && !username) {
1716 fstring fstr_domain;
1718 if (!parse_ntlm_auth_domain_user(full_username, fstr_user, fstr_domain)) {
1719 /* username might be 'tainted', don't print into our new-line deleimianted stream */
1720 printf("Error: Could not parse into "
1721 "domain and username\n");
1723 SAFE_FREE(username);
1725 username = smb_xstrdup(fstr_user);
1726 domain = smb_xstrdup(fstr_domain);
1730 DATA_BLOB nt_session_key, lm_session_key;
1731 struct samr_Password lm_pw, nt_pw;
1732 TALLOC_CTX *mem_ctx = talloc_new(NULL);
1733 ZERO_STRUCT(user_session_key);
1734 ZERO_STRUCT(lm_key);
1736 nt_lm_owf_gen (opt_password, nt_pw.hash, lm_pw.hash);
1737 nt_status = ntlm_password_check(mem_ctx,
1750 error_string = smb_xstrdup(get_friendly_nt_error_msg(nt_status));
1751 if (ntlm_server_1_user_session_key) {
1752 if (nt_session_key.length == sizeof(user_session_key)) {
1753 memcpy(user_session_key,
1754 nt_session_key.data,
1755 sizeof(user_session_key));
1758 if (ntlm_server_1_lm_session_key) {
1759 if (lm_session_key.length == sizeof(lm_key)) {
1761 lm_session_key.data,
1765 TALLOC_FREE(mem_ctx);
1768 uint8_t authoritative = 0;
1771 domain = smb_xstrdup(get_winbind_domain());
1774 if (ntlm_server_1_lm_session_key)
1775 flags |= WBFLAG_PAM_LMKEY;
1777 if (ntlm_server_1_user_session_key)
1778 flags |= WBFLAG_PAM_USER_SESSION_KEY;
1780 nt_status = contact_winbind_auth_crap(username,
1794 if (!NT_STATUS_IS_OK(nt_status)) {
1795 printf("Authenticated: No\n");
1796 printf("Authentication-Error: %s\n.\n",
1800 char *hex_user_session_key;
1802 printf("Authenticated: Yes\n");
1804 if (ntlm_server_1_lm_session_key
1805 && (!all_zero(lm_key,
1807 hex_lm_key = hex_encode_talloc(NULL,
1808 (const unsigned char *)lm_key,
1810 printf("LANMAN-Session-Key: %s\n",
1812 TALLOC_FREE(hex_lm_key);
1815 if (ntlm_server_1_user_session_key
1816 && (!all_zero(user_session_key,
1817 sizeof(user_session_key)))) {
1818 hex_user_session_key = hex_encode_talloc(NULL,
1819 (const unsigned char *)user_session_key,
1820 sizeof(user_session_key));
1821 printf("User-Session-Key: %s\n",
1822 hex_user_session_key);
1823 TALLOC_FREE(hex_user_session_key);
1826 SAFE_FREE(error_string);
1828 /* clear out the state */
1829 challenge = data_blob_null;
1830 nt_response = data_blob_null;
1831 lm_response = data_blob_null;
1832 SAFE_FREE(full_username);
1833 SAFE_FREE(username);
1835 SAFE_FREE(plaintext_password);
1836 ntlm_server_1_user_session_key = False;
1837 ntlm_server_1_lm_session_key = False;
1845 /* Indicates a base64 encoded structure */
1846 parameter = strstr_m(request, ":: ");
1848 parameter = strstr_m(request, ": ");
1851 DEBUG(0, ("Parameter not found!\n"));
1852 printf("Error: Parameter not found!\n.\n");
1869 base64_decode_inplace(parameter);
1872 if (strequal(request, "LANMAN-Challenge")) {
1873 challenge = strhex_to_data_blob(NULL, parameter);
1874 if (challenge.length != 8) {
1875 printf("Error: hex decode of %s failed! "
1876 "(got %d bytes, expected 8)\n.\n",
1878 (int)challenge.length);
1879 challenge = data_blob_null;
1881 } else if (strequal(request, "NT-Response")) {
1882 nt_response = strhex_to_data_blob(NULL, parameter);
1883 if (nt_response.length < 24) {
1884 printf("Error: hex decode of %s failed! "
1885 "(only got %d bytes, needed at least 24)\n.\n",
1887 (int)nt_response.length);
1888 nt_response = data_blob_null;
1890 } else if (strequal(request, "LANMAN-Response")) {
1891 lm_response = strhex_to_data_blob(NULL, parameter);
1892 if (lm_response.length != 24) {
1893 printf("Error: hex decode of %s failed! "
1894 "(got %d bytes, expected 24)\n.\n",
1896 (int)lm_response.length);
1897 lm_response = data_blob_null;
1899 } else if (strequal(request, "Password")) {
1900 plaintext_password = smb_xstrdup(parameter);
1901 } else if (strequal(request, "NT-Domain")) {
1902 domain = smb_xstrdup(parameter);
1903 } else if (strequal(request, "Username")) {
1904 username = smb_xstrdup(parameter);
1905 } else if (strequal(request, "Full-Username")) {
1906 full_username = smb_xstrdup(parameter);
1907 } else if (strequal(request, "Request-User-Session-Key")) {
1908 ntlm_server_1_user_session_key = strequal(parameter, "Yes");
1909 } else if (strequal(request, "Request-LanMan-Session-Key")) {
1910 ntlm_server_1_lm_session_key = strequal(parameter, "Yes");
1912 printf("Error: Unknown request %s\n.\n", request);
1916 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode,
1917 struct loadparm_context *lp_ctx,
1918 struct ntlm_auth_state *state,
1919 char *buf, int length, void **private2)
1921 char *request, *parameter;
1922 static DATA_BLOB new_nt_pswd;
1923 static DATA_BLOB old_nt_hash_enc;
1924 static DATA_BLOB new_lm_pswd;
1925 static DATA_BLOB old_lm_hash_enc;
1926 static char *full_username = NULL;
1927 static char *username = NULL;
1928 static char *domain = NULL;
1929 static char *newpswd = NULL;
1930 static char *oldpswd = NULL;
1932 if (strequal(buf, ".")) {
1933 if(newpswd && oldpswd) {
1934 uchar old_nt_hash[16];
1935 uchar old_lm_hash[16];
1936 uchar new_nt_hash[16];
1937 uchar new_lm_hash[16];
1939 new_nt_pswd = data_blob(NULL, 516);
1940 old_nt_hash_enc = data_blob(NULL, 16);
1942 /* Calculate the MD4 hash (NT compatible) of the
1944 E_md4hash(oldpswd, old_nt_hash);
1945 E_md4hash(newpswd, new_nt_hash);
1947 /* E_deshash returns false for 'long'
1948 passwords (> 14 DOS chars).
1950 Therefore, don't send a buffer
1951 encrypted with the truncated hash
1952 (it could allow an even easier
1953 attack on the password)
1955 Likewise, obey the admin's restriction
1958 if (lp_client_lanman_auth() &&
1959 E_deshash(newpswd, new_lm_hash) &&
1960 E_deshash(oldpswd, old_lm_hash)) {
1961 new_lm_pswd = data_blob(NULL, 516);
1962 old_lm_hash_enc = data_blob(NULL, 16);
1963 encode_pw_buffer(new_lm_pswd.data, newpswd,
1966 arcfour_crypt(new_lm_pswd.data, old_nt_hash, 516);
1967 E_old_pw_hash(new_nt_hash, old_lm_hash,
1968 old_lm_hash_enc.data);
1970 new_lm_pswd.data = NULL;
1971 new_lm_pswd.length = 0;
1972 old_lm_hash_enc.data = NULL;
1973 old_lm_hash_enc.length = 0;
1976 encode_pw_buffer(new_nt_pswd.data, newpswd,
1979 arcfour_crypt(new_nt_pswd.data, old_nt_hash, 516);
1980 E_old_pw_hash(new_nt_hash, old_nt_hash,
1981 old_nt_hash_enc.data);
1984 if (!full_username && !username) {
1985 printf("Error: No username supplied!\n");
1986 } else if ((!new_nt_pswd.data || !old_nt_hash_enc.data) &&
1987 (!new_lm_pswd.data || old_lm_hash_enc.data) ) {
1988 printf("Error: No NT or LM password "
1989 "blobs supplied!\n");
1991 char *error_string = NULL;
1993 if (full_username && !username) {
1995 fstring fstr_domain;
1997 if (!parse_ntlm_auth_domain_user(full_username,
2000 /* username might be 'tainted', don't
2001 * print into our new-line
2002 * deleimianted stream */
2003 printf("Error: Could not "
2004 "parse into domain and "
2006 SAFE_FREE(username);
2007 username = smb_xstrdup(full_username);
2009 SAFE_FREE(username);
2011 username = smb_xstrdup(fstr_user);
2012 domain = smb_xstrdup(fstr_domain);
2017 if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
2024 printf("Password-Change: No\n");
2025 printf("Password-Change-Error: %s\n.\n",
2028 printf("Password-Change: Yes\n");
2031 SAFE_FREE(error_string);
2033 /* clear out the state */
2034 new_nt_pswd = data_blob_null;
2035 old_nt_hash_enc = data_blob_null;
2036 new_lm_pswd = data_blob_null;
2037 old_nt_hash_enc = data_blob_null;
2038 SAFE_FREE(full_username);
2039 SAFE_FREE(username);
2050 /* Indicates a base64 encoded structure */
2051 parameter = strstr_m(request, ":: ");
2053 parameter = strstr_m(request, ": ");
2056 DEBUG(0, ("Parameter not found!\n"));
2057 printf("Error: Parameter not found!\n.\n");
2073 base64_decode_inplace(parameter);
2076 if (strequal(request, "new-nt-password-blob")) {
2077 new_nt_pswd = strhex_to_data_blob(NULL, parameter);
2078 if (new_nt_pswd.length != 516) {
2079 printf("Error: hex decode of %s failed! "
2080 "(got %d bytes, expected 516)\n.\n",
2082 (int)new_nt_pswd.length);
2083 new_nt_pswd = data_blob_null;
2085 } else if (strequal(request, "old-nt-hash-blob")) {
2086 old_nt_hash_enc = strhex_to_data_blob(NULL, parameter);
2087 if (old_nt_hash_enc.length != 16) {
2088 printf("Error: hex decode of %s failed! "
2089 "(got %d bytes, expected 16)\n.\n",
2091 (int)old_nt_hash_enc.length);
2092 old_nt_hash_enc = data_blob_null;
2094 } else if (strequal(request, "new-lm-password-blob")) {
2095 new_lm_pswd = strhex_to_data_blob(NULL, parameter);
2096 if (new_lm_pswd.length != 516) {
2097 printf("Error: hex decode of %s failed! "
2098 "(got %d bytes, expected 516)\n.\n",
2100 (int)new_lm_pswd.length);
2101 new_lm_pswd = data_blob_null;
2104 else if (strequal(request, "old-lm-hash-blob")) {
2105 old_lm_hash_enc = strhex_to_data_blob(NULL, parameter);
2106 if (old_lm_hash_enc.length != 16)
2108 printf("Error: hex decode of %s failed! "
2109 "(got %d bytes, expected 16)\n.\n",
2111 (int)old_lm_hash_enc.length);
2112 old_lm_hash_enc = data_blob_null;
2114 } else if (strequal(request, "nt-domain")) {
2115 domain = smb_xstrdup(parameter);
2116 } else if(strequal(request, "username")) {
2117 username = smb_xstrdup(parameter);
2118 } else if(strequal(request, "full-username")) {
2119 username = smb_xstrdup(parameter);
2120 } else if(strequal(request, "new-password")) {
2121 newpswd = smb_xstrdup(parameter);
2122 } else if (strequal(request, "old-password")) {
2123 oldpswd = smb_xstrdup(parameter);
2125 printf("Error: Unknown request %s\n.\n", request);
2129 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode,
2130 struct loadparm_context *lp_ctx,
2131 struct ntlm_auth_state *state,
2132 stdio_helper_function fn, void **private2)
2135 char tmp[INITIAL_BUFFER_SIZE+1];
2136 int length, buf_size = 0;
2139 buf = talloc_strdup(state->mem_ctx, "");
2141 DEBUG(0, ("Failed to allocate input buffer.\n"));
2142 fprintf(stderr, "ERR\n");
2148 /* this is not a typo - x_fgets doesn't work too well under
2150 if (fgets(tmp, sizeof(tmp)-1, stdin) == NULL) {
2151 if (ferror(stdin)) {
2152 DEBUG(1, ("fgets() failed! dying..... errno=%d "
2153 "(%s)\n", ferror(stdin),
2154 strerror(ferror(stdin))));
2161 buf = talloc_strdup_append_buffer(buf, tmp);
2162 buf_size += INITIAL_BUFFER_SIZE;
2164 if (buf_size > MAX_BUFFER_SIZE) {
2165 DEBUG(2, ("Oversized message\n"));
2166 fprintf(stderr, "ERR\n");
2171 c = strchr(buf, '\n');
2172 } while (c == NULL);
2177 DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf,length));
2179 if (buf[0] == '\0') {
2180 DEBUG(2, ("Invalid Request\n"));
2181 fprintf(stderr, "ERR\n");
2186 fn(stdio_helper_mode, lp_ctx, state, buf, length, private2);
2191 static void squid_stream(enum stdio_helper_mode stdio_mode,
2192 struct loadparm_context *lp_ctx,
2193 stdio_helper_function fn) {
2194 TALLOC_CTX *mem_ctx;
2195 struct ntlm_auth_state *state;
2197 /* initialize FDescs */
2198 setbuf(stdout, NULL);
2199 setbuf(stderr, NULL);
2201 mem_ctx = talloc_init("ntlm_auth");
2203 DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
2204 fprintf(stderr, "ERR\n");
2208 state = talloc_zero(mem_ctx, struct ntlm_auth_state);
2210 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
2211 fprintf(stderr, "ERR\n");
2215 state->mem_ctx = mem_ctx;
2216 state->helper_mode = stdio_mode;
2219 TALLOC_CTX *frame = talloc_stackframe();
2220 manage_squid_request(stdio_mode, lp_ctx, state, fn, NULL);
2226 /* Authenticate a user with a challenge/response */
2228 static bool check_auth_crap(void)
2233 char user_session_key[16];
2235 char *hex_user_session_key;
2237 uint8_t authoritative = 0;
2239 setbuf(stdout, NULL);
2242 flags |= WBFLAG_PAM_LMKEY;
2244 if (request_user_session_key)
2245 flags |= WBFLAG_PAM_USER_SESSION_KEY;
2247 flags |= WBFLAG_PAM_NT_STATUS_SQUASH;
2249 nt_status = contact_winbind_auth_crap(opt_username, opt_domain,
2255 (unsigned char *)lm_key,
2256 (unsigned char *)user_session_key,
2258 &error_string, NULL);
2260 if (!NT_STATUS_IS_OK(nt_status)) {
2261 printf("%s (0x%x)\n", error_string,
2262 NT_STATUS_V(nt_status));
2263 SAFE_FREE(error_string);
2268 && (!all_zero((uint8_t *)lm_key, sizeof(lm_key)))) {
2269 hex_lm_key = hex_encode_talloc(talloc_tos(), (const unsigned char *)lm_key,
2271 printf("LM_KEY: %s\n", hex_lm_key);
2272 TALLOC_FREE(hex_lm_key);
2274 if (request_user_session_key
2275 && (!all_zero((uint8_t *)user_session_key,
2276 sizeof(user_session_key)))) {
2277 hex_user_session_key = hex_encode_talloc(talloc_tos(), (const unsigned char *)user_session_key,
2278 sizeof(user_session_key));
2279 printf("NT_KEY: %s\n", hex_user_session_key);
2280 TALLOC_FREE(hex_user_session_key);
2289 OPT_USERNAME = 1000,
2298 OPT_USER_SESSION_KEY,
2300 OPT_REQUIRE_MEMBERSHIP,
2301 OPT_USE_CACHED_CREDS,
2303 OPT_PAM_WINBIND_CONF,
2305 OPT_TARGET_HOSTNAME,
2309 int main(int argc, const char **argv)
2311 TALLOC_CTX *frame = talloc_stackframe();
2313 const char *helper_protocol = NULL;
2314 int diagnostics = 0;
2316 const char *hex_challenge = NULL;
2317 const char *hex_lm_response = NULL;
2318 const char *hex_nt_response = NULL;
2319 struct loadparm_context *lp_ctx;
2322 /* NOTE: DO NOT change this interface without considering the implications!
2323 This is an external interface, which other programs will use to interact
2327 /* We do not use single-letter command abbreviations, because they harm future
2328 interface stability. */
2330 struct poptOption long_options[] = {
2332 { "helper-protocol", 0, POPT_ARG_STRING, &helper_protocol, OPT_DOMAIN, "operate as a stdio-based helper", "helper protocol to use"},
2333 { "username", 0, POPT_ARG_STRING, &opt_username, OPT_USERNAME, "username"},
2334 { "domain", 0, POPT_ARG_STRING, &opt_domain, OPT_DOMAIN, "domain name"},
2335 { "workstation", 0, POPT_ARG_STRING, &opt_workstation, OPT_WORKSTATION, "workstation"},
2336 { "challenge", 0, POPT_ARG_STRING, &hex_challenge, OPT_CHALLENGE, "challenge (HEX encoded)"},
2337 { "lm-response", 0, POPT_ARG_STRING, &hex_lm_response, OPT_LM, "LM Response to the challenge (HEX encoded)"},
2338 { "nt-response", 0, POPT_ARG_STRING, &hex_nt_response, OPT_NT, "NT or NTLMv2 Response to the challenge (HEX encoded)"},
2339 { "password", 0, POPT_ARG_STRING, &opt_password, OPT_PASSWORD, "User's plaintext password"},
2340 { "request-lm-key", 0, POPT_ARG_NONE, &request_lm_key, OPT_LM_KEY, "Retrieve LM session key"},
2341 { "request-nt-key", 0, POPT_ARG_NONE, &request_user_session_key, OPT_USER_SESSION_KEY, "Retrieve User (NT) session key"},
2342 { "use-cached-creds", 0, POPT_ARG_NONE, &use_cached_creds, OPT_USE_CACHED_CREDS, "Use cached credentials if no password is given"},
2343 { "allow-mschapv2", 0, POPT_ARG_NONE, &opt_allow_mschapv2, OPT_ALLOW_MSCHAPV2, "Explicitly allow MSCHAPv2" },
2344 { "offline-logon", 0, POPT_ARG_NONE, &offline_logon,
2346 "Use cached passwords when DC is offline"},
2347 { "diagnostics", 0, POPT_ARG_NONE, &diagnostics,
2349 "Perform diagnostics on the authentication chain"},
2350 { "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" },
2351 { "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" },
2352 { "target-service", 0, POPT_ARG_STRING, &opt_target_service, OPT_TARGET_SERVICE, "Target service (eg http)" },
2353 { "target-hostname", 0, POPT_ARG_STRING, &opt_target_hostname, OPT_TARGET_HOSTNAME, "Target hostname" },
2354 POPT_COMMON_CONFIGFILE
2360 /* Samba client initialisation */
2363 setup_logging("ntlm_auth", DEBUG_STDERR);
2368 pc = poptGetContext("ntlm_auth", argc, argv, long_options, 0);
2370 /* Parse command line options */
2373 poptPrintHelp(pc, stderr, 0);
2377 while((opt = poptGetNextOpt(pc)) != -1) {
2378 /* Get generic config options like --configfile */
2381 poptFreeContext(pc);
2383 if (!lp_load_global(get_dyn_CONFIGFILE())) {
2384 d_fprintf(stderr, "ntlm_auth: error opening config file %s. Error was %s\n",
2385 get_dyn_CONFIGFILE(), strerror(errno));
2389 pc = poptGetContext(NULL, argc, (const char **)argv, long_options,
2390 POPT_CONTEXT_KEEP_FIRST);
2392 while((opt = poptGetNextOpt(pc)) != -1) {
2395 opt_challenge = strhex_to_data_blob(NULL, hex_challenge);
2396 if (opt_challenge.length != 8) {
2397 fprintf(stderr, "hex decode of %s failed! "
2398 "(only got %d bytes)\n",
2400 (int)opt_challenge.length);
2405 opt_lm_response = strhex_to_data_blob(NULL, hex_lm_response);
2406 if (opt_lm_response.length != 24) {
2407 fprintf(stderr, "hex decode of %s failed! "
2408 "(only got %d bytes)\n",
2410 (int)opt_lm_response.length);
2416 opt_nt_response = strhex_to_data_blob(NULL, hex_nt_response);
2417 if (opt_nt_response.length < 24) {
2418 fprintf(stderr, "hex decode of %s failed! "
2419 "(only got %d bytes)\n",
2421 (int)opt_nt_response.length);
2426 case OPT_REQUIRE_MEMBERSHIP:
2427 if (strncasecmp_m("S-", require_membership_of, 2) == 0) {
2428 require_membership_of_sid = require_membership_of;
2435 char *domain = SMB_STRDUP(opt_username);
2436 char *p = strchr_m(domain, *lp_winbind_separator());
2440 if (opt_domain && !strequal(opt_domain, domain)) {
2441 fprintf(stderr, "Domain specified in username (%s) "
2442 "doesn't match specified domain (%s)!\n\n",
2443 domain, opt_domain);
2444 poptPrintHelp(pc, stderr, 0);
2447 opt_domain = domain;
2453 /* Note: if opt_domain is "" then send no domain */
2454 if (opt_domain == NULL) {
2455 opt_domain = get_winbind_domain();
2458 if (opt_workstation == NULL) {
2459 opt_workstation = "";
2462 lp_ctx = loadparm_init_s3(NULL, loadparm_s3_helpers());
2463 if (lp_ctx == NULL) {
2464 fprintf(stderr, "loadparm_init_s3() failed!\n");
2468 if (helper_protocol) {
2470 for (i=0; i<NUM_HELPER_MODES; i++) {
2471 if (strcmp(helper_protocol, stdio_helper_protocols[i].name) == 0) {
2472 squid_stream(stdio_helper_protocols[i].mode, lp_ctx, stdio_helper_protocols[i].fn);
2476 fprintf(stderr, "unknown helper protocol [%s]\n\n"
2477 "Valid helper protools:\n\n", helper_protocol);
2479 for (i=0; i<NUM_HELPER_MODES; i++) {
2480 fprintf(stderr, "%s\n",
2481 stdio_helper_protocols[i].name);
2487 if (!opt_username || !*opt_username) {
2488 fprintf(stderr, "username must be specified!\n\n");
2489 poptPrintHelp(pc, stderr, 0);
2493 if (opt_challenge.length) {
2494 if (!check_auth_crap()) {
2500 if (!opt_password) {
2501 char pwd[256] = {0};
2504 rc = samba_getpass("Password: ", pwd, sizeof(pwd), false, false);
2506 opt_password = SMB_STRDUP(pwd);
2511 if (!diagnose_ntlm_auth()) {
2517 fstr_sprintf(user, "%s%c%s", opt_domain, winbind_separator(), opt_username);
2518 if (!check_plaintext_auth(user, opt_password, True)) {
2525 poptFreeContext(pc);