source: vendor/current/source3/utils/ntlm_auth.c

Last change on this file was 989, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.7

File size: 68.2 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3
4 Winbind status program.
5
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
12
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.
17
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.
22
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/>.
25*/
26
27#include "includes.h"
28#include "lib/param/param.h"
29#include "popt_common.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 "../lib/crypto/arcfour.h"
41#include "nsswitch/winbind_client.h"
42#include "librpc/gen_ndr/krb5pac.h"
43#include "../lib/util/asn1.h"
44#include "auth/common_auth.h"
45#include "source3/include/auth.h"
46#include "source3/auth/proto.h"
47#include "nsswitch/libwbclient/wbclient.h"
48#include "lib/param/loadparm.h"
49
50#if HAVE_KRB5
51#include "auth/kerberos/pac_utils.h"
52#endif
53
54#ifndef PAM_WINBIND_CONFIG_FILE
55#define PAM_WINBIND_CONFIG_FILE "/etc/security/pam_winbind.conf"
56#endif
57
58#define WINBIND_KRB5_AUTH 0x00000080
59
60#undef DBGC_CLASS
61#define DBGC_CLASS DBGC_WINBIND
62
63#define INITIAL_BUFFER_SIZE 300
64#define MAX_BUFFER_SIZE 630000
65
66enum stdio_helper_mode {
67 SQUID_2_4_BASIC,
68 SQUID_2_5_BASIC,
69 SQUID_2_5_NTLMSSP,
70 NTLMSSP_CLIENT_1,
71 GSS_SPNEGO_SERVER,
72 GSS_SPNEGO_CLIENT,
73 NTLM_SERVER_1,
74 NTLM_CHANGE_PASSWORD_1,
75 NUM_HELPER_MODES
76};
77
78enum ntlm_auth_cli_state {
79 CLIENT_INITIAL = 0,
80 CLIENT_RESPONSE,
81 CLIENT_FINISHED,
82 CLIENT_ERROR
83};
84
85struct ntlm_auth_state {
86 TALLOC_CTX *mem_ctx;
87 enum stdio_helper_mode helper_mode;
88 enum ntlm_auth_cli_state cli_state;
89 struct ntlmssp_state *ntlmssp_state;
90 uint32_t neg_flags;
91 char *want_feature_list;
92 bool have_session_key;
93 DATA_BLOB session_key;
94 DATA_BLOB initial_message;
95 void *gensec_private_1;
96};
97typedef void (*stdio_helper_function)(enum stdio_helper_mode stdio_helper_mode,
98 struct loadparm_context *lp_ctx,
99 struct ntlm_auth_state *state, char *buf,
100 int length, void **private2);
101
102static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
103 struct loadparm_context *lp_ctx,
104 char *buf, int length, void **private1);
105
106static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode,
107 struct loadparm_context *lp_ctx,
108 struct ntlm_auth_state *state,
109 stdio_helper_function fn, void **private2);
110
111static void manage_squid_basic_request (enum stdio_helper_mode stdio_helper_mode,
112 struct loadparm_context *lp_ctx,
113 struct ntlm_auth_state *state,
114 char *buf, int length, void **private2);
115
116static void manage_squid_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode,
117 struct loadparm_context *lp_ctx,
118 struct ntlm_auth_state *state,
119 char *buf, int length, void **private2);
120
121static void manage_client_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode,
122 struct loadparm_context *lp_ctx,
123 struct ntlm_auth_state *state,
124 char *buf, int length, void **private2);
125
126static void manage_gss_spnego_request (enum stdio_helper_mode stdio_helper_mode,
127 struct loadparm_context *lp_ctx,
128 struct ntlm_auth_state *state,
129 char *buf, int length, void **private2);
130
131static void manage_gss_spnego_client_request (enum stdio_helper_mode stdio_helper_mode,
132 struct loadparm_context *lp_ctx,
133 struct ntlm_auth_state *state,
134 char *buf, int length, void **private2);
135
136static void manage_ntlm_server_1_request (enum stdio_helper_mode stdio_helper_mode,
137 struct loadparm_context *lp_ctx,
138 struct ntlm_auth_state *state,
139 char *buf, int length, void **private2);
140
141static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode,
142 struct loadparm_context *lp_ctx,
143 struct ntlm_auth_state *state,
144 char *buf, int length, void **private2);
145
146static const struct {
147 enum stdio_helper_mode mode;
148 const char *name;
149 stdio_helper_function fn;
150} stdio_helper_protocols[] = {
151 { SQUID_2_4_BASIC, "squid-2.4-basic", manage_squid_basic_request},
152 { SQUID_2_5_BASIC, "squid-2.5-basic", manage_squid_basic_request},
153 { SQUID_2_5_NTLMSSP, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request},
154 { NTLMSSP_CLIENT_1, "ntlmssp-client-1", manage_client_ntlmssp_request},
155 { GSS_SPNEGO_SERVER, "gss-spnego", manage_gss_spnego_request},
156 { GSS_SPNEGO_CLIENT, "gss-spnego-client", manage_gss_spnego_client_request},
157 { NTLM_SERVER_1, "ntlm-server-1", manage_ntlm_server_1_request},
158 { NTLM_CHANGE_PASSWORD_1, "ntlm-change-password-1", manage_ntlm_change_password_1_request},
159 { NUM_HELPER_MODES, NULL, NULL}
160};
161
162const char *opt_username;
163const char *opt_domain;
164const char *opt_workstation;
165const char *opt_password;
166static DATA_BLOB opt_challenge;
167static DATA_BLOB opt_lm_response;
168static DATA_BLOB opt_nt_response;
169static int request_lm_key;
170static int request_user_session_key;
171static int use_cached_creds;
172static int offline_logon;
173
174static const char *require_membership_of;
175static const char *require_membership_of_sid;
176static const char *opt_pam_winbind_conf;
177
178const char *opt_target_service;
179const char *opt_target_hostname;
180
181
182/* This is a bit hairy, but the basic idea is to do a password callback
183 to the calling application. The callback comes from within gensec */
184
185static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mode,
186 struct loadparm_context *lp_ctx,
187 struct ntlm_auth_state *state, char *buf, int length,
188 void **password)
189{
190 DATA_BLOB in;
191 if (strlen(buf) < 2) {
192 DEBUG(1, ("query [%s] invalid", buf));
193 x_fprintf(x_stdout, "BH Query invalid\n");
194 return;
195 }
196
197 if (strlen(buf) > 3) {
198 in = base64_decode_data_blob(buf + 3);
199 } else {
200 in = data_blob(NULL, 0);
201 }
202
203 if (strncmp(buf, "PW ", 3) == 0) {
204
205 *password = talloc_strndup(NULL,
206 (const char *)in.data, in.length);
207
208 if (*password == NULL) {
209 DEBUG(1, ("Out of memory\n"));
210 x_fprintf(x_stdout, "BH Out of memory\n");
211 data_blob_free(&in);
212 return;
213 }
214
215 x_fprintf(x_stdout, "OK\n");
216 data_blob_free(&in);
217 return;
218 }
219 DEBUG(1, ("Asked for (and expected) a password\n"));
220 x_fprintf(x_stdout, "BH Expected a password\n");
221 data_blob_free(&in);
222}
223
224/**
225 * Callback for password credentials. This is not async, and when
226 * GENSEC and the credentials code is made async, it will look rather
227 * different.
228 */
229
230static const char *get_password(struct cli_credentials *credentials)
231{
232 TALLOC_CTX *frame = talloc_stackframe();
233 char *password = NULL;
234 struct ntlm_auth_state *state;
235
236 state = talloc_zero(frame, struct ntlm_auth_state);
237 if (state == NULL) {
238 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
239 x_fprintf(x_stderr, "ERR\n");
240 exit(1);
241 }
242
243 state->mem_ctx = state;
244
245 /* Ask for a password */
246 x_fprintf(x_stdout, "PW\n");
247
248 manage_squid_request(NUM_HELPER_MODES /* bogus */, NULL, state, manage_gensec_get_pw_request, (void **)&password);
249 talloc_steal(credentials, password);
250 TALLOC_FREE(frame);
251 return password;
252}
253
254/**
255 * A limited set of features are defined with text strings as needed
256 * by ntlm_auth
257 *
258 */
259static void gensec_want_feature_list(struct gensec_security *state, char* feature_list)
260{
261 if (in_list("NTLMSSP_FEATURE_SESSION_KEY", feature_list, true)) {
262 DEBUG(10, ("want GENSEC_FEATURE_SESSION_KEY\n"));
263 gensec_want_feature(state, GENSEC_FEATURE_SESSION_KEY);
264 }
265 if (in_list("NTLMSSP_FEATURE_SIGN", feature_list, true)) {
266 DEBUG(10, ("want GENSEC_FEATURE_SIGN\n"));
267 gensec_want_feature(state, GENSEC_FEATURE_SIGN);
268 }
269 if (in_list("NTLMSSP_FEATURE_SEAL", feature_list, true)) {
270 DEBUG(10, ("want GENSEC_FEATURE_SEAL\n"));
271 gensec_want_feature(state, GENSEC_FEATURE_SEAL);
272 }
273 if (in_list("NTLMSSP_FEATURE_CCACHE", feature_list, true)) {
274 DEBUG(10, ("want GENSEC_FEATURE_NTLM_CCACHE\n"));
275 gensec_want_feature(state, GENSEC_FEATURE_NTLM_CCACHE);
276 }
277}
278
279static char winbind_separator(void)
280{
281 struct winbindd_response response;
282 static bool got_sep;
283 static char sep;
284
285 if (got_sep)
286 return sep;
287
288 ZERO_STRUCT(response);
289
290 /* Send off request */
291
292 if (winbindd_request_response(NULL, WINBINDD_INFO, NULL, &response) !=
293 NSS_STATUS_SUCCESS) {
294 d_printf("could not obtain winbind separator!\n");
295 return *lp_winbind_separator();
296 }
297
298 sep = response.data.info.winbind_separator;
299 got_sep = True;
300
301 if (!sep) {
302 d_printf("winbind separator was NULL!\n");
303 return *lp_winbind_separator();
304 }
305
306 return sep;
307}
308
309const char *get_winbind_domain(void)
310{
311 struct winbindd_response response;
312
313 static fstring winbind_domain;
314 if (*winbind_domain) {
315 return winbind_domain;
316 }
317
318 ZERO_STRUCT(response);
319
320 /* Send off request */
321
322 if (winbindd_request_response(NULL, WINBINDD_DOMAIN_NAME, NULL, &response) !=
323 NSS_STATUS_SUCCESS) {
324 DEBUG(1, ("could not obtain winbind domain name!\n"));
325 return lp_workgroup();
326 }
327
328 fstrcpy(winbind_domain, response.data.domain_name);
329
330 return winbind_domain;
331
332}
333
334const char *get_winbind_netbios_name(void)
335{
336 struct winbindd_response response;
337
338 static fstring winbind_netbios_name;
339
340 if (*winbind_netbios_name) {
341 return winbind_netbios_name;
342 }
343
344 ZERO_STRUCT(response);
345
346 /* Send off request */
347
348 if (winbindd_request_response(NULL, WINBINDD_NETBIOS_NAME, NULL, &response) !=
349 NSS_STATUS_SUCCESS) {
350 DEBUG(1, ("could not obtain winbind netbios name!\n"));
351 return lp_netbios_name();
352 }
353
354 fstrcpy(winbind_netbios_name, response.data.netbios_name);
355
356 return winbind_netbios_name;
357
358}
359
360DATA_BLOB get_challenge(void)
361{
362 static DATA_BLOB chal;
363 if (opt_challenge.length)
364 return opt_challenge;
365
366 chal = data_blob(NULL, 8);
367
368 generate_random_buffer(chal.data, chal.length);
369 return chal;
370}
371
372/* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
373 form DOMAIN/user into a domain and a user */
374
375static bool parse_ntlm_auth_domain_user(const char *domuser, fstring domain,
376 fstring user)
377{
378
379 char *p = strchr(domuser,winbind_separator());
380
381 if (!p) {
382 return False;
383 }
384
385 fstrcpy(user, p+1);
386 fstrcpy(domain, domuser);
387 domain[PTR_DIFF(p, domuser)] = 0;
388 return strupper_m(domain);
389}
390
391static bool get_require_membership_sid(void) {
392 struct winbindd_request request;
393 struct winbindd_response response;
394
395 if (!require_membership_of) {
396 return True;
397 }
398
399 if (require_membership_of_sid) {
400 return True;
401 }
402
403 /* Otherwise, ask winbindd for the name->sid request */
404
405 ZERO_STRUCT(request);
406 ZERO_STRUCT(response);
407
408 if (!parse_ntlm_auth_domain_user(require_membership_of,
409 request.data.name.dom_name,
410 request.data.name.name)) {
411 DEBUG(0, ("Could not parse %s into separate domain/name parts!\n",
412 require_membership_of));
413 return False;
414 }
415
416 if (winbindd_request_response(NULL, WINBINDD_LOOKUPNAME, &request, &response) !=
417 NSS_STATUS_SUCCESS) {
418 DEBUG(0, ("Winbindd lookupname failed to resolve %s into a SID!\n",
419 require_membership_of));
420 return False;
421 }
422
423 require_membership_of_sid = SMB_STRDUP(response.data.sid.sid);
424
425 if (require_membership_of_sid)
426 return True;
427
428 return False;
429}
430
431/*
432 * Get some configuration from pam_winbind.conf to see if we
433 * need to contact trusted domain
434 */
435
436int get_pam_winbind_config()
437{
438 int ctrl = 0;
439 struct tiniparser_dictionary *d = NULL;
440
441 if (!opt_pam_winbind_conf || !*opt_pam_winbind_conf) {
442 opt_pam_winbind_conf = PAM_WINBIND_CONFIG_FILE;
443 }
444
445 d = tiniparser_load(opt_pam_winbind_conf);
446
447 if (!d) {
448 return 0;
449 }
450
451 if (tiniparser_getboolean(d, "global:krb5_auth", false)) {
452 ctrl |= WINBIND_KRB5_AUTH;
453 }
454
455 tiniparser_freedict(d);
456
457 return ctrl;
458}
459
460/* Authenticate a user with a plaintext password */
461
462static bool check_plaintext_auth(const char *user, const char *pass,
463 bool stdout_diagnostics)
464{
465 struct winbindd_request request;
466 struct winbindd_response response;
467 NSS_STATUS result;
468
469 if (!get_require_membership_sid()) {
470 return False;
471 }
472
473 /* Send off request */
474
475 ZERO_STRUCT(request);
476 ZERO_STRUCT(response);
477
478 fstrcpy(request.data.auth.user, user);
479 fstrcpy(request.data.auth.pass, pass);
480 if (require_membership_of_sid) {
481 strlcpy(request.data.auth.require_membership_of_sid,
482 require_membership_of_sid,
483 sizeof(request.data.auth.require_membership_of_sid));
484 }
485
486 if (offline_logon) {
487 request.flags |= WBFLAG_PAM_CACHED_LOGIN;
488 }
489
490 result = winbindd_request_response(NULL, WINBINDD_PAM_AUTH, &request, &response);
491
492 /* Display response */
493
494 if (stdout_diagnostics) {
495 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
496 d_printf("Reading winbind reply failed! (0x01)\n");
497 }
498
499 d_printf("%s: %s (0x%x)\n",
500 response.data.auth.nt_status_string,
501 response.data.auth.error_string,
502 response.data.auth.nt_status);
503 } else {
504 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
505 DEBUG(1, ("Reading winbind reply failed! (0x01)\n"));
506 }
507
508 DEBUG(3, ("%s: %s (0x%x)\n",
509 response.data.auth.nt_status_string,
510 response.data.auth.error_string,
511 response.data.auth.nt_status));
512 }
513
514 return (result == NSS_STATUS_SUCCESS);
515}
516
517/* authenticate a user with an encrypted username/password */
518
519NTSTATUS contact_winbind_auth_crap(const char *username,
520 const char *domain,
521 const char *workstation,
522 const DATA_BLOB *challenge,
523 const DATA_BLOB *lm_response,
524 const DATA_BLOB *nt_response,
525 uint32_t flags,
526 uint32_t extra_logon_parameters,
527 uint8_t lm_key[8],
528 uint8_t user_session_key[16],
529 char **error_string,
530 char **unix_name)
531{
532 NTSTATUS nt_status;
533 NSS_STATUS result;
534 struct winbindd_request request;
535 struct winbindd_response response;
536
537 if (!get_require_membership_sid()) {
538 return NT_STATUS_INVALID_PARAMETER;
539 }
540
541 ZERO_STRUCT(request);
542 ZERO_STRUCT(response);
543
544 request.flags = flags;
545
546 request.data.auth_crap.logon_parameters = extra_logon_parameters
547 | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT | MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT;
548
549 if (require_membership_of_sid)
550 fstrcpy(request.data.auth_crap.require_membership_of_sid, require_membership_of_sid);
551
552 fstrcpy(request.data.auth_crap.user, username);
553 fstrcpy(request.data.auth_crap.domain, domain);
554
555 fstrcpy(request.data.auth_crap.workstation,
556 workstation);
557
558 memcpy(request.data.auth_crap.chal, challenge->data, MIN(challenge->length, 8));
559
560 if (lm_response && lm_response->length) {
561 memcpy(request.data.auth_crap.lm_resp,
562 lm_response->data,
563 MIN(lm_response->length, sizeof(request.data.auth_crap.lm_resp)));
564 request.data.auth_crap.lm_resp_len = lm_response->length;
565 }
566
567 if (nt_response && nt_response->length) {
568 if (nt_response->length > sizeof(request.data.auth_crap.nt_resp)) {
569 request.flags = request.flags | WBFLAG_BIG_NTLMV2_BLOB;
570 request.extra_len = nt_response->length;
571 request.extra_data.data = SMB_MALLOC_ARRAY(char, request.extra_len);
572 if (request.extra_data.data == NULL) {
573 return NT_STATUS_NO_MEMORY;
574 }
575 memcpy(request.extra_data.data, nt_response->data,
576 nt_response->length);
577
578 } else {
579 memcpy(request.data.auth_crap.nt_resp,
580 nt_response->data, nt_response->length);
581 }
582 request.data.auth_crap.nt_resp_len = nt_response->length;
583 }
584
585 result = winbindd_request_response(NULL, WINBINDD_PAM_AUTH_CRAP, &request, &response);
586 SAFE_FREE(request.extra_data.data);
587
588 /* Display response */
589
590 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
591 nt_status = NT_STATUS_UNSUCCESSFUL;
592 if (error_string)
593 *error_string = smb_xstrdup("Reading winbind reply failed!");
594 winbindd_free_response(&response);
595 return nt_status;
596 }
597
598 nt_status = (NT_STATUS(response.data.auth.nt_status));
599 if (!NT_STATUS_IS_OK(nt_status)) {
600 if (error_string)
601 *error_string = smb_xstrdup(response.data.auth.error_string);
602 winbindd_free_response(&response);
603 return nt_status;
604 }
605
606 if ((flags & WBFLAG_PAM_LMKEY) && lm_key) {
607 memcpy(lm_key, response.data.auth.first_8_lm_hash,
608 sizeof(response.data.auth.first_8_lm_hash));
609 }
610 if ((flags & WBFLAG_PAM_USER_SESSION_KEY) && user_session_key) {
611 memcpy(user_session_key, response.data.auth.user_session_key,
612 sizeof(response.data.auth.user_session_key));
613 }
614
615 if (flags & WBFLAG_PAM_UNIX_NAME) {
616 *unix_name = SMB_STRDUP(response.data.auth.unix_username);
617 if (!*unix_name) {
618 winbindd_free_response(&response);
619 return NT_STATUS_NO_MEMORY;
620 }
621 }
622
623 winbindd_free_response(&response);
624 return nt_status;
625}
626
627/* contact server to change user password using auth crap */
628static NTSTATUS contact_winbind_change_pswd_auth_crap(const char *username,
629 const char *domain,
630 const DATA_BLOB new_nt_pswd,
631 const DATA_BLOB old_nt_hash_enc,
632 const DATA_BLOB new_lm_pswd,
633 const DATA_BLOB old_lm_hash_enc,
634 char **error_string)
635{
636 NTSTATUS nt_status;
637 NSS_STATUS result;
638 struct winbindd_request request;
639 struct winbindd_response response;
640
641 if (!get_require_membership_sid())
642 {
643 if(error_string)
644 *error_string = smb_xstrdup("Can't get membership sid.");
645 return NT_STATUS_INVALID_PARAMETER;
646 }
647
648 ZERO_STRUCT(request);
649 ZERO_STRUCT(response);
650
651 if(username != NULL)
652 fstrcpy(request.data.chng_pswd_auth_crap.user, username);
653 if(domain != NULL)
654 fstrcpy(request.data.chng_pswd_auth_crap.domain,domain);
655
656 if(new_nt_pswd.length)
657 {
658 memcpy(request.data.chng_pswd_auth_crap.new_nt_pswd, new_nt_pswd.data, sizeof(request.data.chng_pswd_auth_crap.new_nt_pswd));
659 request.data.chng_pswd_auth_crap.new_nt_pswd_len = new_nt_pswd.length;
660 }
661
662 if(old_nt_hash_enc.length)
663 {
664 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));
665 request.data.chng_pswd_auth_crap.old_nt_hash_enc_len = old_nt_hash_enc.length;
666 }
667
668 if(new_lm_pswd.length)
669 {
670 memcpy(request.data.chng_pswd_auth_crap.new_lm_pswd, new_lm_pswd.data, sizeof(request.data.chng_pswd_auth_crap.new_lm_pswd));
671 request.data.chng_pswd_auth_crap.new_lm_pswd_len = new_lm_pswd.length;
672 }
673
674 if(old_lm_hash_enc.length)
675 {
676 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));
677 request.data.chng_pswd_auth_crap.old_lm_hash_enc_len = old_lm_hash_enc.length;
678 }
679
680 result = winbindd_request_response(NULL, WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP, &request, &response);
681
682 /* Display response */
683
684 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0))
685 {
686 nt_status = NT_STATUS_UNSUCCESSFUL;
687 if (error_string)
688 *error_string = smb_xstrdup("Reading winbind reply failed!");
689 winbindd_free_response(&response);
690 return nt_status;
691 }
692
693 nt_status = (NT_STATUS(response.data.auth.nt_status));
694 if (!NT_STATUS_IS_OK(nt_status))
695 {
696 if (error_string)
697 *error_string = smb_xstrdup(response.data.auth.error_string);
698 winbindd_free_response(&response);
699 return nt_status;
700 }
701
702 winbindd_free_response(&response);
703
704 return nt_status;
705}
706
707static NTSTATUS ntlm_auth_generate_session_info(struct auth4_context *auth_context,
708 TALLOC_CTX *mem_ctx,
709 void *server_returned_info,
710 const char *original_user_name,
711 uint32_t session_info_flags,
712 struct auth_session_info **session_info_out)
713{
714 const char *unix_username = (const char *)server_returned_info;
715 bool ok;
716 struct dom_sid *sids = NULL;
717 struct auth_session_info *session_info = NULL;
718
719 session_info = talloc_zero(mem_ctx, struct auth_session_info);
720 if (session_info == NULL) {
721 return NT_STATUS_NO_MEMORY;
722 }
723
724 session_info->unix_info = talloc_zero(session_info, struct auth_user_info_unix);
725 if (session_info->unix_info == NULL) {
726 TALLOC_FREE(session_info);
727 return NT_STATUS_NO_MEMORY;
728 }
729 session_info->unix_info->unix_name = talloc_strdup(session_info->unix_info,
730 unix_username);
731 if (session_info->unix_info->unix_name == NULL) {
732 TALLOC_FREE(session_info);
733 return NT_STATUS_NO_MEMORY;
734 }
735
736 session_info->security_token = talloc_zero(session_info, struct security_token);
737 if (session_info->security_token == NULL) {
738 TALLOC_FREE(session_info);
739 return NT_STATUS_NO_MEMORY;
740 }
741
742 sids = talloc_zero_array(session_info->security_token,
743 struct dom_sid, 3);
744 if (sids == NULL) {
745 TALLOC_FREE(session_info);
746 return NT_STATUS_NO_MEMORY;
747 }
748 ok = dom_sid_parse(SID_WORLD, &sids[0]);
749 if (!ok) {
750 TALLOC_FREE(session_info);
751 return NT_STATUS_INTERNAL_ERROR;
752 }
753 ok = dom_sid_parse(SID_NT_NETWORK, &sids[1]);
754 if (!ok) {
755 TALLOC_FREE(session_info);
756 return NT_STATUS_INTERNAL_ERROR;
757 }
758 ok = dom_sid_parse(SID_NT_AUTHENTICATED_USERS, &sids[2]);
759 if (!ok) {
760 TALLOC_FREE(session_info);
761 return NT_STATUS_INTERNAL_ERROR;
762 }
763
764 session_info->security_token->num_sids = talloc_array_length(sids);
765 session_info->security_token->sids = sids;
766
767 *session_info_out = session_info;
768
769 return NT_STATUS_OK;
770}
771
772static NTSTATUS ntlm_auth_generate_session_info_pac(struct auth4_context *auth_ctx,
773 TALLOC_CTX *mem_ctx,
774 struct smb_krb5_context *smb_krb5_context,
775 DATA_BLOB *pac_blob,
776 const char *princ_name,
777 const struct tsocket_address *remote_address,
778 uint32_t session_info_flags,
779 struct auth_session_info **session_info)
780{
781 TALLOC_CTX *tmp_ctx;
782 struct PAC_LOGON_INFO *logon_info = NULL;
783 char *unixuser;
784 NTSTATUS status;
785 char *domain = NULL;
786 char *realm = NULL;
787 char *user = NULL;
788 char *p;
789
790 tmp_ctx = talloc_new(mem_ctx);
791 if (!tmp_ctx) {
792 return NT_STATUS_NO_MEMORY;
793 }
794
795 if (pac_blob) {
796#ifdef HAVE_KRB5
797 status = kerberos_pac_logon_info(tmp_ctx, *pac_blob, NULL, NULL,
798 NULL, NULL, 0, &logon_info);
799#else
800 status = NT_STATUS_ACCESS_DENIED;
801#endif
802 if (!NT_STATUS_IS_OK(status)) {
803 goto done;
804 }
805 }
806
807 DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name));
808
809 p = strchr_m(princ_name, '@');
810 if (!p) {
811 DEBUG(3, ("[%s] Doesn't look like a valid principal\n",
812 princ_name));
813 return NT_STATUS_LOGON_FAILURE;
814 }
815
816 user = talloc_strndup(mem_ctx, princ_name, p - princ_name);
817 if (!user) {
818 return NT_STATUS_NO_MEMORY;
819 }
820
821 realm = talloc_strdup(talloc_tos(), p + 1);
822 if (!realm) {
823 return NT_STATUS_NO_MEMORY;
824 }
825
826 if (!strequal(realm, lp_realm())) {
827 DEBUG(3, ("Ticket for foreign realm %s@%s\n", user, realm));
828 if (!lp_allow_trusted_domains()) {
829 return NT_STATUS_LOGON_FAILURE;
830 }
831 }
832
833 if (logon_info && logon_info->info3.base.logon_domain.string) {
834 domain = talloc_strdup(mem_ctx,
835 logon_info->info3.base.logon_domain.string);
836 if (!domain) {
837 return NT_STATUS_NO_MEMORY;
838 }
839 DEBUG(10, ("Domain is [%s] (using PAC)\n", domain));
840 } else {
841
842 /* If we have winbind running, we can (and must) shorten the
843 username by using the short netbios name. Otherwise we will
844 have inconsistent user names. With Kerberos, we get the
845 fully qualified realm, with ntlmssp we get the short
846 name. And even w2k3 does use ntlmssp if you for example
847 connect to an ip address. */
848
849 wbcErr wbc_status;
850 struct wbcDomainInfo *info = NULL;
851
852 DEBUG(10, ("Mapping [%s] to short name using winbindd\n",
853 realm));
854
855 wbc_status = wbcDomainInfo(realm, &info);
856
857 if (WBC_ERROR_IS_OK(wbc_status)) {
858 domain = talloc_strdup(mem_ctx,
859 info->short_name);
860 wbcFreeMemory(info);
861 } else {
862 DEBUG(3, ("Could not find short name: %s\n",
863 wbcErrorString(wbc_status)));
864 domain = talloc_strdup(mem_ctx, realm);
865 }
866 if (!domain) {
867 return NT_STATUS_NO_MEMORY;
868 }
869 DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain));
870 }
871
872 unixuser = talloc_asprintf(tmp_ctx, "%s%c%s", domain, winbind_separator(), user);
873 if (!unixuser) {
874 status = NT_STATUS_NO_MEMORY;
875 goto done;
876 }
877
878 status = ntlm_auth_generate_session_info(auth_ctx, mem_ctx, unixuser, NULL, session_info_flags, session_info);
879
880done:
881 TALLOC_FREE(tmp_ctx);
882 return status;
883}
884
885
886
887/**
888 * Return the challenge as determined by the authentication subsystem
889 * @return an 8 byte random challenge
890 */
891
892static NTSTATUS ntlm_auth_get_challenge(struct auth4_context *auth_ctx,
893 uint8_t chal[8])
894{
895 if (auth_ctx->challenge.data.length == 8) {
896 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
897 auth_ctx->challenge.set_by));
898 memcpy(chal, auth_ctx->challenge.data.data, 8);
899 return NT_STATUS_OK;
900 }
901
902 if (!auth_ctx->challenge.set_by) {
903 generate_random_buffer(chal, 8);
904
905 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
906 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
907 auth_ctx->challenge.set_by = "random";
908 }
909
910 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
911 auth_ctx->challenge.set_by));
912
913 return NT_STATUS_OK;
914}
915
916/**
917 * NTLM2 authentication modifies the effective challenge,
918 * @param challenge The new challenge value
919 */
920static NTSTATUS ntlm_auth_set_challenge(struct auth4_context *auth_ctx, const uint8_t chal[8], const char *set_by)
921{
922 auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
923 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
924
925 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
926 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
927
928 return NT_STATUS_OK;
929}
930
931/**
932 * Check the password on an NTLMSSP login.
933 *
934 * Return the session keys used on the connection.
935 */
936
937static NTSTATUS winbind_pw_check(struct auth4_context *auth4_context,
938 TALLOC_CTX *mem_ctx,
939 const struct auth_usersupplied_info *user_info,
940 void **server_returned_info,
941 DATA_BLOB *session_key, DATA_BLOB *lm_session_key)
942{
943 static const char zeros[16] = { 0, };
944 NTSTATUS nt_status;
945 char *error_string = NULL;
946 uint8_t lm_key[8];
947 uint8_t user_sess_key[16];
948 char *unix_name = NULL;
949
950 nt_status = contact_winbind_auth_crap(user_info->client.account_name, user_info->client.domain_name,
951 user_info->workstation_name,
952 &auth4_context->challenge.data,
953 &user_info->password.response.lanman,
954 &user_info->password.response.nt,
955 WBFLAG_PAM_LMKEY | WBFLAG_PAM_USER_SESSION_KEY | WBFLAG_PAM_UNIX_NAME,
956 0,
957 lm_key, user_sess_key,
958 &error_string, &unix_name);
959
960 if (NT_STATUS_IS_OK(nt_status)) {
961 if (memcmp(lm_key, zeros, 8) != 0) {
962 *lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
963 memcpy(lm_session_key->data, lm_key, 8);
964 memset(lm_session_key->data+8, '\0', 8);
965 }
966
967 if (memcmp(user_sess_key, zeros, 16) != 0) {
968 *session_key = data_blob_talloc(mem_ctx, user_sess_key, 16);
969 }
970 *server_returned_info = talloc_strdup(mem_ctx,
971 unix_name);
972 } else {
973 DEBUG(NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED) ? 0 : 3,
974 ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
975 user_info->client.domain_name, user_info->client.account_name,
976 user_info->workstation_name,
977 error_string ? error_string : "unknown error (NULL)"));
978 }
979
980 SAFE_FREE(error_string);
981 SAFE_FREE(unix_name);
982 return nt_status;
983}
984
985static NTSTATUS local_pw_check(struct auth4_context *auth4_context,
986 TALLOC_CTX *mem_ctx,
987 const struct auth_usersupplied_info *user_info,
988 void **server_returned_info,
989 DATA_BLOB *session_key, DATA_BLOB *lm_session_key)
990{
991 NTSTATUS nt_status;
992 struct samr_Password lm_pw, nt_pw;
993
994 nt_lm_owf_gen (opt_password, nt_pw.hash, lm_pw.hash);
995
996 nt_status = ntlm_password_check(mem_ctx,
997 true, true, 0,
998 &auth4_context->challenge.data,
999 &user_info->password.response.lanman,
1000 &user_info->password.response.nt,
1001 user_info->client.account_name,
1002 user_info->client.account_name,
1003 user_info->client.domain_name,
1004 &lm_pw, &nt_pw, session_key, lm_session_key);
1005
1006 if (NT_STATUS_IS_OK(nt_status)) {
1007 *server_returned_info = talloc_asprintf(mem_ctx,
1008 "%s%c%s", user_info->client.domain_name,
1009 *lp_winbind_separator(),
1010 user_info->client.account_name);
1011 } else {
1012 DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
1013 user_info->client.domain_name, user_info->client.account_name,
1014 user_info->workstation_name,
1015 nt_errstr(nt_status)));
1016 }
1017 return nt_status;
1018}
1019
1020static NTSTATUS ntlm_auth_prepare_gensec_client(TALLOC_CTX *mem_ctx,
1021 struct loadparm_context *lp_ctx,
1022 struct gensec_security **gensec_security_out)
1023{
1024 struct gensec_security *gensec_security = NULL;
1025 NTSTATUS nt_status;
1026 TALLOC_CTX *tmp_ctx;
1027 const struct gensec_security_ops **backends = NULL;
1028 struct gensec_settings *gensec_settings = NULL;
1029 size_t idx = 0;
1030
1031 tmp_ctx = talloc_new(mem_ctx);
1032 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
1033
1034 gensec_settings = lpcfg_gensec_settings(tmp_ctx, lp_ctx);
1035 if (gensec_settings == NULL) {
1036 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1037 TALLOC_FREE(tmp_ctx);
1038 return NT_STATUS_NO_MEMORY;
1039 }
1040
1041 backends = talloc_zero_array(gensec_settings,
1042 const struct gensec_security_ops *, 4);
1043 if (backends == NULL) {
1044 TALLOC_FREE(tmp_ctx);
1045 return NT_STATUS_NO_MEMORY;
1046 }
1047 gensec_settings->backends = backends;
1048
1049 gensec_init();
1050
1051 /* These need to be in priority order, krb5 before NTLMSSP */
1052#if defined(HAVE_KRB5)
1053 backends[idx++] = &gensec_gse_krb5_security_ops;
1054#endif
1055
1056 backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_NTLMSSP);
1057
1058 backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_SPNEGO);
1059
1060 nt_status = gensec_client_start(NULL, &gensec_security,
1061 gensec_settings);
1062 if (!NT_STATUS_IS_OK(nt_status)) {
1063 TALLOC_FREE(tmp_ctx);
1064 return nt_status;
1065 }
1066
1067 talloc_unlink(tmp_ctx, gensec_settings);
1068
1069 if (opt_target_service != NULL) {
1070 nt_status = gensec_set_target_service(gensec_security,
1071 opt_target_service);
1072 if (!NT_STATUS_IS_OK(nt_status)) {
1073 TALLOC_FREE(tmp_ctx);
1074 return nt_status;
1075 }
1076 }
1077
1078 if (opt_target_hostname != NULL) {
1079 nt_status = gensec_set_target_hostname(gensec_security,
1080 opt_target_hostname);
1081 if (!NT_STATUS_IS_OK(nt_status)) {
1082 TALLOC_FREE(tmp_ctx);
1083 return nt_status;
1084 }
1085 }
1086
1087 *gensec_security_out = talloc_steal(mem_ctx, gensec_security);
1088 TALLOC_FREE(tmp_ctx);
1089 return NT_STATUS_OK;
1090}
1091
1092static struct auth4_context *make_auth4_context_ntlm_auth(TALLOC_CTX *mem_ctx, bool local_pw)
1093{
1094 struct auth4_context *auth4_context = talloc_zero(mem_ctx, struct auth4_context);
1095 if (auth4_context == NULL) {
1096 DEBUG(10, ("failed to allocate auth4_context failed\n"));
1097 return NULL;
1098 }
1099 auth4_context->generate_session_info = ntlm_auth_generate_session_info;
1100 auth4_context->generate_session_info_pac = ntlm_auth_generate_session_info_pac;
1101 auth4_context->get_ntlm_challenge = ntlm_auth_get_challenge;
1102 auth4_context->set_ntlm_challenge = ntlm_auth_set_challenge;
1103 if (local_pw) {
1104 auth4_context->check_ntlm_password = local_pw_check;
1105 } else {
1106 auth4_context->check_ntlm_password = winbind_pw_check;
1107 }
1108 auth4_context->private_data = NULL;
1109 return auth4_context;
1110}
1111
1112static NTSTATUS ntlm_auth_prepare_gensec_server(TALLOC_CTX *mem_ctx,
1113 struct loadparm_context *lp_ctx,
1114 struct gensec_security **gensec_security_out)
1115{
1116 struct gensec_security *gensec_security;
1117 NTSTATUS nt_status;
1118
1119 TALLOC_CTX *tmp_ctx;
1120 const struct gensec_security_ops **backends;
1121 struct gensec_settings *gensec_settings;
1122 size_t idx = 0;
1123 struct cli_credentials *server_credentials;
1124
1125 struct auth4_context *auth4_context;
1126
1127 tmp_ctx = talloc_new(mem_ctx);
1128 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
1129
1130 auth4_context = make_auth4_context_ntlm_auth(tmp_ctx, opt_password);
1131 if (auth4_context == NULL) {
1132 TALLOC_FREE(tmp_ctx);
1133 return NT_STATUS_NO_MEMORY;
1134 }
1135
1136 gensec_settings = lpcfg_gensec_settings(tmp_ctx, lp_ctx);
1137 if (lp_ctx == NULL) {
1138 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1139 TALLOC_FREE(tmp_ctx);
1140 return NT_STATUS_NO_MEMORY;
1141 }
1142
1143 /*
1144 * This should be a 'netbios domain -> DNS domain'
1145 * mapping, and can currently validly return NULL on
1146 * poorly configured systems.
1147 *
1148 * This is used for the NTLMSSP server
1149 *
1150 */
1151 if (opt_password) {
1152 gensec_settings->server_netbios_name = lp_netbios_name();
1153 gensec_settings->server_netbios_domain = lp_workgroup();
1154 } else {
1155 gensec_settings->server_netbios_name = get_winbind_netbios_name();
1156 gensec_settings->server_netbios_domain = get_winbind_domain();
1157 }
1158
1159 gensec_settings->server_dns_domain = strlower_talloc(gensec_settings,
1160 get_mydnsdomname(talloc_tos()));
1161 gensec_settings->server_dns_name = strlower_talloc(gensec_settings,
1162 get_mydnsfullname());
1163
1164 backends = talloc_zero_array(gensec_settings,
1165 const struct gensec_security_ops *, 4);
1166
1167 if (backends == NULL) {
1168 TALLOC_FREE(tmp_ctx);
1169 return NT_STATUS_NO_MEMORY;
1170 }
1171 gensec_settings->backends = backends;
1172
1173 gensec_init();
1174
1175 /* These need to be in priority order, krb5 before NTLMSSP */
1176#if defined(HAVE_KRB5)
1177 backends[idx++] = &gensec_gse_krb5_security_ops;
1178#endif
1179
1180 backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_NTLMSSP);
1181
1182 backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_SPNEGO);
1183
1184 /*
1185 * This is anonymous for now, because we just use it
1186 * to set the kerberos state at the moment
1187 */
1188 server_credentials = cli_credentials_init_anon(tmp_ctx);
1189 if (!server_credentials) {
1190 DEBUG(0, ("auth_generic_prepare: Failed to init server credentials\n"));
1191 return NT_STATUS_NO_MEMORY;
1192 }
1193
1194 cli_credentials_set_conf(server_credentials, lp_ctx);
1195
1196 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC || lp_security() == SEC_ADS || USE_KERBEROS_KEYTAB) {
1197 cli_credentials_set_kerberos_state(server_credentials, CRED_AUTO_USE_KERBEROS);
1198 } else {
1199 cli_credentials_set_kerberos_state(server_credentials, CRED_DONT_USE_KERBEROS);
1200 }
1201
1202 nt_status = gensec_server_start(tmp_ctx, gensec_settings,
1203 auth4_context, &gensec_security);
1204
1205 if (!NT_STATUS_IS_OK(nt_status)) {
1206 TALLOC_FREE(tmp_ctx);
1207 return nt_status;
1208 }
1209
1210 gensec_set_credentials(gensec_security, server_credentials);
1211
1212 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
1213 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
1214
1215 talloc_unlink(tmp_ctx, lp_ctx);
1216 talloc_unlink(tmp_ctx, server_credentials);
1217 talloc_unlink(tmp_ctx, gensec_settings);
1218 talloc_unlink(tmp_ctx, auth4_context);
1219
1220 *gensec_security_out = talloc_steal(mem_ctx, gensec_security);
1221 TALLOC_FREE(tmp_ctx);
1222 return NT_STATUS_OK;
1223}
1224
1225static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode,
1226 struct loadparm_context *lp_ctx,
1227 struct ntlm_auth_state *state,
1228 char *buf, int length, void **private2)
1229{
1230 manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
1231 return;
1232}
1233
1234static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode,
1235 struct loadparm_context *lp_ctx,
1236 struct ntlm_auth_state *state,
1237 char *buf, int length, void **private2)
1238{
1239 char *user, *pass;
1240 user=buf;
1241
1242 pass=(char *)memchr(buf,' ',length);
1243 if (!pass) {
1244 DEBUG(2, ("Password not found. Denying access\n"));
1245 x_fprintf(x_stdout, "ERR\n");
1246 return;
1247 }
1248 *pass='\0';
1249 pass++;
1250
1251 if (state->helper_mode == SQUID_2_5_BASIC) {
1252 rfc1738_unescape(user);
1253 rfc1738_unescape(pass);
1254 }
1255
1256 if (check_plaintext_auth(user, pass, False)) {
1257 x_fprintf(x_stdout, "OK\n");
1258 } else {
1259 x_fprintf(x_stdout, "ERR\n");
1260 }
1261}
1262
1263static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
1264 struct loadparm_context *lp_ctx,
1265 char *buf, int length, void **private1)
1266{
1267 DATA_BLOB in;
1268 DATA_BLOB out = data_blob(NULL, 0);
1269 char *out_base64 = NULL;
1270 const char *reply_arg = NULL;
1271 struct gensec_ntlm_state {
1272 struct gensec_security *gensec_state;
1273 const char *set_password;
1274 };
1275 struct gensec_ntlm_state *state;
1276
1277 NTSTATUS nt_status;
1278 bool first = false;
1279 const char *reply_code;
1280 struct cli_credentials *creds;
1281
1282 static char *want_feature_list = NULL;
1283 static DATA_BLOB session_key;
1284
1285 TALLOC_CTX *mem_ctx;
1286
1287 if (*private1) {
1288 state = (struct gensec_ntlm_state *)*private1;
1289 } else {
1290 state = talloc_zero(NULL, struct gensec_ntlm_state);
1291 if (!state) {
1292 x_fprintf(x_stdout, "BH No Memory\n");
1293 exit(1);
1294 }
1295 *private1 = state;
1296 if (opt_password) {
1297 state->set_password = opt_password;
1298 }
1299 }
1300
1301 if (strlen(buf) < 2) {
1302 DEBUG(1, ("query [%s] invalid", buf));
1303 x_fprintf(x_stdout, "BH Query invalid\n");
1304 return;
1305 }
1306
1307 if (strlen(buf) > 3) {
1308 if(strncmp(buf, "SF ", 3) == 0) {
1309 DEBUG(10, ("Setting flags to negotiate\n"));
1310 talloc_free(want_feature_list);
1311 want_feature_list = talloc_strndup(state, buf+3, strlen(buf)-3);
1312 x_fprintf(x_stdout, "OK\n");
1313 return;
1314 }
1315 in = base64_decode_data_blob(buf + 3);
1316 } else {
1317 in = data_blob(NULL, 0);
1318 }
1319
1320 if (strncmp(buf, "YR", 2) == 0) {
1321 if (state->gensec_state) {
1322 talloc_free(state->gensec_state);
1323 state->gensec_state = NULL;
1324 }
1325 } else if ( (strncmp(buf, "OK", 2) == 0)) {
1326 /* Just return BH, like ntlm_auth from Samba 3 does. */
1327 x_fprintf(x_stdout, "BH Command expected\n");
1328 data_blob_free(&in);
1329 return;
1330 } else if ( (strncmp(buf, "TT ", 3) != 0) &&
1331 (strncmp(buf, "KK ", 3) != 0) &&
1332 (strncmp(buf, "AF ", 3) != 0) &&
1333 (strncmp(buf, "NA ", 3) != 0) &&
1334 (strncmp(buf, "UG", 2) != 0) &&
1335 (strncmp(buf, "PW ", 3) != 0) &&
1336 (strncmp(buf, "GK", 2) != 0) &&
1337 (strncmp(buf, "GF", 2) != 0)) {
1338 DEBUG(1, ("SPNEGO request [%s] invalid prefix\n", buf));
1339 x_fprintf(x_stdout, "BH SPNEGO request invalid prefix\n");
1340 data_blob_free(&in);
1341 return;
1342 }
1343
1344 mem_ctx = talloc_named(NULL, 0, "manage_gensec_request internal mem_ctx");
1345
1346 /* setup gensec */
1347 if (!(state->gensec_state)) {
1348 switch (stdio_helper_mode) {
1349 case GSS_SPNEGO_CLIENT:
1350 /*
1351 * cached credentials are only supported by
1352 * NTLMSSP_CLIENT_1 for now.
1353 */
1354 use_cached_creds = false;
1355 /* fall through */
1356 case NTLMSSP_CLIENT_1:
1357 /* setup the client side */
1358
1359 if (state->set_password != NULL) {
1360 use_cached_creds = false;
1361 }
1362
1363 if (use_cached_creds) {
1364 struct wbcCredentialCacheParams params;
1365 struct wbcCredentialCacheInfo *info = NULL;
1366 struct wbcAuthErrorInfo *error = NULL;
1367 wbcErr wbc_status;
1368
1369 params.account_name = opt_username;
1370 params.domain_name = opt_domain;
1371 params.level = WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP;
1372 params.num_blobs = 0;
1373 params.blobs = NULL;
1374
1375 wbc_status = wbcCredentialCache(&params, &info,
1376 &error);
1377 wbcFreeMemory(error);
1378 if (!WBC_ERROR_IS_OK(wbc_status)) {
1379 use_cached_creds = false;
1380 }
1381 wbcFreeMemory(info);
1382 }
1383
1384 nt_status = ntlm_auth_prepare_gensec_client(state, lp_ctx,
1385 &state->gensec_state);
1386 if (!NT_STATUS_IS_OK(nt_status)) {
1387 x_fprintf(x_stdout, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status));
1388 talloc_free(mem_ctx);
1389 return;
1390 }
1391
1392 creds = cli_credentials_init(state->gensec_state);
1393 cli_credentials_set_conf(creds, lp_ctx);
1394 if (opt_username) {
1395 cli_credentials_set_username(creds, opt_username, CRED_SPECIFIED);
1396 }
1397 if (opt_domain) {
1398 cli_credentials_set_domain(creds, opt_domain, CRED_SPECIFIED);
1399 }
1400 if (use_cached_creds) {
1401 gensec_want_feature(state->gensec_state,
1402 GENSEC_FEATURE_NTLM_CCACHE);
1403 } else if (state->set_password) {
1404 cli_credentials_set_password(creds, state->set_password, CRED_SPECIFIED);
1405 } else {
1406 cli_credentials_set_password_callback(creds, get_password);
1407 }
1408 if (opt_workstation) {
1409 cli_credentials_set_workstation(creds, opt_workstation, CRED_SPECIFIED);
1410 }
1411
1412 gensec_set_credentials(state->gensec_state, creds);
1413
1414 break;
1415 case GSS_SPNEGO_SERVER:
1416 case SQUID_2_5_NTLMSSP:
1417 {
1418 nt_status = ntlm_auth_prepare_gensec_server(state, lp_ctx,
1419 &state->gensec_state);
1420 if (!NT_STATUS_IS_OK(nt_status)) {
1421 x_fprintf(x_stdout, "BH GENSEC mech failed to start: %s\n", nt_errstr(nt_status));
1422 talloc_free(mem_ctx);
1423 return;
1424 }
1425 break;
1426 }
1427 default:
1428 talloc_free(mem_ctx);
1429 abort();
1430 }
1431
1432 gensec_want_feature_list(state->gensec_state, want_feature_list);
1433
1434 switch (stdio_helper_mode) {
1435 case GSS_SPNEGO_CLIENT:
1436 case GSS_SPNEGO_SERVER:
1437 nt_status = gensec_start_mech_by_oid(state->gensec_state, GENSEC_OID_SPNEGO);
1438 if (!in.length) {
1439 first = true;
1440 }
1441 break;
1442 case NTLMSSP_CLIENT_1:
1443 if (!in.length) {
1444 first = true;
1445 }
1446 /* fall through */
1447 case SQUID_2_5_NTLMSSP:
1448 nt_status = gensec_start_mech_by_oid(state->gensec_state, GENSEC_OID_NTLMSSP);
1449 break;
1450 default:
1451 talloc_free(mem_ctx);
1452 abort();
1453 }
1454
1455 if (!NT_STATUS_IS_OK(nt_status)) {
1456 DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status)));
1457 x_fprintf(x_stdout, "BH GENSEC mech failed to start\n");
1458 talloc_free(mem_ctx);
1459 return;
1460 }
1461
1462 }
1463
1464 /* update */
1465
1466 if (strncmp(buf, "PW ", 3) == 0) {
1467 state->set_password = talloc_strndup(state,
1468 (const char *)in.data,
1469 in.length);
1470
1471 cli_credentials_set_password(gensec_get_credentials(state->gensec_state),
1472 state->set_password,
1473 CRED_SPECIFIED);
1474 x_fprintf(x_stdout, "OK\n");
1475 data_blob_free(&in);
1476 talloc_free(mem_ctx);
1477 return;
1478 }
1479
1480 if (strncmp(buf, "GK", 2) == 0) {
1481 char *base64_key;
1482 DEBUG(10, ("Requested session key\n"));
1483 nt_status = gensec_session_key(state->gensec_state, mem_ctx, &session_key);
1484 if(!NT_STATUS_IS_OK(nt_status)) {
1485 DEBUG(1, ("gensec_session_key failed: %s\n", nt_errstr(nt_status)));
1486 x_fprintf(x_stdout, "BH No session key\n");
1487 talloc_free(mem_ctx);
1488 return;
1489 } else {
1490 base64_key = base64_encode_data_blob(state, session_key);
1491 x_fprintf(x_stdout, "GK %s\n", base64_key);
1492 talloc_free(base64_key);
1493 }
1494 talloc_free(mem_ctx);
1495 return;
1496 }
1497
1498 if (strncmp(buf, "GF", 2) == 0) {
1499 uint32_t neg_flags;
1500
1501 DEBUG(10, ("Requested negotiated NTLMSSP feature flags\n"));
1502
1503 neg_flags = gensec_ntlmssp_neg_flags(state->gensec_state);
1504 if (neg_flags == 0) {
1505 x_fprintf(x_stdout, "BH\n");
1506 return;
1507 }
1508
1509 x_fprintf(x_stdout, "GF 0x%08x\n", neg_flags);
1510 return;
1511 }
1512
1513 nt_status = gensec_update(state->gensec_state, mem_ctx, in, &out);
1514
1515 /* don't leak 'bad password'/'no such user' info to the network client */
1516 nt_status = nt_status_squash(nt_status);
1517
1518 if (out.length) {
1519 out_base64 = base64_encode_data_blob(mem_ctx, out);
1520 } else {
1521 out_base64 = NULL;
1522 }
1523
1524 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1525 reply_arg = "*";
1526 if (first && state->gensec_state->gensec_role == GENSEC_CLIENT) {
1527 reply_code = "YR";
1528 } else if (state->gensec_state->gensec_role == GENSEC_CLIENT) {
1529 reply_code = "KK";
1530 } else if (state->gensec_state->gensec_role == GENSEC_SERVER) {
1531 reply_code = "TT";
1532 } else {
1533 abort();
1534 }
1535
1536
1537 } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) {
1538 reply_code = "BH NT_STATUS_ACCESS_DENIED";
1539 reply_arg = nt_errstr(nt_status);
1540 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
1541 } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_UNSUCCESSFUL)) {
1542 reply_code = "BH NT_STATUS_UNSUCCESSFUL";
1543 reply_arg = nt_errstr(nt_status);
1544 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
1545 } else if (!NT_STATUS_IS_OK(nt_status)) {
1546 reply_code = "NA";
1547 reply_arg = nt_errstr(nt_status);
1548 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
1549 } else if /* OK */ (state->gensec_state->gensec_role == GENSEC_SERVER) {
1550 struct auth_session_info *session_info;
1551
1552 nt_status = gensec_session_info(state->gensec_state, mem_ctx, &session_info);
1553 if (!NT_STATUS_IS_OK(nt_status)) {
1554 reply_code = "BH Failed to retrive session info";
1555 reply_arg = nt_errstr(nt_status);
1556 DEBUG(1, ("GENSEC failed to retrieve the session info: %s\n", nt_errstr(nt_status)));
1557 } else {
1558
1559 reply_code = "AF";
1560 reply_arg = talloc_strdup(state->gensec_state, session_info->unix_info->unix_name);
1561 if (reply_arg == NULL) {
1562 reply_code = "BH out of memory";
1563 reply_arg = nt_errstr(NT_STATUS_NO_MEMORY);
1564 }
1565 talloc_free(session_info);
1566 }
1567 } else if (state->gensec_state->gensec_role == GENSEC_CLIENT) {
1568 reply_code = "AF";
1569 reply_arg = out_base64;
1570 } else {
1571 abort();
1572 }
1573
1574 switch (stdio_helper_mode) {
1575 case GSS_SPNEGO_SERVER:
1576 x_fprintf(x_stdout, "%s %s %s\n", reply_code,
1577 out_base64 ? out_base64 : "*",
1578 reply_arg ? reply_arg : "*");
1579 break;
1580 default:
1581 if (out_base64) {
1582 x_fprintf(x_stdout, "%s %s\n", reply_code, out_base64);
1583 } else if (reply_arg) {
1584 x_fprintf(x_stdout, "%s %s\n", reply_code, reply_arg);
1585 } else {
1586 x_fprintf(x_stdout, "%s\n", reply_code);
1587 }
1588 }
1589
1590 talloc_free(mem_ctx);
1591 return;
1592}
1593
1594static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode,
1595 struct loadparm_context *lp_ctx,
1596 struct ntlm_auth_state *state,
1597 char *buf, int length, void **private2)
1598{
1599 manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
1600 return;
1601}
1602
1603static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode,
1604 struct loadparm_context *lp_ctx,
1605 struct ntlm_auth_state *state,
1606 char *buf, int length, void **private2)
1607{
1608 manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
1609 return;
1610}
1611
1612static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode,
1613 struct loadparm_context *lp_ctx,
1614 struct ntlm_auth_state *state,
1615 char *buf, int length, void **private2)
1616{
1617 manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
1618 return;
1619}
1620
1621static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode,
1622 struct loadparm_context *lp_ctx,
1623 struct ntlm_auth_state *state,
1624 char *buf, int length, void **private2)
1625{
1626 char *request, *parameter;
1627 static DATA_BLOB challenge;
1628 static DATA_BLOB lm_response;
1629 static DATA_BLOB nt_response;
1630 static char *full_username;
1631 static char *username;
1632 static char *domain;
1633 static char *plaintext_password;
1634 static bool ntlm_server_1_user_session_key;
1635 static bool ntlm_server_1_lm_session_key;
1636
1637 if (strequal(buf, ".")) {
1638 if (!full_username && !username) {
1639 x_fprintf(x_stdout, "Error: No username supplied!\n");
1640 } else if (plaintext_password) {
1641 /* handle this request as plaintext */
1642 if (!full_username) {
1643 if (asprintf(&full_username, "%s%c%s", domain, winbind_separator(), username) == -1) {
1644 x_fprintf(x_stdout, "Error: Out of memory in asprintf!\n.\n");
1645 return;
1646 }
1647 }
1648 if (check_plaintext_auth(full_username, plaintext_password, False)) {
1649 x_fprintf(x_stdout, "Authenticated: Yes\n");
1650 } else {
1651 x_fprintf(x_stdout, "Authenticated: No\n");
1652 }
1653 } else if (!lm_response.data && !nt_response.data) {
1654 x_fprintf(x_stdout, "Error: No password supplied!\n");
1655 } else if (!challenge.data) {
1656 x_fprintf(x_stdout, "Error: No lanman-challenge supplied!\n");
1657 } else {
1658 char *error_string = NULL;
1659 uchar lm_key[8];
1660 uchar user_session_key[16];
1661 uint32_t flags = 0;
1662 NTSTATUS nt_status;
1663 if (full_username && !username) {
1664 fstring fstr_user;
1665 fstring fstr_domain;
1666
1667 if (!parse_ntlm_auth_domain_user(full_username, fstr_user, fstr_domain)) {
1668 /* username might be 'tainted', don't print into our new-line deleimianted stream */
1669 x_fprintf(x_stdout, "Error: Could not parse into domain and username\n");
1670 }
1671 SAFE_FREE(username);
1672 SAFE_FREE(domain);
1673 username = smb_xstrdup(fstr_user);
1674 domain = smb_xstrdup(fstr_domain);
1675 }
1676
1677 if (opt_password) {
1678 DATA_BLOB nt_session_key, lm_session_key;
1679 struct samr_Password lm_pw, nt_pw;
1680 TALLOC_CTX *mem_ctx = talloc_new(NULL);
1681 ZERO_STRUCT(user_session_key);
1682 ZERO_STRUCT(lm_key);
1683
1684 nt_lm_owf_gen (opt_password, nt_pw.hash, lm_pw.hash);
1685 nt_status = ntlm_password_check(mem_ctx,
1686 true, true, 0,
1687 &challenge,
1688 &lm_response,
1689 &nt_response,
1690 username,
1691 username,
1692 domain,
1693 &lm_pw, &nt_pw,
1694 &nt_session_key,
1695 &lm_session_key);
1696 error_string = smb_xstrdup(get_friendly_nt_error_msg(nt_status));
1697 if (ntlm_server_1_user_session_key) {
1698 if (nt_session_key.length == sizeof(user_session_key)) {
1699 memcpy(user_session_key,
1700 nt_session_key.data,
1701 sizeof(user_session_key));
1702 }
1703 }
1704 if (ntlm_server_1_lm_session_key) {
1705 if (lm_session_key.length == sizeof(lm_key)) {
1706 memcpy(lm_key,
1707 lm_session_key.data,
1708 sizeof(lm_key));
1709 }
1710 }
1711 TALLOC_FREE(mem_ctx);
1712
1713 } else {
1714 if (!domain) {
1715 domain = smb_xstrdup(get_winbind_domain());
1716 }
1717
1718 if (ntlm_server_1_lm_session_key)
1719 flags |= WBFLAG_PAM_LMKEY;
1720
1721 if (ntlm_server_1_user_session_key)
1722 flags |= WBFLAG_PAM_USER_SESSION_KEY;
1723
1724 nt_status = contact_winbind_auth_crap(username,
1725 domain,
1726 lp_netbios_name(),
1727 &challenge,
1728 &lm_response,
1729 &nt_response,
1730 flags, 0,
1731 lm_key,
1732 user_session_key,
1733 &error_string,
1734 NULL);
1735 }
1736
1737 if (!NT_STATUS_IS_OK(nt_status)) {
1738 x_fprintf(x_stdout, "Authenticated: No\n");
1739 x_fprintf(x_stdout, "Authentication-Error: %s\n.\n", error_string);
1740 } else {
1741 static char zeros[16];
1742 char *hex_lm_key;
1743 char *hex_user_session_key;
1744
1745 x_fprintf(x_stdout, "Authenticated: Yes\n");
1746
1747 if (ntlm_server_1_lm_session_key
1748 && (memcmp(zeros, lm_key,
1749 sizeof(lm_key)) != 0)) {
1750 hex_lm_key = hex_encode_talloc(NULL,
1751 (const unsigned char *)lm_key,
1752 sizeof(lm_key));
1753 x_fprintf(x_stdout, "LANMAN-Session-Key: %s\n", hex_lm_key);
1754 TALLOC_FREE(hex_lm_key);
1755 }
1756
1757 if (ntlm_server_1_user_session_key
1758 && (memcmp(zeros, user_session_key,
1759 sizeof(user_session_key)) != 0)) {
1760 hex_user_session_key = hex_encode_talloc(NULL,
1761 (const unsigned char *)user_session_key,
1762 sizeof(user_session_key));
1763 x_fprintf(x_stdout, "User-Session-Key: %s\n", hex_user_session_key);
1764 TALLOC_FREE(hex_user_session_key);
1765 }
1766 }
1767 SAFE_FREE(error_string);
1768 }
1769 /* clear out the state */
1770 challenge = data_blob_null;
1771 nt_response = data_blob_null;
1772 lm_response = data_blob_null;
1773 SAFE_FREE(full_username);
1774 SAFE_FREE(username);
1775 SAFE_FREE(domain);
1776 SAFE_FREE(plaintext_password);
1777 ntlm_server_1_user_session_key = False;
1778 ntlm_server_1_lm_session_key = False;
1779 x_fprintf(x_stdout, ".\n");
1780
1781 return;
1782 }
1783
1784 request = buf;
1785
1786 /* Indicates a base64 encoded structure */
1787 parameter = strstr_m(request, ":: ");
1788 if (!parameter) {
1789 parameter = strstr_m(request, ": ");
1790
1791 if (!parameter) {
1792 DEBUG(0, ("Parameter not found!\n"));
1793 x_fprintf(x_stdout, "Error: Parameter not found!\n.\n");
1794 return;
1795 }
1796
1797 parameter[0] ='\0';
1798 parameter++;
1799 parameter[0] ='\0';
1800 parameter++;
1801
1802 } else {
1803 parameter[0] ='\0';
1804 parameter++;
1805 parameter[0] ='\0';
1806 parameter++;
1807 parameter[0] ='\0';
1808 parameter++;
1809
1810 base64_decode_inplace(parameter);
1811 }
1812
1813 if (strequal(request, "LANMAN-Challenge")) {
1814 challenge = strhex_to_data_blob(NULL, parameter);
1815 if (challenge.length != 8) {
1816 x_fprintf(x_stdout, "Error: hex decode of %s failed! (got %d bytes, expected 8)\n.\n",
1817 parameter,
1818 (int)challenge.length);
1819 challenge = data_blob_null;
1820 }
1821 } else if (strequal(request, "NT-Response")) {
1822 nt_response = strhex_to_data_blob(NULL, parameter);
1823 if (nt_response.length < 24) {
1824 x_fprintf(x_stdout, "Error: hex decode of %s failed! (only got %d bytes, needed at least 24)\n.\n",
1825 parameter,
1826 (int)nt_response.length);
1827 nt_response = data_blob_null;
1828 }
1829 } else if (strequal(request, "LANMAN-Response")) {
1830 lm_response = strhex_to_data_blob(NULL, parameter);
1831 if (lm_response.length != 24) {
1832 x_fprintf(x_stdout, "Error: hex decode of %s failed! (got %d bytes, expected 24)\n.\n",
1833 parameter,
1834 (int)lm_response.length);
1835 lm_response = data_blob_null;
1836 }
1837 } else if (strequal(request, "Password")) {
1838 plaintext_password = smb_xstrdup(parameter);
1839 } else if (strequal(request, "NT-Domain")) {
1840 domain = smb_xstrdup(parameter);
1841 } else if (strequal(request, "Username")) {
1842 username = smb_xstrdup(parameter);
1843 } else if (strequal(request, "Full-Username")) {
1844 full_username = smb_xstrdup(parameter);
1845 } else if (strequal(request, "Request-User-Session-Key")) {
1846 ntlm_server_1_user_session_key = strequal(parameter, "Yes");
1847 } else if (strequal(request, "Request-LanMan-Session-Key")) {
1848 ntlm_server_1_lm_session_key = strequal(parameter, "Yes");
1849 } else {
1850 x_fprintf(x_stdout, "Error: Unknown request %s\n.\n", request);
1851 }
1852}
1853
1854static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode,
1855 struct loadparm_context *lp_ctx,
1856 struct ntlm_auth_state *state,
1857 char *buf, int length, void **private2)
1858{
1859 char *request, *parameter;
1860 static DATA_BLOB new_nt_pswd;
1861 static DATA_BLOB old_nt_hash_enc;
1862 static DATA_BLOB new_lm_pswd;
1863 static DATA_BLOB old_lm_hash_enc;
1864 static char *full_username = NULL;
1865 static char *username = NULL;
1866 static char *domain = NULL;
1867 static char *newpswd = NULL;
1868 static char *oldpswd = NULL;
1869
1870 if (strequal(buf, ".")) {
1871 if(newpswd && oldpswd) {
1872 uchar old_nt_hash[16];
1873 uchar old_lm_hash[16];
1874 uchar new_nt_hash[16];
1875 uchar new_lm_hash[16];
1876
1877 new_nt_pswd = data_blob(NULL, 516);
1878 old_nt_hash_enc = data_blob(NULL, 16);
1879
1880 /* Calculate the MD4 hash (NT compatible) of the
1881 * password */
1882 E_md4hash(oldpswd, old_nt_hash);
1883 E_md4hash(newpswd, new_nt_hash);
1884
1885 /* E_deshash returns false for 'long'
1886 passwords (> 14 DOS chars).
1887
1888 Therefore, don't send a buffer
1889 encrypted with the truncated hash
1890 (it could allow an even easier
1891 attack on the password)
1892
1893 Likewise, obey the admin's restriction
1894 */
1895
1896 if (lp_client_lanman_auth() &&
1897 E_deshash(newpswd, new_lm_hash) &&
1898 E_deshash(oldpswd, old_lm_hash)) {
1899 new_lm_pswd = data_blob(NULL, 516);
1900 old_lm_hash_enc = data_blob(NULL, 16);
1901 encode_pw_buffer(new_lm_pswd.data, newpswd,
1902 STR_UNICODE);
1903
1904 arcfour_crypt(new_lm_pswd.data, old_nt_hash, 516);
1905 E_old_pw_hash(new_nt_hash, old_lm_hash,
1906 old_lm_hash_enc.data);
1907 } else {
1908 new_lm_pswd.data = NULL;
1909 new_lm_pswd.length = 0;
1910 old_lm_hash_enc.data = NULL;
1911 old_lm_hash_enc.length = 0;
1912 }
1913
1914 encode_pw_buffer(new_nt_pswd.data, newpswd,
1915 STR_UNICODE);
1916
1917 arcfour_crypt(new_nt_pswd.data, old_nt_hash, 516);
1918 E_old_pw_hash(new_nt_hash, old_nt_hash,
1919 old_nt_hash_enc.data);
1920 }
1921
1922 if (!full_username && !username) {
1923 x_fprintf(x_stdout, "Error: No username supplied!\n");
1924 } else if ((!new_nt_pswd.data || !old_nt_hash_enc.data) &&
1925 (!new_lm_pswd.data || old_lm_hash_enc.data) ) {
1926 x_fprintf(x_stdout, "Error: No NT or LM password "
1927 "blobs supplied!\n");
1928 } else {
1929 char *error_string = NULL;
1930
1931 if (full_username && !username) {
1932 fstring fstr_user;
1933 fstring fstr_domain;
1934
1935 if (!parse_ntlm_auth_domain_user(full_username,
1936 fstr_user,
1937 fstr_domain)) {
1938 /* username might be 'tainted', don't
1939 * print into our new-line
1940 * deleimianted stream */
1941 x_fprintf(x_stdout, "Error: Could not "
1942 "parse into domain and "
1943 "username\n");
1944 SAFE_FREE(username);
1945 username = smb_xstrdup(full_username);
1946 } else {
1947 SAFE_FREE(username);
1948 SAFE_FREE(domain);
1949 username = smb_xstrdup(fstr_user);
1950 domain = smb_xstrdup(fstr_domain);
1951 }
1952
1953 }
1954
1955 if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
1956 username, domain,
1957 new_nt_pswd,
1958 old_nt_hash_enc,
1959 new_lm_pswd,
1960 old_lm_hash_enc,
1961 &error_string))) {
1962 x_fprintf(x_stdout, "Password-Change: No\n");
1963 x_fprintf(x_stdout, "Password-Change-Error: "
1964 "%s\n.\n", error_string);
1965 } else {
1966 x_fprintf(x_stdout, "Password-Change: Yes\n");
1967 }
1968
1969 SAFE_FREE(error_string);
1970 }
1971 /* clear out the state */
1972 new_nt_pswd = data_blob_null;
1973 old_nt_hash_enc = data_blob_null;
1974 new_lm_pswd = data_blob_null;
1975 old_nt_hash_enc = data_blob_null;
1976 SAFE_FREE(full_username);
1977 SAFE_FREE(username);
1978 SAFE_FREE(domain);
1979 SAFE_FREE(newpswd);
1980 SAFE_FREE(oldpswd);
1981 x_fprintf(x_stdout, ".\n");
1982
1983 return;
1984 }
1985
1986 request = buf;
1987
1988 /* Indicates a base64 encoded structure */
1989 parameter = strstr_m(request, ":: ");
1990 if (!parameter) {
1991 parameter = strstr_m(request, ": ");
1992
1993 if (!parameter) {
1994 DEBUG(0, ("Parameter not found!\n"));
1995 x_fprintf(x_stdout, "Error: Parameter not found!\n.\n");
1996 return;
1997 }
1998
1999 parameter[0] ='\0';
2000 parameter++;
2001 parameter[0] ='\0';
2002 parameter++;
2003 } else {
2004 parameter[0] ='\0';
2005 parameter++;
2006 parameter[0] ='\0';
2007 parameter++;
2008 parameter[0] ='\0';
2009 parameter++;
2010
2011 base64_decode_inplace(parameter);
2012 }
2013
2014 if (strequal(request, "new-nt-password-blob")) {
2015 new_nt_pswd = strhex_to_data_blob(NULL, parameter);
2016 if (new_nt_pswd.length != 516) {
2017 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2018 "(got %d bytes, expected 516)\n.\n",
2019 parameter,
2020 (int)new_nt_pswd.length);
2021 new_nt_pswd = data_blob_null;
2022 }
2023 } else if (strequal(request, "old-nt-hash-blob")) {
2024 old_nt_hash_enc = strhex_to_data_blob(NULL, parameter);
2025 if (old_nt_hash_enc.length != 16) {
2026 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2027 "(got %d bytes, expected 16)\n.\n",
2028 parameter,
2029 (int)old_nt_hash_enc.length);
2030 old_nt_hash_enc = data_blob_null;
2031 }
2032 } else if (strequal(request, "new-lm-password-blob")) {
2033 new_lm_pswd = strhex_to_data_blob(NULL, parameter);
2034 if (new_lm_pswd.length != 516) {
2035 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2036 "(got %d bytes, expected 516)\n.\n",
2037 parameter,
2038 (int)new_lm_pswd.length);
2039 new_lm_pswd = data_blob_null;
2040 }
2041 }
2042 else if (strequal(request, "old-lm-hash-blob")) {
2043 old_lm_hash_enc = strhex_to_data_blob(NULL, parameter);
2044 if (old_lm_hash_enc.length != 16)
2045 {
2046 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2047 "(got %d bytes, expected 16)\n.\n",
2048 parameter,
2049 (int)old_lm_hash_enc.length);
2050 old_lm_hash_enc = data_blob_null;
2051 }
2052 } else if (strequal(request, "nt-domain")) {
2053 domain = smb_xstrdup(parameter);
2054 } else if(strequal(request, "username")) {
2055 username = smb_xstrdup(parameter);
2056 } else if(strequal(request, "full-username")) {
2057 username = smb_xstrdup(parameter);
2058 } else if(strequal(request, "new-password")) {
2059 newpswd = smb_xstrdup(parameter);
2060 } else if (strequal(request, "old-password")) {
2061 oldpswd = smb_xstrdup(parameter);
2062 } else {
2063 x_fprintf(x_stdout, "Error: Unknown request %s\n.\n", request);
2064 }
2065}
2066
2067static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode,
2068 struct loadparm_context *lp_ctx,
2069 struct ntlm_auth_state *state,
2070 stdio_helper_function fn, void **private2)
2071{
2072 char *buf;
2073 char tmp[INITIAL_BUFFER_SIZE+1];
2074 int length, buf_size = 0;
2075 char *c;
2076
2077 buf = talloc_strdup(state->mem_ctx, "");
2078 if (!buf) {
2079 DEBUG(0, ("Failed to allocate input buffer.\n"));
2080 x_fprintf(x_stderr, "ERR\n");
2081 exit(1);
2082 }
2083
2084 do {
2085
2086 /* this is not a typo - x_fgets doesn't work too well under
2087 * squid */
2088 if (fgets(tmp, sizeof(tmp)-1, stdin) == NULL) {
2089 if (ferror(stdin)) {
2090 DEBUG(1, ("fgets() failed! dying..... errno=%d "
2091 "(%s)\n", ferror(stdin),
2092 strerror(ferror(stdin))));
2093
2094 exit(1);
2095 }
2096 exit(0);
2097 }
2098
2099 buf = talloc_strdup_append_buffer(buf, tmp);
2100 buf_size += INITIAL_BUFFER_SIZE;
2101
2102 if (buf_size > MAX_BUFFER_SIZE) {
2103 DEBUG(2, ("Oversized message\n"));
2104 x_fprintf(x_stderr, "ERR\n");
2105 talloc_free(buf);
2106 return;
2107 }
2108
2109 c = strchr(buf, '\n');
2110 } while (c == NULL);
2111
2112 *c = '\0';
2113 length = c-buf;
2114
2115 DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf,length));
2116
2117 if (buf[0] == '\0') {
2118 DEBUG(2, ("Invalid Request\n"));
2119 x_fprintf(x_stderr, "ERR\n");
2120 talloc_free(buf);
2121 return;
2122 }
2123
2124 fn(stdio_helper_mode, lp_ctx, state, buf, length, private2);
2125 talloc_free(buf);
2126}
2127
2128
2129static void squid_stream(enum stdio_helper_mode stdio_mode,
2130 struct loadparm_context *lp_ctx,
2131 stdio_helper_function fn) {
2132 TALLOC_CTX *mem_ctx;
2133 struct ntlm_auth_state *state;
2134
2135 /* initialize FDescs */
2136 x_setbuf(x_stdout, NULL);
2137 x_setbuf(x_stderr, NULL);
2138
2139 mem_ctx = talloc_init("ntlm_auth");
2140 if (!mem_ctx) {
2141 DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
2142 x_fprintf(x_stderr, "ERR\n");
2143 exit(1);
2144 }
2145
2146 state = talloc_zero(mem_ctx, struct ntlm_auth_state);
2147 if (!state) {
2148 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
2149 x_fprintf(x_stderr, "ERR\n");
2150 exit(1);
2151 }
2152
2153 state->mem_ctx = mem_ctx;
2154 state->helper_mode = stdio_mode;
2155
2156 while(1) {
2157 TALLOC_CTX *frame = talloc_stackframe();
2158 manage_squid_request(stdio_mode, lp_ctx, state, fn, NULL);
2159 TALLOC_FREE(frame);
2160 }
2161}
2162
2163
2164/* Authenticate a user with a challenge/response */
2165
2166static bool check_auth_crap(void)
2167{
2168 NTSTATUS nt_status;
2169 uint32_t flags = 0;
2170 char lm_key[8];
2171 char user_session_key[16];
2172 char *hex_lm_key;
2173 char *hex_user_session_key;
2174 char *error_string;
2175 static uint8_t zeros[16];
2176
2177 x_setbuf(x_stdout, NULL);
2178
2179 if (request_lm_key)
2180 flags |= WBFLAG_PAM_LMKEY;
2181
2182 if (request_user_session_key)
2183 flags |= WBFLAG_PAM_USER_SESSION_KEY;
2184
2185 flags |= WBFLAG_PAM_NT_STATUS_SQUASH;
2186
2187 nt_status = contact_winbind_auth_crap(opt_username, opt_domain,
2188 opt_workstation,
2189 &opt_challenge,
2190 &opt_lm_response,
2191 &opt_nt_response,
2192 flags, 0,
2193 (unsigned char *)lm_key,
2194 (unsigned char *)user_session_key,
2195 &error_string, NULL);
2196
2197 if (!NT_STATUS_IS_OK(nt_status)) {
2198 x_fprintf(x_stdout, "%s (0x%x)\n",
2199 error_string,
2200 NT_STATUS_V(nt_status));
2201 SAFE_FREE(error_string);
2202 return False;
2203 }
2204
2205 if (request_lm_key
2206 && (memcmp(zeros, lm_key,
2207 sizeof(lm_key)) != 0)) {
2208 hex_lm_key = hex_encode_talloc(talloc_tos(), (const unsigned char *)lm_key,
2209 sizeof(lm_key));
2210 x_fprintf(x_stdout, "LM_KEY: %s\n", hex_lm_key);
2211 TALLOC_FREE(hex_lm_key);
2212 }
2213 if (request_user_session_key
2214 && (memcmp(zeros, user_session_key,
2215 sizeof(user_session_key)) != 0)) {
2216 hex_user_session_key = hex_encode_talloc(talloc_tos(), (const unsigned char *)user_session_key,
2217 sizeof(user_session_key));
2218 x_fprintf(x_stdout, "NT_KEY: %s\n", hex_user_session_key);
2219 TALLOC_FREE(hex_user_session_key);
2220 }
2221
2222 return True;
2223}
2224
2225/* Main program */
2226
2227enum {
2228 OPT_USERNAME = 1000,
2229 OPT_DOMAIN,
2230 OPT_WORKSTATION,
2231 OPT_CHALLENGE,
2232 OPT_RESPONSE,
2233 OPT_LM,
2234 OPT_NT,
2235 OPT_PASSWORD,
2236 OPT_LM_KEY,
2237 OPT_USER_SESSION_KEY,
2238 OPT_DIAGNOSTICS,
2239 OPT_REQUIRE_MEMBERSHIP,
2240 OPT_USE_CACHED_CREDS,
2241 OPT_PAM_WINBIND_CONF,
2242 OPT_TARGET_SERVICE,
2243 OPT_TARGET_HOSTNAME,
2244 OPT_OFFLINE_LOGON
2245};
2246
2247 int main(int argc, const char **argv)
2248{
2249 TALLOC_CTX *frame = talloc_stackframe();
2250 int opt;
2251 static const char *helper_protocol;
2252 static int diagnostics;
2253
2254 static const char *hex_challenge;
2255 static const char *hex_lm_response;
2256 static const char *hex_nt_response;
2257 struct loadparm_context *lp_ctx;
2258 poptContext pc;
2259
2260 /* NOTE: DO NOT change this interface without considering the implications!
2261 This is an external interface, which other programs will use to interact
2262 with this helper.
2263 */
2264
2265 /* We do not use single-letter command abbreviations, because they harm future
2266 interface stability. */
2267
2268 struct poptOption long_options[] = {
2269 POPT_AUTOHELP
2270 { "helper-protocol", 0, POPT_ARG_STRING, &helper_protocol, OPT_DOMAIN, "operate as a stdio-based helper", "helper protocol to use"},
2271 { "username", 0, POPT_ARG_STRING, &opt_username, OPT_USERNAME, "username"},
2272 { "domain", 0, POPT_ARG_STRING, &opt_domain, OPT_DOMAIN, "domain name"},
2273 { "workstation", 0, POPT_ARG_STRING, &opt_workstation, OPT_WORKSTATION, "workstation"},
2274 { "challenge", 0, POPT_ARG_STRING, &hex_challenge, OPT_CHALLENGE, "challenge (HEX encoded)"},
2275 { "lm-response", 0, POPT_ARG_STRING, &hex_lm_response, OPT_LM, "LM Response to the challenge (HEX encoded)"},
2276 { "nt-response", 0, POPT_ARG_STRING, &hex_nt_response, OPT_NT, "NT or NTLMv2 Response to the challenge (HEX encoded)"},
2277 { "password", 0, POPT_ARG_STRING, &opt_password, OPT_PASSWORD, "User's plaintext password"},
2278 { "request-lm-key", 0, POPT_ARG_NONE, &request_lm_key, OPT_LM_KEY, "Retrieve LM session key"},
2279 { "request-nt-key", 0, POPT_ARG_NONE, &request_user_session_key, OPT_USER_SESSION_KEY, "Retrieve User (NT) session key"},
2280 { "use-cached-creds", 0, POPT_ARG_NONE, &use_cached_creds, OPT_USE_CACHED_CREDS, "Use cached credentials if no password is given"},
2281 { "offline-logon", 0, POPT_ARG_NONE, &offline_logon,
2282 OPT_OFFLINE_LOGON,
2283 "Use cached passwords when DC is offline"},
2284 { "diagnostics", 0, POPT_ARG_NONE, &diagnostics,
2285 OPT_DIAGNOSTICS,
2286 "Perform diagnostics on the authentication chain"},
2287 { "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" },
2288 { "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" },
2289 { "target-service", 0, POPT_ARG_STRING, &opt_target_service, OPT_TARGET_SERVICE, "Target service (eg http)" },
2290 { "target-hostname", 0, POPT_ARG_STRING, &opt_target_hostname, OPT_TARGET_HOSTNAME, "Target hostname" },
2291 POPT_COMMON_CONFIGFILE
2292 POPT_COMMON_VERSION
2293 POPT_COMMON_OPTION
2294 POPT_TABLEEND
2295 };
2296
2297 /* Samba client initialisation */
2298 smb_init_locale();
2299
2300 setup_logging("ntlm_auth", DEBUG_STDERR);
2301
2302 /* Parse options */
2303
2304 pc = poptGetContext("ntlm_auth", argc, argv, long_options, 0);
2305
2306 /* Parse command line options */
2307
2308 if (argc == 1) {
2309 poptPrintHelp(pc, stderr, 0);
2310 return 1;
2311 }
2312
2313 while((opt = poptGetNextOpt(pc)) != -1) {
2314 /* Get generic config options like --configfile */
2315 }
2316
2317 poptFreeContext(pc);
2318
2319 if (!lp_load_global(get_dyn_CONFIGFILE())) {
2320 d_fprintf(stderr, "ntlm_auth: error opening config file %s. Error was %s\n",
2321 get_dyn_CONFIGFILE(), strerror(errno));
2322 exit(1);
2323 }
2324
2325 pc = poptGetContext(NULL, argc, (const char **)argv, long_options,
2326 POPT_CONTEXT_KEEP_FIRST);
2327
2328 while((opt = poptGetNextOpt(pc)) != -1) {
2329 switch (opt) {
2330 case OPT_CHALLENGE:
2331 opt_challenge = strhex_to_data_blob(NULL, hex_challenge);
2332 if (opt_challenge.length != 8) {
2333 x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n",
2334 hex_challenge,
2335 (int)opt_challenge.length);
2336 exit(1);
2337 }
2338 break;
2339 case OPT_LM:
2340 opt_lm_response = strhex_to_data_blob(NULL, hex_lm_response);
2341 if (opt_lm_response.length != 24) {
2342 x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n",
2343 hex_lm_response,
2344 (int)opt_lm_response.length);
2345 exit(1);
2346 }
2347 break;
2348
2349 case OPT_NT:
2350 opt_nt_response = strhex_to_data_blob(NULL, hex_nt_response);
2351 if (opt_nt_response.length < 24) {
2352 x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n",
2353 hex_nt_response,
2354 (int)opt_nt_response.length);
2355 exit(1);
2356 }
2357 break;
2358
2359 case OPT_REQUIRE_MEMBERSHIP:
2360 if (strncasecmp_m("S-", require_membership_of, 2) == 0) {
2361 require_membership_of_sid = require_membership_of;
2362 }
2363 break;
2364 }
2365 }
2366
2367 if (opt_username) {
2368 char *domain = SMB_STRDUP(opt_username);
2369 char *p = strchr_m(domain, *lp_winbind_separator());
2370 if (p) {
2371 opt_username = p+1;
2372 *p = '\0';
2373 if (opt_domain && !strequal(opt_domain, domain)) {
2374 x_fprintf(x_stderr, "Domain specified in username (%s) "
2375 "doesn't match specified domain (%s)!\n\n",
2376 domain, opt_domain);
2377 poptPrintHelp(pc, stderr, 0);
2378 exit(1);
2379 }
2380 opt_domain = domain;
2381 } else {
2382 SAFE_FREE(domain);
2383 }
2384 }
2385
2386 /* Note: if opt_domain is "" then send no domain */
2387 if (opt_domain == NULL) {
2388 opt_domain = get_winbind_domain();
2389 }
2390
2391 if (opt_workstation == NULL) {
2392 opt_workstation = "";
2393 }
2394
2395 lp_ctx = loadparm_init_s3(NULL, loadparm_s3_helpers());
2396 if (lp_ctx == NULL) {
2397 x_fprintf(x_stderr, "loadparm_init_s3() failed!\n");
2398 exit(1);
2399 }
2400
2401 if (helper_protocol) {
2402 int i;
2403 for (i=0; i<NUM_HELPER_MODES; i++) {
2404 if (strcmp(helper_protocol, stdio_helper_protocols[i].name) == 0) {
2405 squid_stream(stdio_helper_protocols[i].mode, lp_ctx, stdio_helper_protocols[i].fn);
2406 exit(0);
2407 }
2408 }
2409 x_fprintf(x_stderr, "unknown helper protocol [%s]\n\nValid helper protools:\n\n", helper_protocol);
2410
2411 for (i=0; i<NUM_HELPER_MODES; i++) {
2412 x_fprintf(x_stderr, "%s\n", stdio_helper_protocols[i].name);
2413 }
2414
2415 exit(1);
2416 }
2417
2418 if (!opt_username || !*opt_username) {
2419 x_fprintf(x_stderr, "username must be specified!\n\n");
2420 poptPrintHelp(pc, stderr, 0);
2421 exit(1);
2422 }
2423
2424 if (opt_challenge.length) {
2425 if (!check_auth_crap()) {
2426 exit(1);
2427 }
2428 exit(0);
2429 }
2430
2431 if (!opt_password) {
2432 char pwd[256] = {0};
2433 int rc;
2434
2435 rc = samba_getpass("Password: ", pwd, sizeof(pwd), false, false);
2436 if (rc == 0) {
2437 opt_password = SMB_STRDUP(pwd);
2438 }
2439 }
2440
2441 if (diagnostics) {
2442 if (!diagnose_ntlm_auth()) {
2443 return 1;
2444 }
2445 } else {
2446 fstring user;
2447
2448 fstr_sprintf(user, "%s%c%s", opt_domain, winbind_separator(), opt_username);
2449 if (!check_plaintext_auth(user, opt_password, True)) {
2450 return 1;
2451 }
2452 }
2453
2454 /* Exit code */
2455
2456 poptFreeContext(pc);
2457 TALLOC_FREE(frame);
2458 return 0;
2459}
Note: See TracBrowser for help on using the repository browser.