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