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