2 Unix SMB/CIFS implementation.
4 Winbind status program.
6 Copyright (C) Tim Potter 2000-2003
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003-2004
8 Copyright (C) Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it> 2000
9 Copyright (C) Robert O'Callahan 2006 (added cached credential code).
10 Copyright (C) Kai Blin <kai@samba.org> 2008
11 Copyright (C) Simo Sorce 2010
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 3 of the License, or
16 (at your option) any later version.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 #include "lib/param/param.h"
29 #include "popt_common.h"
30 #include "utils/ntlm_auth.h"
31 #include "../libcli/auth/libcli_auth.h"
32 #include "auth/ntlmssp/ntlmssp.h"
33 #include "auth/gensec/gensec.h"
34 #include "auth/gensec/gensec_internal.h"
35 #include "auth/credentials/credentials.h"
36 #include "librpc/crypto/gse.h"
38 #include "lib/util/tiniparser.h"
39 #include "../lib/crypto/arcfour.h"
40 #include "nsswitch/winbind_client.h"
41 #include "librpc/gen_ndr/krb5pac.h"
42 #include "../lib/util/asn1.h"
43 #include "auth/common_auth.h"
44 #include "source3/include/auth.h"
45 #include "source3/auth/proto.h"
46 #include "nsswitch/libwbclient/wbclient.h"
47 #include "lib/param/loadparm.h"
48 #include "lib/util/base64.h"
51 #include "auth/kerberos/pac_utils.h"
54 #ifndef PAM_WINBIND_CONFIG_FILE
55 #define PAM_WINBIND_CONFIG_FILE "/etc/security/pam_winbind.conf"
58 #define WINBIND_KRB5_AUTH 0x00000080
61 #define DBGC_CLASS DBGC_WINBIND
63 #define INITIAL_BUFFER_SIZE 300
64 #define MAX_BUFFER_SIZE 630000
66 enum stdio_helper_mode {
74 NTLM_CHANGE_PASSWORD_1,
78 enum ntlm_auth_cli_state {
85 struct ntlm_auth_state {
87 enum stdio_helper_mode helper_mode;
88 enum ntlm_auth_cli_state cli_state;
89 struct ntlmssp_state *ntlmssp_state;
91 char *want_feature_list;
92 bool have_session_key;
93 DATA_BLOB session_key;
94 DATA_BLOB initial_message;
95 void *gensec_private_1;
97 typedef void (*stdio_helper_function)(enum stdio_helper_mode stdio_helper_mode,
98 struct loadparm_context *lp_ctx,
99 struct ntlm_auth_state *state, char *buf,
100 int length, void **private2);
102 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
103 struct loadparm_context *lp_ctx,
104 char *buf, int length, void **private1);
106 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode,
107 struct loadparm_context *lp_ctx,
108 struct ntlm_auth_state *state,
109 stdio_helper_function fn, void **private2);
111 static void manage_squid_basic_request (enum stdio_helper_mode stdio_helper_mode,
112 struct loadparm_context *lp_ctx,
113 struct ntlm_auth_state *state,
114 char *buf, int length, void **private2);
116 static void manage_squid_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode,
117 struct loadparm_context *lp_ctx,
118 struct ntlm_auth_state *state,
119 char *buf, int length, void **private2);
121 static void manage_client_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode,
122 struct loadparm_context *lp_ctx,
123 struct ntlm_auth_state *state,
124 char *buf, int length, void **private2);
126 static void manage_gss_spnego_request (enum stdio_helper_mode stdio_helper_mode,
127 struct loadparm_context *lp_ctx,
128 struct ntlm_auth_state *state,
129 char *buf, int length, void **private2);
131 static void manage_gss_spnego_client_request (enum stdio_helper_mode stdio_helper_mode,
132 struct loadparm_context *lp_ctx,
133 struct ntlm_auth_state *state,
134 char *buf, int length, void **private2);
136 static void manage_ntlm_server_1_request (enum stdio_helper_mode stdio_helper_mode,
137 struct loadparm_context *lp_ctx,
138 struct ntlm_auth_state *state,
139 char *buf, int length, void **private2);
141 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode,
142 struct loadparm_context *lp_ctx,
143 struct ntlm_auth_state *state,
144 char *buf, int length, void **private2);
146 static const struct {
147 enum stdio_helper_mode mode;
149 stdio_helper_function fn;
150 } stdio_helper_protocols[] = {
151 { SQUID_2_4_BASIC, "squid-2.4-basic", manage_squid_basic_request},
152 { SQUID_2_5_BASIC, "squid-2.5-basic", manage_squid_basic_request},
153 { SQUID_2_5_NTLMSSP, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request},
154 { NTLMSSP_CLIENT_1, "ntlmssp-client-1", manage_client_ntlmssp_request},
155 { GSS_SPNEGO_SERVER, "gss-spnego", manage_gss_spnego_request},
156 { GSS_SPNEGO_CLIENT, "gss-spnego-client", manage_gss_spnego_client_request},
157 { NTLM_SERVER_1, "ntlm-server-1", manage_ntlm_server_1_request},
158 { NTLM_CHANGE_PASSWORD_1, "ntlm-change-password-1", manage_ntlm_change_password_1_request},
159 { NUM_HELPER_MODES, NULL, NULL}
162 const char *opt_username;
163 const char *opt_domain;
164 const char *opt_workstation;
165 const char *opt_password;
166 static DATA_BLOB opt_challenge;
167 static DATA_BLOB opt_lm_response;
168 static DATA_BLOB opt_nt_response;
169 static int request_lm_key;
170 static int request_user_session_key;
171 static int use_cached_creds;
172 static int offline_logon;
173 static int opt_allow_mschapv2;
175 static const char *require_membership_of;
176 static const char *require_membership_of_sid;
177 static const char *opt_pam_winbind_conf;
179 const char *opt_target_service;
180 const char *opt_target_hostname;
183 /* This is a bit hairy, but the basic idea is to do a password callback
184 to the calling application. The callback comes from within gensec */
186 static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mode,
187 struct loadparm_context *lp_ctx,
188 struct ntlm_auth_state *state, char *buf, int length,
192 if (strlen(buf) < 2) {
193 DEBUG(1, ("query [%s] invalid", buf));
194 x_fprintf(x_stdout, "BH Query invalid\n");
198 if (strlen(buf) > 3) {
199 in = base64_decode_data_blob(buf + 3);
201 in = data_blob(NULL, 0);
204 if (strncmp(buf, "PW ", 3) == 0) {
206 *password = talloc_strndup(NULL,
207 (const char *)in.data, in.length);
209 if (*password == NULL) {
210 DEBUG(1, ("Out of memory\n"));
211 x_fprintf(x_stdout, "BH Out of memory\n");
216 x_fprintf(x_stdout, "OK\n");
220 DEBUG(1, ("Asked for (and expected) a password\n"));
221 x_fprintf(x_stdout, "BH Expected a password\n");
226 * Callback for password credentials. This is not async, and when
227 * GENSEC and the credentials code is made async, it will look rather
231 static const char *get_password(struct cli_credentials *credentials)
233 TALLOC_CTX *frame = talloc_stackframe();
234 char *password = NULL;
235 struct ntlm_auth_state *state;
237 state = talloc_zero(frame, struct ntlm_auth_state);
239 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
240 x_fprintf(x_stderr, "ERR\n");
244 state->mem_ctx = state;
246 /* Ask for a password */
247 x_fprintf(x_stdout, "PW\n");
249 manage_squid_request(NUM_HELPER_MODES /* bogus */, NULL, state, manage_gensec_get_pw_request, (void **)&password);
250 talloc_steal(credentials, password);
256 * A limited set of features are defined with text strings as needed
260 static void gensec_want_feature_list(struct gensec_security *state, char* feature_list)
262 if (in_list("NTLMSSP_FEATURE_SESSION_KEY", feature_list, true)) {
263 DEBUG(10, ("want GENSEC_FEATURE_SESSION_KEY\n"));
264 gensec_want_feature(state, GENSEC_FEATURE_SESSION_KEY);
266 if (in_list("NTLMSSP_FEATURE_SIGN", feature_list, true)) {
267 DEBUG(10, ("want GENSEC_FEATURE_SIGN\n"));
268 gensec_want_feature(state, GENSEC_FEATURE_SIGN);
270 if (in_list("NTLMSSP_FEATURE_SEAL", feature_list, true)) {
271 DEBUG(10, ("want GENSEC_FEATURE_SEAL\n"));
272 gensec_want_feature(state, GENSEC_FEATURE_SEAL);
274 if (in_list("NTLMSSP_FEATURE_CCACHE", feature_list, true)) {
275 DEBUG(10, ("want GENSEC_FEATURE_NTLM_CCACHE\n"));
276 gensec_want_feature(state, GENSEC_FEATURE_NTLM_CCACHE);
280 static char winbind_separator(void)
282 struct winbindd_response response;
289 ZERO_STRUCT(response);
291 /* Send off request */
293 if (winbindd_request_response(NULL, WINBINDD_INFO, NULL, &response) !=
294 NSS_STATUS_SUCCESS) {
295 d_printf("could not obtain winbind separator!\n");
296 return *lp_winbind_separator();
299 sep = response.data.info.winbind_separator;
303 d_printf("winbind separator was NULL!\n");
304 return *lp_winbind_separator();
310 const char *get_winbind_domain(void)
312 struct winbindd_response response;
314 static fstring winbind_domain;
315 if (*winbind_domain) {
316 return winbind_domain;
319 ZERO_STRUCT(response);
321 /* Send off request */
323 if (winbindd_request_response(NULL, WINBINDD_DOMAIN_NAME, NULL, &response) !=
324 NSS_STATUS_SUCCESS) {
325 DEBUG(1, ("could not obtain winbind domain name!\n"));
326 return lp_workgroup();
329 fstrcpy(winbind_domain, response.data.domain_name);
331 return winbind_domain;
335 const char *get_winbind_netbios_name(void)
337 struct winbindd_response response;
339 static fstring winbind_netbios_name;
341 if (*winbind_netbios_name) {
342 return winbind_netbios_name;
345 ZERO_STRUCT(response);
347 /* Send off request */
349 if (winbindd_request_response(NULL, WINBINDD_NETBIOS_NAME, NULL, &response) !=
350 NSS_STATUS_SUCCESS) {
351 DEBUG(1, ("could not obtain winbind netbios name!\n"));
352 return lp_netbios_name();
355 fstrcpy(winbind_netbios_name, response.data.netbios_name);
357 return winbind_netbios_name;
361 DATA_BLOB get_challenge(void)
363 static DATA_BLOB chal;
364 if (opt_challenge.length)
365 return opt_challenge;
367 chal = data_blob(NULL, 8);
369 generate_random_buffer(chal.data, chal.length);
373 /* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
374 form DOMAIN/user into a domain and a user */
376 static bool parse_ntlm_auth_domain_user(const char *domuser, fstring domain,
380 char *p = strchr(domuser,winbind_separator());
387 fstrcpy(domain, domuser);
388 domain[PTR_DIFF(p, domuser)] = 0;
389 return strupper_m(domain);
392 static bool get_require_membership_sid(void) {
393 struct winbindd_request request;
394 struct winbindd_response response;
396 if (!require_membership_of) {
400 if (require_membership_of_sid) {
404 /* Otherwise, ask winbindd for the name->sid request */
406 ZERO_STRUCT(request);
407 ZERO_STRUCT(response);
409 if (!parse_ntlm_auth_domain_user(require_membership_of,
410 request.data.name.dom_name,
411 request.data.name.name)) {
412 DEBUG(0, ("Could not parse %s into separate domain/name parts!\n",
413 require_membership_of));
417 if (winbindd_request_response(NULL, WINBINDD_LOOKUPNAME, &request, &response) !=
418 NSS_STATUS_SUCCESS) {
419 DEBUG(0, ("Winbindd lookupname failed to resolve %s into a SID!\n",
420 require_membership_of));
424 require_membership_of_sid = SMB_STRDUP(response.data.sid.sid);
426 if (require_membership_of_sid)
433 * Get some configuration from pam_winbind.conf to see if we
434 * need to contact trusted domain
437 int get_pam_winbind_config()
440 struct tiniparser_dictionary *d = NULL;
442 if (!opt_pam_winbind_conf || !*opt_pam_winbind_conf) {
443 opt_pam_winbind_conf = PAM_WINBIND_CONFIG_FILE;
446 d = tiniparser_load(opt_pam_winbind_conf);
452 if (tiniparser_getboolean(d, "global:krb5_auth", false)) {
453 ctrl |= WINBIND_KRB5_AUTH;
456 tiniparser_freedict(d);
461 /* Authenticate a user with a plaintext password */
463 static bool check_plaintext_auth(const char *user, const char *pass,
464 bool stdout_diagnostics)
466 struct winbindd_request request;
467 struct winbindd_response response;
470 if (!get_require_membership_sid()) {
474 /* Send off request */
476 ZERO_STRUCT(request);
477 ZERO_STRUCT(response);
479 fstrcpy(request.data.auth.user, user);
480 fstrcpy(request.data.auth.pass, pass);
481 if (require_membership_of_sid) {
482 strlcpy(request.data.auth.require_membership_of_sid,
483 require_membership_of_sid,
484 sizeof(request.data.auth.require_membership_of_sid));
488 request.flags |= WBFLAG_PAM_CACHED_LOGIN;
491 result = winbindd_request_response(NULL, WINBINDD_PAM_AUTH, &request, &response);
493 /* Display response */
495 if (stdout_diagnostics) {
496 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
497 d_printf("Reading winbind reply failed! (0x01)\n");
500 d_printf("%s: %s (0x%x)\n",
501 response.data.auth.nt_status_string,
502 response.data.auth.error_string,
503 response.data.auth.nt_status);
505 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
506 DEBUG(1, ("Reading winbind reply failed! (0x01)\n"));
509 DEBUG(3, ("%s: %s (0x%x)\n",
510 response.data.auth.nt_status_string,
511 response.data.auth.error_string,
512 response.data.auth.nt_status));
515 return (result == NSS_STATUS_SUCCESS);
518 /* authenticate a user with an encrypted username/password */
520 NTSTATUS contact_winbind_auth_crap(const char *username,
522 const char *workstation,
523 const DATA_BLOB *challenge,
524 const DATA_BLOB *lm_response,
525 const DATA_BLOB *nt_response,
527 uint32_t extra_logon_parameters,
529 uint8_t user_session_key[16],
535 struct winbindd_request request;
536 struct winbindd_response response;
538 if (!get_require_membership_sid()) {
539 return NT_STATUS_INVALID_PARAMETER;
542 ZERO_STRUCT(request);
543 ZERO_STRUCT(response);
545 request.flags = flags;
547 request.data.auth_crap.logon_parameters = extra_logon_parameters
548 | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT | MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT;
550 if (opt_allow_mschapv2) {
551 request.data.auth_crap.logon_parameters |= MSV1_0_ALLOW_MSVCHAPV2;
554 if (require_membership_of_sid)
555 fstrcpy(request.data.auth_crap.require_membership_of_sid, require_membership_of_sid);
557 fstrcpy(request.data.auth_crap.user, username);
558 fstrcpy(request.data.auth_crap.domain, domain);
560 fstrcpy(request.data.auth_crap.workstation,
563 memcpy(request.data.auth_crap.chal, challenge->data, MIN(challenge->length, 8));
565 if (lm_response && lm_response->length) {
566 memcpy(request.data.auth_crap.lm_resp,
568 MIN(lm_response->length, sizeof(request.data.auth_crap.lm_resp)));
569 request.data.auth_crap.lm_resp_len = lm_response->length;
572 if (nt_response && nt_response->length) {
573 if (nt_response->length > sizeof(request.data.auth_crap.nt_resp)) {
574 request.flags = request.flags | WBFLAG_BIG_NTLMV2_BLOB;
575 request.extra_len = nt_response->length;
576 request.extra_data.data = SMB_MALLOC_ARRAY(char, request.extra_len);
577 if (request.extra_data.data == NULL) {
578 return NT_STATUS_NO_MEMORY;
580 memcpy(request.extra_data.data, nt_response->data,
581 nt_response->length);
584 memcpy(request.data.auth_crap.nt_resp,
585 nt_response->data, nt_response->length);
587 request.data.auth_crap.nt_resp_len = nt_response->length;
590 result = winbindd_request_response(NULL, WINBINDD_PAM_AUTH_CRAP, &request, &response);
591 SAFE_FREE(request.extra_data.data);
593 /* Display response */
595 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
596 nt_status = NT_STATUS_UNSUCCESSFUL;
598 *error_string = smb_xstrdup("Reading winbind reply failed!");
599 winbindd_free_response(&response);
603 nt_status = (NT_STATUS(response.data.auth.nt_status));
604 if (!NT_STATUS_IS_OK(nt_status)) {
606 *error_string = smb_xstrdup(response.data.auth.error_string);
607 winbindd_free_response(&response);
611 if ((flags & WBFLAG_PAM_LMKEY) && lm_key) {
612 memcpy(lm_key, response.data.auth.first_8_lm_hash,
613 sizeof(response.data.auth.first_8_lm_hash));
615 if ((flags & WBFLAG_PAM_USER_SESSION_KEY) && user_session_key) {
616 memcpy(user_session_key, response.data.auth.user_session_key,
617 sizeof(response.data.auth.user_session_key));
620 if (flags & WBFLAG_PAM_UNIX_NAME) {
621 *unix_name = SMB_STRDUP(response.data.auth.unix_username);
623 winbindd_free_response(&response);
624 return NT_STATUS_NO_MEMORY;
628 winbindd_free_response(&response);
632 /* contact server to change user password using auth crap */
633 static NTSTATUS contact_winbind_change_pswd_auth_crap(const char *username,
635 const DATA_BLOB new_nt_pswd,
636 const DATA_BLOB old_nt_hash_enc,
637 const DATA_BLOB new_lm_pswd,
638 const DATA_BLOB old_lm_hash_enc,
643 struct winbindd_request request;
644 struct winbindd_response response;
646 if (!get_require_membership_sid())
649 *error_string = smb_xstrdup("Can't get membership sid.");
650 return NT_STATUS_INVALID_PARAMETER;
653 ZERO_STRUCT(request);
654 ZERO_STRUCT(response);
657 fstrcpy(request.data.chng_pswd_auth_crap.user, username);
659 fstrcpy(request.data.chng_pswd_auth_crap.domain,domain);
661 if(new_nt_pswd.length)
663 memcpy(request.data.chng_pswd_auth_crap.new_nt_pswd, new_nt_pswd.data, sizeof(request.data.chng_pswd_auth_crap.new_nt_pswd));
664 request.data.chng_pswd_auth_crap.new_nt_pswd_len = new_nt_pswd.length;
667 if(old_nt_hash_enc.length)
669 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));
670 request.data.chng_pswd_auth_crap.old_nt_hash_enc_len = old_nt_hash_enc.length;
673 if(new_lm_pswd.length)
675 memcpy(request.data.chng_pswd_auth_crap.new_lm_pswd, new_lm_pswd.data, sizeof(request.data.chng_pswd_auth_crap.new_lm_pswd));
676 request.data.chng_pswd_auth_crap.new_lm_pswd_len = new_lm_pswd.length;
679 if(old_lm_hash_enc.length)
681 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));
682 request.data.chng_pswd_auth_crap.old_lm_hash_enc_len = old_lm_hash_enc.length;
685 result = winbindd_request_response(NULL, WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP, &request, &response);
687 /* Display response */
689 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0))
691 nt_status = NT_STATUS_UNSUCCESSFUL;
693 *error_string = smb_xstrdup("Reading winbind reply failed!");
694 winbindd_free_response(&response);
698 nt_status = (NT_STATUS(response.data.auth.nt_status));
699 if (!NT_STATUS_IS_OK(nt_status))
702 *error_string = smb_xstrdup(response.data.auth.error_string);
703 winbindd_free_response(&response);
707 winbindd_free_response(&response);
712 static NTSTATUS ntlm_auth_generate_session_info(struct auth4_context *auth_context,
714 void *server_returned_info,
715 const char *original_user_name,
716 uint32_t session_info_flags,
717 struct auth_session_info **session_info_out)
719 char *unix_username = (char *)server_returned_info;
720 struct auth_session_info *session_info = talloc_zero(mem_ctx, struct auth_session_info);
722 return NT_STATUS_NO_MEMORY;
725 session_info->unix_info = talloc_zero(session_info, struct auth_user_info_unix);
726 if (!session_info->unix_info) {
727 TALLOC_FREE(session_info);
728 return NT_STATUS_NO_MEMORY;
730 session_info->unix_info->unix_name = talloc_steal(session_info->unix_info, unix_username);
732 *session_info_out = session_info;
737 static NTSTATUS ntlm_auth_generate_session_info_pac(struct auth4_context *auth_ctx,
739 struct smb_krb5_context *smb_krb5_context,
741 const char *princ_name,
742 const struct tsocket_address *remote_address,
743 uint32_t session_info_flags,
744 struct auth_session_info **session_info)
747 struct PAC_LOGON_INFO *logon_info = NULL;
755 tmp_ctx = talloc_new(mem_ctx);
757 return NT_STATUS_NO_MEMORY;
762 status = kerberos_pac_logon_info(tmp_ctx, *pac_blob, NULL, NULL,
763 NULL, NULL, 0, &logon_info);
765 status = NT_STATUS_ACCESS_DENIED;
767 if (!NT_STATUS_IS_OK(status)) {
772 DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name));
774 p = strchr_m(princ_name, '@');
776 DEBUG(3, ("[%s] Doesn't look like a valid principal\n",
778 return NT_STATUS_LOGON_FAILURE;
781 user = talloc_strndup(mem_ctx, princ_name, p - princ_name);
783 return NT_STATUS_NO_MEMORY;
786 realm = talloc_strdup(talloc_tos(), p + 1);
788 return NT_STATUS_NO_MEMORY;
791 if (!strequal(realm, lp_realm())) {
792 DEBUG(3, ("Ticket for foreign realm %s@%s\n", user, realm));
793 if (!lp_allow_trusted_domains()) {
794 return NT_STATUS_LOGON_FAILURE;
798 if (logon_info && logon_info->info3.base.logon_domain.string) {
799 domain = talloc_strdup(mem_ctx,
800 logon_info->info3.base.logon_domain.string);
802 return NT_STATUS_NO_MEMORY;
804 DEBUG(10, ("Domain is [%s] (using PAC)\n", domain));
807 /* If we have winbind running, we can (and must) shorten the
808 username by using the short netbios name. Otherwise we will
809 have inconsistent user names. With Kerberos, we get the
810 fully qualified realm, with ntlmssp we get the short
811 name. And even w2k3 does use ntlmssp if you for example
812 connect to an ip address. */
815 struct wbcDomainInfo *info = NULL;
817 DEBUG(10, ("Mapping [%s] to short name using winbindd\n",
820 wbc_status = wbcDomainInfo(realm, &info);
822 if (WBC_ERROR_IS_OK(wbc_status)) {
823 domain = talloc_strdup(mem_ctx,
827 DEBUG(3, ("Could not find short name: %s\n",
828 wbcErrorString(wbc_status)));
829 domain = talloc_strdup(mem_ctx, realm);
832 return NT_STATUS_NO_MEMORY;
834 DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain));
837 unixuser = talloc_asprintf(tmp_ctx, "%s%c%s", domain, winbind_separator(), user);
839 status = NT_STATUS_NO_MEMORY;
843 status = ntlm_auth_generate_session_info(auth_ctx, mem_ctx, unixuser, NULL, session_info_flags, session_info);
846 TALLOC_FREE(tmp_ctx);
853 * Return the challenge as determined by the authentication subsystem
854 * @return an 8 byte random challenge
857 static NTSTATUS ntlm_auth_get_challenge(struct auth4_context *auth_ctx,
860 if (auth_ctx->challenge.data.length == 8) {
861 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
862 auth_ctx->challenge.set_by));
863 memcpy(chal, auth_ctx->challenge.data.data, 8);
867 if (!auth_ctx->challenge.set_by) {
868 generate_random_buffer(chal, 8);
870 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
871 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
872 auth_ctx->challenge.set_by = "random";
875 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
876 auth_ctx->challenge.set_by));
882 * NTLM2 authentication modifies the effective challenge,
883 * @param challenge The new challenge value
885 static NTSTATUS ntlm_auth_set_challenge(struct auth4_context *auth_ctx, const uint8_t chal[8], const char *set_by)
887 auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
888 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
890 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
891 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
897 * Check the password on an NTLMSSP login.
899 * Return the session keys used on the connection.
902 static NTSTATUS winbind_pw_check(struct auth4_context *auth4_context,
904 const struct auth_usersupplied_info *user_info,
905 void **server_returned_info,
906 DATA_BLOB *session_key, DATA_BLOB *lm_session_key)
908 static const char zeros[16] = { 0, };
910 char *error_string = NULL;
912 uint8_t user_sess_key[16];
913 char *unix_name = NULL;
915 nt_status = contact_winbind_auth_crap(user_info->client.account_name, user_info->client.domain_name,
916 user_info->workstation_name,
917 &auth4_context->challenge.data,
918 &user_info->password.response.lanman,
919 &user_info->password.response.nt,
920 WBFLAG_PAM_LMKEY | WBFLAG_PAM_USER_SESSION_KEY | WBFLAG_PAM_UNIX_NAME,
922 lm_key, user_sess_key,
923 &error_string, &unix_name);
925 if (NT_STATUS_IS_OK(nt_status)) {
926 if (memcmp(lm_key, zeros, 8) != 0) {
927 *lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
928 memcpy(lm_session_key->data, lm_key, 8);
929 memset(lm_session_key->data+8, '\0', 8);
932 if (memcmp(user_sess_key, zeros, 16) != 0) {
933 *session_key = data_blob_talloc(mem_ctx, user_sess_key, 16);
935 *server_returned_info = talloc_strdup(mem_ctx,
938 DEBUG(NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED) ? 0 : 3,
939 ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
940 user_info->client.domain_name, user_info->client.account_name,
941 user_info->workstation_name,
942 error_string ? error_string : "unknown error (NULL)"));
945 SAFE_FREE(error_string);
946 SAFE_FREE(unix_name);
950 static NTSTATUS local_pw_check(struct auth4_context *auth4_context,
952 const struct auth_usersupplied_info *user_info,
953 void **server_returned_info,
954 DATA_BLOB *session_key, DATA_BLOB *lm_session_key)
957 struct samr_Password lm_pw, nt_pw;
959 nt_lm_owf_gen (opt_password, nt_pw.hash, lm_pw.hash);
961 nt_status = ntlm_password_check(mem_ctx,
963 &auth4_context->challenge.data,
964 &user_info->password.response.lanman,
965 &user_info->password.response.nt,
966 user_info->client.account_name,
967 user_info->client.account_name,
968 user_info->client.domain_name,
969 &lm_pw, &nt_pw, session_key, lm_session_key);
971 if (NT_STATUS_IS_OK(nt_status)) {
972 *server_returned_info = talloc_asprintf(mem_ctx,
973 "%s%c%s", user_info->client.domain_name,
974 *lp_winbind_separator(),
975 user_info->client.account_name);
977 DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
978 user_info->client.domain_name, user_info->client.account_name,
979 user_info->workstation_name,
980 nt_errstr(nt_status)));
985 static NTSTATUS ntlm_auth_prepare_gensec_client(TALLOC_CTX *mem_ctx,
986 struct loadparm_context *lp_ctx,
987 struct gensec_security **gensec_security_out)
989 struct gensec_security *gensec_security = NULL;
992 const struct gensec_security_ops **backends = NULL;
993 struct gensec_settings *gensec_settings = NULL;
996 tmp_ctx = talloc_new(mem_ctx);
997 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
999 gensec_settings = lpcfg_gensec_settings(tmp_ctx, lp_ctx);
1000 if (gensec_settings == NULL) {
1001 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1002 TALLOC_FREE(tmp_ctx);
1003 return NT_STATUS_NO_MEMORY;
1006 backends = talloc_zero_array(gensec_settings,
1007 const struct gensec_security_ops *, 4);
1008 if (backends == NULL) {
1009 TALLOC_FREE(tmp_ctx);
1010 return NT_STATUS_NO_MEMORY;
1012 gensec_settings->backends = backends;
1016 /* These need to be in priority order, krb5 before NTLMSSP */
1017 #if defined(HAVE_KRB5)
1018 backends[idx++] = &gensec_gse_krb5_security_ops;
1021 backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_NTLMSSP);
1023 backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_SPNEGO);
1025 nt_status = gensec_client_start(NULL, &gensec_security,
1027 if (!NT_STATUS_IS_OK(nt_status)) {
1028 TALLOC_FREE(tmp_ctx);
1032 talloc_unlink(tmp_ctx, gensec_settings);
1034 if (opt_target_service != NULL) {
1035 nt_status = gensec_set_target_service(gensec_security,
1036 opt_target_service);
1037 if (!NT_STATUS_IS_OK(nt_status)) {
1038 TALLOC_FREE(tmp_ctx);
1043 if (opt_target_hostname != NULL) {
1044 nt_status = gensec_set_target_hostname(gensec_security,
1045 opt_target_hostname);
1046 if (!NT_STATUS_IS_OK(nt_status)) {
1047 TALLOC_FREE(tmp_ctx);
1052 *gensec_security_out = talloc_steal(mem_ctx, gensec_security);
1053 TALLOC_FREE(tmp_ctx);
1054 return NT_STATUS_OK;
1057 static struct auth4_context *make_auth4_context_ntlm_auth(TALLOC_CTX *mem_ctx, bool local_pw)
1059 struct auth4_context *auth4_context = talloc_zero(mem_ctx, struct auth4_context);
1060 if (auth4_context == NULL) {
1061 DEBUG(10, ("failed to allocate auth4_context failed\n"));
1064 auth4_context->generate_session_info = ntlm_auth_generate_session_info;
1065 auth4_context->generate_session_info_pac = ntlm_auth_generate_session_info_pac;
1066 auth4_context->get_ntlm_challenge = ntlm_auth_get_challenge;
1067 auth4_context->set_ntlm_challenge = ntlm_auth_set_challenge;
1069 auth4_context->check_ntlm_password = local_pw_check;
1071 auth4_context->check_ntlm_password = winbind_pw_check;
1073 auth4_context->private_data = NULL;
1074 return auth4_context;
1077 static NTSTATUS ntlm_auth_prepare_gensec_server(TALLOC_CTX *mem_ctx,
1078 struct loadparm_context *lp_ctx,
1079 struct gensec_security **gensec_security_out)
1081 struct gensec_security *gensec_security;
1084 TALLOC_CTX *tmp_ctx;
1085 const struct gensec_security_ops **backends;
1086 struct gensec_settings *gensec_settings;
1088 struct cli_credentials *server_credentials;
1090 struct auth4_context *auth4_context;
1092 tmp_ctx = talloc_new(mem_ctx);
1093 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
1095 auth4_context = make_auth4_context_ntlm_auth(tmp_ctx, opt_password);
1096 if (auth4_context == NULL) {
1097 TALLOC_FREE(tmp_ctx);
1098 return NT_STATUS_NO_MEMORY;
1101 gensec_settings = lpcfg_gensec_settings(tmp_ctx, lp_ctx);
1102 if (lp_ctx == NULL) {
1103 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1104 TALLOC_FREE(tmp_ctx);
1105 return NT_STATUS_NO_MEMORY;
1109 * This should be a 'netbios domain -> DNS domain'
1110 * mapping, and can currently validly return NULL on
1111 * poorly configured systems.
1113 * This is used for the NTLMSSP server
1117 gensec_settings->server_netbios_name = lp_netbios_name();
1118 gensec_settings->server_netbios_domain = lp_workgroup();
1120 gensec_settings->server_netbios_name = get_winbind_netbios_name();
1121 gensec_settings->server_netbios_domain = get_winbind_domain();
1124 gensec_settings->server_dns_domain = strlower_talloc(gensec_settings,
1125 get_mydnsdomname(talloc_tos()));
1126 gensec_settings->server_dns_name = strlower_talloc(gensec_settings,
1127 get_mydnsfullname());
1129 backends = talloc_zero_array(gensec_settings,
1130 const struct gensec_security_ops *, 4);
1132 if (backends == NULL) {
1133 TALLOC_FREE(tmp_ctx);
1134 return NT_STATUS_NO_MEMORY;
1136 gensec_settings->backends = backends;
1140 /* These need to be in priority order, krb5 before NTLMSSP */
1141 #if defined(HAVE_KRB5)
1142 backends[idx++] = &gensec_gse_krb5_security_ops;
1145 backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_NTLMSSP);
1147 backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_SPNEGO);
1150 * This is anonymous for now, because we just use it
1151 * to set the kerberos state at the moment
1153 server_credentials = cli_credentials_init_anon(tmp_ctx);
1154 if (!server_credentials) {
1155 DEBUG(0, ("auth_generic_prepare: Failed to init server credentials\n"));
1156 return NT_STATUS_NO_MEMORY;
1159 cli_credentials_set_conf(server_credentials, lp_ctx);
1161 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC || lp_security() == SEC_ADS || USE_KERBEROS_KEYTAB) {
1162 cli_credentials_set_kerberos_state(server_credentials, CRED_AUTO_USE_KERBEROS);
1164 cli_credentials_set_kerberos_state(server_credentials, CRED_DONT_USE_KERBEROS);
1167 nt_status = gensec_server_start(tmp_ctx, gensec_settings,
1168 auth4_context, &gensec_security);
1170 if (!NT_STATUS_IS_OK(nt_status)) {
1171 TALLOC_FREE(tmp_ctx);
1175 gensec_set_credentials(gensec_security, server_credentials);
1177 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
1178 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
1180 talloc_unlink(tmp_ctx, lp_ctx);
1181 talloc_unlink(tmp_ctx, server_credentials);
1182 talloc_unlink(tmp_ctx, gensec_settings);
1183 talloc_unlink(tmp_ctx, auth4_context);
1185 *gensec_security_out = talloc_steal(mem_ctx, gensec_security);
1186 TALLOC_FREE(tmp_ctx);
1187 return NT_STATUS_OK;
1190 static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode,
1191 struct loadparm_context *lp_ctx,
1192 struct ntlm_auth_state *state,
1193 char *buf, int length, void **private2)
1195 manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
1199 static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode,
1200 struct loadparm_context *lp_ctx,
1201 struct ntlm_auth_state *state,
1202 char *buf, int length, void **private2)
1207 pass=(char *)memchr(buf,' ',length);
1209 DEBUG(2, ("Password not found. Denying access\n"));
1210 x_fprintf(x_stdout, "ERR\n");
1216 if (state->helper_mode == SQUID_2_5_BASIC) {
1217 rfc1738_unescape(user);
1218 rfc1738_unescape(pass);
1221 if (check_plaintext_auth(user, pass, False)) {
1222 x_fprintf(x_stdout, "OK\n");
1224 x_fprintf(x_stdout, "ERR\n");
1228 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
1229 struct loadparm_context *lp_ctx,
1230 char *buf, int length, void **private1)
1233 DATA_BLOB out = data_blob(NULL, 0);
1234 char *out_base64 = NULL;
1235 const char *reply_arg = NULL;
1236 struct gensec_ntlm_state {
1237 struct gensec_security *gensec_state;
1238 const char *set_password;
1240 struct gensec_ntlm_state *state;
1244 const char *reply_code;
1245 struct cli_credentials *creds;
1247 static char *want_feature_list = NULL;
1248 static DATA_BLOB session_key;
1250 TALLOC_CTX *mem_ctx;
1253 state = (struct gensec_ntlm_state *)*private1;
1255 state = talloc_zero(NULL, struct gensec_ntlm_state);
1257 x_fprintf(x_stdout, "BH No Memory\n");
1262 state->set_password = opt_password;
1266 if (strlen(buf) < 2) {
1267 DEBUG(1, ("query [%s] invalid", buf));
1268 x_fprintf(x_stdout, "BH Query invalid\n");
1272 if (strlen(buf) > 3) {
1273 if(strncmp(buf, "SF ", 3) == 0) {
1274 DEBUG(10, ("Setting flags to negotiate\n"));
1275 talloc_free(want_feature_list);
1276 want_feature_list = talloc_strndup(state, buf+3, strlen(buf)-3);
1277 x_fprintf(x_stdout, "OK\n");
1280 in = base64_decode_data_blob(buf + 3);
1282 in = data_blob(NULL, 0);
1285 if (strncmp(buf, "YR", 2) == 0) {
1286 if (state->gensec_state) {
1287 talloc_free(state->gensec_state);
1288 state->gensec_state = NULL;
1290 } else if ( (strncmp(buf, "OK", 2) == 0)) {
1291 /* Just return BH, like ntlm_auth from Samba 3 does. */
1292 x_fprintf(x_stdout, "BH Command expected\n");
1293 data_blob_free(&in);
1295 } else if ( (strncmp(buf, "TT ", 3) != 0) &&
1296 (strncmp(buf, "KK ", 3) != 0) &&
1297 (strncmp(buf, "AF ", 3) != 0) &&
1298 (strncmp(buf, "NA ", 3) != 0) &&
1299 (strncmp(buf, "UG", 2) != 0) &&
1300 (strncmp(buf, "PW ", 3) != 0) &&
1301 (strncmp(buf, "GK", 2) != 0) &&
1302 (strncmp(buf, "GF", 2) != 0)) {
1303 DEBUG(1, ("SPNEGO request [%s] invalid prefix\n", buf));
1304 x_fprintf(x_stdout, "BH SPNEGO request invalid prefix\n");
1305 data_blob_free(&in);
1309 mem_ctx = talloc_named(NULL, 0, "manage_gensec_request internal mem_ctx");
1312 if (!(state->gensec_state)) {
1313 switch (stdio_helper_mode) {
1314 case GSS_SPNEGO_CLIENT:
1316 * cached credentials are only supported by
1317 * NTLMSSP_CLIENT_1 for now.
1319 use_cached_creds = false;
1321 case NTLMSSP_CLIENT_1:
1322 /* setup the client side */
1324 if (state->set_password != NULL) {
1325 use_cached_creds = false;
1328 if (use_cached_creds) {
1329 struct wbcCredentialCacheParams params;
1330 struct wbcCredentialCacheInfo *info = NULL;
1331 struct wbcAuthErrorInfo *error = NULL;
1334 params.account_name = opt_username;
1335 params.domain_name = opt_domain;
1336 params.level = WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP;
1337 params.num_blobs = 0;
1338 params.blobs = NULL;
1340 wbc_status = wbcCredentialCache(¶ms, &info,
1342 wbcFreeMemory(error);
1343 if (!WBC_ERROR_IS_OK(wbc_status)) {
1344 use_cached_creds = false;
1346 wbcFreeMemory(info);
1349 nt_status = ntlm_auth_prepare_gensec_client(state, lp_ctx,
1350 &state->gensec_state);
1351 if (!NT_STATUS_IS_OK(nt_status)) {
1352 x_fprintf(x_stdout, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status));
1353 talloc_free(mem_ctx);
1357 creds = cli_credentials_init(state->gensec_state);
1358 cli_credentials_set_conf(creds, lp_ctx);
1360 cli_credentials_set_username(creds, opt_username, CRED_SPECIFIED);
1363 cli_credentials_set_domain(creds, opt_domain, CRED_SPECIFIED);
1365 if (use_cached_creds) {
1366 gensec_want_feature(state->gensec_state,
1367 GENSEC_FEATURE_NTLM_CCACHE);
1368 } else if (state->set_password) {
1369 cli_credentials_set_password(creds, state->set_password, CRED_SPECIFIED);
1371 cli_credentials_set_password_callback(creds, get_password);
1373 if (opt_workstation) {
1374 cli_credentials_set_workstation(creds, opt_workstation, CRED_SPECIFIED);
1377 gensec_set_credentials(state->gensec_state, creds);
1380 case GSS_SPNEGO_SERVER:
1381 case SQUID_2_5_NTLMSSP:
1383 nt_status = ntlm_auth_prepare_gensec_server(state, lp_ctx,
1384 &state->gensec_state);
1385 if (!NT_STATUS_IS_OK(nt_status)) {
1386 x_fprintf(x_stdout, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status));
1387 talloc_free(mem_ctx);
1393 talloc_free(mem_ctx);
1397 gensec_want_feature_list(state->gensec_state, want_feature_list);
1399 switch (stdio_helper_mode) {
1400 case GSS_SPNEGO_CLIENT:
1401 case GSS_SPNEGO_SERVER:
1402 nt_status = gensec_start_mech_by_oid(state->gensec_state, GENSEC_OID_SPNEGO);
1407 case NTLMSSP_CLIENT_1:
1412 case SQUID_2_5_NTLMSSP:
1413 nt_status = gensec_start_mech_by_oid(state->gensec_state, GENSEC_OID_NTLMSSP);
1416 talloc_free(mem_ctx);
1420 if (!NT_STATUS_IS_OK(nt_status)) {
1421 DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status)));
1422 x_fprintf(x_stdout, "BH GENSEC mech failed to start\n");
1423 talloc_free(mem_ctx);
1431 if (strncmp(buf, "PW ", 3) == 0) {
1432 state->set_password = talloc_strndup(state,
1433 (const char *)in.data,
1436 cli_credentials_set_password(gensec_get_credentials(state->gensec_state),
1437 state->set_password,
1439 x_fprintf(x_stdout, "OK\n");
1440 data_blob_free(&in);
1441 talloc_free(mem_ctx);
1445 if (strncmp(buf, "GK", 2) == 0) {
1447 DEBUG(10, ("Requested session key\n"));
1448 nt_status = gensec_session_key(state->gensec_state, mem_ctx, &session_key);
1449 if(!NT_STATUS_IS_OK(nt_status)) {
1450 DEBUG(1, ("gensec_session_key failed: %s\n", nt_errstr(nt_status)));
1451 x_fprintf(x_stdout, "BH No session key\n");
1452 talloc_free(mem_ctx);
1455 base64_key = base64_encode_data_blob(state, session_key);
1456 SMB_ASSERT(base64_key != NULL);
1457 x_fprintf(x_stdout, "GK %s\n", base64_key);
1458 talloc_free(base64_key);
1460 talloc_free(mem_ctx);
1464 if (strncmp(buf, "GF", 2) == 0) {
1467 DEBUG(10, ("Requested negotiated NTLMSSP feature flags\n"));
1469 neg_flags = gensec_ntlmssp_neg_flags(state->gensec_state);
1470 if (neg_flags == 0) {
1471 x_fprintf(x_stdout, "BH\n");
1475 x_fprintf(x_stdout, "GF 0x%08x\n", neg_flags);
1479 nt_status = gensec_update(state->gensec_state, mem_ctx, in, &out);
1481 /* don't leak 'bad password'/'no such user' info to the network client */
1482 nt_status = nt_status_squash(nt_status);
1485 out_base64 = base64_encode_data_blob(mem_ctx, out);
1486 SMB_ASSERT(out_base64 != NULL);
1491 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1493 if (first && state->gensec_state->gensec_role == GENSEC_CLIENT) {
1495 } else if (state->gensec_state->gensec_role == GENSEC_CLIENT) {
1497 } else if (state->gensec_state->gensec_role == GENSEC_SERVER) {
1504 } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) {
1505 reply_code = "BH NT_STATUS_ACCESS_DENIED";
1506 reply_arg = nt_errstr(nt_status);
1507 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
1508 } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_UNSUCCESSFUL)) {
1509 reply_code = "BH NT_STATUS_UNSUCCESSFUL";
1510 reply_arg = nt_errstr(nt_status);
1511 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
1512 } else if (!NT_STATUS_IS_OK(nt_status)) {
1514 reply_arg = nt_errstr(nt_status);
1515 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
1516 } else if /* OK */ (state->gensec_state->gensec_role == GENSEC_SERVER) {
1517 struct auth_session_info *session_info;
1519 nt_status = gensec_session_info(state->gensec_state, mem_ctx, &session_info);
1520 if (!NT_STATUS_IS_OK(nt_status)) {
1521 reply_code = "BH Failed to retrive session info";
1522 reply_arg = nt_errstr(nt_status);
1523 DEBUG(1, ("GENSEC failed to retrieve the session info: %s\n", nt_errstr(nt_status)));
1527 reply_arg = talloc_strdup(state->gensec_state, session_info->unix_info->unix_name);
1528 if (reply_arg == NULL) {
1529 reply_code = "BH out of memory";
1530 reply_arg = nt_errstr(NT_STATUS_NO_MEMORY);
1532 talloc_free(session_info);
1534 } else if (state->gensec_state->gensec_role == GENSEC_CLIENT) {
1536 reply_arg = out_base64;
1541 switch (stdio_helper_mode) {
1542 case GSS_SPNEGO_SERVER:
1543 x_fprintf(x_stdout, "%s %s %s\n", reply_code,
1544 out_base64 ? out_base64 : "*",
1545 reply_arg ? reply_arg : "*");
1549 x_fprintf(x_stdout, "%s %s\n", reply_code, out_base64);
1550 } else if (reply_arg) {
1551 x_fprintf(x_stdout, "%s %s\n", reply_code, reply_arg);
1553 x_fprintf(x_stdout, "%s\n", reply_code);
1557 talloc_free(mem_ctx);
1561 static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode,
1562 struct loadparm_context *lp_ctx,
1563 struct ntlm_auth_state *state,
1564 char *buf, int length, void **private2)
1566 manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
1570 static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode,
1571 struct loadparm_context *lp_ctx,
1572 struct ntlm_auth_state *state,
1573 char *buf, int length, void **private2)
1575 manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
1579 static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode,
1580 struct loadparm_context *lp_ctx,
1581 struct ntlm_auth_state *state,
1582 char *buf, int length, void **private2)
1584 manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
1588 static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode,
1589 struct loadparm_context *lp_ctx,
1590 struct ntlm_auth_state *state,
1591 char *buf, int length, void **private2)
1593 char *request, *parameter;
1594 static DATA_BLOB challenge;
1595 static DATA_BLOB lm_response;
1596 static DATA_BLOB nt_response;
1597 static char *full_username;
1598 static char *username;
1599 static char *domain;
1600 static char *plaintext_password;
1601 static bool ntlm_server_1_user_session_key;
1602 static bool ntlm_server_1_lm_session_key;
1604 if (strequal(buf, ".")) {
1605 if (!full_username && !username) {
1606 x_fprintf(x_stdout, "Error: No username supplied!\n");
1607 } else if (plaintext_password) {
1608 /* handle this request as plaintext */
1609 if (!full_username) {
1610 if (asprintf(&full_username, "%s%c%s", domain, winbind_separator(), username) == -1) {
1611 x_fprintf(x_stdout, "Error: Out of memory in asprintf!\n.\n");
1615 if (check_plaintext_auth(full_username, plaintext_password, False)) {
1616 x_fprintf(x_stdout, "Authenticated: Yes\n");
1618 x_fprintf(x_stdout, "Authenticated: No\n");
1620 } else if (!lm_response.data && !nt_response.data) {
1621 x_fprintf(x_stdout, "Error: No password supplied!\n");
1622 } else if (!challenge.data) {
1623 x_fprintf(x_stdout, "Error: No lanman-challenge supplied!\n");
1625 char *error_string = NULL;
1627 uchar user_session_key[16];
1630 if (full_username && !username) {
1632 fstring fstr_domain;
1634 if (!parse_ntlm_auth_domain_user(full_username, fstr_user, fstr_domain)) {
1635 /* username might be 'tainted', don't print into our new-line deleimianted stream */
1636 x_fprintf(x_stdout, "Error: Could not parse into domain and username\n");
1638 SAFE_FREE(username);
1640 username = smb_xstrdup(fstr_user);
1641 domain = smb_xstrdup(fstr_domain);
1645 DATA_BLOB nt_session_key, lm_session_key;
1646 struct samr_Password lm_pw, nt_pw;
1647 TALLOC_CTX *mem_ctx = talloc_new(NULL);
1648 ZERO_STRUCT(user_session_key);
1649 ZERO_STRUCT(lm_key);
1651 nt_lm_owf_gen (opt_password, nt_pw.hash, lm_pw.hash);
1652 nt_status = ntlm_password_check(mem_ctx,
1663 error_string = smb_xstrdup(get_friendly_nt_error_msg(nt_status));
1664 if (ntlm_server_1_user_session_key) {
1665 if (nt_session_key.length == sizeof(user_session_key)) {
1666 memcpy(user_session_key,
1667 nt_session_key.data,
1668 sizeof(user_session_key));
1671 if (ntlm_server_1_lm_session_key) {
1672 if (lm_session_key.length == sizeof(lm_key)) {
1674 lm_session_key.data,
1678 TALLOC_FREE(mem_ctx);
1682 domain = smb_xstrdup(get_winbind_domain());
1685 if (ntlm_server_1_lm_session_key)
1686 flags |= WBFLAG_PAM_LMKEY;
1688 if (ntlm_server_1_user_session_key)
1689 flags |= WBFLAG_PAM_USER_SESSION_KEY;
1691 nt_status = contact_winbind_auth_crap(username,
1704 if (!NT_STATUS_IS_OK(nt_status)) {
1705 x_fprintf(x_stdout, "Authenticated: No\n");
1706 x_fprintf(x_stdout, "Authentication-Error: %s\n.\n", error_string);
1708 static char zeros[16];
1710 char *hex_user_session_key;
1712 x_fprintf(x_stdout, "Authenticated: Yes\n");
1714 if (ntlm_server_1_lm_session_key
1715 && (memcmp(zeros, lm_key,
1716 sizeof(lm_key)) != 0)) {
1717 hex_lm_key = hex_encode_talloc(NULL,
1718 (const unsigned char *)lm_key,
1720 x_fprintf(x_stdout, "LANMAN-Session-Key: %s\n", hex_lm_key);
1721 TALLOC_FREE(hex_lm_key);
1724 if (ntlm_server_1_user_session_key
1725 && (memcmp(zeros, user_session_key,
1726 sizeof(user_session_key)) != 0)) {
1727 hex_user_session_key = hex_encode_talloc(NULL,
1728 (const unsigned char *)user_session_key,
1729 sizeof(user_session_key));
1730 x_fprintf(x_stdout, "User-Session-Key: %s\n", hex_user_session_key);
1731 TALLOC_FREE(hex_user_session_key);
1734 SAFE_FREE(error_string);
1736 /* clear out the state */
1737 challenge = data_blob_null;
1738 nt_response = data_blob_null;
1739 lm_response = data_blob_null;
1740 SAFE_FREE(full_username);
1741 SAFE_FREE(username);
1743 SAFE_FREE(plaintext_password);
1744 ntlm_server_1_user_session_key = False;
1745 ntlm_server_1_lm_session_key = False;
1746 x_fprintf(x_stdout, ".\n");
1753 /* Indicates a base64 encoded structure */
1754 parameter = strstr_m(request, ":: ");
1756 parameter = strstr_m(request, ": ");
1759 DEBUG(0, ("Parameter not found!\n"));
1760 x_fprintf(x_stdout, "Error: Parameter not found!\n.\n");
1777 base64_decode_inplace(parameter);
1780 if (strequal(request, "LANMAN-Challenge")) {
1781 challenge = strhex_to_data_blob(NULL, parameter);
1782 if (challenge.length != 8) {
1783 x_fprintf(x_stdout, "Error: hex decode of %s failed! (got %d bytes, expected 8)\n.\n",
1785 (int)challenge.length);
1786 challenge = data_blob_null;
1788 } else if (strequal(request, "NT-Response")) {
1789 nt_response = strhex_to_data_blob(NULL, parameter);
1790 if (nt_response.length < 24) {
1791 x_fprintf(x_stdout, "Error: hex decode of %s failed! (only got %d bytes, needed at least 24)\n.\n",
1793 (int)nt_response.length);
1794 nt_response = data_blob_null;
1796 } else if (strequal(request, "LANMAN-Response")) {
1797 lm_response = strhex_to_data_blob(NULL, parameter);
1798 if (lm_response.length != 24) {
1799 x_fprintf(x_stdout, "Error: hex decode of %s failed! (got %d bytes, expected 24)\n.\n",
1801 (int)lm_response.length);
1802 lm_response = data_blob_null;
1804 } else if (strequal(request, "Password")) {
1805 plaintext_password = smb_xstrdup(parameter);
1806 } else if (strequal(request, "NT-Domain")) {
1807 domain = smb_xstrdup(parameter);
1808 } else if (strequal(request, "Username")) {
1809 username = smb_xstrdup(parameter);
1810 } else if (strequal(request, "Full-Username")) {
1811 full_username = smb_xstrdup(parameter);
1812 } else if (strequal(request, "Request-User-Session-Key")) {
1813 ntlm_server_1_user_session_key = strequal(parameter, "Yes");
1814 } else if (strequal(request, "Request-LanMan-Session-Key")) {
1815 ntlm_server_1_lm_session_key = strequal(parameter, "Yes");
1817 x_fprintf(x_stdout, "Error: Unknown request %s\n.\n", request);
1821 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode,
1822 struct loadparm_context *lp_ctx,
1823 struct ntlm_auth_state *state,
1824 char *buf, int length, void **private2)
1826 char *request, *parameter;
1827 static DATA_BLOB new_nt_pswd;
1828 static DATA_BLOB old_nt_hash_enc;
1829 static DATA_BLOB new_lm_pswd;
1830 static DATA_BLOB old_lm_hash_enc;
1831 static char *full_username = NULL;
1832 static char *username = NULL;
1833 static char *domain = NULL;
1834 static char *newpswd = NULL;
1835 static char *oldpswd = NULL;
1837 if (strequal(buf, ".")) {
1838 if(newpswd && oldpswd) {
1839 uchar old_nt_hash[16];
1840 uchar old_lm_hash[16];
1841 uchar new_nt_hash[16];
1842 uchar new_lm_hash[16];
1844 new_nt_pswd = data_blob(NULL, 516);
1845 old_nt_hash_enc = data_blob(NULL, 16);
1847 /* Calculate the MD4 hash (NT compatible) of the
1849 E_md4hash(oldpswd, old_nt_hash);
1850 E_md4hash(newpswd, new_nt_hash);
1852 /* E_deshash returns false for 'long'
1853 passwords (> 14 DOS chars).
1855 Therefore, don't send a buffer
1856 encrypted with the truncated hash
1857 (it could allow an even easier
1858 attack on the password)
1860 Likewise, obey the admin's restriction
1863 if (lp_client_lanman_auth() &&
1864 E_deshash(newpswd, new_lm_hash) &&
1865 E_deshash(oldpswd, old_lm_hash)) {
1866 new_lm_pswd = data_blob(NULL, 516);
1867 old_lm_hash_enc = data_blob(NULL, 16);
1868 encode_pw_buffer(new_lm_pswd.data, newpswd,
1871 arcfour_crypt(new_lm_pswd.data, old_nt_hash, 516);
1872 E_old_pw_hash(new_nt_hash, old_lm_hash,
1873 old_lm_hash_enc.data);
1875 new_lm_pswd.data = NULL;
1876 new_lm_pswd.length = 0;
1877 old_lm_hash_enc.data = NULL;
1878 old_lm_hash_enc.length = 0;
1881 encode_pw_buffer(new_nt_pswd.data, newpswd,
1884 arcfour_crypt(new_nt_pswd.data, old_nt_hash, 516);
1885 E_old_pw_hash(new_nt_hash, old_nt_hash,
1886 old_nt_hash_enc.data);
1889 if (!full_username && !username) {
1890 x_fprintf(x_stdout, "Error: No username supplied!\n");
1891 } else if ((!new_nt_pswd.data || !old_nt_hash_enc.data) &&
1892 (!new_lm_pswd.data || old_lm_hash_enc.data) ) {
1893 x_fprintf(x_stdout, "Error: No NT or LM password "
1894 "blobs supplied!\n");
1896 char *error_string = NULL;
1898 if (full_username && !username) {
1900 fstring fstr_domain;
1902 if (!parse_ntlm_auth_domain_user(full_username,
1905 /* username might be 'tainted', don't
1906 * print into our new-line
1907 * deleimianted stream */
1908 x_fprintf(x_stdout, "Error: Could not "
1909 "parse into domain and "
1911 SAFE_FREE(username);
1912 username = smb_xstrdup(full_username);
1914 SAFE_FREE(username);
1916 username = smb_xstrdup(fstr_user);
1917 domain = smb_xstrdup(fstr_domain);
1922 if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
1929 x_fprintf(x_stdout, "Password-Change: No\n");
1930 x_fprintf(x_stdout, "Password-Change-Error: "
1931 "%s\n.\n", error_string);
1933 x_fprintf(x_stdout, "Password-Change: Yes\n");
1936 SAFE_FREE(error_string);
1938 /* clear out the state */
1939 new_nt_pswd = data_blob_null;
1940 old_nt_hash_enc = data_blob_null;
1941 new_lm_pswd = data_blob_null;
1942 old_nt_hash_enc = data_blob_null;
1943 SAFE_FREE(full_username);
1944 SAFE_FREE(username);
1948 x_fprintf(x_stdout, ".\n");
1955 /* Indicates a base64 encoded structure */
1956 parameter = strstr_m(request, ":: ");
1958 parameter = strstr_m(request, ": ");
1961 DEBUG(0, ("Parameter not found!\n"));
1962 x_fprintf(x_stdout, "Error: Parameter not found!\n.\n");
1978 base64_decode_inplace(parameter);
1981 if (strequal(request, "new-nt-password-blob")) {
1982 new_nt_pswd = strhex_to_data_blob(NULL, parameter);
1983 if (new_nt_pswd.length != 516) {
1984 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
1985 "(got %d bytes, expected 516)\n.\n",
1987 (int)new_nt_pswd.length);
1988 new_nt_pswd = data_blob_null;
1990 } else if (strequal(request, "old-nt-hash-blob")) {
1991 old_nt_hash_enc = strhex_to_data_blob(NULL, parameter);
1992 if (old_nt_hash_enc.length != 16) {
1993 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
1994 "(got %d bytes, expected 16)\n.\n",
1996 (int)old_nt_hash_enc.length);
1997 old_nt_hash_enc = data_blob_null;
1999 } else if (strequal(request, "new-lm-password-blob")) {
2000 new_lm_pswd = strhex_to_data_blob(NULL, parameter);
2001 if (new_lm_pswd.length != 516) {
2002 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2003 "(got %d bytes, expected 516)\n.\n",
2005 (int)new_lm_pswd.length);
2006 new_lm_pswd = data_blob_null;
2009 else if (strequal(request, "old-lm-hash-blob")) {
2010 old_lm_hash_enc = strhex_to_data_blob(NULL, parameter);
2011 if (old_lm_hash_enc.length != 16)
2013 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2014 "(got %d bytes, expected 16)\n.\n",
2016 (int)old_lm_hash_enc.length);
2017 old_lm_hash_enc = data_blob_null;
2019 } else if (strequal(request, "nt-domain")) {
2020 domain = smb_xstrdup(parameter);
2021 } else if(strequal(request, "username")) {
2022 username = smb_xstrdup(parameter);
2023 } else if(strequal(request, "full-username")) {
2024 username = smb_xstrdup(parameter);
2025 } else if(strequal(request, "new-password")) {
2026 newpswd = smb_xstrdup(parameter);
2027 } else if (strequal(request, "old-password")) {
2028 oldpswd = smb_xstrdup(parameter);
2030 x_fprintf(x_stdout, "Error: Unknown request %s\n.\n", request);
2034 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode,
2035 struct loadparm_context *lp_ctx,
2036 struct ntlm_auth_state *state,
2037 stdio_helper_function fn, void **private2)
2040 char tmp[INITIAL_BUFFER_SIZE+1];
2041 int length, buf_size = 0;
2044 buf = talloc_strdup(state->mem_ctx, "");
2046 DEBUG(0, ("Failed to allocate input buffer.\n"));
2047 x_fprintf(x_stderr, "ERR\n");
2053 /* this is not a typo - x_fgets doesn't work too well under
2055 if (fgets(tmp, sizeof(tmp)-1, stdin) == NULL) {
2056 if (ferror(stdin)) {
2057 DEBUG(1, ("fgets() failed! dying..... errno=%d "
2058 "(%s)\n", ferror(stdin),
2059 strerror(ferror(stdin))));
2066 buf = talloc_strdup_append_buffer(buf, tmp);
2067 buf_size += INITIAL_BUFFER_SIZE;
2069 if (buf_size > MAX_BUFFER_SIZE) {
2070 DEBUG(2, ("Oversized message\n"));
2071 x_fprintf(x_stderr, "ERR\n");
2076 c = strchr(buf, '\n');
2077 } while (c == NULL);
2082 DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf,length));
2084 if (buf[0] == '\0') {
2085 DEBUG(2, ("Invalid Request\n"));
2086 x_fprintf(x_stderr, "ERR\n");
2091 fn(stdio_helper_mode, lp_ctx, state, buf, length, private2);
2096 static void squid_stream(enum stdio_helper_mode stdio_mode,
2097 struct loadparm_context *lp_ctx,
2098 stdio_helper_function fn) {
2099 TALLOC_CTX *mem_ctx;
2100 struct ntlm_auth_state *state;
2102 /* initialize FDescs */
2103 x_setbuf(x_stdout, NULL);
2104 x_setbuf(x_stderr, NULL);
2106 mem_ctx = talloc_init("ntlm_auth");
2108 DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
2109 x_fprintf(x_stderr, "ERR\n");
2113 state = talloc_zero(mem_ctx, struct ntlm_auth_state);
2115 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
2116 x_fprintf(x_stderr, "ERR\n");
2120 state->mem_ctx = mem_ctx;
2121 state->helper_mode = stdio_mode;
2124 TALLOC_CTX *frame = talloc_stackframe();
2125 manage_squid_request(stdio_mode, lp_ctx, state, fn, NULL);
2131 /* Authenticate a user with a challenge/response */
2133 static bool check_auth_crap(void)
2138 char user_session_key[16];
2140 char *hex_user_session_key;
2142 static uint8_t zeros[16];
2144 x_setbuf(x_stdout, NULL);
2147 flags |= WBFLAG_PAM_LMKEY;
2149 if (request_user_session_key)
2150 flags |= WBFLAG_PAM_USER_SESSION_KEY;
2152 flags |= WBFLAG_PAM_NT_STATUS_SQUASH;
2154 nt_status = contact_winbind_auth_crap(opt_username, opt_domain,
2160 (unsigned char *)lm_key,
2161 (unsigned char *)user_session_key,
2162 &error_string, NULL);
2164 if (!NT_STATUS_IS_OK(nt_status)) {
2165 x_fprintf(x_stdout, "%s (0x%x)\n",
2167 NT_STATUS_V(nt_status));
2168 SAFE_FREE(error_string);
2173 && (memcmp(zeros, lm_key,
2174 sizeof(lm_key)) != 0)) {
2175 hex_lm_key = hex_encode_talloc(talloc_tos(), (const unsigned char *)lm_key,
2177 x_fprintf(x_stdout, "LM_KEY: %s\n", hex_lm_key);
2178 TALLOC_FREE(hex_lm_key);
2180 if (request_user_session_key
2181 && (memcmp(zeros, user_session_key,
2182 sizeof(user_session_key)) != 0)) {
2183 hex_user_session_key = hex_encode_talloc(talloc_tos(), (const unsigned char *)user_session_key,
2184 sizeof(user_session_key));
2185 x_fprintf(x_stdout, "NT_KEY: %s\n", hex_user_session_key);
2186 TALLOC_FREE(hex_user_session_key);
2195 OPT_USERNAME = 1000,
2204 OPT_USER_SESSION_KEY,
2206 OPT_REQUIRE_MEMBERSHIP,
2207 OPT_USE_CACHED_CREDS,
2209 OPT_PAM_WINBIND_CONF,
2211 OPT_TARGET_HOSTNAME,
2215 int main(int argc, const char **argv)
2217 TALLOC_CTX *frame = talloc_stackframe();
2219 static const char *helper_protocol;
2220 static int diagnostics;
2222 static const char *hex_challenge;
2223 static const char *hex_lm_response;
2224 static const char *hex_nt_response;
2225 struct loadparm_context *lp_ctx;
2228 /* NOTE: DO NOT change this interface without considering the implications!
2229 This is an external interface, which other programs will use to interact
2233 /* We do not use single-letter command abbreviations, because they harm future
2234 interface stability. */
2236 struct poptOption long_options[] = {
2238 { "helper-protocol", 0, POPT_ARG_STRING, &helper_protocol, OPT_DOMAIN, "operate as a stdio-based helper", "helper protocol to use"},
2239 { "username", 0, POPT_ARG_STRING, &opt_username, OPT_USERNAME, "username"},
2240 { "domain", 0, POPT_ARG_STRING, &opt_domain, OPT_DOMAIN, "domain name"},
2241 { "workstation", 0, POPT_ARG_STRING, &opt_workstation, OPT_WORKSTATION, "workstation"},
2242 { "challenge", 0, POPT_ARG_STRING, &hex_challenge, OPT_CHALLENGE, "challenge (HEX encoded)"},
2243 { "lm-response", 0, POPT_ARG_STRING, &hex_lm_response, OPT_LM, "LM Response to the challenge (HEX encoded)"},
2244 { "nt-response", 0, POPT_ARG_STRING, &hex_nt_response, OPT_NT, "NT or NTLMv2 Response to the challenge (HEX encoded)"},
2245 { "password", 0, POPT_ARG_STRING, &opt_password, OPT_PASSWORD, "User's plaintext password"},
2246 { "request-lm-key", 0, POPT_ARG_NONE, &request_lm_key, OPT_LM_KEY, "Retrieve LM session key"},
2247 { "request-nt-key", 0, POPT_ARG_NONE, &request_user_session_key, OPT_USER_SESSION_KEY, "Retrieve User (NT) session key"},
2248 { "use-cached-creds", 0, POPT_ARG_NONE, &use_cached_creds, OPT_USE_CACHED_CREDS, "Use cached credentials if no password is given"},
2249 { "allow-mschapv2", 0, POPT_ARG_NONE, &opt_allow_mschapv2, OPT_ALLOW_MSCHAPV2, "Explicitly allow MSCHAPv2" },
2250 { "offline-logon", 0, POPT_ARG_NONE, &offline_logon,
2252 "Use cached passwords when DC is offline"},
2253 { "diagnostics", 0, POPT_ARG_NONE, &diagnostics,
2255 "Perform diagnostics on the authentication chain"},
2256 { "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" },
2257 { "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" },
2258 { "target-service", 0, POPT_ARG_STRING, &opt_target_service, OPT_TARGET_SERVICE, "Target service (eg http)" },
2259 { "target-hostname", 0, POPT_ARG_STRING, &opt_target_hostname, OPT_TARGET_HOSTNAME, "Target hostname" },
2260 POPT_COMMON_CONFIGFILE
2266 /* Samba client initialisation */
2269 setup_logging("ntlm_auth", DEBUG_STDERR);
2273 pc = poptGetContext("ntlm_auth", argc, argv, long_options, 0);
2275 /* Parse command line options */
2278 poptPrintHelp(pc, stderr, 0);
2282 while((opt = poptGetNextOpt(pc)) != -1) {
2283 /* Get generic config options like --configfile */
2286 poptFreeContext(pc);
2288 if (!lp_load_global(get_dyn_CONFIGFILE())) {
2289 d_fprintf(stderr, "ntlm_auth: error opening config file %s. Error was %s\n",
2290 get_dyn_CONFIGFILE(), strerror(errno));
2294 pc = poptGetContext(NULL, argc, (const char **)argv, long_options,
2295 POPT_CONTEXT_KEEP_FIRST);
2297 while((opt = poptGetNextOpt(pc)) != -1) {
2300 opt_challenge = strhex_to_data_blob(NULL, hex_challenge);
2301 if (opt_challenge.length != 8) {
2302 x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n",
2304 (int)opt_challenge.length);
2309 opt_lm_response = strhex_to_data_blob(NULL, hex_lm_response);
2310 if (opt_lm_response.length != 24) {
2311 x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n",
2313 (int)opt_lm_response.length);
2319 opt_nt_response = strhex_to_data_blob(NULL, hex_nt_response);
2320 if (opt_nt_response.length < 24) {
2321 x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n",
2323 (int)opt_nt_response.length);
2328 case OPT_REQUIRE_MEMBERSHIP:
2329 if (strncasecmp_m("S-", require_membership_of, 2) == 0) {
2330 require_membership_of_sid = require_membership_of;
2337 char *domain = SMB_STRDUP(opt_username);
2338 char *p = strchr_m(domain, *lp_winbind_separator());
2342 if (opt_domain && !strequal(opt_domain, domain)) {
2343 x_fprintf(x_stderr, "Domain specified in username (%s) "
2344 "doesn't match specified domain (%s)!\n\n",
2345 domain, opt_domain);
2346 poptPrintHelp(pc, stderr, 0);
2349 opt_domain = domain;
2355 /* Note: if opt_domain is "" then send no domain */
2356 if (opt_domain == NULL) {
2357 opt_domain = get_winbind_domain();
2360 if (opt_workstation == NULL) {
2361 opt_workstation = "";
2364 lp_ctx = loadparm_init_s3(NULL, loadparm_s3_helpers());
2365 if (lp_ctx == NULL) {
2366 x_fprintf(x_stderr, "loadparm_init_s3() failed!\n");
2370 if (helper_protocol) {
2372 for (i=0; i<NUM_HELPER_MODES; i++) {
2373 if (strcmp(helper_protocol, stdio_helper_protocols[i].name) == 0) {
2374 squid_stream(stdio_helper_protocols[i].mode, lp_ctx, stdio_helper_protocols[i].fn);
2378 x_fprintf(x_stderr, "unknown helper protocol [%s]\n\nValid helper protools:\n\n", helper_protocol);
2380 for (i=0; i<NUM_HELPER_MODES; i++) {
2381 x_fprintf(x_stderr, "%s\n", stdio_helper_protocols[i].name);
2387 if (!opt_username || !*opt_username) {
2388 x_fprintf(x_stderr, "username must be specified!\n\n");
2389 poptPrintHelp(pc, stderr, 0);
2393 if (opt_challenge.length) {
2394 if (!check_auth_crap()) {
2400 if (!opt_password) {
2401 char pwd[256] = {0};
2404 rc = samba_getpass("Password: ", pwd, sizeof(pwd), false, false);
2406 opt_password = SMB_STRDUP(pwd);
2411 if (!diagnose_ntlm_auth()) {
2417 fstr_sprintf(user, "%s%c%s", opt_domain, winbind_separator(), opt_username);
2418 if (!check_plaintext_auth(user, opt_password, True)) {
2425 poptFreeContext(pc);