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