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