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