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