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