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