s3-utils/net_rpc_printer.c: print more info on write error
[Samba/gebeck_regimport.git] / source3 / utils / ntlm_auth.c
blobba11ec736852d9a9eb4b1c854bbd4844083326a1
1 /*
2 Unix SMB/CIFS implementation.
4 Winbind status program.
6 Copyright (C) Tim Potter 2000-2003
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003-2004
8 Copyright (C) Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it> 2000
9 Copyright (C) Robert O'Callahan 2006 (added cached credential code).
10 Copyright (C) Kai Blin <kai@samba.org> 2008
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 3 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include "includes.h"
27 #include "popt_common.h"
28 #include "utils/ntlm_auth.h"
29 #include "../libcli/auth/libcli_auth.h"
30 #include "../libcli/auth/spnego.h"
31 #include "../libcli/auth/ntlmssp.h"
32 #include "smb_krb5.h"
33 #include <iniparser.h>
34 #include "../lib/crypto/arcfour.h"
35 #include "libads/kerberos_proto.h"
36 #include "nsswitch/winbind_client.h"
37 #include "librpc/gen_ndr/krb5pac.h"
38 #include "../lib/util/asn1.h"
40 #ifndef PAM_WINBIND_CONFIG_FILE
41 #define PAM_WINBIND_CONFIG_FILE "/etc/security/pam_winbind.conf"
42 #endif
44 #define WINBIND_KRB5_AUTH 0x00000080
46 #undef DBGC_CLASS
47 #define DBGC_CLASS DBGC_WINBIND
49 #define INITIAL_BUFFER_SIZE 300
50 #define MAX_BUFFER_SIZE 630000
52 enum stdio_helper_mode {
53 SQUID_2_4_BASIC,
54 SQUID_2_5_BASIC,
55 SQUID_2_5_NTLMSSP,
56 NTLMSSP_CLIENT_1,
57 GSS_SPNEGO,
58 GSS_SPNEGO_CLIENT,
59 NTLM_SERVER_1,
60 NTLM_CHANGE_PASSWORD_1,
61 NUM_HELPER_MODES
64 enum ntlm_auth_cli_state {
65 CLIENT_INITIAL = 0,
66 CLIENT_RESPONSE,
67 CLIENT_FINISHED,
68 CLIENT_ERROR
71 enum ntlm_auth_svr_state {
72 SERVER_INITIAL = 0,
73 SERVER_CHALLENGE,
74 SERVER_FINISHED,
75 SERVER_ERROR
78 struct ntlm_auth_state {
79 TALLOC_CTX *mem_ctx;
80 enum stdio_helper_mode helper_mode;
81 enum ntlm_auth_cli_state cli_state;
82 enum ntlm_auth_svr_state svr_state;
83 struct ntlmssp_state *ntlmssp_state;
84 uint32_t neg_flags;
85 char *want_feature_list;
86 char *spnego_mech;
87 char *spnego_mech_oid;
88 bool have_session_key;
89 DATA_BLOB session_key;
90 DATA_BLOB initial_message;
93 typedef void (*stdio_helper_function)(struct ntlm_auth_state *state, char *buf,
94 int length);
96 static void manage_squid_basic_request (struct ntlm_auth_state *state,
97 char *buf, int length);
99 static void manage_squid_ntlmssp_request (struct ntlm_auth_state *state,
100 char *buf, int length);
102 static void manage_client_ntlmssp_request (struct ntlm_auth_state *state,
103 char *buf, int length);
105 static void manage_gss_spnego_request (struct ntlm_auth_state *state,
106 char *buf, int length);
108 static void manage_gss_spnego_client_request (struct ntlm_auth_state *state,
109 char *buf, int length);
111 static void manage_ntlm_server_1_request (struct ntlm_auth_state *state,
112 char *buf, int length);
114 static void manage_ntlm_change_password_1_request(struct ntlm_auth_state *state,
115 char *buf, int length);
117 static const struct {
118 enum stdio_helper_mode mode;
119 const char *name;
120 stdio_helper_function fn;
121 } stdio_helper_protocols[] = {
122 { SQUID_2_4_BASIC, "squid-2.4-basic", manage_squid_basic_request},
123 { SQUID_2_5_BASIC, "squid-2.5-basic", manage_squid_basic_request},
124 { SQUID_2_5_NTLMSSP, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request},
125 { NTLMSSP_CLIENT_1, "ntlmssp-client-1", manage_client_ntlmssp_request},
126 { GSS_SPNEGO, "gss-spnego", manage_gss_spnego_request},
127 { GSS_SPNEGO_CLIENT, "gss-spnego-client", manage_gss_spnego_client_request},
128 { NTLM_SERVER_1, "ntlm-server-1", manage_ntlm_server_1_request},
129 { NTLM_CHANGE_PASSWORD_1, "ntlm-change-password-1", manage_ntlm_change_password_1_request},
130 { NUM_HELPER_MODES, NULL, NULL}
133 const char *opt_username;
134 const char *opt_domain;
135 const char *opt_workstation;
136 const char *opt_password;
137 static DATA_BLOB opt_challenge;
138 static DATA_BLOB opt_lm_response;
139 static DATA_BLOB opt_nt_response;
140 static int request_lm_key;
141 static int request_user_session_key;
142 static int use_cached_creds;
144 static const char *require_membership_of;
145 static const char *require_membership_of_sid;
146 static const char *opt_pam_winbind_conf;
148 static char winbind_separator(void)
150 struct winbindd_response response;
151 static bool got_sep;
152 static char sep;
154 if (got_sep)
155 return sep;
157 ZERO_STRUCT(response);
159 /* Send off request */
161 if (winbindd_request_response(WINBINDD_INFO, NULL, &response) !=
162 NSS_STATUS_SUCCESS) {
163 d_printf("could not obtain winbind separator!\n");
164 return *lp_winbind_separator();
167 sep = response.data.info.winbind_separator;
168 got_sep = True;
170 if (!sep) {
171 d_printf("winbind separator was NULL!\n");
172 return *lp_winbind_separator();
175 return sep;
178 const char *get_winbind_domain(void)
180 struct winbindd_response response;
182 static fstring winbind_domain;
183 if (*winbind_domain) {
184 return winbind_domain;
187 ZERO_STRUCT(response);
189 /* Send off request */
191 if (winbindd_request_response(WINBINDD_DOMAIN_NAME, NULL, &response) !=
192 NSS_STATUS_SUCCESS) {
193 DEBUG(0, ("could not obtain winbind domain name!\n"));
194 return lp_workgroup();
197 fstrcpy(winbind_domain, response.data.domain_name);
199 return winbind_domain;
203 const char *get_winbind_netbios_name(void)
205 struct winbindd_response response;
207 static fstring winbind_netbios_name;
209 if (*winbind_netbios_name) {
210 return winbind_netbios_name;
213 ZERO_STRUCT(response);
215 /* Send off request */
217 if (winbindd_request_response(WINBINDD_NETBIOS_NAME, NULL, &response) !=
218 NSS_STATUS_SUCCESS) {
219 DEBUG(0, ("could not obtain winbind netbios name!\n"));
220 return lp_netbios_name();
223 fstrcpy(winbind_netbios_name, response.data.netbios_name);
225 return winbind_netbios_name;
229 DATA_BLOB get_challenge(void)
231 static DATA_BLOB chal;
232 if (opt_challenge.length)
233 return opt_challenge;
235 chal = data_blob(NULL, 8);
237 generate_random_buffer(chal.data, chal.length);
238 return chal;
241 /* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
242 form DOMAIN/user into a domain and a user */
244 static bool parse_ntlm_auth_domain_user(const char *domuser, fstring domain,
245 fstring user)
248 char *p = strchr(domuser,winbind_separator());
250 if (!p) {
251 return False;
254 fstrcpy(user, p+1);
255 fstrcpy(domain, domuser);
256 domain[PTR_DIFF(p, domuser)] = 0;
257 strupper_m(domain);
259 return True;
262 static bool get_require_membership_sid(void) {
263 struct winbindd_request request;
264 struct winbindd_response response;
266 if (!require_membership_of) {
267 return True;
270 if (require_membership_of_sid) {
271 return True;
274 /* Otherwise, ask winbindd for the name->sid request */
276 ZERO_STRUCT(request);
277 ZERO_STRUCT(response);
279 if (!parse_ntlm_auth_domain_user(require_membership_of,
280 request.data.name.dom_name,
281 request.data.name.name)) {
282 DEBUG(0, ("Could not parse %s into seperate domain/name parts!\n",
283 require_membership_of));
284 return False;
287 if (winbindd_request_response(WINBINDD_LOOKUPNAME, &request, &response) !=
288 NSS_STATUS_SUCCESS) {
289 DEBUG(0, ("Winbindd lookupname failed to resolve %s into a SID!\n",
290 require_membership_of));
291 return False;
294 require_membership_of_sid = SMB_STRDUP(response.data.sid.sid);
296 if (require_membership_of_sid)
297 return True;
299 return False;
303 * Get some configuration from pam_winbind.conf to see if we
304 * need to contact trusted domain
307 int get_pam_winbind_config()
309 int ctrl = 0;
310 dictionary *d = NULL;
312 if (!opt_pam_winbind_conf || !*opt_pam_winbind_conf) {
313 opt_pam_winbind_conf = PAM_WINBIND_CONFIG_FILE;
316 d = iniparser_load(discard_const_p(char, opt_pam_winbind_conf));
318 if (!d) {
319 return 0;
322 if (iniparser_getboolean(d, discard_const_p(char, "global:krb5_auth"), false)) {
323 ctrl |= WINBIND_KRB5_AUTH;
326 iniparser_freedict(d);
328 return ctrl;
331 /* Authenticate a user with a plaintext password */
333 static bool check_plaintext_auth(const char *user, const char *pass,
334 bool stdout_diagnostics)
336 struct winbindd_request request;
337 struct winbindd_response response;
338 NSS_STATUS result;
340 if (!get_require_membership_sid()) {
341 return False;
344 /* Send off request */
346 ZERO_STRUCT(request);
347 ZERO_STRUCT(response);
349 fstrcpy(request.data.auth.user, user);
350 fstrcpy(request.data.auth.pass, pass);
351 if (require_membership_of_sid) {
352 strlcpy(request.data.auth.require_membership_of_sid,
353 require_membership_of_sid,
354 sizeof(request.data.auth.require_membership_of_sid));
357 result = winbindd_request_response(WINBINDD_PAM_AUTH, &request, &response);
359 /* Display response */
361 if (stdout_diagnostics) {
362 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
363 d_printf("Reading winbind reply failed! (0x01)\n");
366 d_printf("%s: %s (0x%x)\n",
367 response.data.auth.nt_status_string,
368 response.data.auth.error_string,
369 response.data.auth.nt_status);
370 } else {
371 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
372 DEBUG(1, ("Reading winbind reply failed! (0x01)\n"));
375 DEBUG(3, ("%s: %s (0x%x)\n",
376 response.data.auth.nt_status_string,
377 response.data.auth.error_string,
378 response.data.auth.nt_status));
381 return (result == NSS_STATUS_SUCCESS);
384 /* authenticate a user with an encrypted username/password */
386 NTSTATUS contact_winbind_auth_crap(const char *username,
387 const char *domain,
388 const char *workstation,
389 const DATA_BLOB *challenge,
390 const DATA_BLOB *lm_response,
391 const DATA_BLOB *nt_response,
392 uint32 flags,
393 uint8 lm_key[8],
394 uint8 user_session_key[16],
395 char **error_string,
396 char **unix_name)
398 NTSTATUS nt_status;
399 NSS_STATUS result;
400 struct winbindd_request request;
401 struct winbindd_response response;
403 if (!get_require_membership_sid()) {
404 return NT_STATUS_INVALID_PARAMETER;
407 ZERO_STRUCT(request);
408 ZERO_STRUCT(response);
410 request.flags = flags;
412 request.data.auth_crap.logon_parameters = MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT | MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT;
414 if (require_membership_of_sid)
415 fstrcpy(request.data.auth_crap.require_membership_of_sid, require_membership_of_sid);
417 fstrcpy(request.data.auth_crap.user, username);
418 fstrcpy(request.data.auth_crap.domain, domain);
420 fstrcpy(request.data.auth_crap.workstation,
421 workstation);
423 memcpy(request.data.auth_crap.chal, challenge->data, MIN(challenge->length, 8));
425 if (lm_response && lm_response->length) {
426 memcpy(request.data.auth_crap.lm_resp,
427 lm_response->data,
428 MIN(lm_response->length, sizeof(request.data.auth_crap.lm_resp)));
429 request.data.auth_crap.lm_resp_len = lm_response->length;
432 if (nt_response && nt_response->length) {
433 if (nt_response->length > sizeof(request.data.auth_crap.nt_resp)) {
434 request.flags = request.flags | WBFLAG_BIG_NTLMV2_BLOB;
435 request.extra_len = nt_response->length;
436 request.extra_data.data = SMB_MALLOC_ARRAY(char, request.extra_len);
437 if (request.extra_data.data == NULL) {
438 return NT_STATUS_NO_MEMORY;
440 memcpy(request.extra_data.data, nt_response->data,
441 nt_response->length);
443 } else {
444 memcpy(request.data.auth_crap.nt_resp,
445 nt_response->data, nt_response->length);
447 request.data.auth_crap.nt_resp_len = nt_response->length;
450 result = winbindd_request_response(WINBINDD_PAM_AUTH_CRAP, &request, &response);
451 SAFE_FREE(request.extra_data.data);
453 /* Display response */
455 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
456 nt_status = NT_STATUS_UNSUCCESSFUL;
457 if (error_string)
458 *error_string = smb_xstrdup("Reading winbind reply failed!");
459 winbindd_free_response(&response);
460 return nt_status;
463 nt_status = (NT_STATUS(response.data.auth.nt_status));
464 if (!NT_STATUS_IS_OK(nt_status)) {
465 if (error_string)
466 *error_string = smb_xstrdup(response.data.auth.error_string);
467 winbindd_free_response(&response);
468 return nt_status;
471 if ((flags & WBFLAG_PAM_LMKEY) && lm_key) {
472 memcpy(lm_key, response.data.auth.first_8_lm_hash,
473 sizeof(response.data.auth.first_8_lm_hash));
475 if ((flags & WBFLAG_PAM_USER_SESSION_KEY) && user_session_key) {
476 memcpy(user_session_key, response.data.auth.user_session_key,
477 sizeof(response.data.auth.user_session_key));
480 if (flags & WBFLAG_PAM_UNIX_NAME) {
481 *unix_name = SMB_STRDUP(response.data.auth.unix_username);
482 if (!*unix_name) {
483 winbindd_free_response(&response);
484 return NT_STATUS_NO_MEMORY;
488 winbindd_free_response(&response);
489 return nt_status;
492 /* contact server to change user password using auth crap */
493 static NTSTATUS contact_winbind_change_pswd_auth_crap(const char *username,
494 const char *domain,
495 const DATA_BLOB new_nt_pswd,
496 const DATA_BLOB old_nt_hash_enc,
497 const DATA_BLOB new_lm_pswd,
498 const DATA_BLOB old_lm_hash_enc,
499 char **error_string)
501 NTSTATUS nt_status;
502 NSS_STATUS result;
503 struct winbindd_request request;
504 struct winbindd_response response;
506 if (!get_require_membership_sid())
508 if(error_string)
509 *error_string = smb_xstrdup("Can't get membership sid.");
510 return NT_STATUS_INVALID_PARAMETER;
513 ZERO_STRUCT(request);
514 ZERO_STRUCT(response);
516 if(username != NULL)
517 fstrcpy(request.data.chng_pswd_auth_crap.user, username);
518 if(domain != NULL)
519 fstrcpy(request.data.chng_pswd_auth_crap.domain,domain);
521 if(new_nt_pswd.length)
523 memcpy(request.data.chng_pswd_auth_crap.new_nt_pswd, new_nt_pswd.data, sizeof(request.data.chng_pswd_auth_crap.new_nt_pswd));
524 request.data.chng_pswd_auth_crap.new_nt_pswd_len = new_nt_pswd.length;
527 if(old_nt_hash_enc.length)
529 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));
530 request.data.chng_pswd_auth_crap.old_nt_hash_enc_len = old_nt_hash_enc.length;
533 if(new_lm_pswd.length)
535 memcpy(request.data.chng_pswd_auth_crap.new_lm_pswd, new_lm_pswd.data, sizeof(request.data.chng_pswd_auth_crap.new_lm_pswd));
536 request.data.chng_pswd_auth_crap.new_lm_pswd_len = new_lm_pswd.length;
539 if(old_lm_hash_enc.length)
541 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));
542 request.data.chng_pswd_auth_crap.old_lm_hash_enc_len = old_lm_hash_enc.length;
545 result = winbindd_request_response(WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP, &request, &response);
547 /* Display response */
549 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0))
551 nt_status = NT_STATUS_UNSUCCESSFUL;
552 if (error_string)
553 *error_string = smb_xstrdup("Reading winbind reply failed!");
554 winbindd_free_response(&response);
555 return nt_status;
558 nt_status = (NT_STATUS(response.data.auth.nt_status));
559 if (!NT_STATUS_IS_OK(nt_status))
561 if (error_string)
562 *error_string = smb_xstrdup(response.data.auth.error_string);
563 winbindd_free_response(&response);
564 return nt_status;
567 winbindd_free_response(&response);
569 return nt_status;
572 static NTSTATUS winbind_pw_check(struct ntlmssp_state *ntlmssp_state, TALLOC_CTX *mem_ctx,
573 DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
575 static const char zeros[16] = { 0, };
576 NTSTATUS nt_status;
577 char *error_string = NULL;
578 uint8 lm_key[8];
579 uint8 user_sess_key[16];
580 char *unix_name = NULL;
582 nt_status = contact_winbind_auth_crap(ntlmssp_state->user, ntlmssp_state->domain,
583 ntlmssp_state->client.netbios_name,
584 &ntlmssp_state->chal,
585 &ntlmssp_state->lm_resp,
586 &ntlmssp_state->nt_resp,
587 WBFLAG_PAM_LMKEY | WBFLAG_PAM_USER_SESSION_KEY | WBFLAG_PAM_UNIX_NAME,
588 lm_key, user_sess_key,
589 &error_string, &unix_name);
591 if (NT_STATUS_IS_OK(nt_status)) {
592 if (memcmp(lm_key, zeros, 8) != 0) {
593 *lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
594 memcpy(lm_session_key->data, lm_key, 8);
595 memset(lm_session_key->data+8, '\0', 8);
598 if (memcmp(user_sess_key, zeros, 16) != 0) {
599 *user_session_key = data_blob_talloc(mem_ctx, user_sess_key, 16);
601 ntlmssp_state->callback_private = talloc_strdup(ntlmssp_state,
602 unix_name);
603 } else {
604 DEBUG(NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED) ? 0 : 3,
605 ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
606 ntlmssp_state->domain, ntlmssp_state->user,
607 ntlmssp_state->client.netbios_name,
608 error_string ? error_string : "unknown error (NULL)"));
609 ntlmssp_state->callback_private = NULL;
612 SAFE_FREE(error_string);
613 SAFE_FREE(unix_name);
614 return nt_status;
617 static NTSTATUS local_pw_check(struct ntlmssp_state *ntlmssp_state, TALLOC_CTX *mem_ctx,
618 DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
620 NTSTATUS nt_status;
621 struct samr_Password lm_pw, nt_pw;
623 nt_lm_owf_gen (opt_password, nt_pw.hash, lm_pw.hash);
625 nt_status = ntlm_password_check(mem_ctx,
626 true, true, 0,
627 &ntlmssp_state->chal,
628 &ntlmssp_state->lm_resp,
629 &ntlmssp_state->nt_resp,
630 ntlmssp_state->user,
631 ntlmssp_state->user,
632 ntlmssp_state->domain,
633 &lm_pw, &nt_pw, user_session_key, lm_session_key);
635 if (NT_STATUS_IS_OK(nt_status)) {
636 ntlmssp_state->callback_private = talloc_asprintf(ntlmssp_state,
637 "%s%c%s", ntlmssp_state->domain,
638 *lp_winbind_separator(),
639 ntlmssp_state->user);
640 } else {
641 DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
642 ntlmssp_state->domain, ntlmssp_state->user,
643 ntlmssp_state->client.netbios_name,
644 nt_errstr(nt_status)));
645 ntlmssp_state->callback_private = NULL;
647 return nt_status;
650 static NTSTATUS ntlm_auth_start_ntlmssp_client(struct ntlmssp_state **client_ntlmssp_state)
652 NTSTATUS status;
653 if ( (opt_username == NULL) || (opt_domain == NULL) ) {
654 status = NT_STATUS_UNSUCCESSFUL;
655 DEBUG(1, ("Need username and domain for NTLMSSP\n"));
656 return NT_STATUS_INVALID_PARAMETER;
659 status = ntlmssp_client_start(NULL,
660 lp_netbios_name(),
661 lp_workgroup(),
662 lp_client_ntlmv2_auth(),
663 client_ntlmssp_state);
665 if (!NT_STATUS_IS_OK(status)) {
666 DEBUG(1, ("Could not start NTLMSSP client: %s\n",
667 nt_errstr(status)));
668 TALLOC_FREE(*client_ntlmssp_state);
669 return status;
672 status = ntlmssp_set_username(*client_ntlmssp_state, opt_username);
674 if (!NT_STATUS_IS_OK(status)) {
675 DEBUG(1, ("Could not set username: %s\n",
676 nt_errstr(status)));
677 TALLOC_FREE(*client_ntlmssp_state);
678 return status;
681 status = ntlmssp_set_domain(*client_ntlmssp_state, opt_domain);
683 if (!NT_STATUS_IS_OK(status)) {
684 DEBUG(1, ("Could not set domain: %s\n",
685 nt_errstr(status)));
686 TALLOC_FREE(*client_ntlmssp_state);
687 return status;
690 if (opt_password) {
691 status = ntlmssp_set_password(*client_ntlmssp_state, opt_password);
693 if (!NT_STATUS_IS_OK(status)) {
694 DEBUG(1, ("Could not set password: %s\n",
695 nt_errstr(status)));
696 TALLOC_FREE(*client_ntlmssp_state);
697 return status;
701 return NT_STATUS_OK;
704 static NTSTATUS ntlm_auth_start_ntlmssp_server(struct ntlmssp_state **ntlmssp_state)
706 NTSTATUS status;
707 const char *netbios_name;
708 const char *netbios_domain;
709 const char *dns_name;
710 char *dns_domain;
711 bool is_standalone = false;
713 if (opt_password) {
714 netbios_name = lp_netbios_name();
715 netbios_domain = lp_workgroup();
716 } else {
717 netbios_name = get_winbind_netbios_name();
718 netbios_domain = get_winbind_domain();
720 /* This should be a 'netbios domain -> DNS domain' mapping */
721 dns_domain = get_mydnsdomname(talloc_tos());
722 if (dns_domain) {
723 strlower_m(dns_domain);
725 dns_name = get_mydnsfullname();
727 status = ntlmssp_server_start(NULL,
728 is_standalone,
729 netbios_name,
730 netbios_domain,
731 dns_name,
732 dns_domain,
733 ntlmssp_state);
734 if (!NT_STATUS_IS_OK(status)) {
735 DEBUG(1, ("Could not start NTLMSSP server: %s\n",
736 nt_errstr(status)));
737 return status;
740 /* Have we been given a local password, or should we ask winbind? */
741 if (opt_password) {
742 (*ntlmssp_state)->check_password = local_pw_check;
743 } else {
744 (*ntlmssp_state)->check_password = winbind_pw_check;
746 return NT_STATUS_OK;
749 /*******************************************************************
750 Used by firefox to drive NTLM auth to IIS servers.
751 *******************************************************************/
753 static NTSTATUS do_ccache_ntlm_auth(DATA_BLOB initial_msg, DATA_BLOB challenge_msg,
754 DATA_BLOB *reply)
756 struct winbindd_request wb_request;
757 struct winbindd_response wb_response;
758 int ctrl = 0;
759 NSS_STATUS result;
761 /* get winbindd to do the ntlmssp step on our behalf */
762 ZERO_STRUCT(wb_request);
763 ZERO_STRUCT(wb_response);
766 * This is tricky here. If we set krb5_auth in pam_winbind.conf
767 * creds for users in trusted domain will be stored the winbindd
768 * child of the trusted domain. If we ask the primary domain for
769 * ntlm_ccache_auth, it will fail. So, we have to ask the trusted
770 * domain's child for ccache_ntlm_auth. that is to say, we have to
771 * set WBFLAG_PAM_CONTACT_TRUSTDOM in request.flags.
773 ctrl = get_pam_winbind_config();
775 if (ctrl & WINBIND_KRB5_AUTH) {
776 wb_request.flags |= WBFLAG_PAM_CONTACT_TRUSTDOM;
779 fstr_sprintf(wb_request.data.ccache_ntlm_auth.user,
780 "%s%c%s", opt_domain, winbind_separator(), opt_username);
781 wb_request.data.ccache_ntlm_auth.uid = geteuid();
782 wb_request.data.ccache_ntlm_auth.initial_blob_len = initial_msg.length;
783 wb_request.data.ccache_ntlm_auth.challenge_blob_len = challenge_msg.length;
784 wb_request.extra_len = initial_msg.length + challenge_msg.length;
786 if (wb_request.extra_len > 0) {
787 wb_request.extra_data.data = SMB_MALLOC_ARRAY(char, wb_request.extra_len);
788 if (wb_request.extra_data.data == NULL) {
789 return NT_STATUS_NO_MEMORY;
792 memcpy(wb_request.extra_data.data, initial_msg.data, initial_msg.length);
793 memcpy(wb_request.extra_data.data + initial_msg.length,
794 challenge_msg.data, challenge_msg.length);
797 result = winbindd_request_response(WINBINDD_CCACHE_NTLMAUTH, &wb_request, &wb_response);
798 SAFE_FREE(wb_request.extra_data.data);
800 if (result != NSS_STATUS_SUCCESS) {
801 winbindd_free_response(&wb_response);
802 return NT_STATUS_UNSUCCESSFUL;
805 if (reply) {
806 *reply = data_blob(wb_response.extra_data.data,
807 wb_response.data.ccache_ntlm_auth.auth_blob_len);
808 if (wb_response.data.ccache_ntlm_auth.auth_blob_len > 0 &&
809 reply->data == NULL) {
810 winbindd_free_response(&wb_response);
811 return NT_STATUS_NO_MEMORY;
815 winbindd_free_response(&wb_response);
816 return NT_STATUS_MORE_PROCESSING_REQUIRED;
819 static void manage_squid_ntlmssp_request_int(struct ntlm_auth_state *state,
820 char *buf, int length,
821 TALLOC_CTX *mem_ctx,
822 char **response)
824 DATA_BLOB request, reply;
825 NTSTATUS nt_status;
827 if (strlen(buf) < 2) {
828 DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf));
829 *response = talloc_strdup(mem_ctx, "BH NTLMSSP query invalid");
830 return;
833 if (strlen(buf) > 3) {
834 if(strncmp(buf, "SF ", 3) == 0){
835 DEBUG(10, ("Setting flags to negotioate\n"));
836 TALLOC_FREE(state->want_feature_list);
837 state->want_feature_list = talloc_strdup(state->mem_ctx,
838 buf+3);
839 *response = talloc_strdup(mem_ctx, "OK");
840 return;
842 request = base64_decode_data_blob(buf + 3);
843 } else {
844 request = data_blob_null;
847 if ((strncmp(buf, "PW ", 3) == 0)) {
848 /* The calling application wants us to use a local password
849 * (rather than winbindd) */
851 opt_password = SMB_STRNDUP((const char *)request.data,
852 request.length);
854 if (opt_password == NULL) {
855 DEBUG(1, ("Out of memory\n"));
856 *response = talloc_strdup(mem_ctx, "BH Out of memory");
857 data_blob_free(&request);
858 return;
861 *response = talloc_strdup(mem_ctx, "OK");
862 data_blob_free(&request);
863 return;
866 if (strncmp(buf, "YR", 2) == 0) {
867 TALLOC_FREE(state->ntlmssp_state);
868 state->svr_state = SERVER_INITIAL;
869 } else if (strncmp(buf, "KK", 2) == 0) {
870 /* No special preprocessing required */
871 } else if (strncmp(buf, "GF", 2) == 0) {
872 DEBUG(10, ("Requested negotiated NTLMSSP flags\n"));
874 if (state->svr_state == SERVER_FINISHED) {
875 *response = talloc_asprintf(mem_ctx, "GF 0x%08x",
876 state->neg_flags);
878 else {
879 *response = talloc_strdup(mem_ctx, "BH\n");
881 data_blob_free(&request);
882 return;
883 } else if (strncmp(buf, "GK", 2) == 0) {
884 DEBUG(10, ("Requested NTLMSSP session key\n"));
885 if(state->have_session_key) {
886 char *key64 = base64_encode_data_blob(state->mem_ctx,
887 state->session_key);
888 *response = talloc_asprintf(mem_ctx, "GK %s",
889 key64 ? key64 : "<NULL>");
890 TALLOC_FREE(key64);
891 } else {
892 *response = talloc_strdup(mem_ctx, "BH");
895 data_blob_free(&request);
896 return;
897 } else {
898 DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf));
899 *response = talloc_strdup(mem_ctx, "BH NTLMSSP query invalid");
900 return;
903 if (!state->ntlmssp_state) {
904 nt_status = ntlm_auth_start_ntlmssp_server(
905 &state->ntlmssp_state);
906 if (!NT_STATUS_IS_OK(nt_status)) {
907 *response = talloc_asprintf(
908 mem_ctx, "BH %s", nt_errstr(nt_status));
909 return;
911 ntlmssp_want_feature_list(state->ntlmssp_state,
912 state->want_feature_list);
915 DEBUG(10, ("got NTLMSSP packet:\n"));
916 dump_data(10, request.data, request.length);
918 nt_status = ntlmssp_update(state->ntlmssp_state, request, &reply);
920 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
921 char *reply_base64 = base64_encode_data_blob(state->mem_ctx,
922 reply);
923 *response = talloc_asprintf(mem_ctx, "TT %s", reply_base64);
924 TALLOC_FREE(reply_base64);
925 data_blob_free(&reply);
926 state->svr_state = SERVER_CHALLENGE;
927 DEBUG(10, ("NTLMSSP challenge\n"));
928 } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) {
929 *response = talloc_asprintf(mem_ctx, "BH %s",
930 nt_errstr(nt_status));
931 DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status)));
933 TALLOC_FREE(state->ntlmssp_state);
934 } else if (!NT_STATUS_IS_OK(nt_status)) {
935 *response = talloc_asprintf(mem_ctx, "NA %s",
936 nt_errstr(nt_status));
937 DEBUG(10, ("NTLMSSP %s\n", nt_errstr(nt_status)));
938 } else {
939 *response = talloc_asprintf(
940 mem_ctx, "AF %s",
941 (char *)state->ntlmssp_state->callback_private);
942 DEBUG(10, ("NTLMSSP OK!\n"));
944 if(state->have_session_key)
945 data_blob_free(&state->session_key);
946 state->session_key = data_blob(
947 state->ntlmssp_state->session_key.data,
948 state->ntlmssp_state->session_key.length);
949 state->neg_flags = state->ntlmssp_state->neg_flags;
950 state->have_session_key = true;
951 state->svr_state = SERVER_FINISHED;
954 data_blob_free(&request);
957 static void manage_squid_ntlmssp_request(struct ntlm_auth_state *state,
958 char *buf, int length)
960 char *response;
962 manage_squid_ntlmssp_request_int(state, buf, length,
963 talloc_tos(), &response);
965 if (response == NULL) {
966 x_fprintf(x_stdout, "BH Out of memory\n");
967 return;
969 x_fprintf(x_stdout, "%s\n", response);
970 TALLOC_FREE(response);
973 static void manage_client_ntlmssp_request(struct ntlm_auth_state *state,
974 char *buf, int length)
976 DATA_BLOB request, reply;
977 NTSTATUS nt_status;
979 if (!opt_username || !*opt_username) {
980 x_fprintf(x_stderr, "username must be specified!\n\n");
981 exit(1);
984 if (strlen(buf) < 2) {
985 DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf));
986 x_fprintf(x_stdout, "BH NTLMSSP query invalid\n");
987 return;
990 if (strlen(buf) > 3) {
991 if(strncmp(buf, "SF ", 3) == 0) {
992 DEBUG(10, ("Looking for flags to negotiate\n"));
993 talloc_free(state->want_feature_list);
994 state->want_feature_list = talloc_strdup(state->mem_ctx,
995 buf+3);
996 x_fprintf(x_stdout, "OK\n");
997 return;
999 request = base64_decode_data_blob(buf + 3);
1000 } else {
1001 request = data_blob_null;
1004 if (strncmp(buf, "PW ", 3) == 0) {
1005 /* We asked for a password and obviously got it :-) */
1007 opt_password = SMB_STRNDUP((const char *)request.data,
1008 request.length);
1010 if (opt_password == NULL) {
1011 DEBUG(1, ("Out of memory\n"));
1012 x_fprintf(x_stdout, "BH Out of memory\n");
1013 data_blob_free(&request);
1014 return;
1017 x_fprintf(x_stdout, "OK\n");
1018 data_blob_free(&request);
1019 return;
1022 if (!state->ntlmssp_state && use_cached_creds) {
1023 /* check whether cached credentials are usable. */
1024 DATA_BLOB empty_blob = data_blob_null;
1026 nt_status = do_ccache_ntlm_auth(empty_blob, empty_blob, NULL);
1027 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1028 /* failed to use cached creds */
1029 use_cached_creds = False;
1033 if (opt_password == NULL && !use_cached_creds) {
1034 /* Request a password from the calling process. After
1035 sending it, the calling process should retry asking for the
1036 negotiate. */
1038 DEBUG(10, ("Requesting password\n"));
1039 x_fprintf(x_stdout, "PW\n");
1040 return;
1043 if (strncmp(buf, "YR", 2) == 0) {
1044 TALLOC_FREE(state->ntlmssp_state);
1045 state->cli_state = CLIENT_INITIAL;
1046 } else if (strncmp(buf, "TT", 2) == 0) {
1047 /* No special preprocessing required */
1048 } else if (strncmp(buf, "GF", 2) == 0) {
1049 DEBUG(10, ("Requested negotiated NTLMSSP flags\n"));
1051 if(state->cli_state == CLIENT_FINISHED) {
1052 x_fprintf(x_stdout, "GF 0x%08x\n", state->neg_flags);
1054 else {
1055 x_fprintf(x_stdout, "BH\n");
1058 data_blob_free(&request);
1059 return;
1060 } else if (strncmp(buf, "GK", 2) == 0 ) {
1061 DEBUG(10, ("Requested session key\n"));
1063 if(state->cli_state == CLIENT_FINISHED) {
1064 char *key64 = base64_encode_data_blob(state->mem_ctx,
1065 state->session_key);
1066 x_fprintf(x_stdout, "GK %s\n", key64?key64:"<NULL>");
1067 TALLOC_FREE(key64);
1069 else {
1070 x_fprintf(x_stdout, "BH\n");
1073 data_blob_free(&request);
1074 return;
1075 } else {
1076 DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf));
1077 x_fprintf(x_stdout, "BH NTLMSSP query invalid\n");
1078 return;
1081 if (!state->ntlmssp_state) {
1082 nt_status = ntlm_auth_start_ntlmssp_client(
1083 &state->ntlmssp_state);
1084 if (!NT_STATUS_IS_OK(nt_status)) {
1085 x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
1086 return;
1088 ntlmssp_want_feature_list(state->ntlmssp_state,
1089 state->want_feature_list);
1090 state->initial_message = data_blob_null;
1093 DEBUG(10, ("got NTLMSSP packet:\n"));
1094 dump_data(10, request.data, request.length);
1096 if (use_cached_creds && !opt_password &&
1097 (state->cli_state == CLIENT_RESPONSE)) {
1098 nt_status = do_ccache_ntlm_auth(state->initial_message, request,
1099 &reply);
1100 } else {
1101 nt_status = ntlmssp_update(state->ntlmssp_state, request,
1102 &reply);
1105 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1106 char *reply_base64 = base64_encode_data_blob(state->mem_ctx,
1107 reply);
1108 if (state->cli_state == CLIENT_INITIAL) {
1109 x_fprintf(x_stdout, "YR %s\n", reply_base64);
1110 state->initial_message = reply;
1111 state->cli_state = CLIENT_RESPONSE;
1112 } else {
1113 x_fprintf(x_stdout, "KK %s\n", reply_base64);
1114 data_blob_free(&reply);
1116 TALLOC_FREE(reply_base64);
1117 DEBUG(10, ("NTLMSSP challenge\n"));
1118 } else if (NT_STATUS_IS_OK(nt_status)) {
1119 char *reply_base64 = base64_encode_data_blob(talloc_tos(),
1120 reply);
1121 x_fprintf(x_stdout, "AF %s\n", reply_base64);
1122 TALLOC_FREE(reply_base64);
1124 if(state->have_session_key)
1125 data_blob_free(&state->session_key);
1127 state->session_key = data_blob(
1128 state->ntlmssp_state->session_key.data,
1129 state->ntlmssp_state->session_key.length);
1130 state->neg_flags = state->ntlmssp_state->neg_flags;
1131 state->have_session_key = true;
1133 DEBUG(10, ("NTLMSSP OK!\n"));
1134 state->cli_state = CLIENT_FINISHED;
1135 TALLOC_FREE(state->ntlmssp_state);
1136 } else {
1137 x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
1138 DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status)));
1139 state->cli_state = CLIENT_ERROR;
1140 TALLOC_FREE(state->ntlmssp_state);
1143 data_blob_free(&request);
1146 static void manage_squid_basic_request(struct ntlm_auth_state *state,
1147 char *buf, int length)
1149 char *user, *pass;
1150 user=buf;
1152 pass=(char *)memchr(buf,' ',length);
1153 if (!pass) {
1154 DEBUG(2, ("Password not found. Denying access\n"));
1155 x_fprintf(x_stdout, "ERR\n");
1156 return;
1158 *pass='\0';
1159 pass++;
1161 if (state->helper_mode == SQUID_2_5_BASIC) {
1162 rfc1738_unescape(user);
1163 rfc1738_unescape(pass);
1166 if (check_plaintext_auth(user, pass, False)) {
1167 x_fprintf(x_stdout, "OK\n");
1168 } else {
1169 x_fprintf(x_stdout, "ERR\n");
1173 static void offer_gss_spnego_mechs(void) {
1175 DATA_BLOB token;
1176 struct spnego_data spnego;
1177 ssize_t len;
1178 char *reply_base64;
1179 TALLOC_CTX *ctx = talloc_tos();
1180 char *principal;
1181 char *myname_lower;
1183 ZERO_STRUCT(spnego);
1185 myname_lower = talloc_strdup(ctx, lp_netbios_name());
1186 if (!myname_lower) {
1187 return;
1189 strlower_m(myname_lower);
1191 principal = talloc_asprintf(ctx, "%s$@%s", myname_lower, lp_realm());
1192 if (!principal) {
1193 return;
1196 /* Server negTokenInit (mech offerings) */
1197 spnego.type = SPNEGO_NEG_TOKEN_INIT;
1198 spnego.negTokenInit.mechTypes = talloc_array(ctx, const char *, 4);
1199 #ifdef HAVE_KRB5
1200 spnego.negTokenInit.mechTypes[0] = talloc_strdup(ctx, OID_KERBEROS5_OLD);
1201 spnego.negTokenInit.mechTypes[1] = talloc_strdup(ctx, OID_KERBEROS5);
1202 spnego.negTokenInit.mechTypes[2] = talloc_strdup(ctx, OID_NTLMSSP);
1203 spnego.negTokenInit.mechTypes[3] = NULL;
1204 #else
1205 spnego.negTokenInit.mechTypes[0] = talloc_strdup(ctx, OID_NTLMSSP);
1206 spnego.negTokenInit.mechTypes[1] = NULL;
1207 #endif
1210 spnego.negTokenInit.mechListMIC = data_blob_talloc(ctx, principal,
1211 strlen(principal));
1213 len = spnego_write_data(ctx, &token, &spnego);
1214 spnego_free_data(&spnego);
1216 if (len == -1) {
1217 DEBUG(1, ("Could not write SPNEGO data blob\n"));
1218 x_fprintf(x_stdout, "BH Could not write SPNEGO data blob\n");
1219 return;
1222 reply_base64 = base64_encode_data_blob(talloc_tos(), token);
1223 x_fprintf(x_stdout, "TT %s *\n", reply_base64);
1225 TALLOC_FREE(reply_base64);
1226 data_blob_free(&token);
1227 DEBUG(10, ("sent SPNEGO negTokenInit\n"));
1228 return;
1231 bool spnego_parse_krb5_wrap(TALLOC_CTX *ctx, DATA_BLOB blob, DATA_BLOB *ticket, uint8 tok_id[2])
1233 bool ret;
1234 ASN1_DATA *data;
1235 int data_remaining;
1237 data = asn1_init(talloc_tos());
1238 if (data == NULL) {
1239 return false;
1242 asn1_load(data, blob);
1243 asn1_start_tag(data, ASN1_APPLICATION(0));
1244 asn1_check_OID(data, OID_KERBEROS5);
1246 data_remaining = asn1_tag_remaining(data);
1248 if (data_remaining < 3) {
1249 data->has_error = True;
1250 } else {
1251 asn1_read(data, tok_id, 2);
1252 data_remaining -= 2;
1253 *ticket = data_blob_talloc(ctx, NULL, data_remaining);
1254 asn1_read(data, ticket->data, ticket->length);
1257 asn1_end_tag(data);
1259 ret = !data->has_error;
1261 if (data->has_error) {
1262 data_blob_free(ticket);
1265 asn1_free(data);
1267 return ret;
1270 static void manage_gss_spnego_request(struct ntlm_auth_state *state,
1271 char *buf, int length)
1273 struct spnego_data request, response;
1274 DATA_BLOB token;
1275 DATA_BLOB raw_in_token = data_blob_null;
1276 DATA_BLOB raw_out_token = data_blob_null;
1277 NTSTATUS status;
1278 ssize_t len;
1279 TALLOC_CTX *ctx = talloc_tos();
1281 char *user = NULL;
1282 char *domain = NULL;
1284 const char *reply_code;
1285 char *reply_base64;
1286 char *reply_argument = NULL;
1287 char *supportedMech = NULL;
1289 if (strlen(buf) < 2) {
1290 DEBUG(1, ("SPENGO query [%s] invalid\n", buf));
1291 x_fprintf(x_stdout, "BH SPENGO query invalid\n");
1292 return;
1295 if (strncmp(buf, "YR", 2) == 0) {
1296 TALLOC_FREE(state->ntlmssp_state);
1297 TALLOC_FREE(state->spnego_mech);
1298 TALLOC_FREE(state->spnego_mech_oid);
1299 } else if (strncmp(buf, "KK", 2) == 0) {
1301 } else {
1302 DEBUG(1, ("SPENGO query [%s] invalid\n", buf));
1303 x_fprintf(x_stdout, "BH SPENGO query invalid\n");
1304 return;
1307 if ( (strlen(buf) == 2)) {
1309 /* no client data, get the negTokenInit offering
1310 mechanisms */
1312 offer_gss_spnego_mechs();
1313 return;
1316 /* All subsequent requests have a blob. This might be negTokenInit or negTokenTarg */
1318 if (strlen(buf) <= 3) {
1319 DEBUG(1, ("GSS-SPNEGO query [%s] invalid\n", buf));
1320 x_fprintf(x_stdout, "BH GSS-SPNEGO query invalid\n");
1321 return;
1324 token = base64_decode_data_blob(buf + 3);
1326 if ((token.length >= 7)
1327 && (strncmp((char *)token.data, "NTLMSSP", 7) == 0)) {
1328 char *reply;
1330 data_blob_free(&token);
1332 DEBUG(10, ("Could not parse GSS-SPNEGO, trying raw "
1333 "ntlmssp\n"));
1335 manage_squid_ntlmssp_request_int(state, buf, length,
1336 talloc_tos(), &reply);
1337 if (reply == NULL) {
1338 x_fprintf(x_stdout, "BH Out of memory\n");
1339 return;
1342 if (strncmp(reply, "AF ", 3) == 0) {
1343 x_fprintf(x_stdout, "AF * %s\n", reply+3);
1344 } else {
1345 x_fprintf(x_stdout, "%s *\n", reply);
1348 TALLOC_FREE(reply);
1349 return;
1352 ZERO_STRUCT(request);
1353 len = spnego_read_data(ctx, token, &request);
1354 data_blob_free(&token);
1356 if (len == -1) {
1357 DEBUG(1, ("GSS-SPNEGO query [%s] invalid\n", buf));
1358 x_fprintf(x_stdout, "BH GSS-SPNEGO query invalid\n");
1359 return;
1362 if (request.type == SPNEGO_NEG_TOKEN_INIT) {
1363 #ifdef HAVE_KRB5
1364 int krb5_idx = -1;
1365 #endif
1366 int ntlm_idx = -1;
1367 int used_idx = -1;
1368 int i;
1370 if (state->spnego_mech) {
1371 DEBUG(1, ("Client restarted SPNEGO with NegTokenInit "
1372 "while mech[%s] was already negotiated\n",
1373 state->spnego_mech));
1374 x_fprintf(x_stdout, "BH Client send NegTokenInit twice\n");
1375 return;
1378 /* Second request from Client. This is where the
1379 client offers its mechanism to use. */
1381 if ( (request.negTokenInit.mechTypes == NULL) ||
1382 (request.negTokenInit.mechTypes[0] == NULL) ) {
1383 DEBUG(1, ("Client did not offer any mechanism\n"));
1384 x_fprintf(x_stdout, "BH Client did not offer any "
1385 "mechanism\n");
1386 return;
1389 status = NT_STATUS_UNSUCCESSFUL;
1390 for (i = 0; request.negTokenInit.mechTypes[i] != NULL; i++) {
1391 DEBUG(10,("got mech[%d][%s]\n",
1392 i, request.negTokenInit.mechTypes[i]));
1393 #ifdef HAVE_KRB5
1394 if (strcmp(request.negTokenInit.mechTypes[i], OID_KERBEROS5_OLD) == 0) {
1395 krb5_idx = i;
1396 break;
1398 if (strcmp(request.negTokenInit.mechTypes[i], OID_KERBEROS5) == 0) {
1399 krb5_idx = i;
1400 break;
1402 #endif
1403 if (strcmp(request.negTokenInit.mechTypes[i], OID_NTLMSSP) == 0) {
1404 ntlm_idx = i;
1405 break;
1409 used_idx = ntlm_idx;
1410 #ifdef HAVE_KRB5
1411 if (krb5_idx != -1) {
1412 ntlm_idx = -1;
1413 used_idx = krb5_idx;
1415 #endif
1416 if (ntlm_idx > -1) {
1417 state->spnego_mech = talloc_strdup(state, "ntlmssp");
1418 if (state->spnego_mech == NULL) {
1419 x_fprintf(x_stdout, "BH Out of memory\n");
1420 return;
1423 if (state->ntlmssp_state) {
1424 DEBUG(1, ("Client wants a new NTLMSSP challenge, but "
1425 "already got one\n"));
1426 x_fprintf(x_stdout, "BH Client wants a new "
1427 "NTLMSSP challenge, but "
1428 "already got one\n");
1429 TALLOC_FREE(state->ntlmssp_state);
1430 return;
1433 status = ntlm_auth_start_ntlmssp_server(&state->ntlmssp_state);
1434 if (!NT_STATUS_IS_OK(status)) {
1435 x_fprintf(x_stdout, "BH %s\n", nt_errstr(status));
1436 return;
1440 #ifdef HAVE_KRB5
1441 if (krb5_idx > -1) {
1442 state->spnego_mech = talloc_strdup(state, "krb5");
1443 if (state->spnego_mech == NULL) {
1444 x_fprintf(x_stdout, "BH Out of memory\n");
1445 return;
1448 #endif
1449 if (used_idx > -1) {
1450 state->spnego_mech_oid = talloc_strdup(state,
1451 request.negTokenInit.mechTypes[used_idx]);
1452 if (state->spnego_mech_oid == NULL) {
1453 x_fprintf(x_stdout, "BH Out of memory\n");
1454 return;
1456 supportedMech = talloc_strdup(ctx, state->spnego_mech_oid);
1457 if (supportedMech == NULL) {
1458 x_fprintf(x_stdout, "BH Out of memory\n");
1459 return;
1462 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1463 } else {
1464 status = NT_STATUS_NOT_SUPPORTED;
1466 if (used_idx == 0) {
1467 status = NT_STATUS_OK;
1468 raw_in_token = request.negTokenInit.mechToken;
1470 } else {
1471 if (state->spnego_mech == NULL) {
1472 DEBUG(1,("Got netTokenTarg without negTokenInit\n"));
1473 x_fprintf(x_stdout, "BH Got a negTokenTarg without "
1474 "negTokenInit\n");
1475 return;
1478 if ((request.negTokenTarg.supportedMech != NULL) &&
1479 (strcmp(request.negTokenTarg.supportedMech, state->spnego_mech_oid) != 0 ) ) {
1480 DEBUG(1, ("Got a negTokenTarg with mech[%s] while [%s] was already negotiated\n",
1481 request.negTokenTarg.supportedMech,
1482 state->spnego_mech_oid));
1483 x_fprintf(x_stdout, "BH Got a negTokenTarg with speficied mech\n");
1484 return;
1487 status = NT_STATUS_OK;
1488 raw_in_token = request.negTokenTarg.responseToken;
1491 if (!NT_STATUS_IS_OK(status)) {
1492 /* error or more processing */
1493 } else if (strcmp(state->spnego_mech, "ntlmssp") == 0) {
1495 DEBUG(10, ("got NTLMSSP packet:\n"));
1496 dump_data(10, raw_in_token.data, raw_in_token.length);
1498 status = ntlmssp_update(state->ntlmssp_state,
1499 raw_in_token,
1500 &raw_out_token);
1501 if (NT_STATUS_IS_OK(status)) {
1502 user = talloc_strdup(ctx, state->ntlmssp_state->user);
1503 domain = talloc_strdup(ctx, state->ntlmssp_state->domain);
1505 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1506 TALLOC_FREE(state->ntlmssp_state);
1508 #ifdef HAVE_KRB5
1509 } else if (strcmp(state->spnego_mech, "krb5") == 0) {
1510 char *principal;
1511 DATA_BLOB ap_rep;
1512 DATA_BLOB session_key;
1513 struct PAC_LOGON_INFO *logon_info = NULL;
1514 DATA_BLOB ticket;
1515 uint8_t tok_id[2];
1517 if (!spnego_parse_krb5_wrap(ctx, raw_in_token,
1518 &ticket, tok_id)) {
1519 DEBUG(1, ("spnego_parse_krb5_wrap failed\n"));
1520 x_fprintf(x_stdout, "BH spnego_parse_krb5_wrap failed\n");
1521 return;
1524 status = ads_verify_ticket(ctx, lp_realm(), 0,
1525 &ticket,
1526 &principal, &logon_info, &ap_rep,
1527 &session_key, True);
1529 /* Now in "principal" we have the name we are authenticated as. */
1531 if (NT_STATUS_IS_OK(status)) {
1533 domain = strchr_m(principal, '@');
1535 if (domain == NULL) {
1536 DEBUG(1, ("Did not get a valid principal "
1537 "from ads_verify_ticket\n"));
1538 x_fprintf(x_stdout, "BH Did not get a "
1539 "valid principal from "
1540 "ads_verify_ticket\n");
1541 return;
1544 *domain++ = '\0';
1545 domain = talloc_strdup(ctx, domain);
1546 user = talloc_strdup(ctx, principal);
1548 if (logon_info) {
1549 netsamlogon_cache_store(
1550 user, &logon_info->info3);
1553 data_blob_free(&ap_rep);
1554 data_blob_free(&session_key);
1556 data_blob_free(&ticket);
1557 #endif
1560 spnego_free_data(&request);
1561 ZERO_STRUCT(response);
1562 response.type = SPNEGO_NEG_TOKEN_TARG;
1564 if (NT_STATUS_IS_OK(status)) {
1565 TALLOC_FREE(state->spnego_mech);
1566 TALLOC_FREE(state->spnego_mech_oid);
1567 response.negTokenTarg.negResult = SPNEGO_ACCEPT_COMPLETED;
1568 response.negTokenTarg.responseToken = raw_out_token;
1569 reply_code = "AF";
1570 reply_argument = talloc_asprintf(ctx, "%s\\%s", domain, user);
1571 } else if (NT_STATUS_EQUAL(status,
1572 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1573 response.negTokenTarg.supportedMech = supportedMech;
1574 response.negTokenTarg.responseToken = raw_out_token;
1575 response.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
1576 reply_code = "TT";
1577 reply_argument = talloc_strdup(ctx, "*");
1578 } else {
1579 TALLOC_FREE(state->spnego_mech);
1580 TALLOC_FREE(state->spnego_mech_oid);
1581 data_blob_free(&raw_out_token);
1582 response.negTokenTarg.negResult = SPNEGO_REJECT;
1583 reply_code = "NA";
1584 reply_argument = talloc_strdup(ctx, nt_errstr(status));
1587 if (!reply_argument) {
1588 DEBUG(1, ("Could not write SPNEGO data blob\n"));
1589 x_fprintf(x_stdout, "BH Could not write SPNEGO data blob\n");
1590 spnego_free_data(&response);
1591 return;
1594 len = spnego_write_data(ctx, &token, &response);
1595 spnego_free_data(&response);
1597 if (len == -1) {
1598 DEBUG(1, ("Could not write SPNEGO data blob\n"));
1599 x_fprintf(x_stdout, "BH Could not write SPNEGO data blob\n");
1600 return;
1603 reply_base64 = base64_encode_data_blob(talloc_tos(), token);
1605 x_fprintf(x_stdout, "%s %s %s\n",
1606 reply_code, reply_base64, reply_argument);
1608 TALLOC_FREE(reply_base64);
1609 data_blob_free(&token);
1611 return;
1614 static struct ntlmssp_state *client_ntlmssp_state = NULL;
1616 static bool manage_client_ntlmssp_init(struct spnego_data spnego)
1618 NTSTATUS status;
1619 DATA_BLOB null_blob = data_blob_null;
1620 DATA_BLOB to_server;
1621 char *to_server_base64;
1622 const char *my_mechs[] = {OID_NTLMSSP, NULL};
1623 TALLOC_CTX *ctx = talloc_tos();
1625 DEBUG(10, ("Got spnego negTokenInit with NTLMSSP\n"));
1627 if (client_ntlmssp_state != NULL) {
1628 DEBUG(1, ("Request for initial SPNEGO request where "
1629 "we already have a state\n"));
1630 return False;
1633 if (!client_ntlmssp_state) {
1634 if (!NT_STATUS_IS_OK(status = ntlm_auth_start_ntlmssp_client(&client_ntlmssp_state))) {
1635 x_fprintf(x_stdout, "BH %s\n", nt_errstr(status));
1636 return False;
1641 if (opt_password == NULL) {
1643 /* Request a password from the calling process. After
1644 sending it, the calling process should retry with
1645 the negTokenInit. */
1647 DEBUG(10, ("Requesting password\n"));
1648 x_fprintf(x_stdout, "PW\n");
1649 return True;
1652 spnego.type = SPNEGO_NEG_TOKEN_INIT;
1653 spnego.negTokenInit.mechTypes = my_mechs;
1654 spnego.negTokenInit.reqFlags = data_blob_null;
1655 spnego.negTokenInit.reqFlagsPadding = 0;
1656 spnego.negTokenInit.mechListMIC = null_blob;
1658 status = ntlmssp_update(client_ntlmssp_state, null_blob,
1659 &spnego.negTokenInit.mechToken);
1661 if ( !(NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) ||
1662 NT_STATUS_IS_OK(status)) ) {
1663 DEBUG(1, ("Expected OK or MORE_PROCESSING_REQUIRED, got: %s\n",
1664 nt_errstr(status)));
1665 TALLOC_FREE(client_ntlmssp_state);
1666 return False;
1669 spnego_write_data(ctx, &to_server, &spnego);
1670 data_blob_free(&spnego.negTokenInit.mechToken);
1672 to_server_base64 = base64_encode_data_blob(talloc_tos(), to_server);
1673 data_blob_free(&to_server);
1674 x_fprintf(x_stdout, "KK %s\n", to_server_base64);
1675 TALLOC_FREE(to_server_base64);
1676 return True;
1679 static void manage_client_ntlmssp_targ(struct spnego_data spnego)
1681 NTSTATUS status;
1682 DATA_BLOB null_blob = data_blob_null;
1683 DATA_BLOB request;
1684 DATA_BLOB to_server;
1685 char *to_server_base64;
1686 TALLOC_CTX *ctx = talloc_tos();
1688 DEBUG(10, ("Got spnego negTokenTarg with NTLMSSP\n"));
1690 if (client_ntlmssp_state == NULL) {
1691 DEBUG(1, ("Got NTLMSSP tArg without a client state\n"));
1692 x_fprintf(x_stdout, "BH Got NTLMSSP tArg without a client state\n");
1693 return;
1696 if (spnego.negTokenTarg.negResult == SPNEGO_REJECT) {
1697 x_fprintf(x_stdout, "NA\n");
1698 TALLOC_FREE(client_ntlmssp_state);
1699 return;
1702 if (spnego.negTokenTarg.negResult == SPNEGO_ACCEPT_COMPLETED) {
1703 x_fprintf(x_stdout, "AF\n");
1704 TALLOC_FREE(client_ntlmssp_state);
1705 return;
1708 status = ntlmssp_update(client_ntlmssp_state,
1709 spnego.negTokenTarg.responseToken,
1710 &request);
1712 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1713 DEBUG(1, ("Expected MORE_PROCESSING_REQUIRED from "
1714 "ntlmssp_client_update, got: %s\n",
1715 nt_errstr(status)));
1716 x_fprintf(x_stdout, "BH Expected MORE_PROCESSING_REQUIRED from "
1717 "ntlmssp_client_update\n");
1718 data_blob_free(&request);
1719 TALLOC_FREE(client_ntlmssp_state);
1720 return;
1723 spnego.type = SPNEGO_NEG_TOKEN_TARG;
1724 spnego.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
1725 spnego.negTokenTarg.supportedMech = (const char *)OID_NTLMSSP;
1726 spnego.negTokenTarg.responseToken = request;
1727 spnego.negTokenTarg.mechListMIC = null_blob;
1729 spnego_write_data(ctx, &to_server, &spnego);
1730 data_blob_free(&request);
1732 to_server_base64 = base64_encode_data_blob(talloc_tos(), to_server);
1733 data_blob_free(&to_server);
1734 x_fprintf(x_stdout, "KK %s\n", to_server_base64);
1735 TALLOC_FREE(to_server_base64);
1736 return;
1739 #ifdef HAVE_KRB5
1741 static bool manage_client_krb5_init(struct spnego_data spnego)
1743 char *principal;
1744 DATA_BLOB tkt, to_server;
1745 DATA_BLOB session_key_krb5 = data_blob_null;
1746 struct spnego_data reply;
1747 char *reply_base64;
1748 int retval;
1750 const char *my_mechs[] = {OID_KERBEROS5_OLD, NULL};
1751 ssize_t len;
1752 TALLOC_CTX *ctx = talloc_tos();
1754 if ( (spnego.negTokenInit.mechListMIC.data == NULL) ||
1755 (spnego.negTokenInit.mechListMIC.length == 0) ) {
1756 DEBUG(1, ("Did not get a principal for krb5\n"));
1757 return False;
1760 principal = (char *)SMB_MALLOC(
1761 spnego.negTokenInit.mechListMIC.length+1);
1763 if (principal == NULL) {
1764 DEBUG(1, ("Could not malloc principal\n"));
1765 return False;
1768 memcpy(principal, spnego.negTokenInit.mechListMIC.data,
1769 spnego.negTokenInit.mechListMIC.length);
1770 principal[spnego.negTokenInit.mechListMIC.length] = '\0';
1772 retval = cli_krb5_get_ticket(ctx, principal, 0,
1773 &tkt, &session_key_krb5,
1774 0, NULL, NULL, NULL);
1775 if (retval) {
1776 char *user = NULL;
1778 /* Let's try to first get the TGT, for that we need a
1779 password. */
1781 if (opt_password == NULL) {
1782 DEBUG(10, ("Requesting password\n"));
1783 x_fprintf(x_stdout, "PW\n");
1784 return True;
1787 user = talloc_asprintf(talloc_tos(), "%s@%s", opt_username, opt_domain);
1788 if (!user) {
1789 return false;
1792 if ((retval = kerberos_kinit_password(user, opt_password, 0, NULL))) {
1793 DEBUG(10, ("Requesting TGT failed: %s\n", error_message(retval)));
1794 return False;
1797 retval = cli_krb5_get_ticket(ctx, principal, 0,
1798 &tkt, &session_key_krb5,
1799 0, NULL, NULL, NULL);
1800 if (retval) {
1801 DEBUG(10, ("Kinit suceeded, but getting a ticket failed: %s\n", error_message(retval)));
1802 return False;
1806 data_blob_free(&session_key_krb5);
1808 ZERO_STRUCT(reply);
1810 reply.type = SPNEGO_NEG_TOKEN_INIT;
1811 reply.negTokenInit.mechTypes = my_mechs;
1812 reply.negTokenInit.reqFlags = data_blob_null;
1813 reply.negTokenInit.reqFlagsPadding = 0;
1814 reply.negTokenInit.mechToken = tkt;
1815 reply.negTokenInit.mechListMIC = data_blob_null;
1817 len = spnego_write_data(ctx, &to_server, &reply);
1818 data_blob_free(&tkt);
1820 if (len == -1) {
1821 DEBUG(1, ("Could not write SPNEGO data blob\n"));
1822 return False;
1825 reply_base64 = base64_encode_data_blob(talloc_tos(), to_server);
1826 x_fprintf(x_stdout, "KK %s *\n", reply_base64);
1828 TALLOC_FREE(reply_base64);
1829 data_blob_free(&to_server);
1830 DEBUG(10, ("sent GSS-SPNEGO KERBEROS5 negTokenInit\n"));
1831 return True;
1834 static void manage_client_krb5_targ(struct spnego_data spnego)
1836 switch (spnego.negTokenTarg.negResult) {
1837 case SPNEGO_ACCEPT_INCOMPLETE:
1838 DEBUG(1, ("Got a Kerberos negTokenTarg with ACCEPT_INCOMPLETE\n"));
1839 x_fprintf(x_stdout, "BH Got a Kerberos negTokenTarg with "
1840 "ACCEPT_INCOMPLETE\n");
1841 break;
1842 case SPNEGO_ACCEPT_COMPLETED:
1843 DEBUG(10, ("Accept completed\n"));
1844 x_fprintf(x_stdout, "AF\n");
1845 break;
1846 case SPNEGO_REJECT:
1847 DEBUG(10, ("Rejected\n"));
1848 x_fprintf(x_stdout, "NA\n");
1849 break;
1850 default:
1851 DEBUG(1, ("Got an invalid negTokenTarg\n"));
1852 x_fprintf(x_stdout, "AF\n");
1856 #endif
1858 static void manage_gss_spnego_client_request(struct ntlm_auth_state *state,
1859 char *buf, int length)
1861 DATA_BLOB request;
1862 struct spnego_data spnego;
1863 ssize_t len;
1864 TALLOC_CTX *ctx = talloc_tos();
1866 if (!opt_username || !*opt_username) {
1867 x_fprintf(x_stderr, "username must be specified!\n\n");
1868 exit(1);
1871 if (strlen(buf) <= 3) {
1872 DEBUG(1, ("SPNEGO query [%s] too short\n", buf));
1873 x_fprintf(x_stdout, "BH SPNEGO query too short\n");
1874 return;
1877 request = base64_decode_data_blob(buf+3);
1879 if (strncmp(buf, "PW ", 3) == 0) {
1881 /* We asked for a password and obviously got it :-) */
1883 opt_password = SMB_STRNDUP((const char *)request.data, request.length);
1885 if (opt_password == NULL) {
1886 DEBUG(1, ("Out of memory\n"));
1887 x_fprintf(x_stdout, "BH Out of memory\n");
1888 data_blob_free(&request);
1889 return;
1892 x_fprintf(x_stdout, "OK\n");
1893 data_blob_free(&request);
1894 return;
1897 if ( (strncmp(buf, "TT ", 3) != 0) &&
1898 (strncmp(buf, "AF ", 3) != 0) &&
1899 (strncmp(buf, "NA ", 3) != 0) ) {
1900 DEBUG(1, ("SPNEGO request [%s] invalid\n", buf));
1901 x_fprintf(x_stdout, "BH SPNEGO request invalid\n");
1902 data_blob_free(&request);
1903 return;
1906 /* So we got a server challenge to generate a SPNEGO
1907 client-to-server request... */
1909 len = spnego_read_data(ctx, request, &spnego);
1910 data_blob_free(&request);
1912 if (len == -1) {
1913 DEBUG(1, ("Could not read SPNEGO data for [%s]\n", buf));
1914 x_fprintf(x_stdout, "BH Could not read SPNEGO data\n");
1915 return;
1918 if (spnego.type == SPNEGO_NEG_TOKEN_INIT) {
1920 /* The server offers a list of mechanisms */
1922 const char **mechType = (const char **)spnego.negTokenInit.mechTypes;
1924 while (*mechType != NULL) {
1926 #ifdef HAVE_KRB5
1927 if ( (strcmp(*mechType, OID_KERBEROS5_OLD) == 0) ||
1928 (strcmp(*mechType, OID_KERBEROS5) == 0) ) {
1929 if (manage_client_krb5_init(spnego))
1930 goto out;
1932 #endif
1934 if (strcmp(*mechType, OID_NTLMSSP) == 0) {
1935 if (manage_client_ntlmssp_init(spnego))
1936 goto out;
1939 mechType++;
1942 DEBUG(1, ("Server offered no compatible mechanism\n"));
1943 x_fprintf(x_stdout, "BH Server offered no compatible mechanism\n");
1944 return;
1947 if (spnego.type == SPNEGO_NEG_TOKEN_TARG) {
1949 if (spnego.negTokenTarg.supportedMech == NULL) {
1950 /* On accept/reject Windows does not send the
1951 mechanism anymore. Handle that here and
1952 shut down the mechanisms. */
1954 switch (spnego.negTokenTarg.negResult) {
1955 case SPNEGO_ACCEPT_COMPLETED:
1956 x_fprintf(x_stdout, "AF\n");
1957 break;
1958 case SPNEGO_REJECT:
1959 x_fprintf(x_stdout, "NA\n");
1960 break;
1961 default:
1962 DEBUG(1, ("Got a negTokenTarg with no mech and an "
1963 "unknown negResult: %d\n",
1964 spnego.negTokenTarg.negResult));
1965 x_fprintf(x_stdout, "BH Got a negTokenTarg with"
1966 " no mech and an unknown "
1967 "negResult\n");
1970 TALLOC_FREE(client_ntlmssp_state);
1971 goto out;
1974 if (strcmp(spnego.negTokenTarg.supportedMech,
1975 OID_NTLMSSP) == 0) {
1976 manage_client_ntlmssp_targ(spnego);
1977 goto out;
1980 #if HAVE_KRB5
1981 if (strcmp(spnego.negTokenTarg.supportedMech,
1982 OID_KERBEROS5_OLD) == 0) {
1983 manage_client_krb5_targ(spnego);
1984 goto out;
1986 #endif
1990 DEBUG(1, ("Got an SPNEGO token I could not handle [%s]!\n", buf));
1991 x_fprintf(x_stdout, "BH Got an SPNEGO token I could not handle\n");
1992 return;
1994 out:
1995 spnego_free_data(&spnego);
1996 return;
1999 static void manage_ntlm_server_1_request(struct ntlm_auth_state *state,
2000 char *buf, int length)
2002 char *request, *parameter;
2003 static DATA_BLOB challenge;
2004 static DATA_BLOB lm_response;
2005 static DATA_BLOB nt_response;
2006 static char *full_username;
2007 static char *username;
2008 static char *domain;
2009 static char *plaintext_password;
2010 static bool ntlm_server_1_user_session_key;
2011 static bool ntlm_server_1_lm_session_key;
2013 if (strequal(buf, ".")) {
2014 if (!full_username && !username) {
2015 x_fprintf(x_stdout, "Error: No username supplied!\n");
2016 } else if (plaintext_password) {
2017 /* handle this request as plaintext */
2018 if (!full_username) {
2019 if (asprintf(&full_username, "%s%c%s", domain, winbind_separator(), username) == -1) {
2020 x_fprintf(x_stdout, "Error: Out of memory in asprintf!\n.\n");
2021 return;
2024 if (check_plaintext_auth(full_username, plaintext_password, False)) {
2025 x_fprintf(x_stdout, "Authenticated: Yes\n");
2026 } else {
2027 x_fprintf(x_stdout, "Authenticated: No\n");
2029 } else if (!lm_response.data && !nt_response.data) {
2030 x_fprintf(x_stdout, "Error: No password supplied!\n");
2031 } else if (!challenge.data) {
2032 x_fprintf(x_stdout, "Error: No lanman-challenge supplied!\n");
2033 } else {
2034 char *error_string = NULL;
2035 uchar lm_key[8];
2036 uchar user_session_key[16];
2037 uint32 flags = 0;
2039 if (full_username && !username) {
2040 fstring fstr_user;
2041 fstring fstr_domain;
2043 if (!parse_ntlm_auth_domain_user(full_username, fstr_user, fstr_domain)) {
2044 /* username might be 'tainted', don't print into our new-line deleimianted stream */
2045 x_fprintf(x_stdout, "Error: Could not parse into domain and username\n");
2047 SAFE_FREE(username);
2048 SAFE_FREE(domain);
2049 username = smb_xstrdup(fstr_user);
2050 domain = smb_xstrdup(fstr_domain);
2053 if (!domain) {
2054 domain = smb_xstrdup(get_winbind_domain());
2057 if (ntlm_server_1_lm_session_key)
2058 flags |= WBFLAG_PAM_LMKEY;
2060 if (ntlm_server_1_user_session_key)
2061 flags |= WBFLAG_PAM_USER_SESSION_KEY;
2063 if (!NT_STATUS_IS_OK(
2064 contact_winbind_auth_crap(username,
2065 domain,
2066 lp_netbios_name(),
2067 &challenge,
2068 &lm_response,
2069 &nt_response,
2070 flags,
2071 lm_key,
2072 user_session_key,
2073 &error_string,
2074 NULL))) {
2076 x_fprintf(x_stdout, "Authenticated: No\n");
2077 x_fprintf(x_stdout, "Authentication-Error: %s\n.\n", error_string);
2078 } else {
2079 static char zeros[16];
2080 char *hex_lm_key;
2081 char *hex_user_session_key;
2083 x_fprintf(x_stdout, "Authenticated: Yes\n");
2085 if (ntlm_server_1_lm_session_key
2086 && (memcmp(zeros, lm_key,
2087 sizeof(lm_key)) != 0)) {
2088 hex_lm_key = hex_encode_talloc(NULL,
2089 (const unsigned char *)lm_key,
2090 sizeof(lm_key));
2091 x_fprintf(x_stdout, "LANMAN-Session-Key: %s\n", hex_lm_key);
2092 TALLOC_FREE(hex_lm_key);
2095 if (ntlm_server_1_user_session_key
2096 && (memcmp(zeros, user_session_key,
2097 sizeof(user_session_key)) != 0)) {
2098 hex_user_session_key = hex_encode_talloc(NULL,
2099 (const unsigned char *)user_session_key,
2100 sizeof(user_session_key));
2101 x_fprintf(x_stdout, "User-Session-Key: %s\n", hex_user_session_key);
2102 TALLOC_FREE(hex_user_session_key);
2105 SAFE_FREE(error_string);
2107 /* clear out the state */
2108 challenge = data_blob_null;
2109 nt_response = data_blob_null;
2110 lm_response = data_blob_null;
2111 SAFE_FREE(full_username);
2112 SAFE_FREE(username);
2113 SAFE_FREE(domain);
2114 SAFE_FREE(plaintext_password);
2115 ntlm_server_1_user_session_key = False;
2116 ntlm_server_1_lm_session_key = False;
2117 x_fprintf(x_stdout, ".\n");
2119 return;
2122 request = buf;
2124 /* Indicates a base64 encoded structure */
2125 parameter = strstr_m(request, ":: ");
2126 if (!parameter) {
2127 parameter = strstr_m(request, ": ");
2129 if (!parameter) {
2130 DEBUG(0, ("Parameter not found!\n"));
2131 x_fprintf(x_stdout, "Error: Parameter not found!\n.\n");
2132 return;
2135 parameter[0] ='\0';
2136 parameter++;
2137 parameter[0] ='\0';
2138 parameter++;
2140 } else {
2141 parameter[0] ='\0';
2142 parameter++;
2143 parameter[0] ='\0';
2144 parameter++;
2145 parameter[0] ='\0';
2146 parameter++;
2148 base64_decode_inplace(parameter);
2151 if (strequal(request, "LANMAN-Challenge")) {
2152 challenge = strhex_to_data_blob(NULL, parameter);
2153 if (challenge.length != 8) {
2154 x_fprintf(x_stdout, "Error: hex decode of %s failed! (got %d bytes, expected 8)\n.\n",
2155 parameter,
2156 (int)challenge.length);
2157 challenge = data_blob_null;
2159 } else if (strequal(request, "NT-Response")) {
2160 nt_response = strhex_to_data_blob(NULL, parameter);
2161 if (nt_response.length < 24) {
2162 x_fprintf(x_stdout, "Error: hex decode of %s failed! (only got %d bytes, needed at least 24)\n.\n",
2163 parameter,
2164 (int)nt_response.length);
2165 nt_response = data_blob_null;
2167 } else if (strequal(request, "LANMAN-Response")) {
2168 lm_response = strhex_to_data_blob(NULL, parameter);
2169 if (lm_response.length != 24) {
2170 x_fprintf(x_stdout, "Error: hex decode of %s failed! (got %d bytes, expected 24)\n.\n",
2171 parameter,
2172 (int)lm_response.length);
2173 lm_response = data_blob_null;
2175 } else if (strequal(request, "Password")) {
2176 plaintext_password = smb_xstrdup(parameter);
2177 } else if (strequal(request, "NT-Domain")) {
2178 domain = smb_xstrdup(parameter);
2179 } else if (strequal(request, "Username")) {
2180 username = smb_xstrdup(parameter);
2181 } else if (strequal(request, "Full-Username")) {
2182 full_username = smb_xstrdup(parameter);
2183 } else if (strequal(request, "Request-User-Session-Key")) {
2184 ntlm_server_1_user_session_key = strequal(parameter, "Yes");
2185 } else if (strequal(request, "Request-LanMan-Session-Key")) {
2186 ntlm_server_1_lm_session_key = strequal(parameter, "Yes");
2187 } else {
2188 x_fprintf(x_stdout, "Error: Unknown request %s\n.\n", request);
2192 static void manage_ntlm_change_password_1_request(struct ntlm_auth_state *state,
2193 char *buf, int length)
2195 char *request, *parameter;
2196 static DATA_BLOB new_nt_pswd;
2197 static DATA_BLOB old_nt_hash_enc;
2198 static DATA_BLOB new_lm_pswd;
2199 static DATA_BLOB old_lm_hash_enc;
2200 static char *full_username = NULL;
2201 static char *username = NULL;
2202 static char *domain = NULL;
2203 static char *newpswd = NULL;
2204 static char *oldpswd = NULL;
2206 if (strequal(buf, ".")) {
2207 if(newpswd && oldpswd) {
2208 uchar old_nt_hash[16];
2209 uchar old_lm_hash[16];
2210 uchar new_nt_hash[16];
2211 uchar new_lm_hash[16];
2213 new_nt_pswd = data_blob(NULL, 516);
2214 old_nt_hash_enc = data_blob(NULL, 16);
2216 /* Calculate the MD4 hash (NT compatible) of the
2217 * password */
2218 E_md4hash(oldpswd, old_nt_hash);
2219 E_md4hash(newpswd, new_nt_hash);
2221 /* E_deshash returns false for 'long'
2222 passwords (> 14 DOS chars).
2224 Therefore, don't send a buffer
2225 encrypted with the truncated hash
2226 (it could allow an even easier
2227 attack on the password)
2229 Likewise, obey the admin's restriction
2232 if (lp_client_lanman_auth() &&
2233 E_deshash(newpswd, new_lm_hash) &&
2234 E_deshash(oldpswd, old_lm_hash)) {
2235 new_lm_pswd = data_blob(NULL, 516);
2236 old_lm_hash_enc = data_blob(NULL, 16);
2237 encode_pw_buffer(new_lm_pswd.data, newpswd,
2238 STR_UNICODE);
2240 arcfour_crypt(new_lm_pswd.data, old_nt_hash, 516);
2241 E_old_pw_hash(new_nt_hash, old_lm_hash,
2242 old_lm_hash_enc.data);
2243 } else {
2244 new_lm_pswd.data = NULL;
2245 new_lm_pswd.length = 0;
2246 old_lm_hash_enc.data = NULL;
2247 old_lm_hash_enc.length = 0;
2250 encode_pw_buffer(new_nt_pswd.data, newpswd,
2251 STR_UNICODE);
2253 arcfour_crypt(new_nt_pswd.data, old_nt_hash, 516);
2254 E_old_pw_hash(new_nt_hash, old_nt_hash,
2255 old_nt_hash_enc.data);
2258 if (!full_username && !username) {
2259 x_fprintf(x_stdout, "Error: No username supplied!\n");
2260 } else if ((!new_nt_pswd.data || !old_nt_hash_enc.data) &&
2261 (!new_lm_pswd.data || old_lm_hash_enc.data) ) {
2262 x_fprintf(x_stdout, "Error: No NT or LM password "
2263 "blobs supplied!\n");
2264 } else {
2265 char *error_string = NULL;
2267 if (full_username && !username) {
2268 fstring fstr_user;
2269 fstring fstr_domain;
2271 if (!parse_ntlm_auth_domain_user(full_username,
2272 fstr_user,
2273 fstr_domain)) {
2274 /* username might be 'tainted', don't
2275 * print into our new-line
2276 * deleimianted stream */
2277 x_fprintf(x_stdout, "Error: Could not "
2278 "parse into domain and "
2279 "username\n");
2280 SAFE_FREE(username);
2281 username = smb_xstrdup(full_username);
2282 } else {
2283 SAFE_FREE(username);
2284 SAFE_FREE(domain);
2285 username = smb_xstrdup(fstr_user);
2286 domain = smb_xstrdup(fstr_domain);
2291 if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
2292 username, domain,
2293 new_nt_pswd,
2294 old_nt_hash_enc,
2295 new_lm_pswd,
2296 old_lm_hash_enc,
2297 &error_string))) {
2298 x_fprintf(x_stdout, "Password-Change: No\n");
2299 x_fprintf(x_stdout, "Password-Change-Error: "
2300 "%s\n.\n", error_string);
2301 } else {
2302 x_fprintf(x_stdout, "Password-Change: Yes\n");
2305 SAFE_FREE(error_string);
2307 /* clear out the state */
2308 new_nt_pswd = data_blob_null;
2309 old_nt_hash_enc = data_blob_null;
2310 new_lm_pswd = data_blob_null;
2311 old_nt_hash_enc = data_blob_null;
2312 SAFE_FREE(full_username);
2313 SAFE_FREE(username);
2314 SAFE_FREE(domain);
2315 SAFE_FREE(newpswd);
2316 SAFE_FREE(oldpswd);
2317 x_fprintf(x_stdout, ".\n");
2319 return;
2322 request = buf;
2324 /* Indicates a base64 encoded structure */
2325 parameter = strstr_m(request, ":: ");
2326 if (!parameter) {
2327 parameter = strstr_m(request, ": ");
2329 if (!parameter) {
2330 DEBUG(0, ("Parameter not found!\n"));
2331 x_fprintf(x_stdout, "Error: Parameter not found!\n.\n");
2332 return;
2335 parameter[0] ='\0';
2336 parameter++;
2337 parameter[0] ='\0';
2338 parameter++;
2339 } else {
2340 parameter[0] ='\0';
2341 parameter++;
2342 parameter[0] ='\0';
2343 parameter++;
2344 parameter[0] ='\0';
2345 parameter++;
2347 base64_decode_inplace(parameter);
2350 if (strequal(request, "new-nt-password-blob")) {
2351 new_nt_pswd = strhex_to_data_blob(NULL, parameter);
2352 if (new_nt_pswd.length != 516) {
2353 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2354 "(got %d bytes, expected 516)\n.\n",
2355 parameter,
2356 (int)new_nt_pswd.length);
2357 new_nt_pswd = data_blob_null;
2359 } else if (strequal(request, "old-nt-hash-blob")) {
2360 old_nt_hash_enc = strhex_to_data_blob(NULL, parameter);
2361 if (old_nt_hash_enc.length != 16) {
2362 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2363 "(got %d bytes, expected 16)\n.\n",
2364 parameter,
2365 (int)old_nt_hash_enc.length);
2366 old_nt_hash_enc = data_blob_null;
2368 } else if (strequal(request, "new-lm-password-blob")) {
2369 new_lm_pswd = strhex_to_data_blob(NULL, parameter);
2370 if (new_lm_pswd.length != 516) {
2371 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2372 "(got %d bytes, expected 516)\n.\n",
2373 parameter,
2374 (int)new_lm_pswd.length);
2375 new_lm_pswd = data_blob_null;
2378 else if (strequal(request, "old-lm-hash-blob")) {
2379 old_lm_hash_enc = strhex_to_data_blob(NULL, parameter);
2380 if (old_lm_hash_enc.length != 16)
2382 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2383 "(got %d bytes, expected 16)\n.\n",
2384 parameter,
2385 (int)old_lm_hash_enc.length);
2386 old_lm_hash_enc = data_blob_null;
2388 } else if (strequal(request, "nt-domain")) {
2389 domain = smb_xstrdup(parameter);
2390 } else if(strequal(request, "username")) {
2391 username = smb_xstrdup(parameter);
2392 } else if(strequal(request, "full-username")) {
2393 username = smb_xstrdup(parameter);
2394 } else if(strequal(request, "new-password")) {
2395 newpswd = smb_xstrdup(parameter);
2396 } else if (strequal(request, "old-password")) {
2397 oldpswd = smb_xstrdup(parameter);
2398 } else {
2399 x_fprintf(x_stdout, "Error: Unknown request %s\n.\n", request);
2403 static void manage_squid_request(struct ntlm_auth_state *state,
2404 stdio_helper_function fn)
2406 char *buf;
2407 char tmp[INITIAL_BUFFER_SIZE+1];
2408 int length, buf_size = 0;
2409 char *c;
2411 buf = talloc_strdup(state->mem_ctx, "");
2412 if (!buf) {
2413 DEBUG(0, ("Failed to allocate input buffer.\n"));
2414 x_fprintf(x_stderr, "ERR\n");
2415 exit(1);
2418 do {
2420 /* this is not a typo - x_fgets doesn't work too well under
2421 * squid */
2422 if (fgets(tmp, sizeof(tmp)-1, stdin) == NULL) {
2423 if (ferror(stdin)) {
2424 DEBUG(1, ("fgets() failed! dying..... errno=%d "
2425 "(%s)\n", ferror(stdin),
2426 strerror(ferror(stdin))));
2428 exit(1);
2430 exit(0);
2433 buf = talloc_strdup_append_buffer(buf, tmp);
2434 buf_size += INITIAL_BUFFER_SIZE;
2436 if (buf_size > MAX_BUFFER_SIZE) {
2437 DEBUG(2, ("Oversized message\n"));
2438 x_fprintf(x_stderr, "ERR\n");
2439 talloc_free(buf);
2440 return;
2443 c = strchr(buf, '\n');
2444 } while (c == NULL);
2446 *c = '\0';
2447 length = c-buf;
2449 DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf,length));
2451 if (buf[0] == '\0') {
2452 DEBUG(2, ("Invalid Request\n"));
2453 x_fprintf(x_stderr, "ERR\n");
2454 talloc_free(buf);
2455 return;
2458 fn(state, buf, length);
2459 talloc_free(buf);
2463 static void squid_stream(enum stdio_helper_mode stdio_mode, stdio_helper_function fn) {
2464 TALLOC_CTX *mem_ctx;
2465 struct ntlm_auth_state *state;
2467 /* initialize FDescs */
2468 x_setbuf(x_stdout, NULL);
2469 x_setbuf(x_stderr, NULL);
2471 mem_ctx = talloc_init("ntlm_auth");
2472 if (!mem_ctx) {
2473 DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
2474 x_fprintf(x_stderr, "ERR\n");
2475 exit(1);
2478 state = talloc_zero(mem_ctx, struct ntlm_auth_state);
2479 if (!state) {
2480 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
2481 x_fprintf(x_stderr, "ERR\n");
2482 exit(1);
2485 state->mem_ctx = mem_ctx;
2486 state->helper_mode = stdio_mode;
2488 while(1) {
2489 TALLOC_CTX *frame = talloc_stackframe();
2490 manage_squid_request(state, fn);
2491 TALLOC_FREE(frame);
2496 /* Authenticate a user with a challenge/response */
2498 static bool check_auth_crap(void)
2500 NTSTATUS nt_status;
2501 uint32 flags = 0;
2502 char lm_key[8];
2503 char user_session_key[16];
2504 char *hex_lm_key;
2505 char *hex_user_session_key;
2506 char *error_string;
2507 static uint8 zeros[16];
2509 x_setbuf(x_stdout, NULL);
2511 if (request_lm_key)
2512 flags |= WBFLAG_PAM_LMKEY;
2514 if (request_user_session_key)
2515 flags |= WBFLAG_PAM_USER_SESSION_KEY;
2517 flags |= WBFLAG_PAM_NT_STATUS_SQUASH;
2519 nt_status = contact_winbind_auth_crap(opt_username, opt_domain,
2520 opt_workstation,
2521 &opt_challenge,
2522 &opt_lm_response,
2523 &opt_nt_response,
2524 flags,
2525 (unsigned char *)lm_key,
2526 (unsigned char *)user_session_key,
2527 &error_string, NULL);
2529 if (!NT_STATUS_IS_OK(nt_status)) {
2530 x_fprintf(x_stdout, "%s (0x%x)\n",
2531 error_string,
2532 NT_STATUS_V(nt_status));
2533 SAFE_FREE(error_string);
2534 return False;
2537 if (request_lm_key
2538 && (memcmp(zeros, lm_key,
2539 sizeof(lm_key)) != 0)) {
2540 hex_lm_key = hex_encode_talloc(talloc_tos(), (const unsigned char *)lm_key,
2541 sizeof(lm_key));
2542 x_fprintf(x_stdout, "LM_KEY: %s\n", hex_lm_key);
2543 TALLOC_FREE(hex_lm_key);
2545 if (request_user_session_key
2546 && (memcmp(zeros, user_session_key,
2547 sizeof(user_session_key)) != 0)) {
2548 hex_user_session_key = hex_encode_talloc(talloc_tos(), (const unsigned char *)user_session_key,
2549 sizeof(user_session_key));
2550 x_fprintf(x_stdout, "NT_KEY: %s\n", hex_user_session_key);
2551 TALLOC_FREE(hex_user_session_key);
2554 return True;
2557 /* Main program */
2559 enum {
2560 OPT_USERNAME = 1000,
2561 OPT_DOMAIN,
2562 OPT_WORKSTATION,
2563 OPT_CHALLENGE,
2564 OPT_RESPONSE,
2565 OPT_LM,
2566 OPT_NT,
2567 OPT_PASSWORD,
2568 OPT_LM_KEY,
2569 OPT_USER_SESSION_KEY,
2570 OPT_DIAGNOSTICS,
2571 OPT_REQUIRE_MEMBERSHIP,
2572 OPT_USE_CACHED_CREDS,
2573 OPT_PAM_WINBIND_CONF
2576 int main(int argc, const char **argv)
2578 TALLOC_CTX *frame = talloc_stackframe();
2579 int opt;
2580 static const char *helper_protocol;
2581 static int diagnostics;
2583 static const char *hex_challenge;
2584 static const char *hex_lm_response;
2585 static const char *hex_nt_response;
2587 poptContext pc;
2589 /* NOTE: DO NOT change this interface without considering the implications!
2590 This is an external interface, which other programs will use to interact
2591 with this helper.
2594 /* We do not use single-letter command abbreviations, because they harm future
2595 interface stability. */
2597 struct poptOption long_options[] = {
2598 POPT_AUTOHELP
2599 { "helper-protocol", 0, POPT_ARG_STRING, &helper_protocol, OPT_DOMAIN, "operate as a stdio-based helper", "helper protocol to use"},
2600 { "username", 0, POPT_ARG_STRING, &opt_username, OPT_USERNAME, "username"},
2601 { "domain", 0, POPT_ARG_STRING, &opt_domain, OPT_DOMAIN, "domain name"},
2602 { "workstation", 0, POPT_ARG_STRING, &opt_workstation, OPT_WORKSTATION, "workstation"},
2603 { "challenge", 0, POPT_ARG_STRING, &hex_challenge, OPT_CHALLENGE, "challenge (HEX encoded)"},
2604 { "lm-response", 0, POPT_ARG_STRING, &hex_lm_response, OPT_LM, "LM Response to the challenge (HEX encoded)"},
2605 { "nt-response", 0, POPT_ARG_STRING, &hex_nt_response, OPT_NT, "NT or NTLMv2 Response to the challenge (HEX encoded)"},
2606 { "password", 0, POPT_ARG_STRING, &opt_password, OPT_PASSWORD, "User's plaintext password"},
2607 { "request-lm-key", 0, POPT_ARG_NONE, &request_lm_key, OPT_LM_KEY, "Retrieve LM session key"},
2608 { "request-nt-key", 0, POPT_ARG_NONE, &request_user_session_key, OPT_USER_SESSION_KEY, "Retrieve User (NT) session key"},
2609 { "use-cached-creds", 0, POPT_ARG_NONE, &use_cached_creds, OPT_USE_CACHED_CREDS, "Use cached credentials if no password is given"},
2610 { "diagnostics", 0, POPT_ARG_NONE, &diagnostics,
2611 OPT_DIAGNOSTICS,
2612 "Perform diagnostics on the authentication chain"},
2613 { "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" },
2614 { "pam-winbind-conf", 0, POPT_ARG_STRING, &opt_pam_winbind_conf, OPT_PAM_WINBIND_CONF, "Require that request must set WBFLAG_PAM_CONTACT_TRUSTDOM when krb5 auth is required" },
2615 POPT_COMMON_CONFIGFILE
2616 POPT_COMMON_VERSION
2617 POPT_TABLEEND
2620 /* Samba client initialisation */
2621 load_case_tables();
2623 setup_logging("ntlm_auth", DEBUG_STDERR);
2625 /* Parse options */
2627 pc = poptGetContext("ntlm_auth", argc, argv, long_options, 0);
2629 /* Parse command line options */
2631 if (argc == 1) {
2632 poptPrintHelp(pc, stderr, 0);
2633 return 1;
2636 while((opt = poptGetNextOpt(pc)) != -1) {
2637 /* Get generic config options like --configfile */
2640 poptFreeContext(pc);
2642 if (!lp_load(get_dyn_CONFIGFILE(), True, False, False, True)) {
2643 d_fprintf(stderr, "ntlm_auth: error opening config file %s. Error was %s\n",
2644 get_dyn_CONFIGFILE(), strerror(errno));
2645 exit(1);
2648 pc = poptGetContext(NULL, argc, (const char **)argv, long_options,
2649 POPT_CONTEXT_KEEP_FIRST);
2651 while((opt = poptGetNextOpt(pc)) != -1) {
2652 switch (opt) {
2653 case OPT_CHALLENGE:
2654 opt_challenge = strhex_to_data_blob(NULL, hex_challenge);
2655 if (opt_challenge.length != 8) {
2656 x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n",
2657 hex_challenge,
2658 (int)opt_challenge.length);
2659 exit(1);
2661 break;
2662 case OPT_LM:
2663 opt_lm_response = strhex_to_data_blob(NULL, hex_lm_response);
2664 if (opt_lm_response.length != 24) {
2665 x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n",
2666 hex_lm_response,
2667 (int)opt_lm_response.length);
2668 exit(1);
2670 break;
2672 case OPT_NT:
2673 opt_nt_response = strhex_to_data_blob(NULL, hex_nt_response);
2674 if (opt_nt_response.length < 24) {
2675 x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n",
2676 hex_nt_response,
2677 (int)opt_nt_response.length);
2678 exit(1);
2680 break;
2682 case OPT_REQUIRE_MEMBERSHIP:
2683 if (strncasecmp_m("S-", require_membership_of, 2) == 0) {
2684 require_membership_of_sid = require_membership_of;
2686 break;
2690 if (opt_username) {
2691 char *domain = SMB_STRDUP(opt_username);
2692 char *p = strchr_m(domain, *lp_winbind_separator());
2693 if (p) {
2694 opt_username = p+1;
2695 *p = '\0';
2696 if (opt_domain && !strequal(opt_domain, domain)) {
2697 x_fprintf(x_stderr, "Domain specified in username (%s) "
2698 "doesn't match specified domain (%s)!\n\n",
2699 domain, opt_domain);
2700 poptPrintHelp(pc, stderr, 0);
2701 exit(1);
2703 opt_domain = domain;
2704 } else {
2705 SAFE_FREE(domain);
2709 /* Note: if opt_domain is "" then send no domain */
2710 if (opt_domain == NULL) {
2711 opt_domain = get_winbind_domain();
2714 if (opt_workstation == NULL) {
2715 opt_workstation = "";
2718 if (helper_protocol) {
2719 int i;
2720 for (i=0; i<NUM_HELPER_MODES; i++) {
2721 if (strcmp(helper_protocol, stdio_helper_protocols[i].name) == 0) {
2722 squid_stream(stdio_helper_protocols[i].mode, stdio_helper_protocols[i].fn);
2723 exit(0);
2726 x_fprintf(x_stderr, "unknown helper protocol [%s]\n\nValid helper protools:\n\n", helper_protocol);
2728 for (i=0; i<NUM_HELPER_MODES; i++) {
2729 x_fprintf(x_stderr, "%s\n", stdio_helper_protocols[i].name);
2732 exit(1);
2735 if (!opt_username || !*opt_username) {
2736 x_fprintf(x_stderr, "username must be specified!\n\n");
2737 poptPrintHelp(pc, stderr, 0);
2738 exit(1);
2741 if (opt_challenge.length) {
2742 if (!check_auth_crap()) {
2743 exit(1);
2745 exit(0);
2748 if (!opt_password) {
2749 opt_password = getpass("password: ");
2752 if (diagnostics) {
2753 if (!diagnose_ntlm_auth()) {
2754 return 1;
2756 } else {
2757 fstring user;
2759 fstr_sprintf(user, "%s%c%s", opt_domain, winbind_separator(), opt_username);
2760 if (!check_plaintext_auth(user, opt_password, True)) {
2761 return 1;
2765 /* Exit code */
2767 poptFreeContext(pc);
2768 TALLOC_FREE(frame);
2769 return 0;