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