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 341 : const char *get_winbind_domain(void)
317 : {
318 : struct wbcInterfaceDetails *details;
319 : wbcErr ret;
320 :
321 : static fstring winbind_domain;
322 341 : if (*winbind_domain) {
323 162 : return winbind_domain;
324 : }
325 :
326 : /* Send off request */
327 :
328 179 : ret = wbcInterfaceDetails(&details);
329 179 : 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 179 : fstrcpy(winbind_domain, details->netbios_domain);
335 :
336 179 : wbcFreeMemory(details);
337 :
338 179 : 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_security_by_oid(GENSEC_OID_KERBEROS5);
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_security_by_oid(GENSEC_OID_KERBEROS5);
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 740 : bool include_krb5_default_ccache = false;
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 140 : 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 46 : if (opt_username == NULL && state->set_password == NULL) {
1555 6 : include_krb5_default_ccache = true;
1556 : }
1557 : FALL_THROUGH;
1558 : case NTLMSSP_CLIENT_1:
1559 : /* setup the client side */
1560 :
1561 116 : if (state->set_password != NULL) {
1562 100 : use_cached_creds = false;
1563 : }
1564 :
1565 116 : if (use_cached_creds) {
1566 : struct wbcCredentialCacheParams params;
1567 10 : struct wbcCredentialCacheInfo *info = NULL;
1568 10 : struct wbcAuthErrorInfo *error = NULL;
1569 : wbcErr wbc_status;
1570 :
1571 10 : params.account_name = opt_username;
1572 10 : params.domain_name = opt_domain;
1573 10 : params.level = WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP;
1574 10 : params.num_blobs = 0;
1575 10 : params.blobs = NULL;
1576 :
1577 10 : wbc_status = wbcCredentialCache(¶ms, &info,
1578 : &error);
1579 10 : wbcFreeMemory(error);
1580 10 : if (!WBC_ERROR_IS_OK(wbc_status)) {
1581 0 : use_cached_creds = false;
1582 : }
1583 10 : wbcFreeMemory(info);
1584 : }
1585 :
1586 116 : nt_status = ntlm_auth_prepare_gensec_client(state, lp_ctx,
1587 : &state->gensec_state);
1588 116 : if (!NT_STATUS_IS_OK(nt_status)) {
1589 0 : printf("BH GENSEC mech failed to start: %s\n",
1590 : nt_errstr(nt_status));
1591 0 : talloc_free(mem_ctx);
1592 0 : return;
1593 : }
1594 :
1595 116 : creds = cli_credentials_init(state->gensec_state);
1596 116 : cli_credentials_set_conf(creds, lp_ctx);
1597 116 : if (opt_username) {
1598 110 : cli_credentials_set_username(creds, opt_username, CRED_SPECIFIED);
1599 : }
1600 116 : if (opt_domain) {
1601 116 : cli_credentials_set_domain(creds, opt_domain, CRED_SPECIFIED);
1602 : }
1603 116 : if (use_cached_creds) {
1604 10 : gensec_want_feature(state->gensec_state,
1605 : GENSEC_FEATURE_NTLM_CCACHE);
1606 106 : } else if (state->set_password) {
1607 100 : cli_credentials_set_password(creds, state->set_password, CRED_SPECIFIED);
1608 6 : } else if (include_krb5_default_ccache) {
1609 6 : const char *error_string = NULL;
1610 : int rc;
1611 :
1612 6 : rc = cli_credentials_set_ccache(creds,
1613 : lp_ctx,
1614 : NULL,
1615 : CRED_SPECIFIED,
1616 : &error_string);
1617 6 : if (rc != 0) {
1618 0 : fprintf(stderr,
1619 : "Warning reading default "
1620 : "krb5 credentials cache: %s\n",
1621 : error_string);
1622 : }
1623 : } else {
1624 0 : cli_credentials_set_password_callback(creds, get_password);
1625 : }
1626 116 : if (opt_workstation) {
1627 116 : cli_credentials_set_workstation(creds, opt_workstation, CRED_SPECIFIED);
1628 : }
1629 :
1630 116 : gensec_set_credentials(state->gensec_state, creds);
1631 :
1632 116 : break;
1633 122 : case GSS_SPNEGO_SERVER:
1634 : case SQUID_2_5_NTLMSSP:
1635 : {
1636 122 : nt_status = ntlm_auth_prepare_gensec_server(state, lp_ctx,
1637 : &state->gensec_state);
1638 122 : if (!NT_STATUS_IS_OK(nt_status)) {
1639 0 : printf("BH GENSEC mech failed to start: %s\n",
1640 : nt_errstr(nt_status));
1641 0 : talloc_free(mem_ctx);
1642 0 : return;
1643 : }
1644 122 : break;
1645 : }
1646 0 : default:
1647 0 : talloc_free(mem_ctx);
1648 0 : abort();
1649 : }
1650 :
1651 238 : gensec_want_feature_list(state->gensec_state, want_feature_list);
1652 :
1653 : /* Session info is not complete, do not pass to auth log */
1654 238 : gensec_want_feature(state->gensec_state, GENSEC_FEATURE_NO_AUTHZ_LOG);
1655 :
1656 238 : switch (stdio_helper_mode) {
1657 118 : case GSS_SPNEGO_CLIENT:
1658 : case GSS_SPNEGO_SERVER:
1659 118 : nt_status = gensec_start_mech_by_oid(state->gensec_state, GENSEC_OID_SPNEGO);
1660 118 : if (!in.length) {
1661 52 : first = true;
1662 : }
1663 118 : break;
1664 70 : case NTLMSSP_CLIENT_1:
1665 70 : if (!in.length) {
1666 70 : first = true;
1667 : }
1668 : FALL_THROUGH;
1669 : case SQUID_2_5_NTLMSSP:
1670 120 : nt_status = gensec_start_mech_by_oid(state->gensec_state, GENSEC_OID_NTLMSSP);
1671 120 : break;
1672 0 : default:
1673 0 : talloc_free(mem_ctx);
1674 0 : abort();
1675 : }
1676 :
1677 238 : if (!NT_STATUS_IS_OK(nt_status)) {
1678 0 : DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status)));
1679 0 : printf("BH GENSEC mech failed to start\n");
1680 0 : talloc_free(mem_ctx);
1681 0 : return;
1682 : }
1683 :
1684 : }
1685 :
1686 : /* update */
1687 :
1688 740 : if (strncmp(buf, "PW ", 3) == 0) {
1689 0 : state->set_password = talloc_strndup(state,
1690 0 : (const char *)in.data,
1691 : in.length);
1692 :
1693 0 : cli_credentials_set_password(gensec_get_credentials(state->gensec_state),
1694 : state->set_password,
1695 : CRED_SPECIFIED);
1696 0 : printf("OK\n");
1697 0 : talloc_free(mem_ctx);
1698 0 : return;
1699 : }
1700 :
1701 740 : if (strncmp(buf, "GK", 2) == 0) {
1702 : char *base64_key;
1703 100 : DEBUG(10, ("Requested session key\n"));
1704 100 : nt_status = gensec_session_key(state->gensec_state, mem_ctx, &session_key);
1705 100 : if(!NT_STATUS_IS_OK(nt_status)) {
1706 0 : DEBUG(1, ("gensec_session_key failed: %s\n", nt_errstr(nt_status)));
1707 0 : printf("BH No session key\n");
1708 0 : talloc_free(mem_ctx);
1709 0 : return;
1710 : } else {
1711 100 : base64_key = base64_encode_data_blob(state, session_key);
1712 100 : SMB_ASSERT(base64_key != NULL);
1713 100 : printf("GK %s\n", base64_key);
1714 100 : talloc_free(base64_key);
1715 : }
1716 100 : talloc_free(mem_ctx);
1717 100 : return;
1718 : }
1719 :
1720 640 : if (strncmp(buf, "GF", 2) == 0) {
1721 : uint32_t neg_flags;
1722 :
1723 100 : DEBUG(10, ("Requested negotiated NTLMSSP feature flags\n"));
1724 :
1725 100 : neg_flags = gensec_ntlmssp_neg_flags(state->gensec_state);
1726 100 : if (neg_flags == 0) {
1727 0 : printf("BH\n");
1728 0 : talloc_free(mem_ctx);
1729 0 : return;
1730 : }
1731 :
1732 100 : printf("GF 0x%08x\n", neg_flags);
1733 100 : talloc_free(mem_ctx);
1734 100 : return;
1735 : }
1736 :
1737 540 : nt_status = gensec_update(state->gensec_state, mem_ctx, in, &out);
1738 :
1739 : /* don't leak 'bad password'/'no such user' info to the network client */
1740 540 : nt_status = nt_status_squash(nt_status);
1741 :
1742 540 : if (out.length) {
1743 424 : out_base64 = base64_encode_data_blob(mem_ctx, out);
1744 424 : SMB_ASSERT(out_base64 != NULL);
1745 : } else {
1746 116 : out_base64 = NULL;
1747 : }
1748 :
1749 540 : if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1750 318 : reply_arg = "*";
1751 318 : if (first && state->gensec_state->gensec_role == GENSEC_CLIENT) {
1752 70 : reply_code = "YR";
1753 248 : } else if (state->gensec_state->gensec_role == GENSEC_CLIENT) {
1754 86 : reply_code = "KK";
1755 162 : } else if (state->gensec_state->gensec_role == GENSEC_SERVER) {
1756 162 : reply_code = "TT";
1757 : } else {
1758 0 : abort();
1759 : }
1760 :
1761 :
1762 222 : } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) {
1763 0 : reply_code = "BH NT_STATUS_ACCESS_DENIED";
1764 0 : reply_arg = nt_errstr(nt_status);
1765 0 : DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
1766 222 : } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_UNSUCCESSFUL)) {
1767 0 : reply_code = "BH NT_STATUS_UNSUCCESSFUL";
1768 0 : reply_arg = nt_errstr(nt_status);
1769 0 : DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
1770 222 : } else if (!NT_STATUS_IS_OK(nt_status)) {
1771 20 : reply_code = "NA";
1772 20 : reply_arg = nt_errstr(nt_status);
1773 20 : DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
1774 202 : } else if /* OK */ (state->gensec_state->gensec_role == GENSEC_SERVER) {
1775 : struct auth_session_info *session_info;
1776 :
1777 96 : nt_status = gensec_session_info(state->gensec_state, mem_ctx, &session_info);
1778 96 : if (!NT_STATUS_IS_OK(nt_status)) {
1779 0 : reply_code = "BH Failed to retrieve session info";
1780 0 : reply_arg = nt_errstr(nt_status);
1781 0 : DEBUG(1, ("GENSEC failed to retrieve the session info: %s\n", nt_errstr(nt_status)));
1782 : } else {
1783 :
1784 96 : reply_code = "AF";
1785 96 : reply_arg = talloc_strdup(state->gensec_state, session_info->unix_info->unix_name);
1786 96 : if (reply_arg == NULL) {
1787 0 : reply_code = "BH out of memory";
1788 0 : reply_arg = nt_errstr(NT_STATUS_NO_MEMORY);
1789 : }
1790 96 : talloc_free(session_info);
1791 : }
1792 106 : } else if (state->gensec_state->gensec_role == GENSEC_CLIENT) {
1793 106 : reply_code = "AF";
1794 106 : reply_arg = out_base64;
1795 : } else {
1796 0 : abort();
1797 : }
1798 :
1799 540 : switch (stdio_helper_mode) {
1800 178 : case GSS_SPNEGO_SERVER:
1801 178 : printf("%s %s %s\n", reply_code,
1802 : out_base64 ? out_base64 : "*",
1803 : reply_arg ? reply_arg : "*");
1804 178 : break;
1805 362 : default:
1806 362 : if (out_base64) {
1807 276 : printf("%s %s\n", reply_code, out_base64);
1808 86 : } else if (reply_arg) {
1809 50 : printf("%s %s\n", reply_code, reply_arg);
1810 : } else {
1811 36 : printf("%s\n", reply_code);
1812 : }
1813 : }
1814 :
1815 540 : talloc_free(mem_ctx);
1816 540 : return;
1817 : }
1818 :
1819 178 : static void manage_gss_spnego_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 178 : manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
1825 178 : return;
1826 : }
1827 :
1828 180 : static void manage_squid_ntlmssp_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 180 : manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
1834 180 : return;
1835 : }
1836 :
1837 122 : static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode,
1838 : struct loadparm_context *lp_ctx,
1839 : struct ntlm_auth_state *state,
1840 : char *buf, int length, void **private2)
1841 : {
1842 122 : manage_gensec_request(stdio_helper_mode, lp_ctx, buf, length, &state->gensec_private_1);
1843 122 : return;
1844 : }
1845 :
1846 280 : static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode,
1847 : struct loadparm_context *lp_ctx,
1848 : struct ntlm_auth_state *state,
1849 : char *buf, int length, void **private2)
1850 : {
1851 : char *request, *parameter;
1852 : static DATA_BLOB challenge;
1853 : static DATA_BLOB lm_response;
1854 : static DATA_BLOB nt_response;
1855 : static char *full_username;
1856 : static char *username;
1857 : static char *domain;
1858 : static char *plaintext_password;
1859 : static bool ntlm_server_1_user_session_key;
1860 : static bool ntlm_server_1_lm_session_key;
1861 :
1862 280 : if (strequal(buf, ".")) {
1863 50 : if (!full_username && !username) {
1864 0 : printf("Error: No username supplied!\n");
1865 50 : } else if (plaintext_password) {
1866 : /* handle this request as plaintext */
1867 20 : if (!full_username) {
1868 20 : if (asprintf(&full_username, "%s%c%s", domain, winbind_separator(), username) == -1) {
1869 0 : printf("Error: Out of memory in "
1870 : "asprintf!\n.\n");
1871 0 : return;
1872 : }
1873 : }
1874 20 : if (check_plaintext_auth(full_username, plaintext_password, False)) {
1875 10 : printf("Authenticated: Yes\n");
1876 : } else {
1877 10 : printf("Authenticated: No\n");
1878 : }
1879 30 : } else if (!lm_response.data && !nt_response.data) {
1880 0 : printf("Error: No password supplied!\n");
1881 30 : } else if (!challenge.data) {
1882 0 : printf("Error: No lanman-challenge supplied!\n");
1883 : } else {
1884 30 : char *error_string = NULL;
1885 : uchar lm_key[8];
1886 : uchar user_session_key[16];
1887 30 : uint32_t flags = 0;
1888 : NTSTATUS nt_status;
1889 30 : if (full_username && !username) {
1890 : fstring fstr_user;
1891 : fstring fstr_domain;
1892 :
1893 0 : if (!parse_ntlm_auth_domain_user(full_username, fstr_user, fstr_domain)) {
1894 : /* username might be 'tainted', don't print into our new-line deleimianted stream */
1895 0 : printf("Error: Could not parse into "
1896 : "domain and username\n");
1897 : }
1898 0 : SAFE_FREE(username);
1899 0 : SAFE_FREE(domain);
1900 0 : username = smb_xstrdup(fstr_user);
1901 0 : domain = smb_xstrdup(fstr_domain);
1902 : }
1903 :
1904 30 : if (opt_password) {
1905 : DATA_BLOB nt_session_key, lm_session_key;
1906 : struct samr_Password lm_pw, nt_pw;
1907 20 : TALLOC_CTX *mem_ctx = talloc_new(NULL);
1908 20 : ZERO_STRUCT(user_session_key);
1909 20 : ZERO_STRUCT(lm_key);
1910 :
1911 20 : nt_lm_owf_gen (opt_password, nt_pw.hash, lm_pw.hash);
1912 20 : nt_status = ntlm_password_check(mem_ctx,
1913 : true,
1914 : NTLM_AUTH_ON,
1915 : 0,
1916 : &challenge,
1917 : &lm_response,
1918 : &nt_response,
1919 : username,
1920 : username,
1921 : domain,
1922 : &lm_pw, &nt_pw,
1923 : &nt_session_key,
1924 : &lm_session_key);
1925 20 : error_string = smb_xstrdup(get_friendly_nt_error_msg(nt_status));
1926 20 : if (ntlm_server_1_user_session_key) {
1927 20 : if (nt_session_key.length == sizeof(user_session_key)) {
1928 10 : memcpy(user_session_key,
1929 10 : nt_session_key.data,
1930 : sizeof(user_session_key));
1931 : }
1932 : }
1933 20 : if (ntlm_server_1_lm_session_key) {
1934 0 : if (lm_session_key.length == sizeof(lm_key)) {
1935 0 : memcpy(lm_key,
1936 0 : lm_session_key.data,
1937 : sizeof(lm_key));
1938 : }
1939 : }
1940 20 : TALLOC_FREE(mem_ctx);
1941 :
1942 : } else {
1943 10 : uint8_t authoritative = 1;
1944 :
1945 10 : if (!domain) {
1946 0 : domain = smb_xstrdup(get_winbind_domain());
1947 : }
1948 :
1949 10 : if (ntlm_server_1_lm_session_key)
1950 0 : flags |= WBFLAG_PAM_LMKEY;
1951 :
1952 10 : if (ntlm_server_1_user_session_key)
1953 10 : flags |= WBFLAG_PAM_USER_SESSION_KEY;
1954 :
1955 10 : nt_status = contact_winbind_auth_crap(username,
1956 : domain,
1957 : lp_netbios_name(),
1958 : &challenge,
1959 : &lm_response,
1960 : &nt_response,
1961 : flags, 0,
1962 : lm_key,
1963 : user_session_key,
1964 : &authoritative,
1965 : &error_string,
1966 : NULL);
1967 : }
1968 :
1969 30 : if (!NT_STATUS_IS_OK(nt_status)) {
1970 20 : printf("Authenticated: No\n");
1971 20 : printf("Authentication-Error: %s\n.\n",
1972 : error_string);
1973 : } else {
1974 : char *hex_lm_key;
1975 : char *hex_user_session_key;
1976 :
1977 10 : printf("Authenticated: Yes\n");
1978 :
1979 10 : if (ntlm_server_1_lm_session_key
1980 0 : && (!all_zero(lm_key,
1981 : sizeof(lm_key)))) {
1982 0 : hex_lm_key = hex_encode_talloc(NULL,
1983 : (const unsigned char *)lm_key,
1984 : sizeof(lm_key));
1985 0 : printf("LANMAN-Session-Key: %s\n",
1986 : hex_lm_key);
1987 0 : TALLOC_FREE(hex_lm_key);
1988 : }
1989 :
1990 10 : if (ntlm_server_1_user_session_key
1991 10 : && (!all_zero(user_session_key,
1992 : sizeof(user_session_key)))) {
1993 10 : hex_user_session_key = hex_encode_talloc(NULL,
1994 : (const unsigned char *)user_session_key,
1995 : sizeof(user_session_key));
1996 10 : printf("User-Session-Key: %s\n",
1997 : hex_user_session_key);
1998 10 : TALLOC_FREE(hex_user_session_key);
1999 : }
2000 : }
2001 30 : SAFE_FREE(error_string);
2002 : }
2003 : /* clear out the state */
2004 50 : challenge = data_blob_null;
2005 50 : nt_response = data_blob_null;
2006 50 : lm_response = data_blob_null;
2007 50 : SAFE_FREE(full_username);
2008 50 : SAFE_FREE(username);
2009 50 : SAFE_FREE(domain);
2010 50 : SAFE_FREE(plaintext_password);
2011 50 : ntlm_server_1_user_session_key = False;
2012 50 : ntlm_server_1_lm_session_key = False;
2013 50 : printf(".\n");
2014 :
2015 50 : return;
2016 : }
2017 :
2018 230 : request = buf;
2019 :
2020 : /* Indicates a base64 encoded structure */
2021 230 : parameter = strstr_m(request, ":: ");
2022 230 : if (!parameter) {
2023 230 : parameter = strstr_m(request, ": ");
2024 :
2025 230 : if (!parameter) {
2026 0 : DEBUG(0, ("Parameter not found!\n"));
2027 0 : printf("Error: Parameter not found!\n.\n");
2028 0 : return;
2029 : }
2030 :
2031 230 : parameter[0] ='\0';
2032 230 : parameter++;
2033 230 : parameter[0] ='\0';
2034 230 : parameter++;
2035 :
2036 : } else {
2037 0 : parameter[0] ='\0';
2038 0 : parameter++;
2039 0 : parameter[0] ='\0';
2040 0 : parameter++;
2041 0 : parameter[0] ='\0';
2042 0 : parameter++;
2043 :
2044 0 : base64_decode_inplace(parameter);
2045 : }
2046 :
2047 230 : if (strequal(request, "LANMAN-Challenge")) {
2048 30 : challenge = strhex_to_data_blob(NULL, parameter);
2049 30 : if (challenge.length != 8) {
2050 0 : printf("Error: hex decode of %s failed! "
2051 : "(got %d bytes, expected 8)\n.\n",
2052 : parameter,
2053 0 : (int)challenge.length);
2054 0 : challenge = data_blob_null;
2055 : }
2056 200 : } else if (strequal(request, "NT-Response")) {
2057 30 : nt_response = strhex_to_data_blob(NULL, parameter);
2058 30 : if (nt_response.length < 24) {
2059 0 : printf("Error: hex decode of %s failed! "
2060 : "(only got %d bytes, needed at least 24)\n.\n",
2061 : parameter,
2062 0 : (int)nt_response.length);
2063 0 : nt_response = data_blob_null;
2064 : }
2065 170 : } else if (strequal(request, "LANMAN-Response")) {
2066 0 : lm_response = strhex_to_data_blob(NULL, parameter);
2067 0 : if (lm_response.length != 24) {
2068 0 : printf("Error: hex decode of %s failed! "
2069 : "(got %d bytes, expected 24)\n.\n",
2070 : parameter,
2071 0 : (int)lm_response.length);
2072 0 : lm_response = data_blob_null;
2073 : }
2074 170 : } else if (strequal(request, "Password")) {
2075 20 : plaintext_password = smb_xstrdup(parameter);
2076 150 : } else if (strequal(request, "NT-Domain")) {
2077 50 : domain = smb_xstrdup(parameter);
2078 100 : } else if (strequal(request, "Username")) {
2079 50 : username = smb_xstrdup(parameter);
2080 50 : } else if (strequal(request, "Full-Username")) {
2081 0 : full_username = smb_xstrdup(parameter);
2082 50 : } else if (strequal(request, "Request-User-Session-Key")) {
2083 50 : ntlm_server_1_user_session_key = strequal(parameter, "Yes");
2084 0 : } else if (strequal(request, "Request-LanMan-Session-Key")) {
2085 0 : ntlm_server_1_lm_session_key = strequal(parameter, "Yes");
2086 : } else {
2087 0 : printf("Error: Unknown request %s\n.\n", request);
2088 : }
2089 : }
2090 :
2091 0 : static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode,
2092 : struct loadparm_context *lp_ctx,
2093 : struct ntlm_auth_state *state,
2094 : char *buf, int length, void **private2)
2095 : {
2096 : char *request, *parameter;
2097 : static DATA_BLOB new_nt_pswd;
2098 : static DATA_BLOB old_nt_hash_enc;
2099 : static DATA_BLOB new_lm_pswd;
2100 : static DATA_BLOB old_lm_hash_enc;
2101 : static char *full_username = NULL;
2102 : static char *username = NULL;
2103 : static char *domain = NULL;
2104 : static char *newpswd = NULL;
2105 : static char *oldpswd = NULL;
2106 :
2107 0 : if (strequal(buf, ".")) {
2108 0 : if(newpswd && oldpswd) {
2109 : uchar old_nt_hash[16];
2110 : uchar old_lm_hash[16];
2111 : uchar new_nt_hash[16];
2112 : uchar new_lm_hash[16];
2113 :
2114 0 : gnutls_cipher_hd_t cipher_hnd = NULL;
2115 0 : gnutls_datum_t old_nt_key = {
2116 : .data = old_nt_hash,
2117 : .size = sizeof(old_nt_hash),
2118 : };
2119 : int rc;
2120 :
2121 0 : new_nt_pswd = data_blob(NULL, 516);
2122 0 : old_nt_hash_enc = data_blob(NULL, 16);
2123 :
2124 : /* Calculate the MD4 hash (NT compatible) of the
2125 : * password */
2126 0 : E_md4hash(oldpswd, old_nt_hash);
2127 0 : E_md4hash(newpswd, new_nt_hash);
2128 :
2129 : /* E_deshash returns false for 'long'
2130 : passwords (> 14 DOS chars).
2131 :
2132 : Therefore, don't send a buffer
2133 : encrypted with the truncated hash
2134 : (it could allow an even easier
2135 : attack on the password)
2136 :
2137 : Likewise, obey the admin's restriction
2138 : */
2139 :
2140 0 : rc = gnutls_cipher_init(&cipher_hnd,
2141 : GNUTLS_CIPHER_ARCFOUR_128,
2142 : &old_nt_key,
2143 : NULL);
2144 0 : if (rc < 0) {
2145 0 : DBG_ERR("gnutls_cipher_init failed: %s\n",
2146 : gnutls_strerror(rc));
2147 0 : if (rc == GNUTLS_E_UNWANTED_ALGORITHM) {
2148 0 : DBG_ERR("Running in FIPS mode, NTLM blocked\n");
2149 : }
2150 0 : return;
2151 : }
2152 :
2153 0 : if (lp_client_lanman_auth() &&
2154 0 : E_deshash(newpswd, new_lm_hash) &&
2155 0 : E_deshash(oldpswd, old_lm_hash)) {
2156 0 : new_lm_pswd = data_blob(NULL, 516);
2157 0 : old_lm_hash_enc = data_blob(NULL, 16);
2158 0 : encode_pw_buffer(new_lm_pswd.data, newpswd,
2159 : STR_UNICODE);
2160 :
2161 0 : rc = gnutls_cipher_encrypt(cipher_hnd,
2162 0 : new_lm_pswd.data,
2163 : 516);
2164 0 : if (rc < 0) {
2165 0 : gnutls_cipher_deinit(cipher_hnd);
2166 0 : return;
2167 : }
2168 0 : rc = E_old_pw_hash(new_nt_hash, old_lm_hash,
2169 : old_lm_hash_enc.data);
2170 0 : if (rc != 0) {
2171 0 : DBG_ERR("E_old_pw_hash failed: %s\n",
2172 : gnutls_strerror(rc));
2173 0 : return;
2174 : }
2175 : } else {
2176 0 : new_lm_pswd.data = NULL;
2177 0 : new_lm_pswd.length = 0;
2178 0 : old_lm_hash_enc.data = NULL;
2179 0 : old_lm_hash_enc.length = 0;
2180 : }
2181 :
2182 0 : encode_pw_buffer(new_nt_pswd.data, newpswd,
2183 : STR_UNICODE);
2184 :
2185 0 : rc = gnutls_cipher_encrypt(cipher_hnd,
2186 0 : new_nt_pswd.data,
2187 : 516);
2188 0 : gnutls_cipher_deinit(cipher_hnd);
2189 0 : if (rc < 0) {
2190 0 : return;
2191 : }
2192 0 : rc = E_old_pw_hash(new_nt_hash, old_nt_hash,
2193 : old_nt_hash_enc.data);
2194 0 : if (rc != 0) {
2195 0 : DBG_ERR("E_old_pw_hash failed: %s\n",
2196 : gnutls_strerror(rc));
2197 0 : return;
2198 : }
2199 :
2200 0 : ZERO_ARRAY(old_nt_hash);
2201 0 : ZERO_ARRAY(old_lm_hash);
2202 0 : ZERO_ARRAY(new_nt_hash);
2203 0 : ZERO_ARRAY(new_lm_hash);
2204 : }
2205 :
2206 0 : if (!full_username && !username) {
2207 0 : printf("Error: No username supplied!\n");
2208 0 : } else if ((!new_nt_pswd.data || !old_nt_hash_enc.data) &&
2209 0 : (!new_lm_pswd.data || old_lm_hash_enc.data) ) {
2210 0 : printf("Error: No NT or LM password "
2211 : "blobs supplied!\n");
2212 : } else {
2213 0 : char *error_string = NULL;
2214 :
2215 0 : if (full_username && !username) {
2216 : fstring fstr_user;
2217 : fstring fstr_domain;
2218 :
2219 0 : if (!parse_ntlm_auth_domain_user(full_username,
2220 : fstr_user,
2221 : fstr_domain)) {
2222 : /* username might be 'tainted', don't
2223 : * print into our new-line
2224 : * deleimianted stream */
2225 0 : printf("Error: Could not "
2226 : "parse into domain and "
2227 : "username\n");
2228 0 : SAFE_FREE(username);
2229 0 : username = smb_xstrdup(full_username);
2230 : } else {
2231 0 : SAFE_FREE(username);
2232 0 : SAFE_FREE(domain);
2233 0 : username = smb_xstrdup(fstr_user);
2234 0 : domain = smb_xstrdup(fstr_domain);
2235 : }
2236 :
2237 : }
2238 :
2239 0 : if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
2240 : username, domain,
2241 : new_nt_pswd,
2242 : old_nt_hash_enc,
2243 : new_lm_pswd,
2244 : old_lm_hash_enc,
2245 : &error_string))) {
2246 0 : printf("Password-Change: No\n");
2247 0 : printf("Password-Change-Error: %s\n.\n",
2248 : error_string);
2249 : } else {
2250 0 : printf("Password-Change: Yes\n");
2251 : }
2252 :
2253 0 : SAFE_FREE(error_string);
2254 : }
2255 : /* clear out the state */
2256 0 : new_nt_pswd = data_blob_null;
2257 0 : old_nt_hash_enc = data_blob_null;
2258 0 : new_lm_pswd = data_blob_null;
2259 0 : old_nt_hash_enc = data_blob_null;
2260 0 : SAFE_FREE(full_username);
2261 0 : SAFE_FREE(username);
2262 0 : SAFE_FREE(domain);
2263 0 : SAFE_FREE(newpswd);
2264 0 : SAFE_FREE(oldpswd);
2265 0 : printf(".\n");
2266 :
2267 0 : return;
2268 : }
2269 :
2270 0 : request = buf;
2271 :
2272 : /* Indicates a base64 encoded structure */
2273 0 : parameter = strstr_m(request, ":: ");
2274 0 : if (!parameter) {
2275 0 : parameter = strstr_m(request, ": ");
2276 :
2277 0 : if (!parameter) {
2278 0 : DEBUG(0, ("Parameter not found!\n"));
2279 0 : printf("Error: Parameter not found!\n.\n");
2280 0 : return;
2281 : }
2282 :
2283 0 : parameter[0] ='\0';
2284 0 : parameter++;
2285 0 : parameter[0] ='\0';
2286 0 : parameter++;
2287 : } else {
2288 0 : parameter[0] ='\0';
2289 0 : parameter++;
2290 0 : parameter[0] ='\0';
2291 0 : parameter++;
2292 0 : parameter[0] ='\0';
2293 0 : parameter++;
2294 :
2295 0 : base64_decode_inplace(parameter);
2296 : }
2297 :
2298 0 : if (strequal(request, "new-nt-password-blob")) {
2299 0 : new_nt_pswd = strhex_to_data_blob(NULL, parameter);
2300 0 : if (new_nt_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_nt_pswd.length);
2305 0 : new_nt_pswd = data_blob_null;
2306 : }
2307 0 : } else if (strequal(request, "old-nt-hash-blob")) {
2308 0 : old_nt_hash_enc = strhex_to_data_blob(NULL, parameter);
2309 0 : if (old_nt_hash_enc.length != 16) {
2310 0 : printf("Error: hex decode of %s failed! "
2311 : "(got %d bytes, expected 16)\n.\n",
2312 : parameter,
2313 0 : (int)old_nt_hash_enc.length);
2314 0 : old_nt_hash_enc = data_blob_null;
2315 : }
2316 0 : } else if (strequal(request, "new-lm-password-blob")) {
2317 0 : new_lm_pswd = strhex_to_data_blob(NULL, parameter);
2318 0 : if (new_lm_pswd.length != 516) {
2319 0 : printf("Error: hex decode of %s failed! "
2320 : "(got %d bytes, expected 516)\n.\n",
2321 : parameter,
2322 0 : (int)new_lm_pswd.length);
2323 0 : new_lm_pswd = data_blob_null;
2324 : }
2325 : }
2326 0 : else if (strequal(request, "old-lm-hash-blob")) {
2327 0 : old_lm_hash_enc = strhex_to_data_blob(NULL, parameter);
2328 0 : if (old_lm_hash_enc.length != 16)
2329 : {
2330 0 : printf("Error: hex decode of %s failed! "
2331 : "(got %d bytes, expected 16)\n.\n",
2332 : parameter,
2333 0 : (int)old_lm_hash_enc.length);
2334 0 : old_lm_hash_enc = data_blob_null;
2335 : }
2336 0 : } else if (strequal(request, "nt-domain")) {
2337 0 : domain = smb_xstrdup(parameter);
2338 0 : } else if(strequal(request, "username")) {
2339 0 : username = smb_xstrdup(parameter);
2340 0 : } else if(strequal(request, "full-username")) {
2341 0 : username = smb_xstrdup(parameter);
2342 0 : } else if(strequal(request, "new-password")) {
2343 0 : newpswd = smb_xstrdup(parameter);
2344 0 : } else if (strequal(request, "old-password")) {
2345 0 : oldpswd = smb_xstrdup(parameter);
2346 : } else {
2347 0 : printf("Error: Unknown request %s\n.\n", request);
2348 : }
2349 : }
2350 :
2351 1348 : static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode,
2352 : struct loadparm_context *lp_ctx,
2353 : struct ntlm_auth_state *state,
2354 : stdio_helper_function fn, void **private2)
2355 : {
2356 : char *buf;
2357 : char tmp[INITIAL_BUFFER_SIZE+1];
2358 1348 : int length, buf_size = 0;
2359 : char *c;
2360 :
2361 1348 : buf = talloc_strdup(state->mem_ctx, "");
2362 1348 : if (!buf) {
2363 0 : DEBUG(0, ("Failed to allocate input buffer.\n"));
2364 0 : fprintf(stderr, "ERR\n");
2365 0 : exit(1);
2366 : }
2367 :
2368 : do {
2369 :
2370 : /* this is not a typo - x_fgets doesn't work too well under
2371 : * squid */
2372 1665 : if (fgets(tmp, sizeof(tmp)-1, stdin) == NULL) {
2373 308 : if (ferror(stdin)) {
2374 0 : DEBUG(1, ("fgets() failed! dying..... errno=%d "
2375 : "(%s)\n", ferror(stdin),
2376 : strerror(ferror(stdin))));
2377 :
2378 0 : exit(1);
2379 : }
2380 308 : exit(0);
2381 : }
2382 :
2383 1357 : buf = talloc_strdup_append_buffer(buf, tmp);
2384 1357 : buf_size += INITIAL_BUFFER_SIZE;
2385 :
2386 1357 : if (buf_size > MAX_BUFFER_SIZE) {
2387 0 : DEBUG(2, ("Oversized message\n"));
2388 0 : fprintf(stderr, "ERR\n");
2389 0 : talloc_free(buf);
2390 0 : return;
2391 : }
2392 :
2393 1357 : c = strchr(buf, '\n');
2394 1357 : } while (c == NULL);
2395 :
2396 1040 : *c = '\0';
2397 1040 : length = c-buf;
2398 :
2399 1040 : DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf,length));
2400 :
2401 1040 : if (buf[0] == '\0') {
2402 0 : DEBUG(2, ("Invalid Request\n"));
2403 0 : fprintf(stderr, "ERR\n");
2404 0 : talloc_free(buf);
2405 0 : return;
2406 : }
2407 :
2408 1040 : fn(stdio_helper_mode, lp_ctx, state, buf, length, private2);
2409 1040 : talloc_free(buf);
2410 : }
2411 :
2412 :
2413 308 : static void squid_stream(enum stdio_helper_mode stdio_mode,
2414 : struct loadparm_context *lp_ctx,
2415 : stdio_helper_function fn) {
2416 : TALLOC_CTX *mem_ctx;
2417 : struct ntlm_auth_state *state;
2418 :
2419 : /* initialize FDescs */
2420 308 : setbuf(stdout, NULL);
2421 308 : setbuf(stderr, NULL);
2422 :
2423 308 : mem_ctx = talloc_init("ntlm_auth");
2424 308 : if (!mem_ctx) {
2425 0 : DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
2426 0 : fprintf(stderr, "ERR\n");
2427 0 : exit(1);
2428 : }
2429 :
2430 308 : state = talloc_zero(mem_ctx, struct ntlm_auth_state);
2431 308 : if (!state) {
2432 0 : DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
2433 0 : fprintf(stderr, "ERR\n");
2434 0 : exit(1);
2435 : }
2436 :
2437 308 : state->mem_ctx = mem_ctx;
2438 308 : state->helper_mode = stdio_mode;
2439 :
2440 1040 : while(1) {
2441 1348 : TALLOC_CTX *frame = talloc_stackframe();
2442 1348 : manage_squid_request(stdio_mode, lp_ctx, state, fn, NULL);
2443 1040 : TALLOC_FREE(frame);
2444 : }
2445 : }
2446 :
2447 :
2448 : /* Authenticate a user with a challenge/response */
2449 :
2450 0 : static bool check_auth_crap(void)
2451 : {
2452 : NTSTATUS nt_status;
2453 0 : uint32_t flags = 0;
2454 : char lm_key[8];
2455 : char user_session_key[16];
2456 : char *hex_lm_key;
2457 : char *hex_user_session_key;
2458 : char *error_string;
2459 0 : uint8_t authoritative = 1;
2460 :
2461 0 : setbuf(stdout, NULL);
2462 :
2463 0 : if (request_lm_key)
2464 0 : flags |= WBFLAG_PAM_LMKEY;
2465 :
2466 0 : if (request_user_session_key)
2467 0 : flags |= WBFLAG_PAM_USER_SESSION_KEY;
2468 :
2469 0 : flags |= WBFLAG_PAM_NT_STATUS_SQUASH;
2470 :
2471 0 : nt_status = contact_winbind_auth_crap(opt_username, opt_domain,
2472 : opt_workstation,
2473 : &opt_challenge,
2474 : &opt_lm_response,
2475 : &opt_nt_response,
2476 : flags, 0,
2477 : (unsigned char *)lm_key,
2478 : (unsigned char *)user_session_key,
2479 : &authoritative,
2480 : &error_string, NULL);
2481 :
2482 0 : if (!NT_STATUS_IS_OK(nt_status)) {
2483 0 : printf("%s (0x%x)\n", error_string,
2484 : NT_STATUS_V(nt_status));
2485 0 : SAFE_FREE(error_string);
2486 0 : return False;
2487 : }
2488 :
2489 0 : if (request_lm_key
2490 0 : && (!all_zero((uint8_t *)lm_key, sizeof(lm_key)))) {
2491 0 : hex_lm_key = hex_encode_talloc(talloc_tos(), (const unsigned char *)lm_key,
2492 : sizeof(lm_key));
2493 0 : printf("LM_KEY: %s\n", hex_lm_key);
2494 0 : TALLOC_FREE(hex_lm_key);
2495 : }
2496 0 : if (request_user_session_key
2497 0 : && (!all_zero((uint8_t *)user_session_key,
2498 : sizeof(user_session_key)))) {
2499 0 : hex_user_session_key = hex_encode_talloc(talloc_tos(), (const unsigned char *)user_session_key,
2500 : sizeof(user_session_key));
2501 0 : printf("NT_KEY: %s\n", hex_user_session_key);
2502 0 : TALLOC_FREE(hex_user_session_key);
2503 : }
2504 :
2505 0 : return True;
2506 : }
2507 :
2508 : /* Main program */
2509 :
2510 : enum {
2511 : OPT_USERNAME = 1000,
2512 : OPT_DOMAIN,
2513 : OPT_WORKSTATION,
2514 : OPT_CHALLENGE,
2515 : OPT_RESPONSE,
2516 : OPT_LM,
2517 : OPT_NT,
2518 : OPT_PASSWORD,
2519 : OPT_LM_KEY,
2520 : OPT_USER_SESSION_KEY,
2521 : OPT_DIAGNOSTICS,
2522 : OPT_REQUIRE_MEMBERSHIP,
2523 : OPT_USE_CACHED_CREDS,
2524 : OPT_ALLOW_MSCHAPV2,
2525 : OPT_PAM_WINBIND_CONF,
2526 : OPT_TARGET_SERVICE,
2527 : OPT_TARGET_HOSTNAME,
2528 : OPT_OFFLINE_LOGON
2529 : };
2530 :
2531 329 : int main(int argc, const char **argv)
2532 : {
2533 329 : TALLOC_CTX *frame = talloc_stackframe();
2534 : int opt;
2535 329 : const char *helper_protocol = NULL;
2536 329 : int diagnostics = 0;
2537 :
2538 329 : const char *hex_challenge = NULL;
2539 329 : const char *hex_lm_response = NULL;
2540 329 : const char *hex_nt_response = NULL;
2541 : struct loadparm_context *lp_ctx;
2542 : poptContext pc;
2543 : bool ok;
2544 :
2545 : /* NOTE: DO NOT change this interface without considering the implications!
2546 : This is an external interface, which other programs will use to interact
2547 : with this helper.
2548 : */
2549 :
2550 : /* We do not use single-letter command abbreviations, because they harm future
2551 : interface stability. */
2552 :
2553 1645 : struct poptOption long_options[] = {
2554 : POPT_AUTOHELP
2555 : {
2556 : .longName = "helper-protocol",
2557 : .shortName = 0,
2558 : .argInfo = POPT_ARG_STRING,
2559 : .arg = &helper_protocol,
2560 : .val = OPT_DOMAIN,
2561 : .descrip = "operate as a stdio-based helper",
2562 : .argDescrip = "helper protocol to use"
2563 : },
2564 : {
2565 : .longName = "username",
2566 : .shortName = 0,
2567 : .argInfo = POPT_ARG_STRING,
2568 : .arg = &opt_username,
2569 : .val = OPT_USERNAME,
2570 : .descrip = "username"
2571 : },
2572 : {
2573 : .longName = "domain",
2574 : .shortName = 0,
2575 : .argInfo = POPT_ARG_STRING,
2576 : .arg = &opt_domain,
2577 : .val = OPT_DOMAIN,
2578 : .descrip = "domain name"
2579 : },
2580 : {
2581 : .longName = "workstation",
2582 : .shortName = 0,
2583 : .argInfo = POPT_ARG_STRING,
2584 : .arg = &opt_workstation,
2585 : .val = OPT_WORKSTATION,
2586 : .descrip = "workstation"
2587 : },
2588 : {
2589 : .longName = "challenge",
2590 : .shortName = 0,
2591 : .argInfo = POPT_ARG_STRING,
2592 : .arg = &hex_challenge,
2593 : .val = OPT_CHALLENGE,
2594 : .descrip = "challenge (HEX encoded)"
2595 : },
2596 : {
2597 : .longName = "lm-response",
2598 : .shortName = 0,
2599 : .argInfo = POPT_ARG_STRING,
2600 : .arg = &hex_lm_response,
2601 : .val = OPT_LM,
2602 : .descrip = "LM Response to the challenge (HEX encoded)"
2603 : },
2604 : {
2605 : .longName = "nt-response",
2606 : .shortName = 0,
2607 : .argInfo = POPT_ARG_STRING,
2608 : .arg = &hex_nt_response,
2609 : .val = OPT_NT,
2610 : .descrip = "NT or NTLMv2 Response to the challenge (HEX encoded)"
2611 : },
2612 : {
2613 : .longName = "password",
2614 : .shortName = 0,
2615 : .argInfo = POPT_ARG_STRING,
2616 : .arg = &opt_password,
2617 : .val = OPT_PASSWORD,
2618 : .descrip = "User's plaintext password"
2619 : },
2620 : {
2621 : .longName = "request-lm-key",
2622 : .shortName = 0,
2623 : .argInfo = POPT_ARG_NONE,
2624 : .arg = &request_lm_key,
2625 : .val = OPT_LM_KEY,
2626 : .descrip = "Retrieve LM session key (or, with --diagnostics, expect LM support)"
2627 : },
2628 : {
2629 : .longName = "request-nt-key",
2630 : .shortName = 0,
2631 : .argInfo = POPT_ARG_NONE,
2632 : .arg = &request_user_session_key,
2633 : .val = OPT_USER_SESSION_KEY,
2634 : .descrip = "Retrieve User (NT) session key"
2635 : },
2636 : {
2637 : .longName = "use-cached-creds",
2638 : .shortName = 0,
2639 : .argInfo = POPT_ARG_NONE,
2640 : .arg = &use_cached_creds,
2641 : .val = OPT_USE_CACHED_CREDS,
2642 : .descrip = "Use cached credentials if no password is given"
2643 : },
2644 : {
2645 : .longName = "allow-mschapv2",
2646 : .shortName = 0,
2647 : .argInfo = POPT_ARG_NONE,
2648 : .arg = &opt_allow_mschapv2,
2649 : .val = OPT_ALLOW_MSCHAPV2,
2650 : .descrip = "Explicitly allow MSCHAPv2",
2651 : },
2652 : {
2653 : .longName = "offline-logon",
2654 : .shortName = 0,
2655 : .argInfo = POPT_ARG_NONE,
2656 : .arg = &offline_logon,
2657 : .val = OPT_OFFLINE_LOGON,
2658 : .descrip = "Use cached passwords when DC is offline"
2659 : },
2660 : {
2661 : .longName = "diagnostics",
2662 : .shortName = 0,
2663 : .argInfo = POPT_ARG_NONE,
2664 : .arg = &diagnostics,
2665 : .val = OPT_DIAGNOSTICS,
2666 : .descrip = "Perform diagnostics on the authentication chain"
2667 : },
2668 : {
2669 : .longName = "require-membership-of",
2670 : .shortName = 0,
2671 : .argInfo = POPT_ARG_STRING,
2672 : .arg = &require_membership_of,
2673 : .val = OPT_REQUIRE_MEMBERSHIP,
2674 : .descrip = "Require that a user be a member of this group (either name or SID) for authentication to succeed",
2675 : },
2676 : {
2677 : .longName = "pam-winbind-conf",
2678 : .shortName = 0,
2679 : .argInfo = POPT_ARG_STRING,
2680 : .arg = &opt_pam_winbind_conf,
2681 : .val = OPT_PAM_WINBIND_CONF,
2682 : .descrip = "Require that request must set WBFLAG_PAM_CONTACT_TRUSTDOM when krb5 auth is required",
2683 : },
2684 : {
2685 : .longName = "target-service",
2686 : .shortName = 0,
2687 : .argInfo = POPT_ARG_STRING,
2688 : .arg = &opt_target_service,
2689 : .val = OPT_TARGET_SERVICE,
2690 : .descrip = "Target service (eg http)",
2691 : },
2692 : {
2693 : .longName = "target-hostname",
2694 : .shortName = 0,
2695 : .argInfo = POPT_ARG_STRING,
2696 : .arg = &opt_target_hostname,
2697 : .val = OPT_TARGET_HOSTNAME,
2698 : .descrip = "Target hostname",
2699 : },
2700 329 : POPT_COMMON_DEBUG_ONLY
2701 329 : POPT_COMMON_CONFIG_ONLY
2702 329 : POPT_COMMON_OPTION_ONLY
2703 329 : POPT_COMMON_VERSION
2704 : POPT_TABLEEND
2705 : };
2706 :
2707 : /* Samba client initialisation */
2708 329 : smb_init_locale();
2709 :
2710 329 : ok = samba_cmdline_init(frame,
2711 : SAMBA_CMDLINE_CONFIG_CLIENT,
2712 : false /* require_smbconf */);
2713 329 : if (!ok) {
2714 0 : DBG_ERR("Failed to init cmdline parser!\n");
2715 0 : TALLOC_FREE(frame);
2716 0 : exit(1);
2717 : }
2718 :
2719 329 : pc = samba_popt_get_context(getprogname(),
2720 : argc,
2721 : argv,
2722 : long_options,
2723 : POPT_CONTEXT_KEEP_FIRST);
2724 329 : if (pc == NULL) {
2725 0 : DBG_ERR("Failed to setup popt context!\n");
2726 0 : TALLOC_FREE(frame);
2727 0 : exit(1);
2728 : }
2729 :
2730 1359 : while((opt = poptGetNextOpt(pc)) != -1) {
2731 962 : switch (opt) {
2732 0 : case OPT_CHALLENGE:
2733 0 : opt_challenge = strhex_to_data_blob(NULL, hex_challenge);
2734 0 : if (opt_challenge.length != 8) {
2735 0 : fprintf(stderr, "hex decode of %s failed! "
2736 : "(only got %d bytes)\n",
2737 : hex_challenge,
2738 0 : (int)opt_challenge.length);
2739 0 : exit(1);
2740 : }
2741 0 : break;
2742 0 : case OPT_LM:
2743 0 : opt_lm_response = strhex_to_data_blob(NULL, hex_lm_response);
2744 0 : if (opt_lm_response.length != 24) {
2745 0 : fprintf(stderr, "hex decode of %s failed! "
2746 : "(only got %d bytes)\n",
2747 : hex_lm_response,
2748 0 : (int)opt_lm_response.length);
2749 0 : exit(1);
2750 : }
2751 0 : break;
2752 :
2753 0 : case OPT_NT:
2754 0 : opt_nt_response = strhex_to_data_blob(NULL, hex_nt_response);
2755 0 : if (opt_nt_response.length < 24) {
2756 0 : fprintf(stderr, "hex decode of %s failed! "
2757 : "(only got %d bytes)\n",
2758 : hex_nt_response,
2759 0 : (int)opt_nt_response.length);
2760 0 : exit(1);
2761 : }
2762 0 : break;
2763 :
2764 80 : case OPT_REQUIRE_MEMBERSHIP:
2765 80 : if (strncasecmp_m("S-", require_membership_of, 2) == 0) {
2766 80 : require_membership_of_sid = require_membership_of;
2767 : }
2768 80 : break;
2769 :
2770 0 : case POPT_ERROR_BADOPT:
2771 0 : fprintf(stderr, "\nInvalid option %s: %s\n\n",
2772 : poptBadOption(pc, 0), poptStrerror(opt));
2773 0 : poptPrintUsage(pc, stderr, 0);
2774 0 : exit(1);
2775 : }
2776 : }
2777 :
2778 329 : if (opt_username) {
2779 171 : char *domain = SMB_STRDUP(opt_username);
2780 171 : char *p = strchr_m(domain, *lp_winbind_separator());
2781 171 : if (p) {
2782 0 : opt_username = p+1;
2783 0 : *p = '\0';
2784 0 : if (opt_domain && !strequal(opt_domain, domain)) {
2785 0 : fprintf(stderr, "Domain specified in username (%s) "
2786 : "doesn't match specified domain (%s)!\n\n",
2787 : domain, opt_domain);
2788 0 : poptPrintHelp(pc, stderr, 0);
2789 0 : exit(1);
2790 : }
2791 0 : opt_domain = domain;
2792 : } else {
2793 171 : SAFE_FREE(domain);
2794 : }
2795 : }
2796 :
2797 : /* Note: if opt_domain is "" then send no domain */
2798 329 : if (opt_domain == NULL) {
2799 159 : opt_domain = get_winbind_domain();
2800 : }
2801 :
2802 329 : if (opt_workstation == NULL) {
2803 329 : opt_workstation = "";
2804 : }
2805 :
2806 329 : lp_ctx = loadparm_init_s3(NULL, loadparm_s3_helpers());
2807 329 : if (lp_ctx == NULL) {
2808 0 : fprintf(stderr, "loadparm_init_s3() failed!\n");
2809 0 : exit(1);
2810 : }
2811 :
2812 329 : if (helper_protocol) {
2813 : int i;
2814 1456 : for (i=0; i<NUM_HELPER_MODES; i++) {
2815 1456 : if (strcmp(helper_protocol, stdio_helper_protocols[i].name) == 0) {
2816 308 : squid_stream(stdio_helper_protocols[i].mode, lp_ctx, stdio_helper_protocols[i].fn);
2817 0 : exit(0);
2818 : }
2819 : }
2820 0 : fprintf(stderr, "unknown helper protocol [%s]\n\n"
2821 : "Valid helper protools:\n\n", helper_protocol);
2822 :
2823 0 : for (i=0; i<NUM_HELPER_MODES; i++) {
2824 0 : fprintf(stderr, "%s\n",
2825 0 : stdio_helper_protocols[i].name);
2826 : }
2827 :
2828 0 : exit(1);
2829 : }
2830 :
2831 21 : if (!opt_username || !*opt_username) {
2832 0 : fprintf(stderr, "username must be specified!\n\n");
2833 0 : poptPrintHelp(pc, stderr, 0);
2834 0 : exit(1);
2835 : }
2836 :
2837 21 : if (opt_challenge.length) {
2838 0 : if (!check_auth_crap()) {
2839 0 : exit(1);
2840 : }
2841 0 : exit(0);
2842 : }
2843 :
2844 21 : if (!opt_password) {
2845 0 : char pwd[256] = {0};
2846 : int rc;
2847 :
2848 0 : rc = samba_getpass("Password: ", pwd, sizeof(pwd), false, false);
2849 0 : if (rc == 0) {
2850 0 : opt_password = SMB_STRDUP(pwd);
2851 : }
2852 : }
2853 :
2854 21 : if (diagnostics) {
2855 20 : if (!diagnose_ntlm_auth(request_lm_key)) {
2856 10 : poptFreeContext(pc);
2857 10 : return 1;
2858 : }
2859 : } else {
2860 : fstring user;
2861 :
2862 1 : fstr_sprintf(user, "%s%c%s", opt_domain, winbind_separator(), opt_username);
2863 1 : if (!check_plaintext_auth(user, opt_password, True)) {
2864 0 : poptFreeContext(pc);
2865 0 : return 1;
2866 : }
2867 : }
2868 :
2869 : /* Exit code */
2870 11 : gfree_all();
2871 11 : poptFreeContext(pc);
2872 11 : TALLOC_FREE(frame);
2873 11 : return 0;
2874 : }
|