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