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