gp: Fix startup scripts add not always set runonce
[Samba.git] / source3 / utils / ntlm_auth.c
blob34f96526d3f94ebef1214553590e14fb9834d4d5
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
11 Copyright (C) Simo Sorce 2010
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 3 of the License, or
16 (at your option) any later version.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include "includes.h"
28 #include "lib/param/param.h"
29 #include "lib/cmdline/cmdline.h"
30 #include "libcli/security/security.h"
31 #include "utils/ntlm_auth.h"
32 #include "../libcli/auth/libcli_auth.h"
33 #include "auth/ntlmssp/ntlmssp.h"
34 #include "auth/gensec/gensec.h"
35 #include "auth/gensec/gensec_internal.h"
36 #include "auth/credentials/credentials.h"
37 #include "librpc/crypto/gse.h"
38 #include "smb_krb5.h"
39 #include "lib/util/tiniparser.h"
40 #include "librpc/gen_ndr/krb5pac.h"
41 #include "auth/common_auth.h"
42 #include "source3/include/auth.h"
43 #include "source3/auth/proto.h"
44 #include "nsswitch/libwbclient/wbclient.h"
45 #include "nsswitch/winbind_struct_protocol.h"
46 #include "nsswitch/libwbclient/wbclient_internal.h"
47 #include "lib/param/loadparm.h"
48 #include "lib/util/base64.h"
49 #include "cmdline_contexts.h"
50 #include "lib/util/tevent_ntstatus.h"
51 #include "lib/util/string_wrappers.h"
53 #include <gnutls/gnutls.h>
54 #include <gnutls/crypto.h>
56 #ifdef HAVE_KRB5
57 #include "auth/kerberos/pac_utils.h"
58 #endif
60 #ifndef PAM_WINBIND_CONFIG_FILE
61 #define PAM_WINBIND_CONFIG_FILE "/etc/security/pam_winbind.conf"
62 #endif
64 #define WINBIND_KRB5_AUTH 0x00000080
66 #undef DBGC_CLASS
67 #define DBGC_CLASS DBGC_WINBIND
69 #define INITIAL_BUFFER_SIZE 300
70 #define MAX_BUFFER_SIZE 630000
72 enum stdio_helper_mode {
73 SQUID_2_4_BASIC,
74 SQUID_2_5_BASIC,
75 SQUID_2_5_NTLMSSP,
76 NTLMSSP_CLIENT_1,
77 GSS_SPNEGO_SERVER,
78 GSS_SPNEGO_CLIENT,
79 NTLM_SERVER_1,
80 NTLM_CHANGE_PASSWORD_1,
81 NUM_HELPER_MODES
84 enum ntlm_auth_cli_state {
85 CLIENT_INITIAL = 0,
86 CLIENT_RESPONSE,
87 CLIENT_FINISHED,
88 CLIENT_ERROR
91 struct ntlm_auth_state {
92 TALLOC_CTX *mem_ctx;
93 enum stdio_helper_mode helper_mode;
94 enum ntlm_auth_cli_state cli_state;
95 struct ntlmssp_state *ntlmssp_state;
96 uint32_t neg_flags;
97 char *want_feature_list;
98 bool have_session_key;
99 DATA_BLOB session_key;
100 DATA_BLOB initial_message;
101 void *gensec_private_1;
103 typedef void (*stdio_helper_function)(enum stdio_helper_mode stdio_helper_mode,
104 struct loadparm_context *lp_ctx,
105 struct ntlm_auth_state *state, char *buf,
106 int length, void **private2);
108 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
109 struct loadparm_context *lp_ctx,
110 char *buf, int length, void **private1);
112 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode,
113 struct loadparm_context *lp_ctx,
114 struct ntlm_auth_state *state,
115 stdio_helper_function fn, void **private2);
117 static void manage_squid_basic_request (enum stdio_helper_mode stdio_helper_mode,
118 struct loadparm_context *lp_ctx,
119 struct ntlm_auth_state *state,
120 char *buf, int length, void **private2);
122 static void manage_squid_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode,
123 struct loadparm_context *lp_ctx,
124 struct ntlm_auth_state *state,
125 char *buf, int length, void **private2);
127 static void manage_client_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode,
128 struct loadparm_context *lp_ctx,
129 struct ntlm_auth_state *state,
130 char *buf, int length, void **private2);
132 static void manage_gss_spnego_request (enum stdio_helper_mode stdio_helper_mode,
133 struct loadparm_context *lp_ctx,
134 struct ntlm_auth_state *state,
135 char *buf, int length, void **private2);
137 static void manage_gss_spnego_client_request (enum stdio_helper_mode stdio_helper_mode,
138 struct loadparm_context *lp_ctx,
139 struct ntlm_auth_state *state,
140 char *buf, int length, void **private2);
142 static void manage_ntlm_server_1_request (enum stdio_helper_mode stdio_helper_mode,
143 struct loadparm_context *lp_ctx,
144 struct ntlm_auth_state *state,
145 char *buf, int length, void **private2);
147 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode,
148 struct loadparm_context *lp_ctx,
149 struct ntlm_auth_state *state,
150 char *buf, int length, void **private2);
152 static const struct {
153 enum stdio_helper_mode mode;
154 const char *name;
155 stdio_helper_function fn;
156 } stdio_helper_protocols[] = {
157 { SQUID_2_4_BASIC, "squid-2.4-basic", manage_squid_basic_request},
158 { SQUID_2_5_BASIC, "squid-2.5-basic", manage_squid_basic_request},
159 { SQUID_2_5_NTLMSSP, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request},
160 { NTLMSSP_CLIENT_1, "ntlmssp-client-1", manage_client_ntlmssp_request},
161 { GSS_SPNEGO_SERVER, "gss-spnego", manage_gss_spnego_request},
162 { GSS_SPNEGO_CLIENT, "gss-spnego-client", manage_gss_spnego_client_request},
163 { NTLM_SERVER_1, "ntlm-server-1", manage_ntlm_server_1_request},
164 { NTLM_CHANGE_PASSWORD_1, "ntlm-change-password-1", manage_ntlm_change_password_1_request},
165 { NUM_HELPER_MODES, NULL, NULL}
168 const char *opt_username;
169 const char *opt_domain;
170 const char *opt_workstation;
171 const char *opt_password;
172 static DATA_BLOB opt_challenge;
173 static DATA_BLOB opt_lm_response;
174 static DATA_BLOB opt_nt_response;
175 static int request_lm_key;
176 static int request_user_session_key;
177 static int use_cached_creds;
178 static int offline_logon;
179 static int opt_allow_mschapv2;
181 static const char *require_membership_of;
182 static const char *require_membership_of_sid;
183 static const char *opt_pam_winbind_conf;
185 const char *opt_target_service;
186 const char *opt_target_hostname;
189 /* This is a bit hairy, but the basic idea is to do a password callback
190 to the calling application. The callback comes from within gensec */
192 static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mode,
193 struct loadparm_context *lp_ctx,
194 struct ntlm_auth_state *state, char *buf, int length,
195 void **password)
197 DATA_BLOB in;
198 if (strlen(buf) < 2) {
199 DEBUG(1, ("query [%s] invalid", buf));
200 printf("BH Query invalid\n");
201 return;
204 if (strlen(buf) > 3) {
205 in = base64_decode_data_blob(buf + 3);
206 } else {
207 in = data_blob(NULL, 0);
210 if (strncmp(buf, "PW ", 3) == 0) {
212 *password = talloc_strndup(NULL,
213 (const char *)in.data, in.length);
215 if (*password == NULL) {
216 DEBUG(1, ("Out of memory\n"));
217 printf("BH Out of memory\n");
218 data_blob_free(&in);
219 return;
222 printf("OK\n");
223 data_blob_free(&in);
224 return;
226 DEBUG(1, ("Asked for (and expected) a password\n"));
227 printf("BH Expected a password\n");
228 data_blob_free(&in);
232 * Callback for password credentials. This is not async, and when
233 * GENSEC and the credentials code is made async, it will look rather
234 * different.
237 static const char *get_password(struct cli_credentials *credentials)
239 TALLOC_CTX *frame = talloc_stackframe();
240 char *password = NULL;
241 struct ntlm_auth_state *state;
243 state = talloc_zero(frame, struct ntlm_auth_state);
244 if (state == NULL) {
245 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
246 fprintf(stderr, "ERR\n");
247 exit(1);
250 state->mem_ctx = state;
252 /* Ask for a password */
253 printf("PW\n");
255 manage_squid_request(NUM_HELPER_MODES /* bogus */, NULL, state, manage_gensec_get_pw_request, (void **)&password);
256 talloc_steal(credentials, password);
257 TALLOC_FREE(frame);
258 return password;
262 * A limited set of features are defined with text strings as needed
263 * by ntlm_auth
266 static void gensec_want_feature_list(struct gensec_security *state, char* feature_list)
268 if (in_list("NTLMSSP_FEATURE_SESSION_KEY", feature_list, true)) {
269 DEBUG(10, ("want GENSEC_FEATURE_SESSION_KEY\n"));
270 gensec_want_feature(state, GENSEC_FEATURE_SESSION_KEY);
272 if (in_list("NTLMSSP_FEATURE_SIGN", feature_list, true)) {
273 DEBUG(10, ("want GENSEC_FEATURE_SIGN\n"));
274 gensec_want_feature(state, GENSEC_FEATURE_SIGN);
276 if (in_list("NTLMSSP_FEATURE_SEAL", feature_list, true)) {
277 DEBUG(10, ("want GENSEC_FEATURE_SEAL\n"));
278 gensec_want_feature(state, GENSEC_FEATURE_SEAL);
280 if (in_list("NTLMSSP_FEATURE_CCACHE", feature_list, true)) {
281 DEBUG(10, ("want GENSEC_FEATURE_NTLM_CCACHE\n"));
282 gensec_want_feature(state, GENSEC_FEATURE_NTLM_CCACHE);
286 static char winbind_separator(void)
288 struct wbcInterfaceDetails *details;
289 wbcErr ret;
290 static bool got_sep;
291 static char sep;
293 if (got_sep)
294 return sep;
296 ret = wbcInterfaceDetails(&details);
297 if (!WBC_ERROR_IS_OK(ret)) {
298 d_fprintf(stderr, "could not obtain winbind separator!\n");
299 return *lp_winbind_separator();
302 sep = details->winbind_separator;
304 wbcFreeMemory(details);
306 got_sep = True;
308 if (!sep) {
309 d_fprintf(stderr, "winbind separator was NULL!\n");
310 return *lp_winbind_separator();
313 return sep;
316 const char *get_winbind_domain(void)
318 struct wbcInterfaceDetails *details;
319 wbcErr ret;
321 static fstring winbind_domain;
322 if (*winbind_domain) {
323 return winbind_domain;
326 /* Send off request */
328 ret = wbcInterfaceDetails(&details);
329 if (!WBC_ERROR_IS_OK(ret)) {
330 DEBUG(1, ("could not obtain winbind domain name!\n"));
331 return lp_workgroup();
334 fstrcpy(winbind_domain, details->netbios_domain);
336 wbcFreeMemory(details);
338 return winbind_domain;
342 const char *get_winbind_netbios_name(void)
344 struct wbcInterfaceDetails *details;
345 wbcErr ret;
347 static fstring winbind_netbios_name;
349 if (*winbind_netbios_name) {
350 return winbind_netbios_name;
353 /* Send off request */
355 ret = wbcInterfaceDetails(&details);
356 if (!WBC_ERROR_IS_OK(ret)) {
357 DEBUG(1, ("could not obtain winbind netbios name!\n"));
358 return lp_netbios_name();
361 fstrcpy(winbind_netbios_name, details->netbios_name);
363 wbcFreeMemory(details);
365 return winbind_netbios_name;
369 DATA_BLOB get_challenge(void)
371 static DATA_BLOB chal;
372 if (opt_challenge.length)
373 return opt_challenge;
375 chal = data_blob(NULL, 8);
377 generate_random_buffer(chal.data, chal.length);
378 return chal;
381 /* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
382 form DOMAIN/user into a domain and a user */
384 static bool parse_ntlm_auth_domain_user(const char *domuser, fstring domain,
385 fstring user)
388 char *p = strchr(domuser,winbind_separator());
390 if (!p) {
391 return False;
394 fstrcpy(user, p+1);
395 fstrcpy(domain, domuser);
396 domain[PTR_DIFF(p, domuser)] = 0;
397 return strupper_m(domain);
400 static bool get_require_membership_sid(void) {
401 fstring domain, name, sidbuf;
402 struct wbcDomainSid sid;
403 enum wbcSidType type;
404 wbcErr ret;
406 if (!require_membership_of) {
407 return True;
410 if (require_membership_of_sid) {
411 return True;
414 /* Otherwise, ask winbindd for the name->sid request */
416 if (!parse_ntlm_auth_domain_user(require_membership_of,
417 domain, name)) {
418 DEBUG(0, ("Could not parse %s into separate domain/name parts!\n",
419 require_membership_of));
420 return False;
423 ret = wbcLookupName(domain, name, &sid, &type);
424 if (!WBC_ERROR_IS_OK(ret)) {
425 DEBUG(0, ("Winbindd lookupname failed to resolve %s into a SID!\n",
426 require_membership_of));
427 return False;
430 wbcSidToStringBuf(&sid, sidbuf, sizeof(sidbuf));
432 require_membership_of_sid = SMB_STRDUP(sidbuf);
434 if (require_membership_of_sid)
435 return True;
437 return False;
441 * Get some configuration from pam_winbind.conf to see if we
442 * need to contact trusted domain
445 int get_pam_winbind_config(void)
447 int ctrl = 0;
448 struct tiniparser_dictionary *d = NULL;
450 if (!opt_pam_winbind_conf || !*opt_pam_winbind_conf) {
451 opt_pam_winbind_conf = PAM_WINBIND_CONFIG_FILE;
454 d = tiniparser_load(opt_pam_winbind_conf);
456 if (!d) {
457 return 0;
460 if (tiniparser_getboolean(d, "global:krb5_auth", false)) {
461 ctrl |= WINBIND_KRB5_AUTH;
464 tiniparser_freedict(d);
466 return ctrl;
469 /* Authenticate a user with a plaintext password */
471 static bool check_plaintext_auth(const char *user, const char *pass,
472 bool stdout_diagnostics)
474 struct winbindd_request request;
475 struct winbindd_response response;
476 wbcErr ret;
478 if (!get_require_membership_sid()) {
479 return False;
482 /* Send off request */
484 ZERO_STRUCT(request);
485 ZERO_STRUCT(response);
487 fstrcpy(request.data.auth.user, user);
488 fstrcpy(request.data.auth.pass, pass);
489 if (require_membership_of_sid) {
490 strlcpy(request.data.auth.require_membership_of_sid,
491 require_membership_of_sid,
492 sizeof(request.data.auth.require_membership_of_sid));
495 if (offline_logon) {
496 request.flags |= WBFLAG_PAM_CACHED_LOGIN;
499 ret = wbcRequestResponse(NULL, WINBINDD_PAM_AUTH,
500 &request, &response);
502 /* Display response */
504 if (stdout_diagnostics) {
505 if (!WBC_ERROR_IS_OK(ret) && (response.data.auth.nt_status == 0)) {
506 d_fprintf(stderr, "Reading winbind reply failed! (0x01)\n");
509 d_printf("%s: %s (0x%x)\n",
510 response.data.auth.nt_status_string,
511 response.data.auth.error_string,
512 response.data.auth.nt_status);
513 } else {
514 if (!WBC_ERROR_IS_OK(ret) && (response.data.auth.nt_status == 0)) {
515 DEBUG(1, ("Reading winbind reply failed! (0x01)\n"));
518 DEBUG(3, ("%s: %s (0x%x)\n",
519 response.data.auth.nt_status_string,
520 response.data.auth.error_string,
521 response.data.auth.nt_status));
524 return WBC_ERROR_IS_OK(ret);
527 /* authenticate a user with an encrypted username/password */
529 NTSTATUS contact_winbind_auth_crap(const char *username,
530 const char *domain,
531 const char *workstation,
532 const DATA_BLOB *challenge,
533 const DATA_BLOB *lm_response,
534 const DATA_BLOB *nt_response,
535 uint32_t flags,
536 uint32_t extra_logon_parameters,
537 uint8_t lm_key[8],
538 uint8_t user_session_key[16],
539 uint8_t *pauthoritative,
540 char **error_string,
541 char **unix_name)
543 NTSTATUS nt_status;
544 wbcErr ret;
545 struct winbindd_request request;
546 struct winbindd_response response;
548 *pauthoritative = 1;
550 if (!get_require_membership_sid()) {
551 return NT_STATUS_INVALID_PARAMETER;
554 ZERO_STRUCT(request);
555 ZERO_STRUCT(response);
557 request.flags = flags;
559 request.data.auth_crap.logon_parameters = extra_logon_parameters
560 | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT | MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT;
562 if (opt_allow_mschapv2) {
563 request.data.auth_crap.logon_parameters |= MSV1_0_ALLOW_MSVCHAPV2;
566 if (require_membership_of_sid)
567 fstrcpy(request.data.auth_crap.require_membership_of_sid, require_membership_of_sid);
569 fstrcpy(request.data.auth_crap.user, username);
570 fstrcpy(request.data.auth_crap.domain, domain);
572 fstrcpy(request.data.auth_crap.workstation,
573 workstation);
575 memcpy(request.data.auth_crap.chal, challenge->data, MIN(challenge->length, 8));
577 if (lm_response && lm_response->length) {
578 memcpy(request.data.auth_crap.lm_resp,
579 lm_response->data,
580 MIN(lm_response->length, sizeof(request.data.auth_crap.lm_resp)));
581 request.data.auth_crap.lm_resp_len = lm_response->length;
584 if (nt_response && nt_response->length) {
585 if (nt_response->length > sizeof(request.data.auth_crap.nt_resp)) {
586 request.flags = request.flags | WBFLAG_BIG_NTLMV2_BLOB;
587 request.extra_len = nt_response->length;
588 request.extra_data.data = SMB_MALLOC_ARRAY(char, request.extra_len);
589 if (request.extra_data.data == NULL) {
590 return NT_STATUS_NO_MEMORY;
592 memcpy(request.extra_data.data, nt_response->data,
593 nt_response->length);
595 } else {
596 memcpy(request.data.auth_crap.nt_resp,
597 nt_response->data, nt_response->length);
599 request.data.auth_crap.nt_resp_len = nt_response->length;
602 ret = wbcRequestResponsePriv(
603 NULL,
604 WINBINDD_PAM_AUTH_CRAP,
605 &request,
606 &response);
607 SAFE_FREE(request.extra_data.data);
609 /* Display response */
611 if (!WBC_ERROR_IS_OK(ret) && (response.data.auth.nt_status == 0)) {
612 nt_status = NT_STATUS_UNSUCCESSFUL;
613 if (error_string)
614 *error_string = smb_xstrdup("Reading winbind reply failed!");
615 winbindd_free_response(&response);
616 return nt_status;
619 nt_status = (NT_STATUS(response.data.auth.nt_status));
620 if (!NT_STATUS_IS_OK(nt_status)) {
621 if (error_string)
622 *error_string = smb_xstrdup(response.data.auth.error_string);
623 *pauthoritative = response.data.auth.authoritative;
624 winbindd_free_response(&response);
625 return nt_status;
628 if ((flags & WBFLAG_PAM_LMKEY) && lm_key) {
629 memcpy(lm_key, response.data.auth.first_8_lm_hash,
630 sizeof(response.data.auth.first_8_lm_hash));
632 if ((flags & WBFLAG_PAM_USER_SESSION_KEY) && user_session_key) {
633 memcpy(user_session_key, response.data.auth.user_session_key,
634 sizeof(response.data.auth.user_session_key));
637 if (flags & WBFLAG_PAM_UNIX_NAME) {
638 *unix_name = SMB_STRDUP(response.data.auth.unix_username);
639 if (!*unix_name) {
640 winbindd_free_response(&response);
641 return NT_STATUS_NO_MEMORY;
645 winbindd_free_response(&response);
646 return nt_status;
649 /* contact server to change user password using auth crap */
650 static NTSTATUS contact_winbind_change_pswd_auth_crap(const char *username,
651 const char *domain,
652 const DATA_BLOB new_nt_pswd,
653 const DATA_BLOB old_nt_hash_enc,
654 const DATA_BLOB new_lm_pswd,
655 const DATA_BLOB old_lm_hash_enc,
656 char **error_string)
658 NTSTATUS nt_status;
659 wbcErr ret;
660 struct winbindd_request request;
661 struct winbindd_response response;
663 if (!get_require_membership_sid())
665 if(error_string)
666 *error_string = smb_xstrdup("Can't get membership sid.");
667 return NT_STATUS_INVALID_PARAMETER;
670 ZERO_STRUCT(request);
671 ZERO_STRUCT(response);
673 if(username != NULL)
674 fstrcpy(request.data.chng_pswd_auth_crap.user, username);
675 if(domain != NULL)
676 fstrcpy(request.data.chng_pswd_auth_crap.domain,domain);
678 if(new_nt_pswd.length)
680 memcpy(request.data.chng_pswd_auth_crap.new_nt_pswd, new_nt_pswd.data, sizeof(request.data.chng_pswd_auth_crap.new_nt_pswd));
681 request.data.chng_pswd_auth_crap.new_nt_pswd_len = new_nt_pswd.length;
684 if(old_nt_hash_enc.length)
686 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));
687 request.data.chng_pswd_auth_crap.old_nt_hash_enc_len = old_nt_hash_enc.length;
690 if(new_lm_pswd.length)
692 memcpy(request.data.chng_pswd_auth_crap.new_lm_pswd, new_lm_pswd.data, sizeof(request.data.chng_pswd_auth_crap.new_lm_pswd));
693 request.data.chng_pswd_auth_crap.new_lm_pswd_len = new_lm_pswd.length;
696 if(old_lm_hash_enc.length)
698 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));
699 request.data.chng_pswd_auth_crap.old_lm_hash_enc_len = old_lm_hash_enc.length;
702 ret = wbcRequestResponse(NULL, WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP,
703 &request, &response);
705 /* Display response */
707 if (!WBC_ERROR_IS_OK(ret) && (response.data.auth.nt_status == 0))
709 nt_status = NT_STATUS_UNSUCCESSFUL;
710 if (error_string)
711 *error_string = smb_xstrdup("Reading winbind reply failed!");
712 winbindd_free_response(&response);
713 return nt_status;
716 nt_status = (NT_STATUS(response.data.auth.nt_status));
717 if (!NT_STATUS_IS_OK(nt_status))
719 if (error_string)
720 *error_string = smb_xstrdup(response.data.auth.error_string);
721 winbindd_free_response(&response);
722 return nt_status;
725 winbindd_free_response(&response);
727 return nt_status;
730 static NTSTATUS ntlm_auth_generate_session_info(struct auth4_context *auth_context,
731 TALLOC_CTX *mem_ctx,
732 void *server_returned_info,
733 const char *original_user_name,
734 uint32_t session_info_flags,
735 struct auth_session_info **session_info_out)
737 const char *unix_username = (const char *)server_returned_info;
738 struct dom_sid *sids = NULL;
739 struct auth_session_info *session_info = NULL;
741 session_info = talloc_zero(mem_ctx, struct auth_session_info);
742 if (session_info == NULL) {
743 return NT_STATUS_NO_MEMORY;
746 session_info->unix_info = talloc_zero(session_info, struct auth_user_info_unix);
747 if (session_info->unix_info == NULL) {
748 TALLOC_FREE(session_info);
749 return NT_STATUS_NO_MEMORY;
751 session_info->unix_info->unix_name = talloc_strdup(session_info->unix_info,
752 unix_username);
753 if (session_info->unix_info->unix_name == NULL) {
754 TALLOC_FREE(session_info);
755 return NT_STATUS_NO_MEMORY;
758 session_info->security_token = talloc_zero(session_info, struct security_token);
759 if (session_info->security_token == NULL) {
760 TALLOC_FREE(session_info);
761 return NT_STATUS_NO_MEMORY;
764 sids = talloc_zero_array(session_info->security_token,
765 struct dom_sid, 3);
766 if (sids == NULL) {
767 TALLOC_FREE(session_info);
768 return NT_STATUS_NO_MEMORY;
770 sid_copy(&sids[0], &global_sid_World);
771 sid_copy(&sids[1], &global_sid_Network);
772 sid_copy(&sids[2], &global_sid_Authenticated_Users);
774 session_info->security_token->num_sids = talloc_array_length(sids);
775 session_info->security_token->sids = sids;
777 *session_info_out = session_info;
779 return NT_STATUS_OK;
782 static NTSTATUS ntlm_auth_generate_session_info_pac(struct auth4_context *auth_ctx,
783 TALLOC_CTX *mem_ctx,
784 struct smb_krb5_context *smb_krb5_context,
785 DATA_BLOB *pac_blob,
786 const char *princ_name,
787 const struct tsocket_address *remote_address,
788 uint32_t session_info_flags,
789 struct auth_session_info **session_info)
791 TALLOC_CTX *tmp_ctx;
792 struct PAC_LOGON_INFO *logon_info = NULL;
793 char *unixuser;
794 NTSTATUS status;
795 const char *domain = "";
796 const char *user = "";
798 tmp_ctx = talloc_new(mem_ctx);
799 if (!tmp_ctx) {
800 return NT_STATUS_NO_MEMORY;
803 if (pac_blob) {
804 #ifdef HAVE_KRB5
805 status = kerberos_pac_logon_info(tmp_ctx, *pac_blob, NULL, NULL,
806 NULL, NULL, 0, &logon_info);
807 #else
808 status = NT_STATUS_ACCESS_DENIED;
809 #endif
810 if (!NT_STATUS_IS_OK(status)) {
811 goto done;
813 } else {
814 status = NT_STATUS_ACCESS_DENIED;
815 DBG_WARNING("Kerberos ticket for[%s] has no PAC: %s\n",
816 princ_name, nt_errstr(status));
817 goto done;
820 if (logon_info->info3.base.account_name.string != NULL) {
821 user = logon_info->info3.base.account_name.string;
822 } else {
823 user = "";
825 if (logon_info->info3.base.logon_domain.string != NULL) {
826 domain = logon_info->info3.base.logon_domain.string;
827 } else {
828 domain = "";
831 if (strlen(user) == 0 || strlen(domain) == 0) {
832 status = NT_STATUS_ACCESS_DENIED;
833 DBG_WARNING("Kerberos ticket for[%s] has invalid "
834 "account_name[%s]/logon_domain[%s]: %s\n",
835 princ_name,
836 logon_info->info3.base.account_name.string,
837 logon_info->info3.base.logon_domain.string,
838 nt_errstr(status));
839 goto done;
842 DBG_NOTICE("Kerberos ticket principal name is [%s] "
843 "account_name[%s]/logon_domain[%s]\n",
844 princ_name, user, domain);
846 if (!strequal(domain, lp_workgroup())) {
847 if (!lp_allow_trusted_domains()) {
848 status = NT_STATUS_LOGON_FAILURE;
849 goto done;
853 unixuser = talloc_asprintf(tmp_ctx, "%s%c%s", domain, winbind_separator(), user);
854 if (!unixuser) {
855 status = NT_STATUS_NO_MEMORY;
856 goto done;
859 status = ntlm_auth_generate_session_info(auth_ctx, mem_ctx, unixuser, NULL, session_info_flags, session_info);
861 done:
862 TALLOC_FREE(tmp_ctx);
863 return status;
869 * Return the challenge as determined by the authentication subsystem
870 * @return an 8 byte random challenge
873 static NTSTATUS ntlm_auth_get_challenge(struct auth4_context *auth_ctx,
874 uint8_t chal[8])
876 if (auth_ctx->challenge.data.length == 8) {
877 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
878 auth_ctx->challenge.set_by));
879 memcpy(chal, auth_ctx->challenge.data.data, 8);
880 return NT_STATUS_OK;
883 if (!auth_ctx->challenge.set_by) {
884 generate_random_buffer(chal, 8);
886 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
887 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
888 auth_ctx->challenge.set_by = "random";
891 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
892 auth_ctx->challenge.set_by));
894 return NT_STATUS_OK;
898 * NTLM2 authentication modifies the effective challenge,
899 * @param challenge The new challenge value
901 static NTSTATUS ntlm_auth_set_challenge(struct auth4_context *auth_ctx, const uint8_t chal[8], const char *set_by)
903 auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
904 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
906 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
907 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
909 return NT_STATUS_OK;
913 * Check the password on an NTLMSSP login.
915 * Return the session keys used on the connection.
918 struct winbind_pw_check_state {
919 uint8_t authoritative;
920 void *server_info;
921 DATA_BLOB nt_session_key;
922 DATA_BLOB lm_session_key;
925 static struct tevent_req *winbind_pw_check_send(
926 TALLOC_CTX *mem_ctx,
927 struct tevent_context *ev,
928 struct auth4_context *auth4_context,
929 const struct auth_usersupplied_info *user_info)
931 struct tevent_req *req = NULL;
932 struct winbind_pw_check_state *state = NULL;
933 NTSTATUS nt_status;
934 char *error_string = NULL;
935 uint8_t lm_key[8];
936 uint8_t user_sess_key[16];
937 char *unix_name = NULL;
939 req = tevent_req_create(
940 mem_ctx, &state, struct winbind_pw_check_state);
941 if (req == NULL) {
942 return NULL;
945 nt_status = contact_winbind_auth_crap(
946 user_info->client.account_name,
947 user_info->client.domain_name,
948 user_info->workstation_name,
949 &auth4_context->challenge.data,
950 &user_info->password.response.lanman,
951 &user_info->password.response.nt,
952 WBFLAG_PAM_LMKEY |
953 WBFLAG_PAM_USER_SESSION_KEY |
954 WBFLAG_PAM_UNIX_NAME,
956 lm_key, user_sess_key,
957 &state->authoritative,
958 &error_string,
959 &unix_name);
961 if (tevent_req_nterror(req, nt_status)) {
962 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) {
963 DBG_ERR("Login for user [%s]\\[%s]@[%s] failed due "
964 "to [%s]\n",
965 user_info->client.domain_name,
966 user_info->client.account_name,
967 user_info->workstation_name,
968 error_string ?
969 error_string :
970 "unknown error (NULL)");
971 } else {
972 DBG_NOTICE("Login for user [%s]\\[%s]@[%s] failed due "
973 "to [%s]\n",
974 user_info->client.domain_name,
975 user_info->client.account_name,
976 user_info->workstation_name,
977 error_string ?
978 error_string :
979 "unknown error (NULL)");
981 goto done;
984 if (!all_zero(lm_key, 8)) {
985 state->lm_session_key = data_blob_talloc(state, NULL, 16);
986 if (tevent_req_nomem(state->lm_session_key.data, req)) {
987 goto done;
989 memcpy(state->lm_session_key.data, lm_key, 8);
990 memset(state->lm_session_key.data+8, '\0', 8);
992 if (!all_zero(user_sess_key, 16)) {
993 state->nt_session_key = data_blob_talloc(
994 state, user_sess_key, 16);
995 if (tevent_req_nomem(state->nt_session_key.data, req)) {
996 goto done;
999 state->server_info = talloc_strdup(state, unix_name);
1000 if (tevent_req_nomem(state->server_info, req)) {
1001 goto done;
1003 tevent_req_done(req);
1005 done:
1006 SAFE_FREE(error_string);
1007 SAFE_FREE(unix_name);
1008 return tevent_req_post(req, ev);
1011 static NTSTATUS winbind_pw_check_recv(struct tevent_req *req,
1012 TALLOC_CTX *mem_ctx,
1013 uint8_t *pauthoritative,
1014 void **server_returned_info,
1015 DATA_BLOB *nt_session_key,
1016 DATA_BLOB *lm_session_key)
1018 struct winbind_pw_check_state *state = tevent_req_data(
1019 req, struct winbind_pw_check_state);
1020 NTSTATUS status;
1022 if (pauthoritative != NULL) {
1023 *pauthoritative = state->authoritative;
1026 if (tevent_req_is_nterror(req, &status)) {
1027 return status;
1030 if (server_returned_info != NULL) {
1031 *server_returned_info = talloc_move(
1032 mem_ctx, &state->server_info);
1034 if (nt_session_key != NULL) {
1035 *nt_session_key = (DATA_BLOB) {
1036 .data = talloc_move(
1037 mem_ctx, &state->nt_session_key.data),
1038 .length = state->nt_session_key.length,
1041 if (lm_session_key != NULL) {
1042 *lm_session_key = (DATA_BLOB) {
1043 .data = talloc_move(
1044 mem_ctx, &state->lm_session_key.data),
1045 .length = state->lm_session_key.length,
1049 return NT_STATUS_OK;
1052 struct local_pw_check_state {
1053 uint8_t authoritative;
1054 void *server_info;
1055 DATA_BLOB nt_session_key;
1056 DATA_BLOB lm_session_key;
1059 static struct tevent_req *local_pw_check_send(
1060 TALLOC_CTX *mem_ctx,
1061 struct tevent_context *ev,
1062 struct auth4_context *auth4_context,
1063 const struct auth_usersupplied_info *user_info)
1065 struct tevent_req *req = NULL;
1066 struct local_pw_check_state *state = NULL;
1067 struct samr_Password lm_pw, nt_pw;
1068 NTSTATUS nt_status;
1070 req = tevent_req_create(
1071 mem_ctx, &state, struct local_pw_check_state);
1072 if (req == NULL) {
1073 return NULL;
1075 state->authoritative = 1;
1077 nt_lm_owf_gen (opt_password, nt_pw.hash, lm_pw.hash);
1079 nt_status = ntlm_password_check(
1080 state,
1081 true,
1082 NTLM_AUTH_ON,
1084 &auth4_context->challenge.data,
1085 &user_info->password.response.lanman,
1086 &user_info->password.response.nt,
1087 user_info->client.account_name,
1088 user_info->client.account_name,
1089 user_info->client.domain_name,
1090 &lm_pw,
1091 &nt_pw,
1092 &state->nt_session_key,
1093 &state->lm_session_key);
1095 if (tevent_req_nterror(req, nt_status)) {
1096 DBG_NOTICE("Login for user [%s]\\[%s]@[%s] failed due to "
1097 "[%s]\n",
1098 user_info->client.domain_name,
1099 user_info->client.account_name,
1100 user_info->workstation_name,
1101 nt_errstr(nt_status));
1102 return tevent_req_post(req, ev);
1105 state->server_info = talloc_asprintf(
1106 state,
1107 "%s%c%s",
1108 user_info->client.domain_name,
1109 *lp_winbind_separator(),
1110 user_info->client.account_name);
1111 if (tevent_req_nomem(state->server_info, req)) {
1112 return tevent_req_post(req, ev);
1115 tevent_req_done(req);
1116 return tevent_req_post(req, ev);
1119 static NTSTATUS local_pw_check_recv(struct tevent_req *req,
1120 TALLOC_CTX *mem_ctx,
1121 uint8_t *pauthoritative,
1122 void **server_returned_info,
1123 DATA_BLOB *nt_session_key,
1124 DATA_BLOB *lm_session_key)
1126 struct local_pw_check_state *state = tevent_req_data(
1127 req, struct local_pw_check_state);
1128 NTSTATUS status;
1130 if (pauthoritative != NULL) {
1131 *pauthoritative = state->authoritative;
1134 if (tevent_req_is_nterror(req, &status)) {
1135 return status;
1138 if (server_returned_info != NULL) {
1139 *server_returned_info = talloc_move(
1140 mem_ctx, &state->server_info);
1142 if (nt_session_key != NULL) {
1143 *nt_session_key = (DATA_BLOB) {
1144 .data = talloc_move(
1145 mem_ctx, &state->nt_session_key.data),
1146 .length = state->nt_session_key.length,
1149 if (lm_session_key != NULL) {
1150 *lm_session_key = (DATA_BLOB) {
1151 .data = talloc_move(
1152 mem_ctx, &state->lm_session_key.data),
1153 .length = state->lm_session_key.length,
1157 return NT_STATUS_OK;
1160 static NTSTATUS ntlm_auth_prepare_gensec_client(TALLOC_CTX *mem_ctx,
1161 struct loadparm_context *lp_ctx,
1162 struct gensec_security **gensec_security_out)
1164 struct gensec_security *gensec_security = NULL;
1165 NTSTATUS nt_status;
1166 TALLOC_CTX *tmp_ctx;
1167 const struct gensec_security_ops **backends = NULL;
1168 struct gensec_settings *gensec_settings = NULL;
1169 size_t idx = 0;
1171 tmp_ctx = talloc_new(mem_ctx);
1172 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
1174 gensec_settings = lpcfg_gensec_settings(tmp_ctx, lp_ctx);
1175 if (gensec_settings == NULL) {
1176 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1177 TALLOC_FREE(tmp_ctx);
1178 return NT_STATUS_NO_MEMORY;
1181 backends = talloc_zero_array(gensec_settings,
1182 const struct gensec_security_ops *, 4);
1183 if (backends == NULL) {
1184 TALLOC_FREE(tmp_ctx);
1185 return NT_STATUS_NO_MEMORY;
1187 gensec_settings->backends = backends;
1189 gensec_init();
1191 /* These need to be in priority order, krb5 before NTLMSSP */
1192 #if defined(HAVE_KRB5)
1193 backends[idx++] = &gensec_gse_krb5_security_ops;
1194 #endif
1196 backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_NTLMSSP);
1198 backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_SPNEGO);
1200 nt_status = gensec_client_start(NULL, &gensec_security,
1201 gensec_settings);
1202 if (!NT_STATUS_IS_OK(nt_status)) {
1203 TALLOC_FREE(tmp_ctx);
1204 return nt_status;
1207 talloc_unlink(tmp_ctx, gensec_settings);
1209 if (opt_target_service != NULL) {
1210 nt_status = gensec_set_target_service(gensec_security,
1211 opt_target_service);
1212 if (!NT_STATUS_IS_OK(nt_status)) {
1213 TALLOC_FREE(tmp_ctx);
1214 return nt_status;
1218 if (opt_target_hostname != NULL) {
1219 nt_status = gensec_set_target_hostname(gensec_security,
1220 opt_target_hostname);
1221 if (!NT_STATUS_IS_OK(nt_status)) {
1222 TALLOC_FREE(tmp_ctx);
1223 return nt_status;
1227 *gensec_security_out = talloc_steal(mem_ctx, gensec_security);
1228 TALLOC_FREE(tmp_ctx);
1229 return NT_STATUS_OK;
1232 static struct auth4_context *make_auth4_context_ntlm_auth(TALLOC_CTX *mem_ctx, bool local_pw)
1234 struct auth4_context *auth4_context = talloc_zero(mem_ctx, struct auth4_context);
1235 if (auth4_context == NULL) {
1236 DEBUG(10, ("failed to allocate auth4_context failed\n"));
1237 return NULL;
1239 auth4_context->generate_session_info = ntlm_auth_generate_session_info;
1240 auth4_context->generate_session_info_pac = ntlm_auth_generate_session_info_pac;
1241 auth4_context->get_ntlm_challenge = ntlm_auth_get_challenge;
1242 auth4_context->set_ntlm_challenge = ntlm_auth_set_challenge;
1243 if (local_pw) {
1244 auth4_context->check_ntlm_password_send = local_pw_check_send;
1245 auth4_context->check_ntlm_password_recv = local_pw_check_recv;
1246 } else {
1247 auth4_context->check_ntlm_password_send =
1248 winbind_pw_check_send;
1249 auth4_context->check_ntlm_password_recv =
1250 winbind_pw_check_recv;
1252 auth4_context->private_data = NULL;
1253 return auth4_context;
1256 static NTSTATUS ntlm_auth_prepare_gensec_server(TALLOC_CTX *mem_ctx,
1257 struct loadparm_context *lp_ctx,
1258 struct gensec_security **gensec_security_out)
1260 struct gensec_security *gensec_security;
1261 NTSTATUS nt_status;
1263 TALLOC_CTX *tmp_ctx;
1264 const struct gensec_security_ops **backends;
1265 struct gensec_settings *gensec_settings;
1266 size_t idx = 0;
1267 struct cli_credentials *server_credentials;
1269 struct auth4_context *auth4_context;
1271 tmp_ctx = talloc_new(mem_ctx);
1272 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
1274 auth4_context = make_auth4_context_ntlm_auth(tmp_ctx, opt_password);
1275 if (auth4_context == NULL) {
1276 TALLOC_FREE(tmp_ctx);
1277 return NT_STATUS_NO_MEMORY;
1280 gensec_settings = lpcfg_gensec_settings(tmp_ctx, lp_ctx);
1281 if (lp_ctx == NULL) {
1282 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1283 TALLOC_FREE(tmp_ctx);
1284 return NT_STATUS_NO_MEMORY;
1288 * This should be a 'netbios domain -> DNS domain'
1289 * mapping, and can currently validly return NULL on
1290 * poorly configured systems.
1292 * This is used for the NTLMSSP server
1295 if (opt_password) {
1296 gensec_settings->server_netbios_name = lp_netbios_name();
1297 gensec_settings->server_netbios_domain = lp_workgroup();
1298 } else {
1299 gensec_settings->server_netbios_name = get_winbind_netbios_name();
1300 gensec_settings->server_netbios_domain = get_winbind_domain();
1303 gensec_settings->server_dns_domain = strlower_talloc(gensec_settings,
1304 get_mydnsdomname(talloc_tos()));
1305 gensec_settings->server_dns_name = strlower_talloc(gensec_settings,
1306 get_mydnsfullname());
1308 backends = talloc_zero_array(gensec_settings,
1309 const struct gensec_security_ops *, 4);
1311 if (backends == NULL) {
1312 TALLOC_FREE(tmp_ctx);
1313 return NT_STATUS_NO_MEMORY;
1315 gensec_settings->backends = backends;
1317 gensec_init();
1319 /* These need to be in priority order, krb5 before NTLMSSP */
1320 #if defined(HAVE_KRB5)
1321 backends[idx++] = &gensec_gse_krb5_security_ops;
1322 #endif
1324 backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_NTLMSSP);
1326 backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_SPNEGO);
1329 * This is anonymous for now, because we just use it
1330 * to set the kerberos state at the moment
1332 server_credentials = cli_credentials_init_anon(tmp_ctx);
1333 if (!server_credentials) {
1334 DBG_ERR("Failed to init server credentials\n");
1335 return NT_STATUS_NO_MEMORY;
1338 cli_credentials_set_conf(server_credentials, lp_ctx);
1340 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC || lp_security() == SEC_ADS || USE_KERBEROS_KEYTAB) {
1341 cli_credentials_set_kerberos_state(server_credentials,
1342 CRED_USE_KERBEROS_DESIRED,
1343 CRED_SPECIFIED);
1344 } else {
1345 cli_credentials_set_kerberos_state(server_credentials,
1346 CRED_USE_KERBEROS_DISABLED,
1347 CRED_SPECIFIED);
1350 nt_status = gensec_server_start(tmp_ctx, gensec_settings,
1351 auth4_context, &gensec_security);
1353 if (!NT_STATUS_IS_OK(nt_status)) {
1354 TALLOC_FREE(tmp_ctx);
1355 return nt_status;
1358 gensec_set_credentials(gensec_security, server_credentials);
1361 * TODO: Allow the caller to pass their own description here
1362 * via a command-line option
1364 nt_status = gensec_set_target_service_description(gensec_security,
1365 "ntlm_auth");
1366 if (!NT_STATUS_IS_OK(nt_status)) {
1367 TALLOC_FREE(tmp_ctx);
1368 return nt_status;
1371 talloc_unlink(tmp_ctx, lp_ctx);
1372 talloc_unlink(tmp_ctx, server_credentials);
1373 talloc_unlink(tmp_ctx, gensec_settings);
1374 talloc_unlink(tmp_ctx, auth4_context);
1376 *gensec_security_out = talloc_steal(mem_ctx, gensec_security);
1377 TALLOC_FREE(tmp_ctx);
1378 return NT_STATUS_OK;
1381 static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode,
1382 struct loadparm_context *lp_ctx,
1383 struct ntlm_auth_state *state,
1384 char *buf, int length, void **private2)
1386 manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
1387 return;
1390 static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode,
1391 struct loadparm_context *lp_ctx,
1392 struct ntlm_auth_state *state,
1393 char *buf, int length, void **private2)
1395 char *user, *pass;
1396 user=buf;
1398 pass=(char *)memchr(buf,' ',length);
1399 if (!pass) {
1400 DEBUG(2, ("Password not found. Denying access\n"));
1401 printf("ERR\n");
1402 return;
1404 *pass='\0';
1405 pass++;
1407 if (state->helper_mode == SQUID_2_5_BASIC) {
1408 char *end = rfc1738_unescape(user);
1409 if (end == NULL || (end - user) != strlen(user)) {
1410 DEBUG(2, ("Badly rfc1738 encoded username: %s; "
1411 "denying access\n", user));
1412 printf("ERR\n");
1413 return;
1415 end = rfc1738_unescape(pass);
1416 if (end == NULL || (end - pass) != strlen(pass)) {
1417 DEBUG(2, ("Badly encoded password for %s; "
1418 "denying access\n", user));
1419 printf("ERR\n");
1420 return;
1424 if (check_plaintext_auth(user, pass, False)) {
1425 printf("OK\n");
1426 } else {
1427 printf("ERR\n");
1431 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
1432 struct loadparm_context *lp_ctx,
1433 char *buf, int length, void **private1)
1435 DATA_BLOB in;
1436 DATA_BLOB out = data_blob(NULL, 0);
1437 char *out_base64 = NULL;
1438 const char *reply_arg = NULL;
1439 struct gensec_ntlm_state {
1440 struct gensec_security *gensec_state;
1441 const char *set_password;
1443 struct gensec_ntlm_state *state;
1445 NTSTATUS nt_status;
1446 bool first = false;
1447 const char *reply_code;
1448 struct cli_credentials *creds;
1450 static char *want_feature_list = NULL;
1451 static DATA_BLOB session_key;
1453 TALLOC_CTX *mem_ctx;
1455 mem_ctx = talloc_named(NULL, 0, "manage_gensec_request internal mem_ctx");
1456 if (mem_ctx == NULL) {
1457 printf("BH No Memory\n");
1458 exit(1);
1461 if (*private1) {
1462 state = talloc_get_type(*private1, struct gensec_ntlm_state);
1463 if (state == NULL) {
1464 DBG_WARNING("*private1 is of type %s\n",
1465 talloc_get_name(*private1));
1466 printf("BH *private1 is of type %s\n",
1467 talloc_get_name(*private1));
1468 exit(1);
1470 } else {
1471 state = talloc_zero(NULL, struct gensec_ntlm_state);
1472 if (!state) {
1473 printf("BH No Memory\n");
1474 exit(1);
1476 *private1 = state;
1477 if (opt_password) {
1478 state->set_password = opt_password;
1482 if (strlen(buf) < 2) {
1483 DEBUG(1, ("query [%s] invalid", buf));
1484 printf("BH Query invalid\n");
1485 talloc_free(mem_ctx);
1486 return;
1489 if (strlen(buf) > 3) {
1490 if(strncmp(buf, "SF ", 3) == 0) {
1491 DEBUG(10, ("Setting flags to negotiate\n"));
1492 talloc_free(want_feature_list);
1493 want_feature_list = talloc_strndup(state, buf+3, strlen(buf)-3);
1494 printf("OK\n");
1495 talloc_free(mem_ctx);
1496 return;
1498 in = base64_decode_data_blob_talloc(mem_ctx, buf + 3);
1499 } else {
1500 in = data_blob(NULL, 0);
1503 if (strncmp(buf, "YR", 2) == 0) {
1504 if (state->gensec_state) {
1505 talloc_free(state->gensec_state);
1506 state->gensec_state = NULL;
1508 } else if ( (strncmp(buf, "OK", 2) == 0)) {
1509 /* Just return BH, like ntlm_auth from Samba 3 does. */
1510 printf("BH Command expected\n");
1511 talloc_free(mem_ctx);
1512 return;
1513 } else if ( (strncmp(buf, "TT ", 3) != 0) &&
1514 (strncmp(buf, "KK ", 3) != 0) &&
1515 (strncmp(buf, "AF ", 3) != 0) &&
1516 (strncmp(buf, "NA ", 3) != 0) &&
1517 (strncmp(buf, "UG", 2) != 0) &&
1518 (strncmp(buf, "PW ", 3) != 0) &&
1519 (strncmp(buf, "GK", 2) != 0) &&
1520 (strncmp(buf, "GF", 2) != 0)) {
1521 DEBUG(1, ("SPNEGO request [%s] invalid prefix\n", buf));
1522 printf("BH SPNEGO request invalid prefix\n");
1523 talloc_free(mem_ctx);
1524 return;
1527 /* setup gensec */
1528 if (!(state->gensec_state)) {
1529 switch (stdio_helper_mode) {
1530 case GSS_SPNEGO_CLIENT:
1532 * cached credentials are only supported by
1533 * NTLMSSP_CLIENT_1 for now.
1535 use_cached_creds = false;
1536 FALL_THROUGH;
1537 case NTLMSSP_CLIENT_1:
1538 /* setup the client side */
1540 if (state->set_password != NULL) {
1541 use_cached_creds = false;
1544 if (use_cached_creds) {
1545 struct wbcCredentialCacheParams params;
1546 struct wbcCredentialCacheInfo *info = NULL;
1547 struct wbcAuthErrorInfo *error = NULL;
1548 wbcErr wbc_status;
1550 params.account_name = opt_username;
1551 params.domain_name = opt_domain;
1552 params.level = WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP;
1553 params.num_blobs = 0;
1554 params.blobs = NULL;
1556 wbc_status = wbcCredentialCache(&params, &info,
1557 &error);
1558 wbcFreeMemory(error);
1559 if (!WBC_ERROR_IS_OK(wbc_status)) {
1560 use_cached_creds = false;
1562 wbcFreeMemory(info);
1565 nt_status = ntlm_auth_prepare_gensec_client(state, lp_ctx,
1566 &state->gensec_state);
1567 if (!NT_STATUS_IS_OK(nt_status)) {
1568 printf("BH GENSEC mech failed to start: %s\n",
1569 nt_errstr(nt_status));
1570 talloc_free(mem_ctx);
1571 return;
1574 creds = cli_credentials_init(state->gensec_state);
1575 cli_credentials_set_conf(creds, lp_ctx);
1576 if (opt_username) {
1577 cli_credentials_set_username(creds, opt_username, CRED_SPECIFIED);
1579 if (opt_domain) {
1580 cli_credentials_set_domain(creds, opt_domain, CRED_SPECIFIED);
1582 if (use_cached_creds) {
1583 gensec_want_feature(state->gensec_state,
1584 GENSEC_FEATURE_NTLM_CCACHE);
1585 } else if (state->set_password) {
1586 cli_credentials_set_password(creds, state->set_password, CRED_SPECIFIED);
1587 } else {
1588 cli_credentials_set_password_callback(creds, get_password);
1590 if (opt_workstation) {
1591 cli_credentials_set_workstation(creds, opt_workstation, CRED_SPECIFIED);
1594 gensec_set_credentials(state->gensec_state, creds);
1596 break;
1597 case GSS_SPNEGO_SERVER:
1598 case SQUID_2_5_NTLMSSP:
1600 nt_status = ntlm_auth_prepare_gensec_server(state, lp_ctx,
1601 &state->gensec_state);
1602 if (!NT_STATUS_IS_OK(nt_status)) {
1603 printf("BH GENSEC mech failed to start: %s\n",
1604 nt_errstr(nt_status));
1605 talloc_free(mem_ctx);
1606 return;
1608 break;
1610 default:
1611 talloc_free(mem_ctx);
1612 abort();
1615 gensec_want_feature_list(state->gensec_state, want_feature_list);
1617 /* Session info is not complete, do not pass to auth log */
1618 gensec_want_feature(state->gensec_state, GENSEC_FEATURE_NO_AUTHZ_LOG);
1620 switch (stdio_helper_mode) {
1621 case GSS_SPNEGO_CLIENT:
1622 case GSS_SPNEGO_SERVER:
1623 nt_status = gensec_start_mech_by_oid(state->gensec_state, GENSEC_OID_SPNEGO);
1624 if (!in.length) {
1625 first = true;
1627 break;
1628 case NTLMSSP_CLIENT_1:
1629 if (!in.length) {
1630 first = true;
1632 FALL_THROUGH;
1633 case SQUID_2_5_NTLMSSP:
1634 nt_status = gensec_start_mech_by_oid(state->gensec_state, GENSEC_OID_NTLMSSP);
1635 break;
1636 default:
1637 talloc_free(mem_ctx);
1638 abort();
1641 if (!NT_STATUS_IS_OK(nt_status)) {
1642 DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status)));
1643 printf("BH GENSEC mech failed to start\n");
1644 talloc_free(mem_ctx);
1645 return;
1650 /* update */
1652 if (strncmp(buf, "PW ", 3) == 0) {
1653 state->set_password = talloc_strndup(state,
1654 (const char *)in.data,
1655 in.length);
1657 cli_credentials_set_password(gensec_get_credentials(state->gensec_state),
1658 state->set_password,
1659 CRED_SPECIFIED);
1660 printf("OK\n");
1661 talloc_free(mem_ctx);
1662 return;
1665 if (strncmp(buf, "GK", 2) == 0) {
1666 char *base64_key;
1667 DEBUG(10, ("Requested session key\n"));
1668 nt_status = gensec_session_key(state->gensec_state, mem_ctx, &session_key);
1669 if(!NT_STATUS_IS_OK(nt_status)) {
1670 DEBUG(1, ("gensec_session_key failed: %s\n", nt_errstr(nt_status)));
1671 printf("BH No session key\n");
1672 talloc_free(mem_ctx);
1673 return;
1674 } else {
1675 base64_key = base64_encode_data_blob(state, session_key);
1676 SMB_ASSERT(base64_key != NULL);
1677 printf("GK %s\n", base64_key);
1678 talloc_free(base64_key);
1680 talloc_free(mem_ctx);
1681 return;
1684 if (strncmp(buf, "GF", 2) == 0) {
1685 uint32_t neg_flags;
1687 DEBUG(10, ("Requested negotiated NTLMSSP feature flags\n"));
1689 neg_flags = gensec_ntlmssp_neg_flags(state->gensec_state);
1690 if (neg_flags == 0) {
1691 printf("BH\n");
1692 talloc_free(mem_ctx);
1693 return;
1696 printf("GF 0x%08x\n", neg_flags);
1697 talloc_free(mem_ctx);
1698 return;
1701 nt_status = gensec_update(state->gensec_state, mem_ctx, in, &out);
1703 /* don't leak 'bad password'/'no such user' info to the network client */
1704 nt_status = nt_status_squash(nt_status);
1706 if (out.length) {
1707 out_base64 = base64_encode_data_blob(mem_ctx, out);
1708 SMB_ASSERT(out_base64 != NULL);
1709 } else {
1710 out_base64 = NULL;
1713 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1714 reply_arg = "*";
1715 if (first && state->gensec_state->gensec_role == GENSEC_CLIENT) {
1716 reply_code = "YR";
1717 } else if (state->gensec_state->gensec_role == GENSEC_CLIENT) {
1718 reply_code = "KK";
1719 } else if (state->gensec_state->gensec_role == GENSEC_SERVER) {
1720 reply_code = "TT";
1721 } else {
1722 abort();
1726 } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) {
1727 reply_code = "BH NT_STATUS_ACCESS_DENIED";
1728 reply_arg = nt_errstr(nt_status);
1729 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
1730 } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_UNSUCCESSFUL)) {
1731 reply_code = "BH NT_STATUS_UNSUCCESSFUL";
1732 reply_arg = nt_errstr(nt_status);
1733 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
1734 } else if (!NT_STATUS_IS_OK(nt_status)) {
1735 reply_code = "NA";
1736 reply_arg = nt_errstr(nt_status);
1737 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
1738 } else if /* OK */ (state->gensec_state->gensec_role == GENSEC_SERVER) {
1739 struct auth_session_info *session_info;
1741 nt_status = gensec_session_info(state->gensec_state, mem_ctx, &session_info);
1742 if (!NT_STATUS_IS_OK(nt_status)) {
1743 reply_code = "BH Failed to retrieve session info";
1744 reply_arg = nt_errstr(nt_status);
1745 DEBUG(1, ("GENSEC failed to retrieve the session info: %s\n", nt_errstr(nt_status)));
1746 } else {
1748 reply_code = "AF";
1749 reply_arg = talloc_strdup(state->gensec_state, session_info->unix_info->unix_name);
1750 if (reply_arg == NULL) {
1751 reply_code = "BH out of memory";
1752 reply_arg = nt_errstr(NT_STATUS_NO_MEMORY);
1754 talloc_free(session_info);
1756 } else if (state->gensec_state->gensec_role == GENSEC_CLIENT) {
1757 reply_code = "AF";
1758 reply_arg = out_base64;
1759 } else {
1760 abort();
1763 switch (stdio_helper_mode) {
1764 case GSS_SPNEGO_SERVER:
1765 printf("%s %s %s\n", reply_code,
1766 out_base64 ? out_base64 : "*",
1767 reply_arg ? reply_arg : "*");
1768 break;
1769 default:
1770 if (out_base64) {
1771 printf("%s %s\n", reply_code, out_base64);
1772 } else if (reply_arg) {
1773 printf("%s %s\n", reply_code, reply_arg);
1774 } else {
1775 printf("%s\n", reply_code);
1779 talloc_free(mem_ctx);
1780 return;
1783 static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode,
1784 struct loadparm_context *lp_ctx,
1785 struct ntlm_auth_state *state,
1786 char *buf, int length, void **private2)
1788 manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
1789 return;
1792 static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode,
1793 struct loadparm_context *lp_ctx,
1794 struct ntlm_auth_state *state,
1795 char *buf, int length, void **private2)
1797 manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
1798 return;
1801 static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode,
1802 struct loadparm_context *lp_ctx,
1803 struct ntlm_auth_state *state,
1804 char *buf, int length, void **private2)
1806 manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
1807 return;
1810 static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode,
1811 struct loadparm_context *lp_ctx,
1812 struct ntlm_auth_state *state,
1813 char *buf, int length, void **private2)
1815 char *request, *parameter;
1816 static DATA_BLOB challenge;
1817 static DATA_BLOB lm_response;
1818 static DATA_BLOB nt_response;
1819 static char *full_username;
1820 static char *username;
1821 static char *domain;
1822 static char *plaintext_password;
1823 static bool ntlm_server_1_user_session_key;
1824 static bool ntlm_server_1_lm_session_key;
1826 if (strequal(buf, ".")) {
1827 if (!full_username && !username) {
1828 printf("Error: No username supplied!\n");
1829 } else if (plaintext_password) {
1830 /* handle this request as plaintext */
1831 if (!full_username) {
1832 if (asprintf(&full_username, "%s%c%s", domain, winbind_separator(), username) == -1) {
1833 printf("Error: Out of memory in "
1834 "asprintf!\n.\n");
1835 return;
1838 if (check_plaintext_auth(full_username, plaintext_password, False)) {
1839 printf("Authenticated: Yes\n");
1840 } else {
1841 printf("Authenticated: No\n");
1843 } else if (!lm_response.data && !nt_response.data) {
1844 printf("Error: No password supplied!\n");
1845 } else if (!challenge.data) {
1846 printf("Error: No lanman-challenge supplied!\n");
1847 } else {
1848 char *error_string = NULL;
1849 uchar lm_key[8];
1850 uchar user_session_key[16];
1851 uint32_t flags = 0;
1852 NTSTATUS nt_status;
1853 if (full_username && !username) {
1854 fstring fstr_user;
1855 fstring fstr_domain;
1857 if (!parse_ntlm_auth_domain_user(full_username, fstr_user, fstr_domain)) {
1858 /* username might be 'tainted', don't print into our new-line deleimianted stream */
1859 printf("Error: Could not parse into "
1860 "domain and username\n");
1862 SAFE_FREE(username);
1863 SAFE_FREE(domain);
1864 username = smb_xstrdup(fstr_user);
1865 domain = smb_xstrdup(fstr_domain);
1868 if (opt_password) {
1869 DATA_BLOB nt_session_key, lm_session_key;
1870 struct samr_Password lm_pw, nt_pw;
1871 TALLOC_CTX *mem_ctx = talloc_new(NULL);
1872 ZERO_STRUCT(user_session_key);
1873 ZERO_STRUCT(lm_key);
1875 nt_lm_owf_gen (opt_password, nt_pw.hash, lm_pw.hash);
1876 nt_status = ntlm_password_check(mem_ctx,
1877 true,
1878 NTLM_AUTH_ON,
1880 &challenge,
1881 &lm_response,
1882 &nt_response,
1883 username,
1884 username,
1885 domain,
1886 &lm_pw, &nt_pw,
1887 &nt_session_key,
1888 &lm_session_key);
1889 error_string = smb_xstrdup(get_friendly_nt_error_msg(nt_status));
1890 if (ntlm_server_1_user_session_key) {
1891 if (nt_session_key.length == sizeof(user_session_key)) {
1892 memcpy(user_session_key,
1893 nt_session_key.data,
1894 sizeof(user_session_key));
1897 if (ntlm_server_1_lm_session_key) {
1898 if (lm_session_key.length == sizeof(lm_key)) {
1899 memcpy(lm_key,
1900 lm_session_key.data,
1901 sizeof(lm_key));
1904 TALLOC_FREE(mem_ctx);
1906 } else {
1907 uint8_t authoritative = 1;
1909 if (!domain) {
1910 domain = smb_xstrdup(get_winbind_domain());
1913 if (ntlm_server_1_lm_session_key)
1914 flags |= WBFLAG_PAM_LMKEY;
1916 if (ntlm_server_1_user_session_key)
1917 flags |= WBFLAG_PAM_USER_SESSION_KEY;
1919 nt_status = contact_winbind_auth_crap(username,
1920 domain,
1921 lp_netbios_name(),
1922 &challenge,
1923 &lm_response,
1924 &nt_response,
1925 flags, 0,
1926 lm_key,
1927 user_session_key,
1928 &authoritative,
1929 &error_string,
1930 NULL);
1933 if (!NT_STATUS_IS_OK(nt_status)) {
1934 printf("Authenticated: No\n");
1935 printf("Authentication-Error: %s\n.\n",
1936 error_string);
1937 } else {
1938 char *hex_lm_key;
1939 char *hex_user_session_key;
1941 printf("Authenticated: Yes\n");
1943 if (ntlm_server_1_lm_session_key
1944 && (!all_zero(lm_key,
1945 sizeof(lm_key)))) {
1946 hex_lm_key = hex_encode_talloc(NULL,
1947 (const unsigned char *)lm_key,
1948 sizeof(lm_key));
1949 printf("LANMAN-Session-Key: %s\n",
1950 hex_lm_key);
1951 TALLOC_FREE(hex_lm_key);
1954 if (ntlm_server_1_user_session_key
1955 && (!all_zero(user_session_key,
1956 sizeof(user_session_key)))) {
1957 hex_user_session_key = hex_encode_talloc(NULL,
1958 (const unsigned char *)user_session_key,
1959 sizeof(user_session_key));
1960 printf("User-Session-Key: %s\n",
1961 hex_user_session_key);
1962 TALLOC_FREE(hex_user_session_key);
1965 SAFE_FREE(error_string);
1967 /* clear out the state */
1968 challenge = data_blob_null;
1969 nt_response = data_blob_null;
1970 lm_response = data_blob_null;
1971 SAFE_FREE(full_username);
1972 SAFE_FREE(username);
1973 SAFE_FREE(domain);
1974 SAFE_FREE(plaintext_password);
1975 ntlm_server_1_user_session_key = False;
1976 ntlm_server_1_lm_session_key = False;
1977 printf(".\n");
1979 return;
1982 request = buf;
1984 /* Indicates a base64 encoded structure */
1985 parameter = strstr_m(request, ":: ");
1986 if (!parameter) {
1987 parameter = strstr_m(request, ": ");
1989 if (!parameter) {
1990 DEBUG(0, ("Parameter not found!\n"));
1991 printf("Error: Parameter not found!\n.\n");
1992 return;
1995 parameter[0] ='\0';
1996 parameter++;
1997 parameter[0] ='\0';
1998 parameter++;
2000 } else {
2001 parameter[0] ='\0';
2002 parameter++;
2003 parameter[0] ='\0';
2004 parameter++;
2005 parameter[0] ='\0';
2006 parameter++;
2008 base64_decode_inplace(parameter);
2011 if (strequal(request, "LANMAN-Challenge")) {
2012 challenge = strhex_to_data_blob(NULL, parameter);
2013 if (challenge.length != 8) {
2014 printf("Error: hex decode of %s failed! "
2015 "(got %d bytes, expected 8)\n.\n",
2016 parameter,
2017 (int)challenge.length);
2018 challenge = data_blob_null;
2020 } else if (strequal(request, "NT-Response")) {
2021 nt_response = strhex_to_data_blob(NULL, parameter);
2022 if (nt_response.length < 24) {
2023 printf("Error: hex decode of %s failed! "
2024 "(only got %d bytes, needed at least 24)\n.\n",
2025 parameter,
2026 (int)nt_response.length);
2027 nt_response = data_blob_null;
2029 } else if (strequal(request, "LANMAN-Response")) {
2030 lm_response = strhex_to_data_blob(NULL, parameter);
2031 if (lm_response.length != 24) {
2032 printf("Error: hex decode of %s failed! "
2033 "(got %d bytes, expected 24)\n.\n",
2034 parameter,
2035 (int)lm_response.length);
2036 lm_response = data_blob_null;
2038 } else if (strequal(request, "Password")) {
2039 plaintext_password = smb_xstrdup(parameter);
2040 } else if (strequal(request, "NT-Domain")) {
2041 domain = smb_xstrdup(parameter);
2042 } else if (strequal(request, "Username")) {
2043 username = smb_xstrdup(parameter);
2044 } else if (strequal(request, "Full-Username")) {
2045 full_username = smb_xstrdup(parameter);
2046 } else if (strequal(request, "Request-User-Session-Key")) {
2047 ntlm_server_1_user_session_key = strequal(parameter, "Yes");
2048 } else if (strequal(request, "Request-LanMan-Session-Key")) {
2049 ntlm_server_1_lm_session_key = strequal(parameter, "Yes");
2050 } else {
2051 printf("Error: Unknown request %s\n.\n", request);
2055 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode,
2056 struct loadparm_context *lp_ctx,
2057 struct ntlm_auth_state *state,
2058 char *buf, int length, void **private2)
2060 char *request, *parameter;
2061 static DATA_BLOB new_nt_pswd;
2062 static DATA_BLOB old_nt_hash_enc;
2063 static DATA_BLOB new_lm_pswd;
2064 static DATA_BLOB old_lm_hash_enc;
2065 static char *full_username = NULL;
2066 static char *username = NULL;
2067 static char *domain = NULL;
2068 static char *newpswd = NULL;
2069 static char *oldpswd = NULL;
2071 if (strequal(buf, ".")) {
2072 if(newpswd && oldpswd) {
2073 uchar old_nt_hash[16];
2074 uchar old_lm_hash[16];
2075 uchar new_nt_hash[16];
2076 uchar new_lm_hash[16];
2078 gnutls_cipher_hd_t cipher_hnd = NULL;
2079 gnutls_datum_t old_nt_key = {
2080 .data = old_nt_hash,
2081 .size = sizeof(old_nt_hash),
2083 int rc;
2085 new_nt_pswd = data_blob(NULL, 516);
2086 old_nt_hash_enc = data_blob(NULL, 16);
2088 /* Calculate the MD4 hash (NT compatible) of the
2089 * password */
2090 E_md4hash(oldpswd, old_nt_hash);
2091 E_md4hash(newpswd, new_nt_hash);
2093 /* E_deshash returns false for 'long'
2094 passwords (> 14 DOS chars).
2096 Therefore, don't send a buffer
2097 encrypted with the truncated hash
2098 (it could allow an even easier
2099 attack on the password)
2101 Likewise, obey the admin's restriction
2104 rc = gnutls_cipher_init(&cipher_hnd,
2105 GNUTLS_CIPHER_ARCFOUR_128,
2106 &old_nt_key,
2107 NULL);
2108 if (rc < 0) {
2109 DBG_ERR("gnutls_cipher_init failed: %s\n",
2110 gnutls_strerror(rc));
2111 if (rc == GNUTLS_E_UNWANTED_ALGORITHM) {
2112 DBG_ERR("Running in FIPS mode, NTLM blocked\n");
2114 return;
2117 if (lp_client_lanman_auth() &&
2118 E_deshash(newpswd, new_lm_hash) &&
2119 E_deshash(oldpswd, old_lm_hash)) {
2120 new_lm_pswd = data_blob(NULL, 516);
2121 old_lm_hash_enc = data_blob(NULL, 16);
2122 encode_pw_buffer(new_lm_pswd.data, newpswd,
2123 STR_UNICODE);
2125 rc = gnutls_cipher_encrypt(cipher_hnd,
2126 new_lm_pswd.data,
2127 516);
2128 if (rc < 0) {
2129 gnutls_cipher_deinit(cipher_hnd);
2130 return;
2132 rc = E_old_pw_hash(new_nt_hash, old_lm_hash,
2133 old_lm_hash_enc.data);
2134 if (rc != 0) {
2135 DBG_ERR("E_old_pw_hash failed: %s\n",
2136 gnutls_strerror(rc));
2137 return;
2139 } else {
2140 new_lm_pswd.data = NULL;
2141 new_lm_pswd.length = 0;
2142 old_lm_hash_enc.data = NULL;
2143 old_lm_hash_enc.length = 0;
2146 encode_pw_buffer(new_nt_pswd.data, newpswd,
2147 STR_UNICODE);
2149 rc = gnutls_cipher_encrypt(cipher_hnd,
2150 new_nt_pswd.data,
2151 516);
2152 gnutls_cipher_deinit(cipher_hnd);
2153 if (rc < 0) {
2154 return;
2156 rc = E_old_pw_hash(new_nt_hash, old_nt_hash,
2157 old_nt_hash_enc.data);
2158 if (rc != 0) {
2159 DBG_ERR("E_old_pw_hash failed: %s\n",
2160 gnutls_strerror(rc));
2161 return;
2164 ZERO_ARRAY(old_nt_hash);
2165 ZERO_ARRAY(old_lm_hash);
2166 ZERO_ARRAY(new_nt_hash);
2167 ZERO_ARRAY(new_lm_hash);
2170 if (!full_username && !username) {
2171 printf("Error: No username supplied!\n");
2172 } else if ((!new_nt_pswd.data || !old_nt_hash_enc.data) &&
2173 (!new_lm_pswd.data || old_lm_hash_enc.data) ) {
2174 printf("Error: No NT or LM password "
2175 "blobs supplied!\n");
2176 } else {
2177 char *error_string = NULL;
2179 if (full_username && !username) {
2180 fstring fstr_user;
2181 fstring fstr_domain;
2183 if (!parse_ntlm_auth_domain_user(full_username,
2184 fstr_user,
2185 fstr_domain)) {
2186 /* username might be 'tainted', don't
2187 * print into our new-line
2188 * deleimianted stream */
2189 printf("Error: Could not "
2190 "parse into domain and "
2191 "username\n");
2192 SAFE_FREE(username);
2193 username = smb_xstrdup(full_username);
2194 } else {
2195 SAFE_FREE(username);
2196 SAFE_FREE(domain);
2197 username = smb_xstrdup(fstr_user);
2198 domain = smb_xstrdup(fstr_domain);
2203 if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
2204 username, domain,
2205 new_nt_pswd,
2206 old_nt_hash_enc,
2207 new_lm_pswd,
2208 old_lm_hash_enc,
2209 &error_string))) {
2210 printf("Password-Change: No\n");
2211 printf("Password-Change-Error: %s\n.\n",
2212 error_string);
2213 } else {
2214 printf("Password-Change: Yes\n");
2217 SAFE_FREE(error_string);
2219 /* clear out the state */
2220 new_nt_pswd = data_blob_null;
2221 old_nt_hash_enc = data_blob_null;
2222 new_lm_pswd = data_blob_null;
2223 old_nt_hash_enc = data_blob_null;
2224 SAFE_FREE(full_username);
2225 SAFE_FREE(username);
2226 SAFE_FREE(domain);
2227 SAFE_FREE(newpswd);
2228 SAFE_FREE(oldpswd);
2229 printf(".\n");
2231 return;
2234 request = buf;
2236 /* Indicates a base64 encoded structure */
2237 parameter = strstr_m(request, ":: ");
2238 if (!parameter) {
2239 parameter = strstr_m(request, ": ");
2241 if (!parameter) {
2242 DEBUG(0, ("Parameter not found!\n"));
2243 printf("Error: Parameter not found!\n.\n");
2244 return;
2247 parameter[0] ='\0';
2248 parameter++;
2249 parameter[0] ='\0';
2250 parameter++;
2251 } else {
2252 parameter[0] ='\0';
2253 parameter++;
2254 parameter[0] ='\0';
2255 parameter++;
2256 parameter[0] ='\0';
2257 parameter++;
2259 base64_decode_inplace(parameter);
2262 if (strequal(request, "new-nt-password-blob")) {
2263 new_nt_pswd = strhex_to_data_blob(NULL, parameter);
2264 if (new_nt_pswd.length != 516) {
2265 printf("Error: hex decode of %s failed! "
2266 "(got %d bytes, expected 516)\n.\n",
2267 parameter,
2268 (int)new_nt_pswd.length);
2269 new_nt_pswd = data_blob_null;
2271 } else if (strequal(request, "old-nt-hash-blob")) {
2272 old_nt_hash_enc = strhex_to_data_blob(NULL, parameter);
2273 if (old_nt_hash_enc.length != 16) {
2274 printf("Error: hex decode of %s failed! "
2275 "(got %d bytes, expected 16)\n.\n",
2276 parameter,
2277 (int)old_nt_hash_enc.length);
2278 old_nt_hash_enc = data_blob_null;
2280 } else if (strequal(request, "new-lm-password-blob")) {
2281 new_lm_pswd = strhex_to_data_blob(NULL, parameter);
2282 if (new_lm_pswd.length != 516) {
2283 printf("Error: hex decode of %s failed! "
2284 "(got %d bytes, expected 516)\n.\n",
2285 parameter,
2286 (int)new_lm_pswd.length);
2287 new_lm_pswd = data_blob_null;
2290 else if (strequal(request, "old-lm-hash-blob")) {
2291 old_lm_hash_enc = strhex_to_data_blob(NULL, parameter);
2292 if (old_lm_hash_enc.length != 16)
2294 printf("Error: hex decode of %s failed! "
2295 "(got %d bytes, expected 16)\n.\n",
2296 parameter,
2297 (int)old_lm_hash_enc.length);
2298 old_lm_hash_enc = data_blob_null;
2300 } else if (strequal(request, "nt-domain")) {
2301 domain = smb_xstrdup(parameter);
2302 } else if(strequal(request, "username")) {
2303 username = smb_xstrdup(parameter);
2304 } else if(strequal(request, "full-username")) {
2305 username = smb_xstrdup(parameter);
2306 } else if(strequal(request, "new-password")) {
2307 newpswd = smb_xstrdup(parameter);
2308 } else if (strequal(request, "old-password")) {
2309 oldpswd = smb_xstrdup(parameter);
2310 } else {
2311 printf("Error: Unknown request %s\n.\n", request);
2315 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode,
2316 struct loadparm_context *lp_ctx,
2317 struct ntlm_auth_state *state,
2318 stdio_helper_function fn, void **private2)
2320 char *buf;
2321 char tmp[INITIAL_BUFFER_SIZE+1];
2322 int length, buf_size = 0;
2323 char *c;
2325 buf = talloc_strdup(state->mem_ctx, "");
2326 if (!buf) {
2327 DEBUG(0, ("Failed to allocate input buffer.\n"));
2328 fprintf(stderr, "ERR\n");
2329 exit(1);
2332 do {
2334 /* this is not a typo - x_fgets doesn't work too well under
2335 * squid */
2336 if (fgets(tmp, sizeof(tmp)-1, stdin) == NULL) {
2337 if (ferror(stdin)) {
2338 DEBUG(1, ("fgets() failed! dying..... errno=%d "
2339 "(%s)\n", ferror(stdin),
2340 strerror(ferror(stdin))));
2342 exit(1);
2344 exit(0);
2347 buf = talloc_strdup_append_buffer(buf, tmp);
2348 buf_size += INITIAL_BUFFER_SIZE;
2350 if (buf_size > MAX_BUFFER_SIZE) {
2351 DEBUG(2, ("Oversized message\n"));
2352 fprintf(stderr, "ERR\n");
2353 talloc_free(buf);
2354 return;
2357 c = strchr(buf, '\n');
2358 } while (c == NULL);
2360 *c = '\0';
2361 length = c-buf;
2363 DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf,length));
2365 if (buf[0] == '\0') {
2366 DEBUG(2, ("Invalid Request\n"));
2367 fprintf(stderr, "ERR\n");
2368 talloc_free(buf);
2369 return;
2372 fn(stdio_helper_mode, lp_ctx, state, buf, length, private2);
2373 talloc_free(buf);
2377 static void squid_stream(enum stdio_helper_mode stdio_mode,
2378 struct loadparm_context *lp_ctx,
2379 stdio_helper_function fn) {
2380 TALLOC_CTX *mem_ctx;
2381 struct ntlm_auth_state *state;
2383 /* initialize FDescs */
2384 setbuf(stdout, NULL);
2385 setbuf(stderr, NULL);
2387 mem_ctx = talloc_init("ntlm_auth");
2388 if (!mem_ctx) {
2389 DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
2390 fprintf(stderr, "ERR\n");
2391 exit(1);
2394 state = talloc_zero(mem_ctx, struct ntlm_auth_state);
2395 if (!state) {
2396 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
2397 fprintf(stderr, "ERR\n");
2398 exit(1);
2401 state->mem_ctx = mem_ctx;
2402 state->helper_mode = stdio_mode;
2404 while(1) {
2405 TALLOC_CTX *frame = talloc_stackframe();
2406 manage_squid_request(stdio_mode, lp_ctx, state, fn, NULL);
2407 TALLOC_FREE(frame);
2412 /* Authenticate a user with a challenge/response */
2414 static bool check_auth_crap(void)
2416 NTSTATUS nt_status;
2417 uint32_t flags = 0;
2418 char lm_key[8];
2419 char user_session_key[16];
2420 char *hex_lm_key;
2421 char *hex_user_session_key;
2422 char *error_string;
2423 uint8_t authoritative = 1;
2425 setbuf(stdout, NULL);
2427 if (request_lm_key)
2428 flags |= WBFLAG_PAM_LMKEY;
2430 if (request_user_session_key)
2431 flags |= WBFLAG_PAM_USER_SESSION_KEY;
2433 flags |= WBFLAG_PAM_NT_STATUS_SQUASH;
2435 nt_status = contact_winbind_auth_crap(opt_username, opt_domain,
2436 opt_workstation,
2437 &opt_challenge,
2438 &opt_lm_response,
2439 &opt_nt_response,
2440 flags, 0,
2441 (unsigned char *)lm_key,
2442 (unsigned char *)user_session_key,
2443 &authoritative,
2444 &error_string, NULL);
2446 if (!NT_STATUS_IS_OK(nt_status)) {
2447 printf("%s (0x%x)\n", error_string,
2448 NT_STATUS_V(nt_status));
2449 SAFE_FREE(error_string);
2450 return False;
2453 if (request_lm_key
2454 && (!all_zero((uint8_t *)lm_key, sizeof(lm_key)))) {
2455 hex_lm_key = hex_encode_talloc(talloc_tos(), (const unsigned char *)lm_key,
2456 sizeof(lm_key));
2457 printf("LM_KEY: %s\n", hex_lm_key);
2458 TALLOC_FREE(hex_lm_key);
2460 if (request_user_session_key
2461 && (!all_zero((uint8_t *)user_session_key,
2462 sizeof(user_session_key)))) {
2463 hex_user_session_key = hex_encode_talloc(talloc_tos(), (const unsigned char *)user_session_key,
2464 sizeof(user_session_key));
2465 printf("NT_KEY: %s\n", hex_user_session_key);
2466 TALLOC_FREE(hex_user_session_key);
2469 return True;
2472 /* Main program */
2474 enum {
2475 OPT_USERNAME = 1000,
2476 OPT_DOMAIN,
2477 OPT_WORKSTATION,
2478 OPT_CHALLENGE,
2479 OPT_RESPONSE,
2480 OPT_LM,
2481 OPT_NT,
2482 OPT_PASSWORD,
2483 OPT_LM_KEY,
2484 OPT_USER_SESSION_KEY,
2485 OPT_DIAGNOSTICS,
2486 OPT_REQUIRE_MEMBERSHIP,
2487 OPT_USE_CACHED_CREDS,
2488 OPT_ALLOW_MSCHAPV2,
2489 OPT_PAM_WINBIND_CONF,
2490 OPT_TARGET_SERVICE,
2491 OPT_TARGET_HOSTNAME,
2492 OPT_OFFLINE_LOGON
2495 int main(int argc, const char **argv)
2497 TALLOC_CTX *frame = talloc_stackframe();
2498 int opt;
2499 const char *helper_protocol = NULL;
2500 int diagnostics = 0;
2502 const char *hex_challenge = NULL;
2503 const char *hex_lm_response = NULL;
2504 const char *hex_nt_response = NULL;
2505 struct loadparm_context *lp_ctx;
2506 poptContext pc;
2507 bool ok;
2509 /* NOTE: DO NOT change this interface without considering the implications!
2510 This is an external interface, which other programs will use to interact
2511 with this helper.
2514 /* We do not use single-letter command abbreviations, because they harm future
2515 interface stability. */
2517 struct poptOption long_options[] = {
2518 POPT_AUTOHELP
2520 .longName = "helper-protocol",
2521 .shortName = 0,
2522 .argInfo = POPT_ARG_STRING,
2523 .arg = &helper_protocol,
2524 .val = OPT_DOMAIN,
2525 .descrip = "operate as a stdio-based helper",
2526 .argDescrip = "helper protocol to use"
2529 .longName = "username",
2530 .shortName = 0,
2531 .argInfo = POPT_ARG_STRING,
2532 .arg = &opt_username,
2533 .val = OPT_USERNAME,
2534 .descrip = "username"
2537 .longName = "domain",
2538 .shortName = 0,
2539 .argInfo = POPT_ARG_STRING,
2540 .arg = &opt_domain,
2541 .val = OPT_DOMAIN,
2542 .descrip = "domain name"
2545 .longName = "workstation",
2546 .shortName = 0,
2547 .argInfo = POPT_ARG_STRING,
2548 .arg = &opt_workstation,
2549 .val = OPT_WORKSTATION,
2550 .descrip = "workstation"
2553 .longName = "challenge",
2554 .shortName = 0,
2555 .argInfo = POPT_ARG_STRING,
2556 .arg = &hex_challenge,
2557 .val = OPT_CHALLENGE,
2558 .descrip = "challenge (HEX encoded)"
2561 .longName = "lm-response",
2562 .shortName = 0,
2563 .argInfo = POPT_ARG_STRING,
2564 .arg = &hex_lm_response,
2565 .val = OPT_LM,
2566 .descrip = "LM Response to the challenge (HEX encoded)"
2569 .longName = "nt-response",
2570 .shortName = 0,
2571 .argInfo = POPT_ARG_STRING,
2572 .arg = &hex_nt_response,
2573 .val = OPT_NT,
2574 .descrip = "NT or NTLMv2 Response to the challenge (HEX encoded)"
2577 .longName = "password",
2578 .shortName = 0,
2579 .argInfo = POPT_ARG_STRING,
2580 .arg = &opt_password,
2581 .val = OPT_PASSWORD,
2582 .descrip = "User's plaintext password"
2585 .longName = "request-lm-key",
2586 .shortName = 0,
2587 .argInfo = POPT_ARG_NONE,
2588 .arg = &request_lm_key,
2589 .val = OPT_LM_KEY,
2590 .descrip = "Retrieve LM session key (or, with --diagnostics, expect LM support)"
2593 .longName = "request-nt-key",
2594 .shortName = 0,
2595 .argInfo = POPT_ARG_NONE,
2596 .arg = &request_user_session_key,
2597 .val = OPT_USER_SESSION_KEY,
2598 .descrip = "Retrieve User (NT) session key"
2601 .longName = "use-cached-creds",
2602 .shortName = 0,
2603 .argInfo = POPT_ARG_NONE,
2604 .arg = &use_cached_creds,
2605 .val = OPT_USE_CACHED_CREDS,
2606 .descrip = "Use cached credentials if no password is given"
2609 .longName = "allow-mschapv2",
2610 .shortName = 0,
2611 .argInfo = POPT_ARG_NONE,
2612 .arg = &opt_allow_mschapv2,
2613 .val = OPT_ALLOW_MSCHAPV2,
2614 .descrip = "Explicitly allow MSCHAPv2",
2617 .longName = "offline-logon",
2618 .shortName = 0,
2619 .argInfo = POPT_ARG_NONE,
2620 .arg = &offline_logon,
2621 .val = OPT_OFFLINE_LOGON,
2622 .descrip = "Use cached passwords when DC is offline"
2625 .longName = "diagnostics",
2626 .shortName = 0,
2627 .argInfo = POPT_ARG_NONE,
2628 .arg = &diagnostics,
2629 .val = OPT_DIAGNOSTICS,
2630 .descrip = "Perform diagnostics on the authentication chain"
2633 .longName = "require-membership-of",
2634 .shortName = 0,
2635 .argInfo = POPT_ARG_STRING,
2636 .arg = &require_membership_of,
2637 .val = OPT_REQUIRE_MEMBERSHIP,
2638 .descrip = "Require that a user be a member of this group (either name or SID) for authentication to succeed",
2641 .longName = "pam-winbind-conf",
2642 .shortName = 0,
2643 .argInfo = POPT_ARG_STRING,
2644 .arg = &opt_pam_winbind_conf,
2645 .val = OPT_PAM_WINBIND_CONF,
2646 .descrip = "Require that request must set WBFLAG_PAM_CONTACT_TRUSTDOM when krb5 auth is required",
2649 .longName = "target-service",
2650 .shortName = 0,
2651 .argInfo = POPT_ARG_STRING,
2652 .arg = &opt_target_service,
2653 .val = OPT_TARGET_SERVICE,
2654 .descrip = "Target service (eg http)",
2657 .longName = "target-hostname",
2658 .shortName = 0,
2659 .argInfo = POPT_ARG_STRING,
2660 .arg = &opt_target_hostname,
2661 .val = OPT_TARGET_HOSTNAME,
2662 .descrip = "Target hostname",
2664 POPT_COMMON_DEBUG_ONLY
2665 POPT_COMMON_CONFIG_ONLY
2666 POPT_COMMON_OPTION_ONLY
2667 POPT_COMMON_VERSION
2668 POPT_TABLEEND
2671 /* Samba client initialisation */
2672 smb_init_locale();
2674 ok = samba_cmdline_init(frame,
2675 SAMBA_CMDLINE_CONFIG_CLIENT,
2676 false /* require_smbconf */);
2677 if (!ok) {
2678 DBG_ERR("Failed to init cmdline parser!\n");
2679 TALLOC_FREE(frame);
2680 exit(1);
2683 pc = samba_popt_get_context(getprogname(),
2684 argc,
2685 argv,
2686 long_options,
2687 POPT_CONTEXT_KEEP_FIRST);
2688 if (pc == NULL) {
2689 DBG_ERR("Failed to setup popt context!\n");
2690 TALLOC_FREE(frame);
2691 exit(1);
2694 while((opt = poptGetNextOpt(pc)) != -1) {
2695 switch (opt) {
2696 case OPT_CHALLENGE:
2697 opt_challenge = strhex_to_data_blob(NULL, hex_challenge);
2698 if (opt_challenge.length != 8) {
2699 fprintf(stderr, "hex decode of %s failed! "
2700 "(only got %d bytes)\n",
2701 hex_challenge,
2702 (int)opt_challenge.length);
2703 exit(1);
2705 break;
2706 case OPT_LM:
2707 opt_lm_response = strhex_to_data_blob(NULL, hex_lm_response);
2708 if (opt_lm_response.length != 24) {
2709 fprintf(stderr, "hex decode of %s failed! "
2710 "(only got %d bytes)\n",
2711 hex_lm_response,
2712 (int)opt_lm_response.length);
2713 exit(1);
2715 break;
2717 case OPT_NT:
2718 opt_nt_response = strhex_to_data_blob(NULL, hex_nt_response);
2719 if (opt_nt_response.length < 24) {
2720 fprintf(stderr, "hex decode of %s failed! "
2721 "(only got %d bytes)\n",
2722 hex_nt_response,
2723 (int)opt_nt_response.length);
2724 exit(1);
2726 break;
2728 case OPT_REQUIRE_MEMBERSHIP:
2729 if (strncasecmp_m("S-", require_membership_of, 2) == 0) {
2730 require_membership_of_sid = require_membership_of;
2732 break;
2734 case POPT_ERROR_BADOPT:
2735 fprintf(stderr, "\nInvalid option %s: %s\n\n",
2736 poptBadOption(pc, 0), poptStrerror(opt));
2737 poptPrintUsage(pc, stderr, 0);
2738 exit(1);
2742 if (opt_username) {
2743 char *domain = SMB_STRDUP(opt_username);
2744 char *p = strchr_m(domain, *lp_winbind_separator());
2745 if (p) {
2746 opt_username = p+1;
2747 *p = '\0';
2748 if (opt_domain && !strequal(opt_domain, domain)) {
2749 fprintf(stderr, "Domain specified in username (%s) "
2750 "doesn't match specified domain (%s)!\n\n",
2751 domain, opt_domain);
2752 poptPrintHelp(pc, stderr, 0);
2753 exit(1);
2755 opt_domain = domain;
2756 } else {
2757 SAFE_FREE(domain);
2761 /* Note: if opt_domain is "" then send no domain */
2762 if (opt_domain == NULL) {
2763 opt_domain = get_winbind_domain();
2766 if (opt_workstation == NULL) {
2767 opt_workstation = "";
2770 lp_ctx = loadparm_init_s3(NULL, loadparm_s3_helpers());
2771 if (lp_ctx == NULL) {
2772 fprintf(stderr, "loadparm_init_s3() failed!\n");
2773 exit(1);
2776 if (helper_protocol) {
2777 int i;
2778 for (i=0; i<NUM_HELPER_MODES; i++) {
2779 if (strcmp(helper_protocol, stdio_helper_protocols[i].name) == 0) {
2780 squid_stream(stdio_helper_protocols[i].mode, lp_ctx, stdio_helper_protocols[i].fn);
2781 exit(0);
2784 fprintf(stderr, "unknown helper protocol [%s]\n\n"
2785 "Valid helper protools:\n\n", helper_protocol);
2787 for (i=0; i<NUM_HELPER_MODES; i++) {
2788 fprintf(stderr, "%s\n",
2789 stdio_helper_protocols[i].name);
2792 exit(1);
2795 if (!opt_username || !*opt_username) {
2796 fprintf(stderr, "username must be specified!\n\n");
2797 poptPrintHelp(pc, stderr, 0);
2798 exit(1);
2801 if (opt_challenge.length) {
2802 if (!check_auth_crap()) {
2803 exit(1);
2805 exit(0);
2808 if (!opt_password) {
2809 char pwd[256] = {0};
2810 int rc;
2812 rc = samba_getpass("Password: ", pwd, sizeof(pwd), false, false);
2813 if (rc == 0) {
2814 opt_password = SMB_STRDUP(pwd);
2818 if (diagnostics) {
2819 if (!diagnose_ntlm_auth(request_lm_key)) {
2820 poptFreeContext(pc);
2821 return 1;
2823 } else {
2824 fstring user;
2826 fstr_sprintf(user, "%s%c%s", opt_domain, winbind_separator(), opt_username);
2827 if (!check_plaintext_auth(user, opt_password, True)) {
2828 poptFreeContext(pc);
2829 return 1;
2833 /* Exit code */
2835 poptFreeContext(pc);
2836 TALLOC_FREE(frame);
2837 return 0;