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 SQUID_BUFFER_SIZE 2010
33 enum stdio_helper_mode {
41 NTLM_CHANGE_PASSWORD_1,
45 typedef void (*stdio_helper_function)(enum stdio_helper_mode stdio_helper_mode,
46 char *buf, int length);
48 static void manage_squid_basic_request (enum stdio_helper_mode stdio_helper_mode,
49 char *buf, int length);
51 static void manage_squid_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode,
52 char *buf, int length);
54 static void manage_client_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode,
55 char *buf, int length);
57 static void manage_gss_spnego_request (enum stdio_helper_mode stdio_helper_mode,
58 char *buf, int length);
60 static void manage_gss_spnego_client_request (enum stdio_helper_mode stdio_helper_mode,
61 char *buf, int length);
63 static void manage_ntlm_server_1_request (enum stdio_helper_mode stdio_helper_mode,
64 char *buf, int length);
66 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode helper_mode, char *buf, int length);
69 enum stdio_helper_mode mode;
71 stdio_helper_function fn;
72 } stdio_helper_protocols[] = {
73 { SQUID_2_4_BASIC, "squid-2.4-basic", manage_squid_basic_request},
74 { SQUID_2_5_BASIC, "squid-2.5-basic", manage_squid_basic_request},
75 { SQUID_2_5_NTLMSSP, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request},
76 { NTLMSSP_CLIENT_1, "ntlmssp-client-1", manage_client_ntlmssp_request},
77 { GSS_SPNEGO, "gss-spnego", manage_gss_spnego_request},
78 { GSS_SPNEGO_CLIENT, "gss-spnego-client", manage_gss_spnego_client_request},
79 { NTLM_SERVER_1, "ntlm-server-1", manage_ntlm_server_1_request},
80 { NTLM_CHANGE_PASSWORD_1, "ntlm-change-password-1", manage_ntlm_change_password_1_request},
81 { NUM_HELPER_MODES, NULL, NULL}
84 extern int winbindd_fd;
86 const char *opt_username;
87 const char *opt_domain;
88 const char *opt_workstation;
89 const char *opt_password;
90 static DATA_BLOB opt_challenge;
91 static DATA_BLOB opt_lm_response;
92 static DATA_BLOB opt_nt_response;
93 static int request_lm_key;
94 static int request_user_session_key;
95 static int use_cached_creds;
97 static const char *require_membership_of;
98 static const char *require_membership_of_sid;
100 static char winbind_separator(void)
102 struct winbindd_response response;
109 ZERO_STRUCT(response);
111 /* Send off request */
113 if (winbindd_request_response(WINBINDD_INFO, NULL, &response) !=
114 NSS_STATUS_SUCCESS) {
115 d_printf("could not obtain winbind separator!\n");
116 return *lp_winbind_separator();
119 sep = response.data.info.winbind_separator;
123 d_printf("winbind separator was NULL!\n");
124 return *lp_winbind_separator();
130 const char *get_winbind_domain(void)
132 struct winbindd_response response;
134 static fstring winbind_domain;
135 if (*winbind_domain) {
136 return winbind_domain;
139 ZERO_STRUCT(response);
141 /* Send off request */
143 if (winbindd_request_response(WINBINDD_DOMAIN_NAME, NULL, &response) !=
144 NSS_STATUS_SUCCESS) {
145 DEBUG(0, ("could not obtain winbind domain name!\n"));
146 return lp_workgroup();
149 fstrcpy(winbind_domain, response.data.domain_name);
151 return winbind_domain;
155 const char *get_winbind_netbios_name(void)
157 struct winbindd_response response;
159 static fstring winbind_netbios_name;
161 if (*winbind_netbios_name) {
162 return winbind_netbios_name;
165 ZERO_STRUCT(response);
167 /* Send off request */
169 if (winbindd_request_response(WINBINDD_NETBIOS_NAME, NULL, &response) !=
170 NSS_STATUS_SUCCESS) {
171 DEBUG(0, ("could not obtain winbind netbios name!\n"));
172 return global_myname();
175 fstrcpy(winbind_netbios_name, response.data.netbios_name);
177 return winbind_netbios_name;
181 DATA_BLOB get_challenge(void)
183 static DATA_BLOB chal;
184 if (opt_challenge.length)
185 return opt_challenge;
187 chal = data_blob(NULL, 8);
189 generate_random_buffer(chal.data, chal.length);
193 /* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
194 form DOMAIN/user into a domain and a user */
196 static bool parse_ntlm_auth_domain_user(const char *domuser, fstring domain,
200 char *p = strchr(domuser,winbind_separator());
207 fstrcpy(domain, domuser);
208 domain[PTR_DIFF(p, domuser)] = 0;
214 static bool get_require_membership_sid(void) {
215 struct winbindd_request request;
216 struct winbindd_response response;
218 if (!require_membership_of) {
222 if (require_membership_of_sid) {
226 /* Otherwise, ask winbindd for the name->sid request */
228 ZERO_STRUCT(request);
229 ZERO_STRUCT(response);
231 if (!parse_ntlm_auth_domain_user(require_membership_of,
232 request.data.name.dom_name,
233 request.data.name.name)) {
234 DEBUG(0, ("Could not parse %s into seperate domain/name parts!\n",
235 require_membership_of));
239 if (winbindd_request_response(WINBINDD_LOOKUPNAME, &request, &response) !=
240 NSS_STATUS_SUCCESS) {
241 DEBUG(0, ("Winbindd lookupname failed to resolve %s into a SID!\n",
242 require_membership_of));
246 require_membership_of_sid = SMB_STRDUP(response.data.sid.sid);
248 if (require_membership_of_sid)
253 /* Authenticate a user with a plaintext password */
255 static bool check_plaintext_auth(const char *user, const char *pass,
256 bool stdout_diagnostics)
258 struct winbindd_request request;
259 struct winbindd_response response;
262 if (!get_require_membership_sid()) {
266 /* Send off request */
268 ZERO_STRUCT(request);
269 ZERO_STRUCT(response);
271 fstrcpy(request.data.auth.user, user);
272 fstrcpy(request.data.auth.pass, pass);
273 if (require_membership_of_sid)
274 pstrcpy(request.data.auth.require_membership_of_sid, require_membership_of_sid);
276 result = winbindd_request_response(WINBINDD_PAM_AUTH, &request, &response);
278 /* Display response */
280 if (stdout_diagnostics) {
281 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
282 d_printf("Reading winbind reply failed! (0x01)\n");
285 d_printf("%s: %s (0x%x)\n",
286 response.data.auth.nt_status_string,
287 response.data.auth.error_string,
288 response.data.auth.nt_status);
290 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
291 DEBUG(1, ("Reading winbind reply failed! (0x01)\n"));
294 DEBUG(3, ("%s: %s (0x%x)\n",
295 response.data.auth.nt_status_string,
296 response.data.auth.error_string,
297 response.data.auth.nt_status));
300 return (result == NSS_STATUS_SUCCESS);
303 /* authenticate a user with an encrypted username/password */
305 NTSTATUS contact_winbind_auth_crap(const char *username,
307 const char *workstation,
308 const DATA_BLOB *challenge,
309 const DATA_BLOB *lm_response,
310 const DATA_BLOB *nt_response,
313 uint8 user_session_key[16],
319 struct winbindd_request request;
320 struct winbindd_response response;
322 if (!get_require_membership_sid()) {
323 return NT_STATUS_INVALID_PARAMETER;
326 ZERO_STRUCT(request);
327 ZERO_STRUCT(response);
329 request.flags = flags;
331 request.data.auth_crap.logon_parameters = MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT | MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT;
333 if (require_membership_of_sid)
334 fstrcpy(request.data.auth_crap.require_membership_of_sid, require_membership_of_sid);
336 fstrcpy(request.data.auth_crap.user, username);
337 fstrcpy(request.data.auth_crap.domain, domain);
339 fstrcpy(request.data.auth_crap.workstation,
342 memcpy(request.data.auth_crap.chal, challenge->data, MIN(challenge->length, 8));
344 if (lm_response && lm_response->length) {
345 memcpy(request.data.auth_crap.lm_resp,
347 MIN(lm_response->length, sizeof(request.data.auth_crap.lm_resp)));
348 request.data.auth_crap.lm_resp_len = lm_response->length;
351 if (nt_response && nt_response->length) {
352 memcpy(request.data.auth_crap.nt_resp,
354 MIN(nt_response->length, sizeof(request.data.auth_crap.nt_resp)));
355 request.data.auth_crap.nt_resp_len = nt_response->length;
358 result = winbindd_request_response(WINBINDD_PAM_AUTH_CRAP, &request, &response);
360 /* Display response */
362 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
363 nt_status = NT_STATUS_UNSUCCESSFUL;
365 *error_string = smb_xstrdup("Reading winbind reply failed!");
366 winbindd_free_response(&response);
370 nt_status = (NT_STATUS(response.data.auth.nt_status));
371 if (!NT_STATUS_IS_OK(nt_status)) {
373 *error_string = smb_xstrdup(response.data.auth.error_string);
374 winbindd_free_response(&response);
378 if ((flags & WBFLAG_PAM_LMKEY) && lm_key) {
379 memcpy(lm_key, response.data.auth.first_8_lm_hash,
380 sizeof(response.data.auth.first_8_lm_hash));
382 if ((flags & WBFLAG_PAM_USER_SESSION_KEY) && user_session_key) {
383 memcpy(user_session_key, response.data.auth.user_session_key,
384 sizeof(response.data.auth.user_session_key));
387 if (flags & WBFLAG_PAM_UNIX_NAME) {
388 *unix_name = SMB_STRDUP((char *)response.extra_data.data);
390 winbindd_free_response(&response);
391 return NT_STATUS_NO_MEMORY;
395 winbindd_free_response(&response);
399 /* contact server to change user password using auth crap */
400 static NTSTATUS contact_winbind_change_pswd_auth_crap(const char *username,
402 const DATA_BLOB new_nt_pswd,
403 const DATA_BLOB old_nt_hash_enc,
404 const DATA_BLOB new_lm_pswd,
405 const DATA_BLOB old_lm_hash_enc,
410 struct winbindd_request request;
411 struct winbindd_response response;
413 if (!get_require_membership_sid())
416 *error_string = smb_xstrdup("Can't get membership sid.");
417 return NT_STATUS_INVALID_PARAMETER;
420 ZERO_STRUCT(request);
421 ZERO_STRUCT(response);
424 fstrcpy(request.data.chng_pswd_auth_crap.user, username);
426 fstrcpy(request.data.chng_pswd_auth_crap.domain,domain);
428 if(new_nt_pswd.length)
430 memcpy(request.data.chng_pswd_auth_crap.new_nt_pswd, new_nt_pswd.data, sizeof(request.data.chng_pswd_auth_crap.new_nt_pswd));
431 request.data.chng_pswd_auth_crap.new_nt_pswd_len = new_nt_pswd.length;
434 if(old_nt_hash_enc.length)
436 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));
437 request.data.chng_pswd_auth_crap.old_nt_hash_enc_len = old_nt_hash_enc.length;
440 if(new_lm_pswd.length)
442 memcpy(request.data.chng_pswd_auth_crap.new_lm_pswd, new_lm_pswd.data, sizeof(request.data.chng_pswd_auth_crap.new_lm_pswd));
443 request.data.chng_pswd_auth_crap.new_lm_pswd_len = new_lm_pswd.length;
446 if(old_lm_hash_enc.length)
448 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));
449 request.data.chng_pswd_auth_crap.old_lm_hash_enc_len = old_lm_hash_enc.length;
452 result = winbindd_request_response(WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP, &request, &response);
454 /* Display response */
456 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0))
458 nt_status = NT_STATUS_UNSUCCESSFUL;
460 *error_string = smb_xstrdup("Reading winbind reply failed!");
461 winbindd_free_response(&response);
465 nt_status = (NT_STATUS(response.data.auth.nt_status));
466 if (!NT_STATUS_IS_OK(nt_status))
469 *error_string = smb_xstrdup(response.data.auth.error_string);
470 winbindd_free_response(&response);
474 winbindd_free_response(&response);
479 static NTSTATUS winbind_pw_check(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
481 static const char zeros[16] = { 0, };
485 uint8 user_sess_key[16];
488 nt_status = contact_winbind_auth_crap(ntlmssp_state->user, ntlmssp_state->domain,
489 ntlmssp_state->workstation,
490 &ntlmssp_state->chal,
491 &ntlmssp_state->lm_resp,
492 &ntlmssp_state->nt_resp,
493 WBFLAG_PAM_LMKEY | WBFLAG_PAM_USER_SESSION_KEY | WBFLAG_PAM_UNIX_NAME,
494 lm_key, user_sess_key,
495 &error_string, &unix_name);
497 if (NT_STATUS_IS_OK(nt_status)) {
498 if (memcmp(lm_key, zeros, 8) != 0) {
499 *lm_session_key = data_blob(NULL, 16);
500 memcpy(lm_session_key->data, lm_key, 8);
501 memset(lm_session_key->data+8, '\0', 8);
504 if (memcmp(user_sess_key, zeros, 16) != 0) {
505 *user_session_key = data_blob(user_sess_key, 16);
507 ntlmssp_state->auth_context = talloc_strdup(ntlmssp_state->mem_ctx, unix_name);
508 SAFE_FREE(unix_name);
510 DEBUG(NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED) ? 0 : 3,
511 ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
512 ntlmssp_state->domain, ntlmssp_state->user,
513 ntlmssp_state->workstation,
514 error_string ? error_string : "unknown error (NULL)"));
515 ntlmssp_state->auth_context = NULL;
520 static NTSTATUS local_pw_check(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
523 uint8 lm_pw[16], nt_pw[16];
525 nt_lm_owf_gen (opt_password, nt_pw, lm_pw);
527 nt_status = ntlm_password_check(ntlmssp_state->mem_ctx,
528 &ntlmssp_state->chal,
529 &ntlmssp_state->lm_resp,
530 &ntlmssp_state->nt_resp,
534 ntlmssp_state->domain,
535 lm_pw, nt_pw, user_session_key, lm_session_key);
537 if (NT_STATUS_IS_OK(nt_status)) {
538 ntlmssp_state->auth_context = talloc_asprintf(ntlmssp_state->mem_ctx,
539 "%s%c%s", ntlmssp_state->domain,
540 *lp_winbind_separator(),
541 ntlmssp_state->user);
543 DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
544 ntlmssp_state->domain, ntlmssp_state->user, ntlmssp_state->workstation,
545 nt_errstr(nt_status)));
546 ntlmssp_state->auth_context = NULL;
551 static NTSTATUS ntlm_auth_start_ntlmssp_client(NTLMSSP_STATE **client_ntlmssp_state)
554 if ( (opt_username == NULL) || (opt_domain == NULL) ) {
555 status = NT_STATUS_UNSUCCESSFUL;
556 DEBUG(1, ("Need username and domain for NTLMSSP\n"));
557 return NT_STATUS_INVALID_PARAMETER;
560 status = ntlmssp_client_start(client_ntlmssp_state);
562 if (!NT_STATUS_IS_OK(status)) {
563 DEBUG(1, ("Could not start NTLMSSP client: %s\n",
565 ntlmssp_end(client_ntlmssp_state);
569 status = ntlmssp_set_username(*client_ntlmssp_state, opt_username);
571 if (!NT_STATUS_IS_OK(status)) {
572 DEBUG(1, ("Could not set username: %s\n",
574 ntlmssp_end(client_ntlmssp_state);
578 status = ntlmssp_set_domain(*client_ntlmssp_state, opt_domain);
580 if (!NT_STATUS_IS_OK(status)) {
581 DEBUG(1, ("Could not set domain: %s\n",
583 ntlmssp_end(client_ntlmssp_state);
588 status = ntlmssp_set_password(*client_ntlmssp_state, opt_password);
590 if (!NT_STATUS_IS_OK(status)) {
591 DEBUG(1, ("Could not set password: %s\n",
593 ntlmssp_end(client_ntlmssp_state);
601 static NTSTATUS ntlm_auth_start_ntlmssp_server(NTLMSSP_STATE **ntlmssp_state)
603 NTSTATUS status = ntlmssp_server_start(ntlmssp_state);
605 if (!NT_STATUS_IS_OK(status)) {
606 DEBUG(1, ("Could not start NTLMSSP server: %s\n",
611 /* Have we been given a local password, or should we ask winbind? */
613 (*ntlmssp_state)->check_password = local_pw_check;
614 (*ntlmssp_state)->get_domain = lp_workgroup;
615 (*ntlmssp_state)->get_global_myname = global_myname;
617 (*ntlmssp_state)->check_password = winbind_pw_check;
618 (*ntlmssp_state)->get_domain = get_winbind_domain;
619 (*ntlmssp_state)->get_global_myname = get_winbind_netbios_name;
624 /*******************************************************************
625 Used by firefox to drive NTLM auth to IIS servers.
626 *******************************************************************/
628 static NTSTATUS do_ccache_ntlm_auth(DATA_BLOB initial_msg, DATA_BLOB challenge_msg,
631 struct winbindd_request wb_request;
632 struct winbindd_response wb_response;
635 /* get winbindd to do the ntlmssp step on our behalf */
636 ZERO_STRUCT(wb_request);
637 ZERO_STRUCT(wb_response);
639 fstr_sprintf(wb_request.data.ccache_ntlm_auth.user,
640 "%s%c%s", opt_domain, winbind_separator(), opt_username);
641 wb_request.data.ccache_ntlm_auth.uid = geteuid();
642 wb_request.data.ccache_ntlm_auth.initial_blob_len = initial_msg.length;
643 wb_request.data.ccache_ntlm_auth.challenge_blob_len = challenge_msg.length;
644 wb_request.extra_len = initial_msg.length + challenge_msg.length;
646 if (wb_request.extra_len > 0) {
647 wb_request.extra_data.data = SMB_MALLOC_ARRAY(char, wb_request.extra_len);
648 if (wb_request.extra_data.data == NULL) {
649 return NT_STATUS_NO_MEMORY;
652 memcpy(wb_request.extra_data.data, initial_msg.data, initial_msg.length);
653 memcpy(wb_request.extra_data.data + initial_msg.length,
654 challenge_msg.data, challenge_msg.length);
657 result = winbindd_request_response(WINBINDD_CCACHE_NTLMAUTH, &wb_request, &wb_response);
658 SAFE_FREE(wb_request.extra_data.data);
660 if (result != NSS_STATUS_SUCCESS) {
661 winbindd_free_response(&wb_response);
662 return NT_STATUS_UNSUCCESSFUL;
666 *reply = data_blob(wb_response.extra_data.data,
667 wb_response.data.ccache_ntlm_auth.auth_blob_len);
668 if (wb_response.data.ccache_ntlm_auth.auth_blob_len > 0 &&
669 reply->data == NULL) {
670 winbindd_free_response(&wb_response);
671 return NT_STATUS_NO_MEMORY;
675 winbindd_free_response(&wb_response);
676 return NT_STATUS_MORE_PROCESSING_REQUIRED;
679 static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode,
680 char *buf, int length)
682 static NTLMSSP_STATE *ntlmssp_state = NULL;
683 static char* want_feature_list = NULL;
684 static uint32 neg_flags = 0;
685 static bool have_session_key = False;
686 static DATA_BLOB session_key;
687 DATA_BLOB request, reply;
690 if (strlen(buf) < 2) {
691 DEBUG(1, ("NTLMSSP query [%s] invalid", buf));
692 x_fprintf(x_stdout, "BH\n");
696 if (strlen(buf) > 3) {
697 if(strncmp(buf, "SF ", 3) == 0){
698 DEBUG(10, ("Setting flags to negotioate\n"));
699 SAFE_FREE(want_feature_list);
700 want_feature_list = SMB_STRNDUP(buf+3, strlen(buf)-3);
701 x_fprintf(x_stdout, "OK\n");
704 request = base64_decode_data_blob(buf + 3);
706 request = data_blob_null;
709 if ((strncmp(buf, "PW ", 3) == 0)) {
710 /* The calling application wants us to use a local password (rather than winbindd) */
712 opt_password = SMB_STRNDUP((const char *)request.data, request.length);
714 if (opt_password == NULL) {
715 DEBUG(1, ("Out of memory\n"));
716 x_fprintf(x_stdout, "BH\n");
717 data_blob_free(&request);
721 x_fprintf(x_stdout, "OK\n");
722 data_blob_free(&request);
726 if (strncmp(buf, "YR", 2) == 0) {
728 ntlmssp_end(&ntlmssp_state);
729 } else if (strncmp(buf, "KK", 2) == 0) {
731 } else if (strncmp(buf, "GF", 2) == 0) {
732 DEBUG(10, ("Requested negotiated NTLMSSP flags\n"));
733 x_fprintf(x_stdout, "GF 0x%08lx\n", have_session_key?neg_flags:0l);
734 data_blob_free(&request);
736 } else if (strncmp(buf, "GK", 2) == 0) {
737 DEBUG(10, ("Requested NTLMSSP session key\n"));
738 if(have_session_key) {
739 char *key64 = base64_encode_data_blob(session_key);
740 x_fprintf(x_stdout, "GK %s\n", key64?key64:"<NULL>");
743 x_fprintf(x_stdout, "BH\n");
746 data_blob_free(&request);
749 DEBUG(1, ("NTLMSSP query [%s] invalid", buf));
750 x_fprintf(x_stdout, "BH\n");
754 if (!ntlmssp_state) {
755 if (!NT_STATUS_IS_OK(nt_status = ntlm_auth_start_ntlmssp_server(&ntlmssp_state))) {
756 x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
759 ntlmssp_want_feature_list(ntlmssp_state, want_feature_list);
762 DEBUG(10, ("got NTLMSSP packet:\n"));
763 dump_data(10, request.data, request.length);
765 nt_status = ntlmssp_update(ntlmssp_state, request, &reply);
767 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
768 char *reply_base64 = base64_encode_data_blob(reply);
769 x_fprintf(x_stdout, "TT %s\n", reply_base64);
770 SAFE_FREE(reply_base64);
771 data_blob_free(&reply);
772 DEBUG(10, ("NTLMSSP challenge\n"));
773 } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) {
774 x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
775 DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status)));
777 ntlmssp_end(&ntlmssp_state);
778 } else if (!NT_STATUS_IS_OK(nt_status)) {
779 x_fprintf(x_stdout, "NA %s\n", nt_errstr(nt_status));
780 DEBUG(10, ("NTLMSSP %s\n", nt_errstr(nt_status)));
782 x_fprintf(x_stdout, "AF %s\n", (char *)ntlmssp_state->auth_context);
783 DEBUG(10, ("NTLMSSP OK!\n"));
786 data_blob_free(&session_key);
787 session_key = data_blob(ntlmssp_state->session_key.data,
788 ntlmssp_state->session_key.length);
789 neg_flags = ntlmssp_state->neg_flags;
790 have_session_key = True;
793 data_blob_free(&request);
796 static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode,
797 char *buf, int length)
799 /* The statics here are *HORRIBLE* and this entire concept
800 needs to be rewritten. Essentially it's using these statics
801 as the state in a state machine. BLEEEGH ! JRA. */
803 static NTLMSSP_STATE *ntlmssp_state = NULL;
804 static DATA_BLOB initial_message;
805 static char* want_feature_list = NULL;
806 static uint32 neg_flags = 0;
807 static bool have_session_key = False;
808 static DATA_BLOB session_key;
809 DATA_BLOB request, reply;
813 if (!opt_username || !*opt_username) {
814 x_fprintf(x_stderr, "username must be specified!\n\n");
818 if (strlen(buf) < 2) {
819 DEBUG(1, ("NTLMSSP query [%s] invalid", buf));
820 x_fprintf(x_stdout, "BH\n");
824 if (strlen(buf) > 3) {
825 if(strncmp(buf, "SF ", 3) == 0) {
826 DEBUG(10, ("Looking for flags to negotiate\n"));
827 SAFE_FREE(want_feature_list);
828 want_feature_list = SMB_STRNDUP(buf+3, strlen(buf)-3);
829 x_fprintf(x_stdout, "OK\n");
832 request = base64_decode_data_blob(buf + 3);
834 request = data_blob_null;
837 if (strncmp(buf, "PW ", 3) == 0) {
838 /* We asked for a password and obviously got it :-) */
840 opt_password = SMB_STRNDUP((const char *)request.data, request.length);
842 if (opt_password == NULL) {
843 DEBUG(1, ("Out of memory\n"));
844 x_fprintf(x_stdout, "BH\n");
845 data_blob_free(&request);
849 x_fprintf(x_stdout, "OK\n");
850 data_blob_free(&request);
854 if (!ntlmssp_state && use_cached_creds) {
855 /* check whether credentials are usable. */
856 DATA_BLOB empty_blob = data_blob_null;
858 nt_status = do_ccache_ntlm_auth(empty_blob, empty_blob, NULL);
859 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
860 /* failed to use cached creds */
861 use_cached_creds = False;
865 if (opt_password == NULL && !use_cached_creds) {
867 /* Request a password from the calling process. After
868 sending it, the calling process should retry asking for the negotiate. */
870 DEBUG(10, ("Requesting password\n"));
871 x_fprintf(x_stdout, "PW\n");
875 if (strncmp(buf, "YR", 2) == 0) {
877 ntlmssp_end(&ntlmssp_state);
878 } else if (strncmp(buf, "TT", 2) == 0) {
880 } else if (strncmp(buf, "GF", 2) == 0) {
881 DEBUG(10, ("Requested negotiated NTLMSSP flags\n"));
882 x_fprintf(x_stdout, "GF 0x%08lx\n", have_session_key?neg_flags:0l);
883 data_blob_free(&request);
885 } else if (strncmp(buf, "GK", 2) == 0 ) {
886 DEBUG(10, ("Requested session key\n"));
888 if(have_session_key) {
889 char *key64 = base64_encode_data_blob(session_key);
890 x_fprintf(x_stdout, "GK %s\n", key64?key64:"<NULL>");
894 x_fprintf(x_stdout, "BH\n");
897 data_blob_free(&request);
900 DEBUG(1, ("NTLMSSP query [%s] invalid", buf));
901 x_fprintf(x_stdout, "BH\n");
905 if (!ntlmssp_state) {
906 if (!NT_STATUS_IS_OK(nt_status = ntlm_auth_start_ntlmssp_client(&ntlmssp_state))) {
907 x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
910 ntlmssp_want_feature_list(ntlmssp_state, want_feature_list);
912 initial_message = data_blob_null;
915 DEBUG(10, ("got NTLMSSP packet:\n"));
916 dump_data(10, request.data, request.length);
918 if (use_cached_creds && !opt_password && !first) {
919 nt_status = do_ccache_ntlm_auth(initial_message, request, &reply);
921 nt_status = ntlmssp_update(ntlmssp_state, request, &reply);
924 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
925 char *reply_base64 = base64_encode_data_blob(reply);
927 x_fprintf(x_stdout, "YR %s\n", reply_base64);
929 x_fprintf(x_stdout, "KK %s\n", reply_base64);
931 SAFE_FREE(reply_base64);
933 initial_message = reply;
935 data_blob_free(&reply);
937 DEBUG(10, ("NTLMSSP challenge\n"));
938 } else if (NT_STATUS_IS_OK(nt_status)) {
939 char *reply_base64 = base64_encode_data_blob(reply);
940 x_fprintf(x_stdout, "AF %s\n", reply_base64);
941 SAFE_FREE(reply_base64);
944 data_blob_free(&session_key);
946 session_key = data_blob(ntlmssp_state->session_key.data,
947 ntlmssp_state->session_key.length);
948 neg_flags = ntlmssp_state->neg_flags;
949 have_session_key = True;
951 DEBUG(10, ("NTLMSSP OK!\n"));
953 ntlmssp_end(&ntlmssp_state);
955 x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
956 DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status)));
958 ntlmssp_end(&ntlmssp_state);
961 data_blob_free(&request);
964 static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode,
965 char *buf, int length)
970 pass=(char *)memchr(buf,' ',length);
972 DEBUG(2, ("Password not found. Denying access\n"));
973 x_fprintf(x_stdout, "ERR\n");
979 if (stdio_helper_mode == SQUID_2_5_BASIC) {
980 rfc1738_unescape(user);
981 rfc1738_unescape(pass);
984 if (check_plaintext_auth(user, pass, False)) {
985 x_fprintf(x_stdout, "OK\n");
987 x_fprintf(x_stdout, "ERR\n");
991 static void offer_gss_spnego_mechs(void) {
999 pstring myname_lower;
1001 ZERO_STRUCT(spnego);
1003 pstrcpy(myname_lower, global_myname());
1004 strlower_m(myname_lower);
1006 pstr_sprintf(principal, "%s$@%s", myname_lower, lp_realm());
1008 /* Server negTokenInit (mech offerings) */
1009 spnego.type = SPNEGO_NEG_TOKEN_INIT;
1010 spnego.negTokenInit.mechTypes = SMB_XMALLOC_ARRAY(const char *, 2);
1012 spnego.negTokenInit.mechTypes[0] = smb_xstrdup(OID_KERBEROS5_OLD);
1013 spnego.negTokenInit.mechTypes[1] = smb_xstrdup(OID_NTLMSSP);
1014 spnego.negTokenInit.mechTypes[2] = NULL;
1016 spnego.negTokenInit.mechTypes[0] = smb_xstrdup(OID_NTLMSSP);
1017 spnego.negTokenInit.mechTypes[1] = NULL;
1021 spnego.negTokenInit.mechListMIC = data_blob(principal,
1024 len = write_spnego_data(&token, &spnego);
1025 free_spnego_data(&spnego);
1028 DEBUG(1, ("Could not write SPNEGO data blob\n"));
1029 x_fprintf(x_stdout, "BH\n");
1033 reply_base64 = base64_encode_data_blob(token);
1034 x_fprintf(x_stdout, "TT %s *\n", reply_base64);
1036 SAFE_FREE(reply_base64);
1037 data_blob_free(&token);
1038 DEBUG(10, ("sent SPNEGO negTokenInit\n"));
1042 static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode,
1043 char *buf, int length)
1045 static NTLMSSP_STATE *ntlmssp_state = NULL;
1046 SPNEGO_DATA request, response;
1052 char *domain = NULL;
1054 const char *reply_code;
1056 pstring reply_argument;
1058 if (strlen(buf) < 2) {
1059 DEBUG(1, ("SPENGO query [%s] invalid", buf));
1060 x_fprintf(x_stdout, "BH\n");
1064 if (strncmp(buf, "YR", 2) == 0) {
1066 ntlmssp_end(&ntlmssp_state);
1067 } else if (strncmp(buf, "KK", 2) == 0) {
1070 DEBUG(1, ("SPENGO query [%s] invalid", buf));
1071 x_fprintf(x_stdout, "BH\n");
1075 if ( (strlen(buf) == 2)) {
1077 /* no client data, get the negTokenInit offering
1080 offer_gss_spnego_mechs();
1084 /* All subsequent requests have a blob. This might be negTokenInit or negTokenTarg */
1086 if (strlen(buf) <= 3) {
1087 DEBUG(1, ("GSS-SPNEGO query [%s] invalid\n", buf));
1088 x_fprintf(x_stdout, "BH\n");
1092 token = base64_decode_data_blob(buf + 3);
1093 len = read_spnego_data(token, &request);
1094 data_blob_free(&token);
1097 DEBUG(1, ("GSS-SPNEGO query [%s] invalid", buf));
1098 x_fprintf(x_stdout, "BH\n");
1102 if (request.type == SPNEGO_NEG_TOKEN_INIT) {
1104 /* Second request from Client. This is where the
1105 client offers its mechanism to use. */
1107 if ( (request.negTokenInit.mechTypes == NULL) ||
1108 (request.negTokenInit.mechTypes[0] == NULL) ) {
1109 DEBUG(1, ("Client did not offer any mechanism"));
1110 x_fprintf(x_stdout, "BH\n");
1114 status = NT_STATUS_UNSUCCESSFUL;
1115 if (strcmp(request.negTokenInit.mechTypes[0], OID_NTLMSSP) == 0) {
1117 if ( request.negTokenInit.mechToken.data == NULL ) {
1118 DEBUG(1, ("Client did not provide NTLMSSP data\n"));
1119 x_fprintf(x_stdout, "BH\n");
1123 if ( ntlmssp_state != NULL ) {
1124 DEBUG(1, ("Client wants a new NTLMSSP challenge, but "
1125 "already got one\n"));
1126 x_fprintf(x_stdout, "BH\n");
1127 ntlmssp_end(&ntlmssp_state);
1131 if (!NT_STATUS_IS_OK(status = ntlm_auth_start_ntlmssp_server(&ntlmssp_state))) {
1132 x_fprintf(x_stdout, "BH %s\n", nt_errstr(status));
1136 DEBUG(10, ("got NTLMSSP packet:\n"));
1137 dump_data(10, request.negTokenInit.mechToken.data,
1138 request.negTokenInit.mechToken.length);
1140 response.type = SPNEGO_NEG_TOKEN_TARG;
1141 response.negTokenTarg.supportedMech = SMB_STRDUP(OID_NTLMSSP);
1142 response.negTokenTarg.mechListMIC = data_blob_null;
1144 status = ntlmssp_update(ntlmssp_state,
1145 request.negTokenInit.mechToken,
1146 &response.negTokenTarg.responseToken);
1150 if (strcmp(request.negTokenInit.mechTypes[0], OID_KERBEROS5_OLD) == 0) {
1152 TALLOC_CTX *mem_ctx = talloc_init("manage_gss_spnego_request");
1155 DATA_BLOB session_key;
1157 if ( request.negTokenInit.mechToken.data == NULL ) {
1158 DEBUG(1, ("Client did not provide Kerberos data\n"));
1159 x_fprintf(x_stdout, "BH\n");
1163 response.type = SPNEGO_NEG_TOKEN_TARG;
1164 response.negTokenTarg.supportedMech = SMB_STRDUP(OID_KERBEROS5_OLD);
1165 response.negTokenTarg.mechListMIC = data_blob_null;
1166 response.negTokenTarg.responseToken = data_blob_null;
1168 status = ads_verify_ticket(mem_ctx, lp_realm(), 0,
1169 &request.negTokenInit.mechToken,
1170 &principal, NULL, &ap_rep,
1171 &session_key, True);
1173 talloc_destroy(mem_ctx);
1175 /* Now in "principal" we have the name we are
1176 authenticated as. */
1178 if (NT_STATUS_IS_OK(status)) {
1180 domain = strchr_m(principal, '@');
1182 if (domain == NULL) {
1183 DEBUG(1, ("Did not get a valid principal "
1184 "from ads_verify_ticket\n"));
1185 x_fprintf(x_stdout, "BH\n");
1190 domain = SMB_STRDUP(domain);
1191 user = SMB_STRDUP(principal);
1193 data_blob_free(&ap_rep);
1195 SAFE_FREE(principal);
1202 if ( (request.negTokenTarg.supportedMech == NULL) ||
1203 ( strcmp(request.negTokenTarg.supportedMech, OID_NTLMSSP) != 0 ) ) {
1204 /* Kerberos should never send a negTokenTarg, OID_NTLMSSP
1205 is the only one we support that sends this stuff */
1206 DEBUG(1, ("Got a negTokenTarg for something non-NTLMSSP: %s\n",
1207 request.negTokenTarg.supportedMech));
1208 x_fprintf(x_stdout, "BH\n");
1212 if (request.negTokenTarg.responseToken.data == NULL) {
1213 DEBUG(1, ("Got a negTokenTarg without a responseToken!\n"));
1214 x_fprintf(x_stdout, "BH\n");
1218 status = ntlmssp_update(ntlmssp_state,
1219 request.negTokenTarg.responseToken,
1220 &response.negTokenTarg.responseToken);
1222 response.type = SPNEGO_NEG_TOKEN_TARG;
1223 response.negTokenTarg.supportedMech = SMB_STRDUP(OID_NTLMSSP);
1224 response.negTokenTarg.mechListMIC = data_blob_null;
1226 if (NT_STATUS_IS_OK(status)) {
1227 user = SMB_STRDUP(ntlmssp_state->user);
1228 domain = SMB_STRDUP(ntlmssp_state->domain);
1229 ntlmssp_end(&ntlmssp_state);
1233 free_spnego_data(&request);
1235 if (NT_STATUS_IS_OK(status)) {
1236 response.negTokenTarg.negResult = SPNEGO_ACCEPT_COMPLETED;
1238 pstr_sprintf(reply_argument, "%s\\%s", domain, user);
1239 } else if (NT_STATUS_EQUAL(status,
1240 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1241 response.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
1243 pstr_sprintf(reply_argument, "*");
1245 response.negTokenTarg.negResult = SPNEGO_REJECT;
1247 pstrcpy(reply_argument, nt_errstr(status));
1253 len = write_spnego_data(&token, &response);
1254 free_spnego_data(&response);
1257 DEBUG(1, ("Could not write SPNEGO data blob\n"));
1258 x_fprintf(x_stdout, "BH\n");
1262 reply_base64 = base64_encode_data_blob(token);
1264 x_fprintf(x_stdout, "%s %s %s\n",
1265 reply_code, reply_base64, reply_argument);
1267 SAFE_FREE(reply_base64);
1268 data_blob_free(&token);
1273 static NTLMSSP_STATE *client_ntlmssp_state = NULL;
1275 static bool manage_client_ntlmssp_init(SPNEGO_DATA spnego)
1278 DATA_BLOB null_blob = data_blob_null;
1279 DATA_BLOB to_server;
1280 char *to_server_base64;
1281 const char *my_mechs[] = {OID_NTLMSSP, NULL};
1283 DEBUG(10, ("Got spnego negTokenInit with NTLMSSP\n"));
1285 if (client_ntlmssp_state != NULL) {
1286 DEBUG(1, ("Request for initial SPNEGO request where "
1287 "we already have a state\n"));
1291 if (!client_ntlmssp_state) {
1292 if (!NT_STATUS_IS_OK(status = ntlm_auth_start_ntlmssp_client(&client_ntlmssp_state))) {
1293 x_fprintf(x_stdout, "BH %s\n", nt_errstr(status));
1299 if (opt_password == NULL) {
1301 /* Request a password from the calling process. After
1302 sending it, the calling process should retry with
1303 the negTokenInit. */
1305 DEBUG(10, ("Requesting password\n"));
1306 x_fprintf(x_stdout, "PW\n");
1310 spnego.type = SPNEGO_NEG_TOKEN_INIT;
1311 spnego.negTokenInit.mechTypes = my_mechs;
1312 spnego.negTokenInit.reqFlags = 0;
1313 spnego.negTokenInit.mechListMIC = null_blob;
1315 status = ntlmssp_update(client_ntlmssp_state, null_blob,
1316 &spnego.negTokenInit.mechToken);
1318 if ( !(NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) ||
1319 NT_STATUS_IS_OK(status)) ) {
1320 DEBUG(1, ("Expected OK or MORE_PROCESSING_REQUIRED, got: %s\n",
1321 nt_errstr(status)));
1322 ntlmssp_end(&client_ntlmssp_state);
1326 write_spnego_data(&to_server, &spnego);
1327 data_blob_free(&spnego.negTokenInit.mechToken);
1329 to_server_base64 = base64_encode_data_blob(to_server);
1330 data_blob_free(&to_server);
1331 x_fprintf(x_stdout, "KK %s\n", to_server_base64);
1332 SAFE_FREE(to_server_base64);
1336 static void manage_client_ntlmssp_targ(SPNEGO_DATA spnego)
1339 DATA_BLOB null_blob = data_blob_null;
1341 DATA_BLOB to_server;
1342 char *to_server_base64;
1344 DEBUG(10, ("Got spnego negTokenTarg with NTLMSSP\n"));
1346 if (client_ntlmssp_state == NULL) {
1347 DEBUG(1, ("Got NTLMSSP tArg without a client state\n"));
1348 x_fprintf(x_stdout, "BH\n");
1352 if (spnego.negTokenTarg.negResult == SPNEGO_REJECT) {
1353 x_fprintf(x_stdout, "NA\n");
1354 ntlmssp_end(&client_ntlmssp_state);
1358 if (spnego.negTokenTarg.negResult == SPNEGO_ACCEPT_COMPLETED) {
1359 x_fprintf(x_stdout, "AF\n");
1360 ntlmssp_end(&client_ntlmssp_state);
1364 status = ntlmssp_update(client_ntlmssp_state,
1365 spnego.negTokenTarg.responseToken,
1368 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1369 DEBUG(1, ("Expected MORE_PROCESSING_REQUIRED from "
1370 "ntlmssp_client_update, got: %s\n",
1371 nt_errstr(status)));
1372 x_fprintf(x_stdout, "BH\n");
1373 data_blob_free(&request);
1374 ntlmssp_end(&client_ntlmssp_state);
1378 spnego.type = SPNEGO_NEG_TOKEN_TARG;
1379 spnego.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
1380 spnego.negTokenTarg.supportedMech = (char *)OID_NTLMSSP;
1381 spnego.negTokenTarg.responseToken = request;
1382 spnego.negTokenTarg.mechListMIC = null_blob;
1384 write_spnego_data(&to_server, &spnego);
1385 data_blob_free(&request);
1387 to_server_base64 = base64_encode_data_blob(to_server);
1388 data_blob_free(&to_server);
1389 x_fprintf(x_stdout, "KK %s\n", to_server_base64);
1390 SAFE_FREE(to_server_base64);
1396 static bool manage_client_krb5_init(SPNEGO_DATA spnego)
1399 DATA_BLOB tkt, to_server;
1400 DATA_BLOB session_key_krb5 = data_blob_null;
1405 const char *my_mechs[] = {OID_KERBEROS5_OLD, NULL};
1408 if ( (spnego.negTokenInit.mechListMIC.data == NULL) ||
1409 (spnego.negTokenInit.mechListMIC.length == 0) ) {
1410 DEBUG(1, ("Did not get a principal for krb5\n"));
1414 principal = (char *)SMB_MALLOC(
1415 spnego.negTokenInit.mechListMIC.length+1);
1417 if (principal == NULL) {
1418 DEBUG(1, ("Could not malloc principal\n"));
1422 memcpy(principal, spnego.negTokenInit.mechListMIC.data,
1423 spnego.negTokenInit.mechListMIC.length);
1424 principal[spnego.negTokenInit.mechListMIC.length] = '\0';
1426 retval = cli_krb5_get_ticket(principal, 0, &tkt, &session_key_krb5, 0, NULL, NULL);
1432 /* Let's try to first get the TGT, for that we need a
1435 if (opt_password == NULL) {
1436 DEBUG(10, ("Requesting password\n"));
1437 x_fprintf(x_stdout, "PW\n");
1441 pstr_sprintf(user, "%s@%s", opt_username, opt_domain);
1443 if ((retval = kerberos_kinit_password(user, opt_password, 0, NULL))) {
1444 DEBUG(10, ("Requesting TGT failed: %s\n", error_message(retval)));
1448 retval = cli_krb5_get_ticket(principal, 0, &tkt, &session_key_krb5, 0, NULL, NULL);
1451 DEBUG(10, ("Kinit suceeded, but getting a ticket failed: %s\n", error_message(retval)));
1456 data_blob_free(&session_key_krb5);
1460 reply.type = SPNEGO_NEG_TOKEN_INIT;
1461 reply.negTokenInit.mechTypes = my_mechs;
1462 reply.negTokenInit.reqFlags = 0;
1463 reply.negTokenInit.mechToken = tkt;
1464 reply.negTokenInit.mechListMIC = data_blob_null;
1466 len = write_spnego_data(&to_server, &reply);
1467 data_blob_free(&tkt);
1470 DEBUG(1, ("Could not write SPNEGO data blob\n"));
1474 reply_base64 = base64_encode_data_blob(to_server);
1475 x_fprintf(x_stdout, "KK %s *\n", reply_base64);
1477 SAFE_FREE(reply_base64);
1478 data_blob_free(&to_server);
1479 DEBUG(10, ("sent GSS-SPNEGO KERBEROS5 negTokenInit\n"));
1483 static void manage_client_krb5_targ(SPNEGO_DATA spnego)
1485 switch (spnego.negTokenTarg.negResult) {
1486 case SPNEGO_ACCEPT_INCOMPLETE:
1487 DEBUG(1, ("Got a Kerberos negTokenTarg with ACCEPT_INCOMPLETE\n"));
1488 x_fprintf(x_stdout, "BH\n");
1490 case SPNEGO_ACCEPT_COMPLETED:
1491 DEBUG(10, ("Accept completed\n"));
1492 x_fprintf(x_stdout, "AF\n");
1495 DEBUG(10, ("Rejected\n"));
1496 x_fprintf(x_stdout, "NA\n");
1499 DEBUG(1, ("Got an invalid negTokenTarg\n"));
1500 x_fprintf(x_stdout, "AF\n");
1506 static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode,
1507 char *buf, int length)
1513 if (!opt_username || !*opt_username) {
1514 x_fprintf(x_stderr, "username must be specified!\n\n");
1518 if (strlen(buf) <= 3) {
1519 DEBUG(1, ("SPNEGO query [%s] too short\n", buf));
1520 x_fprintf(x_stdout, "BH\n");
1524 request = base64_decode_data_blob(buf+3);
1526 if (strncmp(buf, "PW ", 3) == 0) {
1528 /* We asked for a password and obviously got it :-) */
1530 opt_password = SMB_STRNDUP((const char *)request.data, request.length);
1532 if (opt_password == NULL) {
1533 DEBUG(1, ("Out of memory\n"));
1534 x_fprintf(x_stdout, "BH\n");
1535 data_blob_free(&request);
1539 x_fprintf(x_stdout, "OK\n");
1540 data_blob_free(&request);
1544 if ( (strncmp(buf, "TT ", 3) != 0) &&
1545 (strncmp(buf, "AF ", 3) != 0) &&
1546 (strncmp(buf, "NA ", 3) != 0) ) {
1547 DEBUG(1, ("SPNEGO request [%s] invalid\n", buf));
1548 x_fprintf(x_stdout, "BH\n");
1549 data_blob_free(&request);
1553 /* So we got a server challenge to generate a SPNEGO
1554 client-to-server request... */
1556 len = read_spnego_data(request, &spnego);
1557 data_blob_free(&request);
1560 DEBUG(1, ("Could not read SPNEGO data for [%s]\n", buf));
1561 x_fprintf(x_stdout, "BH\n");
1565 if (spnego.type == SPNEGO_NEG_TOKEN_INIT) {
1567 /* The server offers a list of mechanisms */
1569 const char **mechType = (const char **)spnego.negTokenInit.mechTypes;
1571 while (*mechType != NULL) {
1574 if ( (strcmp(*mechType, OID_KERBEROS5_OLD) == 0) ||
1575 (strcmp(*mechType, OID_KERBEROS5) == 0) ) {
1576 if (manage_client_krb5_init(spnego))
1581 if (strcmp(*mechType, OID_NTLMSSP) == 0) {
1582 if (manage_client_ntlmssp_init(spnego))
1589 DEBUG(1, ("Server offered no compatible mechanism\n"));
1590 x_fprintf(x_stdout, "BH\n");
1594 if (spnego.type == SPNEGO_NEG_TOKEN_TARG) {
1596 if (spnego.negTokenTarg.supportedMech == NULL) {
1597 /* On accept/reject Windows does not send the
1598 mechanism anymore. Handle that here and
1599 shut down the mechanisms. */
1601 switch (spnego.negTokenTarg.negResult) {
1602 case SPNEGO_ACCEPT_COMPLETED:
1603 x_fprintf(x_stdout, "AF\n");
1606 x_fprintf(x_stdout, "NA\n");
1609 DEBUG(1, ("Got a negTokenTarg with no mech and an "
1610 "unknown negResult: %d\n",
1611 spnego.negTokenTarg.negResult));
1612 x_fprintf(x_stdout, "BH\n");
1615 ntlmssp_end(&client_ntlmssp_state);
1619 if (strcmp(spnego.negTokenTarg.supportedMech,
1620 OID_NTLMSSP) == 0) {
1621 manage_client_ntlmssp_targ(spnego);
1626 if (strcmp(spnego.negTokenTarg.supportedMech,
1627 OID_KERBEROS5_OLD) == 0) {
1628 manage_client_krb5_targ(spnego);
1635 DEBUG(1, ("Got an SPNEGO token I could not handle [%s]!\n", buf));
1636 x_fprintf(x_stdout, "BH\n");
1640 free_spnego_data(&spnego);
1644 static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode,
1645 char *buf, int length)
1647 char *request, *parameter;
1648 static DATA_BLOB challenge;
1649 static DATA_BLOB lm_response;
1650 static DATA_BLOB nt_response;
1651 static char *full_username;
1652 static char *username;
1653 static char *domain;
1654 static char *plaintext_password;
1655 static bool ntlm_server_1_user_session_key;
1656 static bool ntlm_server_1_lm_session_key;
1658 if (strequal(buf, ".")) {
1659 if (!full_username && !username) {
1660 x_fprintf(x_stdout, "Error: No username supplied!\n");
1661 } else if (plaintext_password) {
1662 /* handle this request as plaintext */
1663 if (!full_username) {
1664 if (asprintf(&full_username, "%s%c%s", domain, winbind_separator(), username) == -1) {
1665 x_fprintf(x_stdout, "Error: Out of memory in asprintf!\n.\n");
1669 if (check_plaintext_auth(full_username, plaintext_password, False)) {
1670 x_fprintf(x_stdout, "Authenticated: Yes\n");
1672 x_fprintf(x_stdout, "Authenticated: No\n");
1674 } else if (!lm_response.data && !nt_response.data) {
1675 x_fprintf(x_stdout, "Error: No password supplied!\n");
1676 } else if (!challenge.data) {
1677 x_fprintf(x_stdout, "Error: No lanman-challenge supplied!\n");
1679 char *error_string = NULL;
1681 uchar user_session_key[16];
1684 if (full_username && !username) {
1686 fstring fstr_domain;
1688 if (!parse_ntlm_auth_domain_user(full_username, fstr_user, fstr_domain)) {
1689 /* username might be 'tainted', don't print into our new-line deleimianted stream */
1690 x_fprintf(x_stdout, "Error: Could not parse into domain and username\n");
1692 SAFE_FREE(username);
1694 username = smb_xstrdup(fstr_user);
1695 domain = smb_xstrdup(fstr_domain);
1699 domain = smb_xstrdup(get_winbind_domain());
1702 if (ntlm_server_1_lm_session_key)
1703 flags |= WBFLAG_PAM_LMKEY;
1705 if (ntlm_server_1_user_session_key)
1706 flags |= WBFLAG_PAM_USER_SESSION_KEY;
1708 if (!NT_STATUS_IS_OK(
1709 contact_winbind_auth_crap(username,
1721 x_fprintf(x_stdout, "Authenticated: No\n");
1722 x_fprintf(x_stdout, "Authentication-Error: %s\n.\n", error_string);
1723 SAFE_FREE(error_string);
1725 static char zeros[16];
1727 char *hex_user_session_key;
1729 x_fprintf(x_stdout, "Authenticated: Yes\n");
1731 if (ntlm_server_1_lm_session_key
1732 && (memcmp(zeros, lm_key,
1733 sizeof(lm_key)) != 0)) {
1734 hex_lm_key = hex_encode(NULL,
1735 (const unsigned char *)lm_key,
1737 x_fprintf(x_stdout, "LANMAN-Session-Key: %s\n", hex_lm_key);
1738 TALLOC_FREE(hex_lm_key);
1741 if (ntlm_server_1_user_session_key
1742 && (memcmp(zeros, user_session_key,
1743 sizeof(user_session_key)) != 0)) {
1744 hex_user_session_key = hex_encode(NULL,
1745 (const unsigned char *)user_session_key,
1746 sizeof(user_session_key));
1747 x_fprintf(x_stdout, "User-Session-Key: %s\n", hex_user_session_key);
1748 TALLOC_FREE(hex_user_session_key);
1752 /* clear out the state */
1753 challenge = data_blob_null;
1754 nt_response = data_blob_null;
1755 lm_response = data_blob_null;
1756 SAFE_FREE(full_username);
1757 SAFE_FREE(username);
1759 SAFE_FREE(plaintext_password);
1760 ntlm_server_1_user_session_key = False;
1761 ntlm_server_1_lm_session_key = False;
1762 x_fprintf(x_stdout, ".\n");
1769 /* Indicates a base64 encoded structure */
1770 parameter = strstr_m(request, ":: ");
1772 parameter = strstr_m(request, ": ");
1775 DEBUG(0, ("Parameter not found!\n"));
1776 x_fprintf(x_stdout, "Error: Parameter not found!\n.\n");
1793 base64_decode_inplace(parameter);
1796 if (strequal(request, "LANMAN-Challenge")) {
1797 challenge = strhex_to_data_blob(NULL, parameter);
1798 if (challenge.length != 8) {
1799 x_fprintf(x_stdout, "Error: hex decode of %s failed! (got %d bytes, expected 8)\n.\n",
1801 (int)challenge.length);
1802 challenge = data_blob_null;
1804 } else if (strequal(request, "NT-Response")) {
1805 nt_response = strhex_to_data_blob(NULL, parameter);
1806 if (nt_response.length < 24) {
1807 x_fprintf(x_stdout, "Error: hex decode of %s failed! (only got %d bytes, needed at least 24)\n.\n",
1809 (int)nt_response.length);
1810 nt_response = data_blob_null;
1812 } else if (strequal(request, "LANMAN-Response")) {
1813 lm_response = strhex_to_data_blob(NULL, parameter);
1814 if (lm_response.length != 24) {
1815 x_fprintf(x_stdout, "Error: hex decode of %s failed! (got %d bytes, expected 24)\n.\n",
1817 (int)lm_response.length);
1818 lm_response = data_blob_null;
1820 } else if (strequal(request, "Password")) {
1821 plaintext_password = smb_xstrdup(parameter);
1822 } else if (strequal(request, "NT-Domain")) {
1823 domain = smb_xstrdup(parameter);
1824 } else if (strequal(request, "Username")) {
1825 username = smb_xstrdup(parameter);
1826 } else if (strequal(request, "Full-Username")) {
1827 full_username = smb_xstrdup(parameter);
1828 } else if (strequal(request, "Request-User-Session-Key")) {
1829 ntlm_server_1_user_session_key = strequal(parameter, "Yes");
1830 } else if (strequal(request, "Request-LanMan-Session-Key")) {
1831 ntlm_server_1_lm_session_key = strequal(parameter, "Yes");
1833 x_fprintf(x_stdout, "Error: Unknown request %s\n.\n", request);
1837 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode helper_mode, char *buf, int length)
1839 char *request, *parameter;
1840 static DATA_BLOB new_nt_pswd;
1841 static DATA_BLOB old_nt_hash_enc;
1842 static DATA_BLOB new_lm_pswd;
1843 static DATA_BLOB old_lm_hash_enc;
1844 static char *full_username = NULL;
1845 static char *username = NULL;
1846 static char *domain = NULL;
1847 static char *newpswd = NULL;
1848 static char *oldpswd = NULL;
1850 if (strequal(buf, ".")) {
1851 if(newpswd && oldpswd) {
1852 uchar old_nt_hash[16];
1853 uchar old_lm_hash[16];
1854 uchar new_nt_hash[16];
1855 uchar new_lm_hash[16];
1857 new_nt_pswd = data_blob(NULL, 516);
1858 old_nt_hash_enc = data_blob(NULL, 16);
1860 /* Calculate the MD4 hash (NT compatible) of the
1862 E_md4hash(oldpswd, old_nt_hash);
1863 E_md4hash(newpswd, new_nt_hash);
1865 /* E_deshash returns false for 'long'
1866 passwords (> 14 DOS chars).
1868 Therefore, don't send a buffer
1869 encrypted with the truncated hash
1870 (it could allow an even easier
1871 attack on the password)
1873 Likewise, obey the admin's restriction
1876 if (lp_client_lanman_auth() &&
1877 E_deshash(newpswd, new_lm_hash) &&
1878 E_deshash(oldpswd, old_lm_hash)) {
1879 new_lm_pswd = data_blob(NULL, 516);
1880 old_lm_hash_enc = data_blob(NULL, 16);
1881 encode_pw_buffer(new_lm_pswd.data, newpswd,
1884 SamOEMhash(new_lm_pswd.data, old_nt_hash, 516);
1885 E_old_pw_hash(new_nt_hash, old_lm_hash,
1886 old_lm_hash_enc.data);
1888 new_lm_pswd.data = NULL;
1889 new_lm_pswd.length = 0;
1890 old_lm_hash_enc.data = NULL;
1891 old_lm_hash_enc.length = 0;
1894 encode_pw_buffer(new_nt_pswd.data, newpswd,
1897 SamOEMhash(new_nt_pswd.data, old_nt_hash, 516);
1898 E_old_pw_hash(new_nt_hash, old_nt_hash,
1899 old_nt_hash_enc.data);
1902 if (!full_username && !username) {
1903 x_fprintf(x_stdout, "Error: No username supplied!\n");
1904 } else if ((!new_nt_pswd.data || !old_nt_hash_enc.data) &&
1905 (!new_lm_pswd.data || old_lm_hash_enc.data) ) {
1906 x_fprintf(x_stdout, "Error: No NT or LM password "
1907 "blobs supplied!\n");
1909 char *error_string = NULL;
1911 if (full_username && !username) {
1913 fstring fstr_domain;
1915 if (!parse_ntlm_auth_domain_user(full_username,
1918 /* username might be 'tainted', don't
1919 * print into our new-line
1920 * deleimianted stream */
1921 x_fprintf(x_stdout, "Error: Could not "
1922 "parse into domain and "
1924 SAFE_FREE(username);
1925 username = smb_xstrdup(full_username);
1927 SAFE_FREE(username);
1929 username = smb_xstrdup(fstr_user);
1930 domain = smb_xstrdup(fstr_domain);
1935 if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
1942 x_fprintf(x_stdout, "Password-Change: No\n");
1943 x_fprintf(x_stdout, "Password-Change-Error: "
1944 "%s\n.\n", error_string);
1946 x_fprintf(x_stdout, "Password-Change: Yes\n");
1949 SAFE_FREE(error_string);
1951 /* clear out the state */
1952 new_nt_pswd = data_blob_null;
1953 old_nt_hash_enc = data_blob_null;
1954 new_lm_pswd = data_blob_null;
1955 old_nt_hash_enc = data_blob_null;
1956 SAFE_FREE(full_username);
1957 SAFE_FREE(username);
1961 x_fprintf(x_stdout, ".\n");
1968 /* Indicates a base64 encoded structure */
1969 parameter = strstr_m(request, ":: ");
1971 parameter = strstr_m(request, ": ");
1974 DEBUG(0, ("Parameter not found!\n"));
1975 x_fprintf(x_stdout, "Error: Parameter not found!\n.\n");
1991 base64_decode_inplace(parameter);
1994 if (strequal(request, "new-nt-password-blob")) {
1995 new_nt_pswd = strhex_to_data_blob(NULL, parameter);
1996 if (new_nt_pswd.length != 516) {
1997 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
1998 "(got %d bytes, expected 516)\n.\n",
2000 (int)new_nt_pswd.length);
2001 new_nt_pswd = data_blob_null;
2003 } else if (strequal(request, "old-nt-hash-blob")) {
2004 old_nt_hash_enc = strhex_to_data_blob(NULL, parameter);
2005 if (old_nt_hash_enc.length != 16) {
2006 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2007 "(got %d bytes, expected 16)\n.\n",
2009 (int)old_nt_hash_enc.length);
2010 old_nt_hash_enc = data_blob_null;
2012 } else if (strequal(request, "new-lm-password-blob")) {
2013 new_lm_pswd = strhex_to_data_blob(NULL, parameter);
2014 if (new_lm_pswd.length != 516) {
2015 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2016 "(got %d bytes, expected 516)\n.\n",
2018 (int)new_lm_pswd.length);
2019 new_lm_pswd = data_blob_null;
2022 else if (strequal(request, "old-lm-hash-blob")) {
2023 old_lm_hash_enc = strhex_to_data_blob(NULL, parameter);
2024 if (old_lm_hash_enc.length != 16)
2026 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2027 "(got %d bytes, expected 16)\n.\n",
2029 (int)old_lm_hash_enc.length);
2030 old_lm_hash_enc = data_blob_null;
2032 } else if (strequal(request, "nt-domain")) {
2033 domain = smb_xstrdup(parameter);
2034 } else if(strequal(request, "username")) {
2035 username = smb_xstrdup(parameter);
2036 } else if(strequal(request, "full-username")) {
2037 username = smb_xstrdup(parameter);
2038 } else if(strequal(request, "new-password")) {
2039 newpswd = smb_xstrdup(parameter);
2040 } else if (strequal(request, "old-password")) {
2041 oldpswd = smb_xstrdup(parameter);
2043 x_fprintf(x_stdout, "Error: Unknown request %s\n.\n", request);
2047 static void manage_squid_request(enum stdio_helper_mode helper_mode, stdio_helper_function fn)
2049 char buf[SQUID_BUFFER_SIZE+1];
2054 /* this is not a typo - x_fgets doesn't work too well under squid */
2055 if (fgets(buf, sizeof(buf)-1, stdin) == NULL) {
2056 if (ferror(stdin)) {
2057 DEBUG(1, ("fgets() failed! dying..... errno=%d (%s)\n", ferror(stdin),
2058 strerror(ferror(stdin))));
2060 exit(1); /* BIIG buffer */
2065 c=(char *)memchr(buf,'\n',sizeof(buf)-1);
2074 DEBUG(2, ("Oversized message\n"));
2075 x_fprintf(x_stderr, "ERR\n");
2080 DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf,length));
2082 if (buf[0] == '\0') {
2083 DEBUG(2, ("Invalid Request\n"));
2084 x_fprintf(x_stderr, "ERR\n");
2088 fn(helper_mode, buf, length);
2092 static void squid_stream(enum stdio_helper_mode stdio_mode, stdio_helper_function fn) {
2093 /* initialize FDescs */
2094 x_setbuf(x_stdout, NULL);
2095 x_setbuf(x_stderr, NULL);
2097 manage_squid_request(stdio_mode, fn);
2102 /* Authenticate a user with a challenge/response */
2104 static bool check_auth_crap(void)
2109 char user_session_key[16];
2111 char *hex_user_session_key;
2113 static uint8 zeros[16];
2115 x_setbuf(x_stdout, NULL);
2118 flags |= WBFLAG_PAM_LMKEY;
2120 if (request_user_session_key)
2121 flags |= WBFLAG_PAM_USER_SESSION_KEY;
2123 flags |= WBFLAG_PAM_NT_STATUS_SQUASH;
2125 nt_status = contact_winbind_auth_crap(opt_username, opt_domain,
2131 (unsigned char *)lm_key,
2132 (unsigned char *)user_session_key,
2133 &error_string, NULL);
2135 if (!NT_STATUS_IS_OK(nt_status)) {
2136 x_fprintf(x_stdout, "%s (0x%x)\n",
2138 NT_STATUS_V(nt_status));
2139 SAFE_FREE(error_string);
2144 && (memcmp(zeros, lm_key,
2145 sizeof(lm_key)) != 0)) {
2146 hex_lm_key = hex_encode(NULL, (const unsigned char *)lm_key,
2148 x_fprintf(x_stdout, "LM_KEY: %s\n", hex_lm_key);
2149 TALLOC_FREE(hex_lm_key);
2151 if (request_user_session_key
2152 && (memcmp(zeros, user_session_key,
2153 sizeof(user_session_key)) != 0)) {
2154 hex_user_session_key = hex_encode(NULL, (const unsigned char *)user_session_key,
2155 sizeof(user_session_key));
2156 x_fprintf(x_stdout, "NT_KEY: %s\n", hex_user_session_key);
2157 TALLOC_FREE(hex_user_session_key);
2166 OPT_USERNAME = 1000,
2175 OPT_USER_SESSION_KEY,
2177 OPT_REQUIRE_MEMBERSHIP,
2178 OPT_USE_CACHED_CREDS
2181 int main(int argc, const char **argv)
2184 static const char *helper_protocol;
2185 static int diagnostics;
2187 static const char *hex_challenge;
2188 static const char *hex_lm_response;
2189 static const char *hex_nt_response;
2193 /* NOTE: DO NOT change this interface without considering the implications!
2194 This is an external interface, which other programs will use to interact
2198 /* We do not use single-letter command abbreviations, because they harm future
2199 interface stability. */
2201 struct poptOption long_options[] = {
2203 { "helper-protocol", 0, POPT_ARG_STRING, &helper_protocol, OPT_DOMAIN, "operate as a stdio-based helper", "helper protocol to use"},
2204 { "username", 0, POPT_ARG_STRING, &opt_username, OPT_USERNAME, "username"},
2205 { "domain", 0, POPT_ARG_STRING, &opt_domain, OPT_DOMAIN, "domain name"},
2206 { "workstation", 0, POPT_ARG_STRING, &opt_workstation, OPT_WORKSTATION, "workstation"},
2207 { "challenge", 0, POPT_ARG_STRING, &hex_challenge, OPT_CHALLENGE, "challenge (HEX encoded)"},
2208 { "lm-response", 0, POPT_ARG_STRING, &hex_lm_response, OPT_LM, "LM Response to the challenge (HEX encoded)"},
2209 { "nt-response", 0, POPT_ARG_STRING, &hex_nt_response, OPT_NT, "NT or NTLMv2 Response to the challenge (HEX encoded)"},
2210 { "password", 0, POPT_ARG_STRING, &opt_password, OPT_PASSWORD, "User's plaintext password"},
2211 { "request-lm-key", 0, POPT_ARG_NONE, &request_lm_key, OPT_LM_KEY, "Retrieve LM session key"},
2212 { "request-nt-key", 0, POPT_ARG_NONE, &request_user_session_key, OPT_USER_SESSION_KEY, "Retrieve User (NT) session key"},
2213 { "use-cached-creds", 0, POPT_ARG_NONE, &use_cached_creds, OPT_USE_CACHED_CREDS, "Use cached credentials if no password is given"},
2214 { "diagnostics", 0, POPT_ARG_NONE, &diagnostics, OPT_DIAGNOSTICS, "Perform diagnostics on the authentictaion chain"},
2215 { "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" },
2220 /* Samba client initialisation */
2225 /* Samba client initialisation */
2227 if (!lp_load(dyn_CONFIGFILE, True, False, False, True)) {
2228 d_fprintf(stderr, "ntlm_auth: error opening config file %s. Error was %s\n",
2229 dyn_CONFIGFILE, strerror(errno));
2235 pc = poptGetContext("ntlm_auth", argc, argv, long_options, 0);
2237 /* Parse command line options */
2240 poptPrintHelp(pc, stderr, 0);
2244 pc = poptGetContext(NULL, argc, (const char **)argv, long_options,
2245 POPT_CONTEXT_KEEP_FIRST);
2247 while((opt = poptGetNextOpt(pc)) != -1) {
2250 opt_challenge = strhex_to_data_blob(NULL, hex_challenge);
2251 if (opt_challenge.length != 8) {
2252 x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n",
2254 (int)opt_challenge.length);
2259 opt_lm_response = strhex_to_data_blob(NULL, hex_lm_response);
2260 if (opt_lm_response.length != 24) {
2261 x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n",
2263 (int)opt_lm_response.length);
2269 opt_nt_response = strhex_to_data_blob(NULL, hex_nt_response);
2270 if (opt_nt_response.length < 24) {
2271 x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n",
2273 (int)opt_nt_response.length);
2278 case OPT_REQUIRE_MEMBERSHIP:
2279 if (StrnCaseCmp("S-", require_membership_of, 2) == 0) {
2280 require_membership_of_sid = require_membership_of;
2287 char *domain = SMB_STRDUP(opt_username);
2288 char *p = strchr_m(domain, *lp_winbind_separator());
2292 if (opt_domain && !strequal(opt_domain, domain)) {
2293 x_fprintf(x_stderr, "Domain specified in username (%s) "
2294 "doesn't match specified domain (%s)!\n\n",
2295 domain, opt_domain);
2296 poptPrintHelp(pc, stderr, 0);
2299 opt_domain = domain;
2305 /* Note: if opt_domain is "" then send no domain */
2306 if (opt_domain == NULL) {
2307 opt_domain = get_winbind_domain();
2310 if (opt_workstation == NULL) {
2311 opt_workstation = "";
2314 if (helper_protocol) {
2316 for (i=0; i<NUM_HELPER_MODES; i++) {
2317 if (strcmp(helper_protocol, stdio_helper_protocols[i].name) == 0) {
2318 squid_stream(stdio_helper_protocols[i].mode, stdio_helper_protocols[i].fn);
2322 x_fprintf(x_stderr, "unknown helper protocol [%s]\n\nValid helper protools:\n\n", helper_protocol);
2324 for (i=0; i<NUM_HELPER_MODES; i++) {
2325 x_fprintf(x_stderr, "%s\n", stdio_helper_protocols[i].name);
2331 if (!opt_username || !*opt_username) {
2332 x_fprintf(x_stderr, "username must be specified!\n\n");
2333 poptPrintHelp(pc, stderr, 0);
2337 if (opt_challenge.length) {
2338 if (!check_auth_crap()) {
2344 if (!opt_password) {
2345 opt_password = getpass("password: ");
2349 if (!diagnose_ntlm_auth()) {
2355 fstr_sprintf(user, "%s%c%s", opt_domain, winbind_separator(), opt_username);
2356 if (!check_plaintext_auth(user, opt_password, True)) {
2363 poptFreeContext(pc);