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).
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include "utils/ntlm_auth.h"
29 #define DBGC_CLASS DBGC_WINBIND
31 #define INITIAL_BUFFER_SIZE 300
32 #define MAX_BUFFER_SIZE 630000
34 enum stdio_helper_mode {
42 NTLM_CHANGE_PASSWORD_1,
46 enum ntlm_auth_cli_state {
53 enum ntlm_auth_svr_state {
60 struct ntlm_auth_state {
62 enum stdio_helper_mode helper_mode;
63 enum ntlm_auth_cli_state cli_state;
64 enum ntlm_auth_svr_state svr_state;
65 struct ntlmssp_state *ntlmssp_state;
67 char *want_feature_list;
68 bool have_session_key;
69 DATA_BLOB session_key;
70 DATA_BLOB initial_message;
73 typedef void (*stdio_helper_function)(struct ntlm_auth_state *state, char *buf,
76 static void manage_squid_basic_request (struct ntlm_auth_state *state,
77 char *buf, int length);
79 static void manage_squid_ntlmssp_request (struct ntlm_auth_state *state,
80 char *buf, int length);
82 static void manage_client_ntlmssp_request (struct ntlm_auth_state *state,
83 char *buf, int length);
85 static void manage_gss_spnego_request (struct ntlm_auth_state *state,
86 char *buf, int length);
88 static void manage_gss_spnego_client_request (struct ntlm_auth_state *state,
89 char *buf, int length);
91 static void manage_ntlm_server_1_request (struct ntlm_auth_state *state,
92 char *buf, int length);
94 static void manage_ntlm_change_password_1_request(struct ntlm_auth_state *state,
95 char *buf, int length);
98 enum stdio_helper_mode mode;
100 stdio_helper_function fn;
101 } stdio_helper_protocols[] = {
102 { SQUID_2_4_BASIC, "squid-2.4-basic", manage_squid_basic_request},
103 { SQUID_2_5_BASIC, "squid-2.5-basic", manage_squid_basic_request},
104 { SQUID_2_5_NTLMSSP, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request},
105 { NTLMSSP_CLIENT_1, "ntlmssp-client-1", manage_client_ntlmssp_request},
106 { GSS_SPNEGO, "gss-spnego", manage_gss_spnego_request},
107 { GSS_SPNEGO_CLIENT, "gss-spnego-client", manage_gss_spnego_client_request},
108 { NTLM_SERVER_1, "ntlm-server-1", manage_ntlm_server_1_request},
109 { NTLM_CHANGE_PASSWORD_1, "ntlm-change-password-1", manage_ntlm_change_password_1_request},
110 { NUM_HELPER_MODES, NULL, NULL}
113 extern int winbindd_fd;
115 const char *opt_username;
116 const char *opt_domain;
117 const char *opt_workstation;
118 const char *opt_password;
119 static DATA_BLOB opt_challenge;
120 static DATA_BLOB opt_lm_response;
121 static DATA_BLOB opt_nt_response;
122 static int request_lm_key;
123 static int request_user_session_key;
124 static int use_cached_creds;
126 static const char *require_membership_of;
127 static const char *require_membership_of_sid;
129 static char winbind_separator(void)
131 struct winbindd_response response;
138 ZERO_STRUCT(response);
140 /* Send off request */
142 if (winbindd_request_response(WINBINDD_INFO, NULL, &response) !=
143 NSS_STATUS_SUCCESS) {
144 d_printf("could not obtain winbind separator!\n");
145 return *lp_winbind_separator();
148 sep = response.data.info.winbind_separator;
152 d_printf("winbind separator was NULL!\n");
153 return *lp_winbind_separator();
159 const char *get_winbind_domain(void)
161 struct winbindd_response response;
163 static fstring winbind_domain;
164 if (*winbind_domain) {
165 return winbind_domain;
168 ZERO_STRUCT(response);
170 /* Send off request */
172 if (winbindd_request_response(WINBINDD_DOMAIN_NAME, NULL, &response) !=
173 NSS_STATUS_SUCCESS) {
174 DEBUG(0, ("could not obtain winbind domain name!\n"));
175 return lp_workgroup();
178 fstrcpy(winbind_domain, response.data.domain_name);
180 return winbind_domain;
184 const char *get_winbind_netbios_name(void)
186 struct winbindd_response response;
188 static fstring winbind_netbios_name;
190 if (*winbind_netbios_name) {
191 return winbind_netbios_name;
194 ZERO_STRUCT(response);
196 /* Send off request */
198 if (winbindd_request_response(WINBINDD_NETBIOS_NAME, NULL, &response) !=
199 NSS_STATUS_SUCCESS) {
200 DEBUG(0, ("could not obtain winbind netbios name!\n"));
201 return global_myname();
204 fstrcpy(winbind_netbios_name, response.data.netbios_name);
206 return winbind_netbios_name;
210 DATA_BLOB get_challenge(void)
212 static DATA_BLOB chal;
213 if (opt_challenge.length)
214 return opt_challenge;
216 chal = data_blob(NULL, 8);
218 generate_random_buffer(chal.data, chal.length);
222 /* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
223 form DOMAIN/user into a domain and a user */
225 static bool parse_ntlm_auth_domain_user(const char *domuser, fstring domain,
229 char *p = strchr(domuser,winbind_separator());
236 fstrcpy(domain, domuser);
237 domain[PTR_DIFF(p, domuser)] = 0;
243 static bool get_require_membership_sid(void) {
244 struct winbindd_request request;
245 struct winbindd_response response;
247 if (!require_membership_of) {
251 if (require_membership_of_sid) {
255 /* Otherwise, ask winbindd for the name->sid request */
257 ZERO_STRUCT(request);
258 ZERO_STRUCT(response);
260 if (!parse_ntlm_auth_domain_user(require_membership_of,
261 request.data.name.dom_name,
262 request.data.name.name)) {
263 DEBUG(0, ("Could not parse %s into seperate domain/name parts!\n",
264 require_membership_of));
268 if (winbindd_request_response(WINBINDD_LOOKUPNAME, &request, &response) !=
269 NSS_STATUS_SUCCESS) {
270 DEBUG(0, ("Winbindd lookupname failed to resolve %s into a SID!\n",
271 require_membership_of));
275 require_membership_of_sid = SMB_STRDUP(response.data.sid.sid);
277 if (require_membership_of_sid)
282 /* Authenticate a user with a plaintext password */
284 static bool check_plaintext_auth(const char *user, const char *pass,
285 bool stdout_diagnostics)
287 struct winbindd_request request;
288 struct winbindd_response response;
291 if (!get_require_membership_sid()) {
295 /* Send off request */
297 ZERO_STRUCT(request);
298 ZERO_STRUCT(response);
300 fstrcpy(request.data.auth.user, user);
301 fstrcpy(request.data.auth.pass, pass);
302 if (require_membership_of_sid) {
303 strlcpy(request.data.auth.require_membership_of_sid,
304 require_membership_of_sid,
305 sizeof(request.data.auth.require_membership_of_sid));
308 result = winbindd_request_response(WINBINDD_PAM_AUTH, &request, &response);
310 /* Display response */
312 if (stdout_diagnostics) {
313 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
314 d_printf("Reading winbind reply failed! (0x01)\n");
317 d_printf("%s: %s (0x%x)\n",
318 response.data.auth.nt_status_string,
319 response.data.auth.error_string,
320 response.data.auth.nt_status);
322 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
323 DEBUG(1, ("Reading winbind reply failed! (0x01)\n"));
326 DEBUG(3, ("%s: %s (0x%x)\n",
327 response.data.auth.nt_status_string,
328 response.data.auth.error_string,
329 response.data.auth.nt_status));
332 return (result == NSS_STATUS_SUCCESS);
335 /* authenticate a user with an encrypted username/password */
337 NTSTATUS contact_winbind_auth_crap(const char *username,
339 const char *workstation,
340 const DATA_BLOB *challenge,
341 const DATA_BLOB *lm_response,
342 const DATA_BLOB *nt_response,
345 uint8 user_session_key[16],
351 struct winbindd_request request;
352 struct winbindd_response response;
354 if (!get_require_membership_sid()) {
355 return NT_STATUS_INVALID_PARAMETER;
358 ZERO_STRUCT(request);
359 ZERO_STRUCT(response);
361 request.flags = flags;
363 request.data.auth_crap.logon_parameters = MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT | MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT;
365 if (require_membership_of_sid)
366 fstrcpy(request.data.auth_crap.require_membership_of_sid, require_membership_of_sid);
368 fstrcpy(request.data.auth_crap.user, username);
369 fstrcpy(request.data.auth_crap.domain, domain);
371 fstrcpy(request.data.auth_crap.workstation,
374 memcpy(request.data.auth_crap.chal, challenge->data, MIN(challenge->length, 8));
376 if (lm_response && lm_response->length) {
377 memcpy(request.data.auth_crap.lm_resp,
379 MIN(lm_response->length, sizeof(request.data.auth_crap.lm_resp)));
380 request.data.auth_crap.lm_resp_len = lm_response->length;
383 if (nt_response && nt_response->length) {
384 memcpy(request.data.auth_crap.nt_resp,
386 MIN(nt_response->length, sizeof(request.data.auth_crap.nt_resp)));
387 request.data.auth_crap.nt_resp_len = nt_response->length;
390 result = winbindd_request_response(WINBINDD_PAM_AUTH_CRAP, &request, &response);
392 /* Display response */
394 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
395 nt_status = NT_STATUS_UNSUCCESSFUL;
397 *error_string = smb_xstrdup("Reading winbind reply failed!");
398 winbindd_free_response(&response);
402 nt_status = (NT_STATUS(response.data.auth.nt_status));
403 if (!NT_STATUS_IS_OK(nt_status)) {
405 *error_string = smb_xstrdup(response.data.auth.error_string);
406 winbindd_free_response(&response);
410 if ((flags & WBFLAG_PAM_LMKEY) && lm_key) {
411 memcpy(lm_key, response.data.auth.first_8_lm_hash,
412 sizeof(response.data.auth.first_8_lm_hash));
414 if ((flags & WBFLAG_PAM_USER_SESSION_KEY) && user_session_key) {
415 memcpy(user_session_key, response.data.auth.user_session_key,
416 sizeof(response.data.auth.user_session_key));
419 if (flags & WBFLAG_PAM_UNIX_NAME) {
420 *unix_name = SMB_STRDUP((char *)response.extra_data.data);
422 winbindd_free_response(&response);
423 return NT_STATUS_NO_MEMORY;
427 winbindd_free_response(&response);
431 /* contact server to change user password using auth crap */
432 static NTSTATUS contact_winbind_change_pswd_auth_crap(const char *username,
434 const DATA_BLOB new_nt_pswd,
435 const DATA_BLOB old_nt_hash_enc,
436 const DATA_BLOB new_lm_pswd,
437 const DATA_BLOB old_lm_hash_enc,
442 struct winbindd_request request;
443 struct winbindd_response response;
445 if (!get_require_membership_sid())
448 *error_string = smb_xstrdup("Can't get membership sid.");
449 return NT_STATUS_INVALID_PARAMETER;
452 ZERO_STRUCT(request);
453 ZERO_STRUCT(response);
456 fstrcpy(request.data.chng_pswd_auth_crap.user, username);
458 fstrcpy(request.data.chng_pswd_auth_crap.domain,domain);
460 if(new_nt_pswd.length)
462 memcpy(request.data.chng_pswd_auth_crap.new_nt_pswd, new_nt_pswd.data, sizeof(request.data.chng_pswd_auth_crap.new_nt_pswd));
463 request.data.chng_pswd_auth_crap.new_nt_pswd_len = new_nt_pswd.length;
466 if(old_nt_hash_enc.length)
468 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));
469 request.data.chng_pswd_auth_crap.old_nt_hash_enc_len = old_nt_hash_enc.length;
472 if(new_lm_pswd.length)
474 memcpy(request.data.chng_pswd_auth_crap.new_lm_pswd, new_lm_pswd.data, sizeof(request.data.chng_pswd_auth_crap.new_lm_pswd));
475 request.data.chng_pswd_auth_crap.new_lm_pswd_len = new_lm_pswd.length;
478 if(old_lm_hash_enc.length)
480 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));
481 request.data.chng_pswd_auth_crap.old_lm_hash_enc_len = old_lm_hash_enc.length;
484 result = winbindd_request_response(WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP, &request, &response);
486 /* Display response */
488 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0))
490 nt_status = NT_STATUS_UNSUCCESSFUL;
492 *error_string = smb_xstrdup("Reading winbind reply failed!");
493 winbindd_free_response(&response);
497 nt_status = (NT_STATUS(response.data.auth.nt_status));
498 if (!NT_STATUS_IS_OK(nt_status))
501 *error_string = smb_xstrdup(response.data.auth.error_string);
502 winbindd_free_response(&response);
506 winbindd_free_response(&response);
511 static NTSTATUS winbind_pw_check(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
513 static const char zeros[16] = { 0, };
517 uint8 user_sess_key[16];
520 nt_status = contact_winbind_auth_crap(ntlmssp_state->user, ntlmssp_state->domain,
521 ntlmssp_state->workstation,
522 &ntlmssp_state->chal,
523 &ntlmssp_state->lm_resp,
524 &ntlmssp_state->nt_resp,
525 WBFLAG_PAM_LMKEY | WBFLAG_PAM_USER_SESSION_KEY | WBFLAG_PAM_UNIX_NAME,
526 lm_key, user_sess_key,
527 &error_string, &unix_name);
529 if (NT_STATUS_IS_OK(nt_status)) {
530 if (memcmp(lm_key, zeros, 8) != 0) {
531 *lm_session_key = data_blob(NULL, 16);
532 memcpy(lm_session_key->data, lm_key, 8);
533 memset(lm_session_key->data+8, '\0', 8);
536 if (memcmp(user_sess_key, zeros, 16) != 0) {
537 *user_session_key = data_blob(user_sess_key, 16);
539 ntlmssp_state->auth_context = talloc_strdup(ntlmssp_state->mem_ctx, unix_name);
540 SAFE_FREE(unix_name);
542 DEBUG(NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED) ? 0 : 3,
543 ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
544 ntlmssp_state->domain, ntlmssp_state->user,
545 ntlmssp_state->workstation,
546 error_string ? error_string : "unknown error (NULL)"));
547 ntlmssp_state->auth_context = NULL;
552 static NTSTATUS local_pw_check(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
555 uint8 lm_pw[16], nt_pw[16];
557 nt_lm_owf_gen (opt_password, nt_pw, lm_pw);
559 nt_status = ntlm_password_check(ntlmssp_state->mem_ctx,
560 &ntlmssp_state->chal,
561 &ntlmssp_state->lm_resp,
562 &ntlmssp_state->nt_resp,
566 ntlmssp_state->domain,
567 lm_pw, nt_pw, user_session_key, lm_session_key);
569 if (NT_STATUS_IS_OK(nt_status)) {
570 ntlmssp_state->auth_context = talloc_asprintf(ntlmssp_state->mem_ctx,
571 "%s%c%s", ntlmssp_state->domain,
572 *lp_winbind_separator(),
573 ntlmssp_state->user);
575 DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
576 ntlmssp_state->domain, ntlmssp_state->user, ntlmssp_state->workstation,
577 nt_errstr(nt_status)));
578 ntlmssp_state->auth_context = NULL;
583 static NTSTATUS ntlm_auth_start_ntlmssp_client(NTLMSSP_STATE **client_ntlmssp_state)
586 if ( (opt_username == NULL) || (opt_domain == NULL) ) {
587 status = NT_STATUS_UNSUCCESSFUL;
588 DEBUG(1, ("Need username and domain for NTLMSSP\n"));
589 return NT_STATUS_INVALID_PARAMETER;
592 status = ntlmssp_client_start(client_ntlmssp_state);
594 if (!NT_STATUS_IS_OK(status)) {
595 DEBUG(1, ("Could not start NTLMSSP client: %s\n",
597 ntlmssp_end(client_ntlmssp_state);
601 status = ntlmssp_set_username(*client_ntlmssp_state, opt_username);
603 if (!NT_STATUS_IS_OK(status)) {
604 DEBUG(1, ("Could not set username: %s\n",
606 ntlmssp_end(client_ntlmssp_state);
610 status = ntlmssp_set_domain(*client_ntlmssp_state, opt_domain);
612 if (!NT_STATUS_IS_OK(status)) {
613 DEBUG(1, ("Could not set domain: %s\n",
615 ntlmssp_end(client_ntlmssp_state);
620 status = ntlmssp_set_password(*client_ntlmssp_state, opt_password);
622 if (!NT_STATUS_IS_OK(status)) {
623 DEBUG(1, ("Could not set password: %s\n",
625 ntlmssp_end(client_ntlmssp_state);
633 static NTSTATUS ntlm_auth_start_ntlmssp_server(NTLMSSP_STATE **ntlmssp_state)
635 NTSTATUS status = ntlmssp_server_start(ntlmssp_state);
637 if (!NT_STATUS_IS_OK(status)) {
638 DEBUG(1, ("Could not start NTLMSSP server: %s\n",
643 /* Have we been given a local password, or should we ask winbind? */
645 (*ntlmssp_state)->check_password = local_pw_check;
646 (*ntlmssp_state)->get_domain = lp_workgroup;
647 (*ntlmssp_state)->get_global_myname = global_myname;
649 (*ntlmssp_state)->check_password = winbind_pw_check;
650 (*ntlmssp_state)->get_domain = get_winbind_domain;
651 (*ntlmssp_state)->get_global_myname = get_winbind_netbios_name;
656 /*******************************************************************
657 Used by firefox to drive NTLM auth to IIS servers.
658 *******************************************************************/
660 static NTSTATUS do_ccache_ntlm_auth(DATA_BLOB initial_msg, DATA_BLOB challenge_msg,
663 struct winbindd_request wb_request;
664 struct winbindd_response wb_response;
667 /* get winbindd to do the ntlmssp step on our behalf */
668 ZERO_STRUCT(wb_request);
669 ZERO_STRUCT(wb_response);
671 fstr_sprintf(wb_request.data.ccache_ntlm_auth.user,
672 "%s%c%s", opt_domain, winbind_separator(), opt_username);
673 wb_request.data.ccache_ntlm_auth.uid = geteuid();
674 wb_request.data.ccache_ntlm_auth.initial_blob_len = initial_msg.length;
675 wb_request.data.ccache_ntlm_auth.challenge_blob_len = challenge_msg.length;
676 wb_request.extra_len = initial_msg.length + challenge_msg.length;
678 if (wb_request.extra_len > 0) {
679 wb_request.extra_data.data = SMB_MALLOC_ARRAY(char, wb_request.extra_len);
680 if (wb_request.extra_data.data == NULL) {
681 return NT_STATUS_NO_MEMORY;
684 memcpy(wb_request.extra_data.data, initial_msg.data, initial_msg.length);
685 memcpy(wb_request.extra_data.data + initial_msg.length,
686 challenge_msg.data, challenge_msg.length);
689 result = winbindd_request_response(WINBINDD_CCACHE_NTLMAUTH, &wb_request, &wb_response);
690 SAFE_FREE(wb_request.extra_data.data);
692 if (result != NSS_STATUS_SUCCESS) {
693 winbindd_free_response(&wb_response);
694 return NT_STATUS_UNSUCCESSFUL;
698 *reply = data_blob(wb_response.extra_data.data,
699 wb_response.data.ccache_ntlm_auth.auth_blob_len);
700 if (wb_response.data.ccache_ntlm_auth.auth_blob_len > 0 &&
701 reply->data == NULL) {
702 winbindd_free_response(&wb_response);
703 return NT_STATUS_NO_MEMORY;
707 winbindd_free_response(&wb_response);
708 return NT_STATUS_MORE_PROCESSING_REQUIRED;
711 static void manage_squid_ntlmssp_request(struct ntlm_auth_state *state,
712 char *buf, int length)
714 static NTLMSSP_STATE *ntlmssp_state = NULL;
715 static char* want_feature_list = NULL;
716 static uint32 neg_flags = 0;
717 static bool have_session_key = False;
718 static DATA_BLOB session_key;
719 DATA_BLOB request, reply;
722 if (strlen(buf) < 2) {
723 DEBUG(1, ("NTLMSSP query [%s] invalid", buf));
724 x_fprintf(x_stdout, "BH\n");
728 if (strlen(buf) > 3) {
729 if(strncmp(buf, "SF ", 3) == 0){
730 DEBUG(10, ("Setting flags to negotioate\n"));
731 SAFE_FREE(want_feature_list);
732 want_feature_list = SMB_STRNDUP(buf+3, strlen(buf)-3);
733 x_fprintf(x_stdout, "OK\n");
736 request = base64_decode_data_blob(buf + 3);
738 request = data_blob_null;
741 if ((strncmp(buf, "PW ", 3) == 0)) {
742 /* The calling application wants us to use a local password (rather than winbindd) */
744 opt_password = SMB_STRNDUP((const char *)request.data, request.length);
746 if (opt_password == NULL) {
747 DEBUG(1, ("Out of memory\n"));
748 x_fprintf(x_stdout, "BH\n");
749 data_blob_free(&request);
753 x_fprintf(x_stdout, "OK\n");
754 data_blob_free(&request);
758 if (strncmp(buf, "YR", 2) == 0) {
760 ntlmssp_end(&ntlmssp_state);
761 } else if (strncmp(buf, "KK", 2) == 0) {
763 } else if (strncmp(buf, "GF", 2) == 0) {
764 DEBUG(10, ("Requested negotiated NTLMSSP flags\n"));
765 x_fprintf(x_stdout, "GF 0x%08lx\n", have_session_key?neg_flags:0l);
766 data_blob_free(&request);
768 } else if (strncmp(buf, "GK", 2) == 0) {
769 DEBUG(10, ("Requested NTLMSSP session key\n"));
770 if(have_session_key) {
771 char *key64 = base64_encode_data_blob(talloc_tos(),
773 x_fprintf(x_stdout, "GK %s\n", key64?key64:"<NULL>");
776 x_fprintf(x_stdout, "BH\n");
779 data_blob_free(&request);
782 DEBUG(1, ("NTLMSSP query [%s] invalid", buf));
783 x_fprintf(x_stdout, "BH\n");
787 if (!ntlmssp_state) {
788 if (!NT_STATUS_IS_OK(nt_status = ntlm_auth_start_ntlmssp_server(&ntlmssp_state))) {
789 x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
792 ntlmssp_want_feature_list(ntlmssp_state, want_feature_list);
795 DEBUG(10, ("got NTLMSSP packet:\n"));
796 dump_data(10, request.data, request.length);
798 nt_status = ntlmssp_update(ntlmssp_state, request, &reply);
800 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
801 char *reply_base64 = base64_encode_data_blob(talloc_tos(),
803 x_fprintf(x_stdout, "TT %s\n", reply_base64);
804 TALLOC_FREE(reply_base64);
805 data_blob_free(&reply);
806 DEBUG(10, ("NTLMSSP challenge\n"));
807 } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) {
808 x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
809 DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status)));
811 ntlmssp_end(&ntlmssp_state);
812 } else if (!NT_STATUS_IS_OK(nt_status)) {
813 x_fprintf(x_stdout, "NA %s\n", nt_errstr(nt_status));
814 DEBUG(10, ("NTLMSSP %s\n", nt_errstr(nt_status)));
816 x_fprintf(x_stdout, "AF %s\n", (char *)ntlmssp_state->auth_context);
817 DEBUG(10, ("NTLMSSP OK!\n"));
820 data_blob_free(&session_key);
821 session_key = data_blob(ntlmssp_state->session_key.data,
822 ntlmssp_state->session_key.length);
823 neg_flags = ntlmssp_state->neg_flags;
824 have_session_key = True;
827 data_blob_free(&request);
830 static void manage_client_ntlmssp_request(struct ntlm_auth_state *state,
831 char *buf, int length)
833 DATA_BLOB request, reply;
836 if (!opt_username || !*opt_username) {
837 x_fprintf(x_stderr, "username must be specified!\n\n");
841 if (strlen(buf) < 2) {
842 DEBUG(1, ("NTLMSSP query [%s] invalid", buf));
843 x_fprintf(x_stdout, "BH\n");
847 if (strlen(buf) > 3) {
848 if(strncmp(buf, "SF ", 3) == 0) {
849 DEBUG(10, ("Looking for flags to negotiate\n"));
850 talloc_free(state->want_feature_list);
851 state->want_feature_list = talloc_strdup(state->mem_ctx,
853 x_fprintf(x_stdout, "OK\n");
856 request = base64_decode_data_blob(buf + 3);
858 request = data_blob_null;
861 if (strncmp(buf, "PW ", 3) == 0) {
862 /* We asked for a password and obviously got it :-) */
864 opt_password = SMB_STRNDUP((const char *)request.data,
867 if (opt_password == NULL) {
868 DEBUG(1, ("Out of memory\n"));
869 x_fprintf(x_stdout, "BH\n");
870 data_blob_free(&request);
874 x_fprintf(x_stdout, "OK\n");
875 data_blob_free(&request);
879 if (!state->ntlmssp_state && use_cached_creds) {
880 /* check whether cached credentials are usable. */
881 DATA_BLOB empty_blob = data_blob_null;
883 nt_status = do_ccache_ntlm_auth(empty_blob, empty_blob, NULL);
884 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
885 /* failed to use cached creds */
886 use_cached_creds = False;
890 if (opt_password == NULL && !use_cached_creds) {
891 /* Request a password from the calling process. After
892 sending it, the calling process should retry asking for the
895 DEBUG(10, ("Requesting password\n"));
896 x_fprintf(x_stdout, "PW\n");
900 if (strncmp(buf, "YR", 2) == 0) {
901 if (state->ntlmssp_state)
902 ntlmssp_end(&state->ntlmssp_state);
903 state->cli_state = CLIENT_INITIAL;
904 } else if (strncmp(buf, "TT", 2) == 0) {
905 /* No special preprocessing required */
906 } else if (strncmp(buf, "GF", 2) == 0) {
907 DEBUG(10, ("Requested negotiated NTLMSSP flags\n"));
909 if(state->cli_state == CLIENT_FINISHED) {
910 x_fprintf(x_stdout, "GF 0x%08x\n", state->neg_flags);
913 x_fprintf(x_stdout, "BH\n");
916 data_blob_free(&request);
918 } else if (strncmp(buf, "GK", 2) == 0 ) {
919 DEBUG(10, ("Requested session key\n"));
921 if(state->cli_state == CLIENT_FINISHED) {
922 char *key64 = base64_encode_data_blob(state->mem_ctx,
924 x_fprintf(x_stdout, "GK %s\n", key64?key64:"<NULL>");
928 x_fprintf(x_stdout, "BH\n");
931 data_blob_free(&request);
934 DEBUG(1, ("NTLMSSP query [%s] invalid", buf));
935 x_fprintf(x_stdout, "BH\n");
939 if (!state->ntlmssp_state) {
940 nt_status = ntlm_auth_start_ntlmssp_client(
941 &state->ntlmssp_state);
942 if (!NT_STATUS_IS_OK(nt_status)) {
943 x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
946 ntlmssp_want_feature_list(state->ntlmssp_state,
947 state->want_feature_list);
948 state->initial_message = data_blob_null;
951 DEBUG(10, ("got NTLMSSP packet:\n"));
952 dump_data(10, request.data, request.length);
954 if (use_cached_creds && !opt_password &&
955 (state->cli_state == CLIENT_RESPONSE)) {
956 nt_status = do_ccache_ntlm_auth(state->initial_message, request,
959 nt_status = ntlmssp_update(state->ntlmssp_state, request,
963 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
964 char *reply_base64 = base64_encode_data_blob(state->mem_ctx,
966 if (state->cli_state == CLIENT_INITIAL) {
967 x_fprintf(x_stdout, "YR %s\n", reply_base64);
968 state->initial_message = reply;
969 state->cli_state = CLIENT_RESPONSE;
971 x_fprintf(x_stdout, "KK %s\n", reply_base64);
972 data_blob_free(&reply);
974 TALLOC_FREE(reply_base64);
975 DEBUG(10, ("NTLMSSP challenge\n"));
976 } else if (NT_STATUS_IS_OK(nt_status)) {
977 char *reply_base64 = base64_encode_data_blob(talloc_tos(),
979 x_fprintf(x_stdout, "AF %s\n", reply_base64);
980 TALLOC_FREE(reply_base64);
982 if(state->have_session_key)
983 data_blob_free(&state->session_key);
985 state->session_key = data_blob(
986 state->ntlmssp_state->session_key.data,
987 state->ntlmssp_state->session_key.length);
988 state->neg_flags = state->ntlmssp_state->neg_flags;
989 state->have_session_key = true;
991 DEBUG(10, ("NTLMSSP OK!\n"));
992 state->cli_state = CLIENT_FINISHED;
993 if (state->ntlmssp_state)
994 ntlmssp_end(&state->ntlmssp_state);
996 x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
997 DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status)));
998 state->cli_state = CLIENT_ERROR;
999 if (state->ntlmssp_state)
1000 ntlmssp_end(&state->ntlmssp_state);
1003 data_blob_free(&request);
1006 static void manage_squid_basic_request(struct ntlm_auth_state *state,
1007 char *buf, int length)
1012 pass=(char *)memchr(buf,' ',length);
1014 DEBUG(2, ("Password not found. Denying access\n"));
1015 x_fprintf(x_stdout, "ERR\n");
1021 if (state->helper_mode == SQUID_2_5_BASIC) {
1022 rfc1738_unescape(user);
1023 rfc1738_unescape(pass);
1026 if (check_plaintext_auth(user, pass, False)) {
1027 x_fprintf(x_stdout, "OK\n");
1029 x_fprintf(x_stdout, "ERR\n");
1033 static void offer_gss_spnego_mechs(void) {
1039 TALLOC_CTX *ctx = talloc_tos();
1043 ZERO_STRUCT(spnego);
1045 myname_lower = talloc_strdup(ctx, global_myname());
1046 if (!myname_lower) {
1049 strlower_m(myname_lower);
1051 principal = talloc_asprintf(ctx, "%s$@%s", myname_lower, lp_realm());
1056 /* Server negTokenInit (mech offerings) */
1057 spnego.type = SPNEGO_NEG_TOKEN_INIT;
1058 spnego.negTokenInit.mechTypes = SMB_XMALLOC_ARRAY(const char *, 2);
1060 spnego.negTokenInit.mechTypes[0] = smb_xstrdup(OID_KERBEROS5_OLD);
1061 spnego.negTokenInit.mechTypes[1] = smb_xstrdup(OID_NTLMSSP);
1062 spnego.negTokenInit.mechTypes[2] = NULL;
1064 spnego.negTokenInit.mechTypes[0] = smb_xstrdup(OID_NTLMSSP);
1065 spnego.negTokenInit.mechTypes[1] = NULL;
1069 spnego.negTokenInit.mechListMIC = data_blob(principal,
1072 len = write_spnego_data(&token, &spnego);
1073 free_spnego_data(&spnego);
1076 DEBUG(1, ("Could not write SPNEGO data blob\n"));
1077 x_fprintf(x_stdout, "BH\n");
1081 reply_base64 = base64_encode_data_blob(talloc_tos(), token);
1082 x_fprintf(x_stdout, "TT %s *\n", reply_base64);
1084 TALLOC_FREE(reply_base64);
1085 data_blob_free(&token);
1086 DEBUG(10, ("sent SPNEGO negTokenInit\n"));
1090 static void manage_gss_spnego_request(struct ntlm_auth_state *state,
1091 char *buf, int length)
1093 static NTLMSSP_STATE *ntlmssp_state = NULL;
1094 SPNEGO_DATA request, response;
1098 TALLOC_CTX *ctx = talloc_tos();
1101 char *domain = NULL;
1103 const char *reply_code;
1105 char *reply_argument = NULL;
1107 if (strlen(buf) < 2) {
1108 DEBUG(1, ("SPENGO query [%s] invalid", buf));
1109 x_fprintf(x_stdout, "BH\n");
1113 if (strncmp(buf, "YR", 2) == 0) {
1115 ntlmssp_end(&ntlmssp_state);
1116 } else if (strncmp(buf, "KK", 2) == 0) {
1119 DEBUG(1, ("SPENGO query [%s] invalid", buf));
1120 x_fprintf(x_stdout, "BH\n");
1124 if ( (strlen(buf) == 2)) {
1126 /* no client data, get the negTokenInit offering
1129 offer_gss_spnego_mechs();
1133 /* All subsequent requests have a blob. This might be negTokenInit or negTokenTarg */
1135 if (strlen(buf) <= 3) {
1136 DEBUG(1, ("GSS-SPNEGO query [%s] invalid\n", buf));
1137 x_fprintf(x_stdout, "BH\n");
1141 token = base64_decode_data_blob(buf + 3);
1142 len = read_spnego_data(token, &request);
1143 data_blob_free(&token);
1146 DEBUG(1, ("GSS-SPNEGO query [%s] invalid", buf));
1147 x_fprintf(x_stdout, "BH\n");
1151 if (request.type == SPNEGO_NEG_TOKEN_INIT) {
1153 /* Second request from Client. This is where the
1154 client offers its mechanism to use. */
1156 if ( (request.negTokenInit.mechTypes == NULL) ||
1157 (request.negTokenInit.mechTypes[0] == NULL) ) {
1158 DEBUG(1, ("Client did not offer any mechanism"));
1159 x_fprintf(x_stdout, "BH\n");
1163 status = NT_STATUS_UNSUCCESSFUL;
1164 if (strcmp(request.negTokenInit.mechTypes[0], OID_NTLMSSP) == 0) {
1166 if ( request.negTokenInit.mechToken.data == NULL ) {
1167 DEBUG(1, ("Client did not provide NTLMSSP data\n"));
1168 x_fprintf(x_stdout, "BH\n");
1172 if ( ntlmssp_state != NULL ) {
1173 DEBUG(1, ("Client wants a new NTLMSSP challenge, but "
1174 "already got one\n"));
1175 x_fprintf(x_stdout, "BH\n");
1176 ntlmssp_end(&ntlmssp_state);
1180 if (!NT_STATUS_IS_OK(status = ntlm_auth_start_ntlmssp_server(&ntlmssp_state))) {
1181 x_fprintf(x_stdout, "BH %s\n", nt_errstr(status));
1185 DEBUG(10, ("got NTLMSSP packet:\n"));
1186 dump_data(10, request.negTokenInit.mechToken.data,
1187 request.negTokenInit.mechToken.length);
1189 response.type = SPNEGO_NEG_TOKEN_TARG;
1190 response.negTokenTarg.supportedMech = SMB_STRDUP(OID_NTLMSSP);
1191 response.negTokenTarg.mechListMIC = data_blob_null;
1193 status = ntlmssp_update(ntlmssp_state,
1194 request.negTokenInit.mechToken,
1195 &response.negTokenTarg.responseToken);
1199 if (strcmp(request.negTokenInit.mechTypes[0], OID_KERBEROS5_OLD) == 0) {
1201 TALLOC_CTX *mem_ctx = talloc_init("manage_gss_spnego_request");
1204 DATA_BLOB session_key;
1205 PAC_DATA *pac_data = NULL;
1207 if ( request.negTokenInit.mechToken.data == NULL ) {
1208 DEBUG(1, ("Client did not provide Kerberos data\n"));
1209 x_fprintf(x_stdout, "BH\n");
1213 response.type = SPNEGO_NEG_TOKEN_TARG;
1214 response.negTokenTarg.supportedMech = SMB_STRDUP(OID_KERBEROS5_OLD);
1215 response.negTokenTarg.mechListMIC = data_blob_null;
1216 response.negTokenTarg.responseToken = data_blob_null;
1218 status = ads_verify_ticket(mem_ctx, lp_realm(), 0,
1219 &request.negTokenInit.mechToken,
1220 &principal, &pac_data, &ap_rep,
1221 &session_key, True);
1223 talloc_destroy(mem_ctx);
1225 /* Now in "principal" we have the name we are
1226 authenticated as. */
1228 if (NT_STATUS_IS_OK(status)) {
1230 domain = strchr_m(principal, '@');
1232 if (domain == NULL) {
1233 DEBUG(1, ("Did not get a valid principal "
1234 "from ads_verify_ticket\n"));
1235 x_fprintf(x_stdout, "BH\n");
1240 domain = SMB_STRDUP(domain);
1241 user = SMB_STRDUP(principal);
1243 data_blob_free(&ap_rep);
1245 SAFE_FREE(principal);
1252 if ( (request.negTokenTarg.supportedMech == NULL) ||
1253 ( strcmp(request.negTokenTarg.supportedMech, OID_NTLMSSP) != 0 ) ) {
1254 /* Kerberos should never send a negTokenTarg, OID_NTLMSSP
1255 is the only one we support that sends this stuff */
1256 DEBUG(1, ("Got a negTokenTarg for something non-NTLMSSP: %s\n",
1257 request.negTokenTarg.supportedMech));
1258 x_fprintf(x_stdout, "BH\n");
1262 if (request.negTokenTarg.responseToken.data == NULL) {
1263 DEBUG(1, ("Got a negTokenTarg without a responseToken!\n"));
1264 x_fprintf(x_stdout, "BH\n");
1268 status = ntlmssp_update(ntlmssp_state,
1269 request.negTokenTarg.responseToken,
1270 &response.negTokenTarg.responseToken);
1272 response.type = SPNEGO_NEG_TOKEN_TARG;
1273 response.negTokenTarg.supportedMech = SMB_STRDUP(OID_NTLMSSP);
1274 response.negTokenTarg.mechListMIC = data_blob_null;
1276 if (NT_STATUS_IS_OK(status)) {
1277 user = SMB_STRDUP(ntlmssp_state->user);
1278 domain = SMB_STRDUP(ntlmssp_state->domain);
1279 ntlmssp_end(&ntlmssp_state);
1283 free_spnego_data(&request);
1285 if (NT_STATUS_IS_OK(status)) {
1286 response.negTokenTarg.negResult = SPNEGO_ACCEPT_COMPLETED;
1288 reply_argument = talloc_asprintf(ctx, "%s\\%s", domain, user);
1289 } else if (NT_STATUS_EQUAL(status,
1290 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1291 response.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
1293 reply_argument = talloc_strdup(ctx, "*");
1295 response.negTokenTarg.negResult = SPNEGO_REJECT;
1297 reply_argument = talloc_strdup(ctx, nt_errstr(status));
1300 if (!reply_argument) {
1301 DEBUG(1, ("Could not write SPNEGO data blob\n"));
1302 x_fprintf(x_stdout, "BH\n");
1309 len = write_spnego_data(&token, &response);
1310 free_spnego_data(&response);
1313 DEBUG(1, ("Could not write SPNEGO data blob\n"));
1314 x_fprintf(x_stdout, "BH\n");
1318 reply_base64 = base64_encode_data_blob(talloc_tos(), token);
1320 x_fprintf(x_stdout, "%s %s %s\n",
1321 reply_code, reply_base64, reply_argument);
1323 TALLOC_FREE(reply_base64);
1324 data_blob_free(&token);
1329 static NTLMSSP_STATE *client_ntlmssp_state = NULL;
1331 static bool manage_client_ntlmssp_init(SPNEGO_DATA spnego)
1334 DATA_BLOB null_blob = data_blob_null;
1335 DATA_BLOB to_server;
1336 char *to_server_base64;
1337 const char *my_mechs[] = {OID_NTLMSSP, NULL};
1339 DEBUG(10, ("Got spnego negTokenInit with NTLMSSP\n"));
1341 if (client_ntlmssp_state != NULL) {
1342 DEBUG(1, ("Request for initial SPNEGO request where "
1343 "we already have a state\n"));
1347 if (!client_ntlmssp_state) {
1348 if (!NT_STATUS_IS_OK(status = ntlm_auth_start_ntlmssp_client(&client_ntlmssp_state))) {
1349 x_fprintf(x_stdout, "BH %s\n", nt_errstr(status));
1355 if (opt_password == NULL) {
1357 /* Request a password from the calling process. After
1358 sending it, the calling process should retry with
1359 the negTokenInit. */
1361 DEBUG(10, ("Requesting password\n"));
1362 x_fprintf(x_stdout, "PW\n");
1366 spnego.type = SPNEGO_NEG_TOKEN_INIT;
1367 spnego.negTokenInit.mechTypes = my_mechs;
1368 spnego.negTokenInit.reqFlags = 0;
1369 spnego.negTokenInit.mechListMIC = null_blob;
1371 status = ntlmssp_update(client_ntlmssp_state, null_blob,
1372 &spnego.negTokenInit.mechToken);
1374 if ( !(NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) ||
1375 NT_STATUS_IS_OK(status)) ) {
1376 DEBUG(1, ("Expected OK or MORE_PROCESSING_REQUIRED, got: %s\n",
1377 nt_errstr(status)));
1378 ntlmssp_end(&client_ntlmssp_state);
1382 write_spnego_data(&to_server, &spnego);
1383 data_blob_free(&spnego.negTokenInit.mechToken);
1385 to_server_base64 = base64_encode_data_blob(talloc_tos(), to_server);
1386 data_blob_free(&to_server);
1387 x_fprintf(x_stdout, "KK %s\n", to_server_base64);
1388 TALLOC_FREE(to_server_base64);
1392 static void manage_client_ntlmssp_targ(SPNEGO_DATA spnego)
1395 DATA_BLOB null_blob = data_blob_null;
1397 DATA_BLOB to_server;
1398 char *to_server_base64;
1400 DEBUG(10, ("Got spnego negTokenTarg with NTLMSSP\n"));
1402 if (client_ntlmssp_state == NULL) {
1403 DEBUG(1, ("Got NTLMSSP tArg without a client state\n"));
1404 x_fprintf(x_stdout, "BH\n");
1408 if (spnego.negTokenTarg.negResult == SPNEGO_REJECT) {
1409 x_fprintf(x_stdout, "NA\n");
1410 ntlmssp_end(&client_ntlmssp_state);
1414 if (spnego.negTokenTarg.negResult == SPNEGO_ACCEPT_COMPLETED) {
1415 x_fprintf(x_stdout, "AF\n");
1416 ntlmssp_end(&client_ntlmssp_state);
1420 status = ntlmssp_update(client_ntlmssp_state,
1421 spnego.negTokenTarg.responseToken,
1424 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1425 DEBUG(1, ("Expected MORE_PROCESSING_REQUIRED from "
1426 "ntlmssp_client_update, got: %s\n",
1427 nt_errstr(status)));
1428 x_fprintf(x_stdout, "BH\n");
1429 data_blob_free(&request);
1430 ntlmssp_end(&client_ntlmssp_state);
1434 spnego.type = SPNEGO_NEG_TOKEN_TARG;
1435 spnego.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
1436 spnego.negTokenTarg.supportedMech = (char *)OID_NTLMSSP;
1437 spnego.negTokenTarg.responseToken = request;
1438 spnego.negTokenTarg.mechListMIC = null_blob;
1440 write_spnego_data(&to_server, &spnego);
1441 data_blob_free(&request);
1443 to_server_base64 = base64_encode_data_blob(talloc_tos(), to_server);
1444 data_blob_free(&to_server);
1445 x_fprintf(x_stdout, "KK %s\n", to_server_base64);
1446 TALLOC_FREE(to_server_base64);
1452 static bool manage_client_krb5_init(SPNEGO_DATA spnego)
1455 DATA_BLOB tkt, to_server;
1456 DATA_BLOB session_key_krb5 = data_blob_null;
1461 const char *my_mechs[] = {OID_KERBEROS5_OLD, NULL};
1464 if ( (spnego.negTokenInit.mechListMIC.data == NULL) ||
1465 (spnego.negTokenInit.mechListMIC.length == 0) ) {
1466 DEBUG(1, ("Did not get a principal for krb5\n"));
1470 principal = (char *)SMB_MALLOC(
1471 spnego.negTokenInit.mechListMIC.length+1);
1473 if (principal == NULL) {
1474 DEBUG(1, ("Could not malloc principal\n"));
1478 memcpy(principal, spnego.negTokenInit.mechListMIC.data,
1479 spnego.negTokenInit.mechListMIC.length);
1480 principal[spnego.negTokenInit.mechListMIC.length] = '\0';
1482 retval = cli_krb5_get_ticket(principal, 0, &tkt, &session_key_krb5, 0, NULL, NULL);
1487 /* Let's try to first get the TGT, for that we need a
1490 if (opt_password == NULL) {
1491 DEBUG(10, ("Requesting password\n"));
1492 x_fprintf(x_stdout, "PW\n");
1496 user = talloc_asprintf(talloc_tos(), "%s@%s", opt_username, opt_domain);
1501 if ((retval = kerberos_kinit_password(user, opt_password, 0, NULL))) {
1502 DEBUG(10, ("Requesting TGT failed: %s\n", error_message(retval)));
1506 retval = cli_krb5_get_ticket(principal, 0, &tkt, &session_key_krb5, 0, NULL, NULL);
1509 DEBUG(10, ("Kinit suceeded, but getting a ticket failed: %s\n", error_message(retval)));
1514 data_blob_free(&session_key_krb5);
1518 reply.type = SPNEGO_NEG_TOKEN_INIT;
1519 reply.negTokenInit.mechTypes = my_mechs;
1520 reply.negTokenInit.reqFlags = 0;
1521 reply.negTokenInit.mechToken = tkt;
1522 reply.negTokenInit.mechListMIC = data_blob_null;
1524 len = write_spnego_data(&to_server, &reply);
1525 data_blob_free(&tkt);
1528 DEBUG(1, ("Could not write SPNEGO data blob\n"));
1532 reply_base64 = base64_encode_data_blob(talloc_tos(), to_server);
1533 x_fprintf(x_stdout, "KK %s *\n", reply_base64);
1535 TALLOC_FREE(reply_base64);
1536 data_blob_free(&to_server);
1537 DEBUG(10, ("sent GSS-SPNEGO KERBEROS5 negTokenInit\n"));
1541 static void manage_client_krb5_targ(SPNEGO_DATA spnego)
1543 switch (spnego.negTokenTarg.negResult) {
1544 case SPNEGO_ACCEPT_INCOMPLETE:
1545 DEBUG(1, ("Got a Kerberos negTokenTarg with ACCEPT_INCOMPLETE\n"));
1546 x_fprintf(x_stdout, "BH\n");
1548 case SPNEGO_ACCEPT_COMPLETED:
1549 DEBUG(10, ("Accept completed\n"));
1550 x_fprintf(x_stdout, "AF\n");
1553 DEBUG(10, ("Rejected\n"));
1554 x_fprintf(x_stdout, "NA\n");
1557 DEBUG(1, ("Got an invalid negTokenTarg\n"));
1558 x_fprintf(x_stdout, "AF\n");
1564 static void manage_gss_spnego_client_request(struct ntlm_auth_state *state,
1565 char *buf, int length)
1571 if (!opt_username || !*opt_username) {
1572 x_fprintf(x_stderr, "username must be specified!\n\n");
1576 if (strlen(buf) <= 3) {
1577 DEBUG(1, ("SPNEGO query [%s] too short\n", buf));
1578 x_fprintf(x_stdout, "BH\n");
1582 request = base64_decode_data_blob(buf+3);
1584 if (strncmp(buf, "PW ", 3) == 0) {
1586 /* We asked for a password and obviously got it :-) */
1588 opt_password = SMB_STRNDUP((const char *)request.data, request.length);
1590 if (opt_password == NULL) {
1591 DEBUG(1, ("Out of memory\n"));
1592 x_fprintf(x_stdout, "BH\n");
1593 data_blob_free(&request);
1597 x_fprintf(x_stdout, "OK\n");
1598 data_blob_free(&request);
1602 if ( (strncmp(buf, "TT ", 3) != 0) &&
1603 (strncmp(buf, "AF ", 3) != 0) &&
1604 (strncmp(buf, "NA ", 3) != 0) ) {
1605 DEBUG(1, ("SPNEGO request [%s] invalid\n", buf));
1606 x_fprintf(x_stdout, "BH\n");
1607 data_blob_free(&request);
1611 /* So we got a server challenge to generate a SPNEGO
1612 client-to-server request... */
1614 len = read_spnego_data(request, &spnego);
1615 data_blob_free(&request);
1618 DEBUG(1, ("Could not read SPNEGO data for [%s]\n", buf));
1619 x_fprintf(x_stdout, "BH\n");
1623 if (spnego.type == SPNEGO_NEG_TOKEN_INIT) {
1625 /* The server offers a list of mechanisms */
1627 const char **mechType = (const char **)spnego.negTokenInit.mechTypes;
1629 while (*mechType != NULL) {
1632 if ( (strcmp(*mechType, OID_KERBEROS5_OLD) == 0) ||
1633 (strcmp(*mechType, OID_KERBEROS5) == 0) ) {
1634 if (manage_client_krb5_init(spnego))
1639 if (strcmp(*mechType, OID_NTLMSSP) == 0) {
1640 if (manage_client_ntlmssp_init(spnego))
1647 DEBUG(1, ("Server offered no compatible mechanism\n"));
1648 x_fprintf(x_stdout, "BH\n");
1652 if (spnego.type == SPNEGO_NEG_TOKEN_TARG) {
1654 if (spnego.negTokenTarg.supportedMech == NULL) {
1655 /* On accept/reject Windows does not send the
1656 mechanism anymore. Handle that here and
1657 shut down the mechanisms. */
1659 switch (spnego.negTokenTarg.negResult) {
1660 case SPNEGO_ACCEPT_COMPLETED:
1661 x_fprintf(x_stdout, "AF\n");
1664 x_fprintf(x_stdout, "NA\n");
1667 DEBUG(1, ("Got a negTokenTarg with no mech and an "
1668 "unknown negResult: %d\n",
1669 spnego.negTokenTarg.negResult));
1670 x_fprintf(x_stdout, "BH\n");
1673 ntlmssp_end(&client_ntlmssp_state);
1677 if (strcmp(spnego.negTokenTarg.supportedMech,
1678 OID_NTLMSSP) == 0) {
1679 manage_client_ntlmssp_targ(spnego);
1684 if (strcmp(spnego.negTokenTarg.supportedMech,
1685 OID_KERBEROS5_OLD) == 0) {
1686 manage_client_krb5_targ(spnego);
1693 DEBUG(1, ("Got an SPNEGO token I could not handle [%s]!\n", buf));
1694 x_fprintf(x_stdout, "BH\n");
1698 free_spnego_data(&spnego);
1702 static void manage_ntlm_server_1_request(struct ntlm_auth_state *state,
1703 char *buf, int length)
1705 char *request, *parameter;
1706 static DATA_BLOB challenge;
1707 static DATA_BLOB lm_response;
1708 static DATA_BLOB nt_response;
1709 static char *full_username;
1710 static char *username;
1711 static char *domain;
1712 static char *plaintext_password;
1713 static bool ntlm_server_1_user_session_key;
1714 static bool ntlm_server_1_lm_session_key;
1716 if (strequal(buf, ".")) {
1717 if (!full_username && !username) {
1718 x_fprintf(x_stdout, "Error: No username supplied!\n");
1719 } else if (plaintext_password) {
1720 /* handle this request as plaintext */
1721 if (!full_username) {
1722 if (asprintf(&full_username, "%s%c%s", domain, winbind_separator(), username) == -1) {
1723 x_fprintf(x_stdout, "Error: Out of memory in asprintf!\n.\n");
1727 if (check_plaintext_auth(full_username, plaintext_password, False)) {
1728 x_fprintf(x_stdout, "Authenticated: Yes\n");
1730 x_fprintf(x_stdout, "Authenticated: No\n");
1732 } else if (!lm_response.data && !nt_response.data) {
1733 x_fprintf(x_stdout, "Error: No password supplied!\n");
1734 } else if (!challenge.data) {
1735 x_fprintf(x_stdout, "Error: No lanman-challenge supplied!\n");
1737 char *error_string = NULL;
1739 uchar user_session_key[16];
1742 if (full_username && !username) {
1744 fstring fstr_domain;
1746 if (!parse_ntlm_auth_domain_user(full_username, fstr_user, fstr_domain)) {
1747 /* username might be 'tainted', don't print into our new-line deleimianted stream */
1748 x_fprintf(x_stdout, "Error: Could not parse into domain and username\n");
1750 SAFE_FREE(username);
1752 username = smb_xstrdup(fstr_user);
1753 domain = smb_xstrdup(fstr_domain);
1757 domain = smb_xstrdup(get_winbind_domain());
1760 if (ntlm_server_1_lm_session_key)
1761 flags |= WBFLAG_PAM_LMKEY;
1763 if (ntlm_server_1_user_session_key)
1764 flags |= WBFLAG_PAM_USER_SESSION_KEY;
1766 if (!NT_STATUS_IS_OK(
1767 contact_winbind_auth_crap(username,
1779 x_fprintf(x_stdout, "Authenticated: No\n");
1780 x_fprintf(x_stdout, "Authentication-Error: %s\n.\n", error_string);
1781 SAFE_FREE(error_string);
1783 static char zeros[16];
1785 char *hex_user_session_key;
1787 x_fprintf(x_stdout, "Authenticated: Yes\n");
1789 if (ntlm_server_1_lm_session_key
1790 && (memcmp(zeros, lm_key,
1791 sizeof(lm_key)) != 0)) {
1792 hex_lm_key = hex_encode(NULL,
1793 (const unsigned char *)lm_key,
1795 x_fprintf(x_stdout, "LANMAN-Session-Key: %s\n", hex_lm_key);
1796 TALLOC_FREE(hex_lm_key);
1799 if (ntlm_server_1_user_session_key
1800 && (memcmp(zeros, user_session_key,
1801 sizeof(user_session_key)) != 0)) {
1802 hex_user_session_key = hex_encode(NULL,
1803 (const unsigned char *)user_session_key,
1804 sizeof(user_session_key));
1805 x_fprintf(x_stdout, "User-Session-Key: %s\n", hex_user_session_key);
1806 TALLOC_FREE(hex_user_session_key);
1810 /* clear out the state */
1811 challenge = data_blob_null;
1812 nt_response = data_blob_null;
1813 lm_response = data_blob_null;
1814 SAFE_FREE(full_username);
1815 SAFE_FREE(username);
1817 SAFE_FREE(plaintext_password);
1818 ntlm_server_1_user_session_key = False;
1819 ntlm_server_1_lm_session_key = False;
1820 x_fprintf(x_stdout, ".\n");
1827 /* Indicates a base64 encoded structure */
1828 parameter = strstr_m(request, ":: ");
1830 parameter = strstr_m(request, ": ");
1833 DEBUG(0, ("Parameter not found!\n"));
1834 x_fprintf(x_stdout, "Error: Parameter not found!\n.\n");
1851 base64_decode_inplace(parameter);
1854 if (strequal(request, "LANMAN-Challenge")) {
1855 challenge = strhex_to_data_blob(NULL, parameter);
1856 if (challenge.length != 8) {
1857 x_fprintf(x_stdout, "Error: hex decode of %s failed! (got %d bytes, expected 8)\n.\n",
1859 (int)challenge.length);
1860 challenge = data_blob_null;
1862 } else if (strequal(request, "NT-Response")) {
1863 nt_response = strhex_to_data_blob(NULL, parameter);
1864 if (nt_response.length < 24) {
1865 x_fprintf(x_stdout, "Error: hex decode of %s failed! (only got %d bytes, needed at least 24)\n.\n",
1867 (int)nt_response.length);
1868 nt_response = data_blob_null;
1870 } else if (strequal(request, "LANMAN-Response")) {
1871 lm_response = strhex_to_data_blob(NULL, parameter);
1872 if (lm_response.length != 24) {
1873 x_fprintf(x_stdout, "Error: hex decode of %s failed! (got %d bytes, expected 24)\n.\n",
1875 (int)lm_response.length);
1876 lm_response = data_blob_null;
1878 } else if (strequal(request, "Password")) {
1879 plaintext_password = smb_xstrdup(parameter);
1880 } else if (strequal(request, "NT-Domain")) {
1881 domain = smb_xstrdup(parameter);
1882 } else if (strequal(request, "Username")) {
1883 username = smb_xstrdup(parameter);
1884 } else if (strequal(request, "Full-Username")) {
1885 full_username = smb_xstrdup(parameter);
1886 } else if (strequal(request, "Request-User-Session-Key")) {
1887 ntlm_server_1_user_session_key = strequal(parameter, "Yes");
1888 } else if (strequal(request, "Request-LanMan-Session-Key")) {
1889 ntlm_server_1_lm_session_key = strequal(parameter, "Yes");
1891 x_fprintf(x_stdout, "Error: Unknown request %s\n.\n", request);
1895 static void manage_ntlm_change_password_1_request(struct ntlm_auth_state *state,
1896 char *buf, int length)
1898 char *request, *parameter;
1899 static DATA_BLOB new_nt_pswd;
1900 static DATA_BLOB old_nt_hash_enc;
1901 static DATA_BLOB new_lm_pswd;
1902 static DATA_BLOB old_lm_hash_enc;
1903 static char *full_username = NULL;
1904 static char *username = NULL;
1905 static char *domain = NULL;
1906 static char *newpswd = NULL;
1907 static char *oldpswd = NULL;
1909 if (strequal(buf, ".")) {
1910 if(newpswd && oldpswd) {
1911 uchar old_nt_hash[16];
1912 uchar old_lm_hash[16];
1913 uchar new_nt_hash[16];
1914 uchar new_lm_hash[16];
1916 new_nt_pswd = data_blob(NULL, 516);
1917 old_nt_hash_enc = data_blob(NULL, 16);
1919 /* Calculate the MD4 hash (NT compatible) of the
1921 E_md4hash(oldpswd, old_nt_hash);
1922 E_md4hash(newpswd, new_nt_hash);
1924 /* E_deshash returns false for 'long'
1925 passwords (> 14 DOS chars).
1927 Therefore, don't send a buffer
1928 encrypted with the truncated hash
1929 (it could allow an even easier
1930 attack on the password)
1932 Likewise, obey the admin's restriction
1935 if (lp_client_lanman_auth() &&
1936 E_deshash(newpswd, new_lm_hash) &&
1937 E_deshash(oldpswd, old_lm_hash)) {
1938 new_lm_pswd = data_blob(NULL, 516);
1939 old_lm_hash_enc = data_blob(NULL, 16);
1940 encode_pw_buffer(new_lm_pswd.data, newpswd,
1943 SamOEMhash(new_lm_pswd.data, old_nt_hash, 516);
1944 E_old_pw_hash(new_nt_hash, old_lm_hash,
1945 old_lm_hash_enc.data);
1947 new_lm_pswd.data = NULL;
1948 new_lm_pswd.length = 0;
1949 old_lm_hash_enc.data = NULL;
1950 old_lm_hash_enc.length = 0;
1953 encode_pw_buffer(new_nt_pswd.data, newpswd,
1956 SamOEMhash(new_nt_pswd.data, old_nt_hash, 516);
1957 E_old_pw_hash(new_nt_hash, old_nt_hash,
1958 old_nt_hash_enc.data);
1961 if (!full_username && !username) {
1962 x_fprintf(x_stdout, "Error: No username supplied!\n");
1963 } else if ((!new_nt_pswd.data || !old_nt_hash_enc.data) &&
1964 (!new_lm_pswd.data || old_lm_hash_enc.data) ) {
1965 x_fprintf(x_stdout, "Error: No NT or LM password "
1966 "blobs supplied!\n");
1968 char *error_string = NULL;
1970 if (full_username && !username) {
1972 fstring fstr_domain;
1974 if (!parse_ntlm_auth_domain_user(full_username,
1977 /* username might be 'tainted', don't
1978 * print into our new-line
1979 * deleimianted stream */
1980 x_fprintf(x_stdout, "Error: Could not "
1981 "parse into domain and "
1983 SAFE_FREE(username);
1984 username = smb_xstrdup(full_username);
1986 SAFE_FREE(username);
1988 username = smb_xstrdup(fstr_user);
1989 domain = smb_xstrdup(fstr_domain);
1994 if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
2001 x_fprintf(x_stdout, "Password-Change: No\n");
2002 x_fprintf(x_stdout, "Password-Change-Error: "
2003 "%s\n.\n", error_string);
2005 x_fprintf(x_stdout, "Password-Change: Yes\n");
2008 SAFE_FREE(error_string);
2010 /* clear out the state */
2011 new_nt_pswd = data_blob_null;
2012 old_nt_hash_enc = data_blob_null;
2013 new_lm_pswd = data_blob_null;
2014 old_nt_hash_enc = data_blob_null;
2015 SAFE_FREE(full_username);
2016 SAFE_FREE(username);
2020 x_fprintf(x_stdout, ".\n");
2027 /* Indicates a base64 encoded structure */
2028 parameter = strstr_m(request, ":: ");
2030 parameter = strstr_m(request, ": ");
2033 DEBUG(0, ("Parameter not found!\n"));
2034 x_fprintf(x_stdout, "Error: Parameter not found!\n.\n");
2050 base64_decode_inplace(parameter);
2053 if (strequal(request, "new-nt-password-blob")) {
2054 new_nt_pswd = strhex_to_data_blob(NULL, parameter);
2055 if (new_nt_pswd.length != 516) {
2056 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2057 "(got %d bytes, expected 516)\n.\n",
2059 (int)new_nt_pswd.length);
2060 new_nt_pswd = data_blob_null;
2062 } else if (strequal(request, "old-nt-hash-blob")) {
2063 old_nt_hash_enc = strhex_to_data_blob(NULL, parameter);
2064 if (old_nt_hash_enc.length != 16) {
2065 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2066 "(got %d bytes, expected 16)\n.\n",
2068 (int)old_nt_hash_enc.length);
2069 old_nt_hash_enc = data_blob_null;
2071 } else if (strequal(request, "new-lm-password-blob")) {
2072 new_lm_pswd = strhex_to_data_blob(NULL, parameter);
2073 if (new_lm_pswd.length != 516) {
2074 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2075 "(got %d bytes, expected 516)\n.\n",
2077 (int)new_lm_pswd.length);
2078 new_lm_pswd = data_blob_null;
2081 else if (strequal(request, "old-lm-hash-blob")) {
2082 old_lm_hash_enc = strhex_to_data_blob(NULL, parameter);
2083 if (old_lm_hash_enc.length != 16)
2085 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2086 "(got %d bytes, expected 16)\n.\n",
2088 (int)old_lm_hash_enc.length);
2089 old_lm_hash_enc = data_blob_null;
2091 } else if (strequal(request, "nt-domain")) {
2092 domain = smb_xstrdup(parameter);
2093 } else if(strequal(request, "username")) {
2094 username = smb_xstrdup(parameter);
2095 } else if(strequal(request, "full-username")) {
2096 username = smb_xstrdup(parameter);
2097 } else if(strequal(request, "new-password")) {
2098 newpswd = smb_xstrdup(parameter);
2099 } else if (strequal(request, "old-password")) {
2100 oldpswd = smb_xstrdup(parameter);
2102 x_fprintf(x_stdout, "Error: Unknown request %s\n.\n", request);
2106 static void manage_squid_request(struct ntlm_auth_state *state,
2107 stdio_helper_function fn)
2110 char tmp[INITIAL_BUFFER_SIZE+1];
2111 int length, buf_size = 0;
2114 buf = talloc_strdup(state->mem_ctx, "");
2116 DEBUG(0, ("Failed to allocate input buffer.\n"));
2117 x_fprintf(x_stderr, "ERR\n");
2123 /* this is not a typo - x_fgets doesn't work too well under
2125 if (fgets(tmp, sizeof(tmp)-1, stdin) == NULL) {
2126 if (ferror(stdin)) {
2127 DEBUG(1, ("fgets() failed! dying..... errno=%d "
2128 "(%s)\n", ferror(stdin),
2129 strerror(ferror(stdin))));
2136 buf = talloc_strdup_append_buffer(buf, tmp);
2137 buf_size += INITIAL_BUFFER_SIZE;
2139 if (buf_size > MAX_BUFFER_SIZE) {
2140 DEBUG(2, ("Oversized message\n"));
2141 x_fprintf(x_stderr, "ERR\n");
2146 c = strchr(buf, '\n');
2147 } while (c == NULL);
2152 DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf,length));
2154 if (buf[0] == '\0') {
2155 DEBUG(2, ("Invalid Request\n"));
2156 x_fprintf(x_stderr, "ERR\n");
2161 fn(state, buf, length);
2166 static void squid_stream(enum stdio_helper_mode stdio_mode, stdio_helper_function fn) {
2167 TALLOC_CTX *mem_ctx;
2168 struct ntlm_auth_state *state;
2170 /* initialize FDescs */
2171 x_setbuf(x_stdout, NULL);
2172 x_setbuf(x_stderr, NULL);
2174 mem_ctx = talloc_init("ntlm_auth");
2176 DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
2177 x_fprintf(x_stderr, "ERR\n");
2181 state = talloc_zero(mem_ctx, struct ntlm_auth_state);
2183 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
2184 x_fprintf(x_stderr, "ERR\n");
2188 state->mem_ctx = mem_ctx;
2189 state->helper_mode = stdio_mode;
2192 manage_squid_request(state, fn);
2197 /* Authenticate a user with a challenge/response */
2199 static bool check_auth_crap(void)
2204 char user_session_key[16];
2206 char *hex_user_session_key;
2208 static uint8 zeros[16];
2210 x_setbuf(x_stdout, NULL);
2213 flags |= WBFLAG_PAM_LMKEY;
2215 if (request_user_session_key)
2216 flags |= WBFLAG_PAM_USER_SESSION_KEY;
2218 flags |= WBFLAG_PAM_NT_STATUS_SQUASH;
2220 nt_status = contact_winbind_auth_crap(opt_username, opt_domain,
2226 (unsigned char *)lm_key,
2227 (unsigned char *)user_session_key,
2228 &error_string, NULL);
2230 if (!NT_STATUS_IS_OK(nt_status)) {
2231 x_fprintf(x_stdout, "%s (0x%x)\n",
2233 NT_STATUS_V(nt_status));
2234 SAFE_FREE(error_string);
2239 && (memcmp(zeros, lm_key,
2240 sizeof(lm_key)) != 0)) {
2241 hex_lm_key = hex_encode(NULL, (const unsigned char *)lm_key,
2243 x_fprintf(x_stdout, "LM_KEY: %s\n", hex_lm_key);
2244 TALLOC_FREE(hex_lm_key);
2246 if (request_user_session_key
2247 && (memcmp(zeros, user_session_key,
2248 sizeof(user_session_key)) != 0)) {
2249 hex_user_session_key = hex_encode(NULL, (const unsigned char *)user_session_key,
2250 sizeof(user_session_key));
2251 x_fprintf(x_stdout, "NT_KEY: %s\n", hex_user_session_key);
2252 TALLOC_FREE(hex_user_session_key);
2261 OPT_USERNAME = 1000,
2270 OPT_USER_SESSION_KEY,
2272 OPT_REQUIRE_MEMBERSHIP,
2273 OPT_USE_CACHED_CREDS
2276 int main(int argc, const char **argv)
2278 TALLOC_CTX *frame = talloc_stackframe();
2280 static const char *helper_protocol;
2281 static int diagnostics;
2283 static const char *hex_challenge;
2284 static const char *hex_lm_response;
2285 static const char *hex_nt_response;
2289 /* NOTE: DO NOT change this interface without considering the implications!
2290 This is an external interface, which other programs will use to interact
2294 /* We do not use single-letter command abbreviations, because they harm future
2295 interface stability. */
2297 struct poptOption long_options[] = {
2299 { "helper-protocol", 0, POPT_ARG_STRING, &helper_protocol, OPT_DOMAIN, "operate as a stdio-based helper", "helper protocol to use"},
2300 { "username", 0, POPT_ARG_STRING, &opt_username, OPT_USERNAME, "username"},
2301 { "domain", 0, POPT_ARG_STRING, &opt_domain, OPT_DOMAIN, "domain name"},
2302 { "workstation", 0, POPT_ARG_STRING, &opt_workstation, OPT_WORKSTATION, "workstation"},
2303 { "challenge", 0, POPT_ARG_STRING, &hex_challenge, OPT_CHALLENGE, "challenge (HEX encoded)"},
2304 { "lm-response", 0, POPT_ARG_STRING, &hex_lm_response, OPT_LM, "LM Response to the challenge (HEX encoded)"},
2305 { "nt-response", 0, POPT_ARG_STRING, &hex_nt_response, OPT_NT, "NT or NTLMv2 Response to the challenge (HEX encoded)"},
2306 { "password", 0, POPT_ARG_STRING, &opt_password, OPT_PASSWORD, "User's plaintext password"},
2307 { "request-lm-key", 0, POPT_ARG_NONE, &request_lm_key, OPT_LM_KEY, "Retrieve LM session key"},
2308 { "request-nt-key", 0, POPT_ARG_NONE, &request_user_session_key, OPT_USER_SESSION_KEY, "Retrieve User (NT) session key"},
2309 { "use-cached-creds", 0, POPT_ARG_NONE, &use_cached_creds, OPT_USE_CACHED_CREDS, "Use cached credentials if no password is given"},
2310 { "diagnostics", 0, POPT_ARG_NONE, &diagnostics, OPT_DIAGNOSTICS, "Perform diagnostics on the authentictaion chain"},
2311 { "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" },
2316 /* Samba client initialisation */
2321 /* Samba client initialisation */
2323 if (!lp_load(get_dyn_CONFIGFILE(), True, False, False, True)) {
2324 d_fprintf(stderr, "ntlm_auth: error opening config file %s. Error was %s\n",
2325 get_dyn_CONFIGFILE(), strerror(errno));
2331 pc = poptGetContext("ntlm_auth", argc, argv, long_options, 0);
2333 /* Parse command line options */
2336 poptPrintHelp(pc, stderr, 0);
2340 pc = poptGetContext(NULL, argc, (const char **)argv, long_options,
2341 POPT_CONTEXT_KEEP_FIRST);
2343 while((opt = poptGetNextOpt(pc)) != -1) {
2346 opt_challenge = strhex_to_data_blob(NULL, hex_challenge);
2347 if (opt_challenge.length != 8) {
2348 x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n",
2350 (int)opt_challenge.length);
2355 opt_lm_response = strhex_to_data_blob(NULL, hex_lm_response);
2356 if (opt_lm_response.length != 24) {
2357 x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n",
2359 (int)opt_lm_response.length);
2365 opt_nt_response = strhex_to_data_blob(NULL, hex_nt_response);
2366 if (opt_nt_response.length < 24) {
2367 x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n",
2369 (int)opt_nt_response.length);
2374 case OPT_REQUIRE_MEMBERSHIP:
2375 if (StrnCaseCmp("S-", require_membership_of, 2) == 0) {
2376 require_membership_of_sid = require_membership_of;
2383 char *domain = SMB_STRDUP(opt_username);
2384 char *p = strchr_m(domain, *lp_winbind_separator());
2388 if (opt_domain && !strequal(opt_domain, domain)) {
2389 x_fprintf(x_stderr, "Domain specified in username (%s) "
2390 "doesn't match specified domain (%s)!\n\n",
2391 domain, opt_domain);
2392 poptPrintHelp(pc, stderr, 0);
2395 opt_domain = domain;
2401 /* Note: if opt_domain is "" then send no domain */
2402 if (opt_domain == NULL) {
2403 opt_domain = get_winbind_domain();
2406 if (opt_workstation == NULL) {
2407 opt_workstation = "";
2410 if (helper_protocol) {
2412 for (i=0; i<NUM_HELPER_MODES; i++) {
2413 if (strcmp(helper_protocol, stdio_helper_protocols[i].name) == 0) {
2414 squid_stream(stdio_helper_protocols[i].mode, stdio_helper_protocols[i].fn);
2418 x_fprintf(x_stderr, "unknown helper protocol [%s]\n\nValid helper protools:\n\n", helper_protocol);
2420 for (i=0; i<NUM_HELPER_MODES; i++) {
2421 x_fprintf(x_stderr, "%s\n", stdio_helper_protocols[i].name);
2427 if (!opt_username || !*opt_username) {
2428 x_fprintf(x_stderr, "username must be specified!\n\n");
2429 poptPrintHelp(pc, stderr, 0);
2433 if (opt_challenge.length) {
2434 if (!check_auth_crap()) {
2440 if (!opt_password) {
2441 opt_password = getpass("password: ");
2445 if (!diagnose_ntlm_auth()) {
2451 fstr_sprintf(user, "%s%c%s", opt_domain, winbind_separator(), opt_username);
2452 if (!check_plaintext_auth(user, opt_password, True)) {
2459 poptFreeContext(pc);