b38995712cd719e97d1d352dc125ca60d53c8645
[kai/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
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 3 of the License, or
15    (at your option) any later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21
22    You should have received a copy of the GNU General Public License
23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24 */
25
26 #include "includes.h"
27 #include "lib/param/param.h"
28 #include "popt_common.h"
29 #include "utils/ntlm_auth.h"
30 #include "../libcli/auth/libcli_auth.h"
31 #include "../libcli/auth/spnego.h"
32 #include "auth/ntlmssp/ntlmssp.h"
33 #include "auth/gensec/gensec.h"
34 #include "auth/credentials/credentials.h"
35 #include "librpc/crypto/gse.h"
36 #include "smb_krb5.h"
37 #include <iniparser.h>
38 #include "../lib/crypto/arcfour.h"
39 #include "libads/kerberos_proto.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
45 #ifndef PAM_WINBIND_CONFIG_FILE
46 #define PAM_WINBIND_CONFIG_FILE "/etc/security/pam_winbind.conf"
47 #endif
48
49 #define WINBIND_KRB5_AUTH       0x00000080
50
51 #undef DBGC_CLASS
52 #define DBGC_CLASS DBGC_WINBIND
53
54 #define INITIAL_BUFFER_SIZE 300
55 #define MAX_BUFFER_SIZE 630000
56
57 enum stdio_helper_mode {
58         SQUID_2_4_BASIC,
59         SQUID_2_5_BASIC,
60         SQUID_2_5_NTLMSSP,
61         NTLMSSP_CLIENT_1,
62         GSS_SPNEGO,
63         GSS_SPNEGO_CLIENT,
64         NTLM_SERVER_1,
65         NTLM_CHANGE_PASSWORD_1,
66         NUM_HELPER_MODES
67 };
68
69 enum ntlm_auth_cli_state {
70         CLIENT_INITIAL = 0,
71         CLIENT_RESPONSE,
72         CLIENT_FINISHED,
73         CLIENT_ERROR
74 };
75
76 enum ntlm_auth_svr_state {
77         SERVER_INITIAL = 0,
78         SERVER_CHALLENGE,
79         SERVER_FINISHED,
80         SERVER_ERROR
81 };
82
83 struct ntlm_auth_state {
84         TALLOC_CTX *mem_ctx;
85         enum stdio_helper_mode helper_mode;
86         enum ntlm_auth_cli_state cli_state;
87         enum ntlm_auth_svr_state svr_state;
88         struct ntlmssp_state *ntlmssp_state;
89         struct gensec_security *gensec_security;
90         uint32_t neg_flags;
91         char *want_feature_list;
92         char *spnego_mech;
93         char *spnego_mech_oid;
94         bool have_session_key;
95         DATA_BLOB session_key;
96         DATA_BLOB initial_message;
97 };
98
99 typedef void (*stdio_helper_function)(struct ntlm_auth_state *state, char *buf,
100                                         int length);
101
102 static void manage_squid_basic_request (struct ntlm_auth_state *state,
103                                         char *buf, int length);
104
105 static void manage_squid_ntlmssp_request (struct ntlm_auth_state *state,
106                                         char *buf, int length);
107
108 static void manage_client_ntlmssp_request (struct ntlm_auth_state *state,
109                                         char *buf, int length);
110
111 static void manage_gss_spnego_request (struct ntlm_auth_state *state,
112                                         char *buf, int length);
113
114 static void manage_gss_spnego_client_request (struct ntlm_auth_state *state,
115                                         char *buf, int length);
116
117 static void manage_ntlm_server_1_request (struct ntlm_auth_state *state,
118                                         char *buf, int length);
119
120 static void manage_ntlm_change_password_1_request(struct ntlm_auth_state *state,
121                                         char *buf, int length);
122
123 static const struct {
124         enum stdio_helper_mode mode;
125         const char *name;
126         stdio_helper_function fn;
127 } stdio_helper_protocols[] = {
128         { SQUID_2_4_BASIC, "squid-2.4-basic", manage_squid_basic_request},
129         { SQUID_2_5_BASIC, "squid-2.5-basic", manage_squid_basic_request},
130         { SQUID_2_5_NTLMSSP, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request},
131         { NTLMSSP_CLIENT_1, "ntlmssp-client-1", manage_client_ntlmssp_request},
132         { GSS_SPNEGO, "gss-spnego", manage_gss_spnego_request},
133         { GSS_SPNEGO_CLIENT, "gss-spnego-client", manage_gss_spnego_client_request},
134         { NTLM_SERVER_1, "ntlm-server-1", manage_ntlm_server_1_request},
135         { NTLM_CHANGE_PASSWORD_1, "ntlm-change-password-1", manage_ntlm_change_password_1_request},
136         { NUM_HELPER_MODES, NULL, NULL}
137 };
138
139 const char *opt_username;
140 const char *opt_domain;
141 const char *opt_workstation;
142 const char *opt_password;
143 static DATA_BLOB opt_challenge;
144 static DATA_BLOB opt_lm_response;
145 static DATA_BLOB opt_nt_response;
146 static int request_lm_key;
147 static int request_user_session_key;
148 static int use_cached_creds;
149
150 static const char *require_membership_of;
151 static const char *require_membership_of_sid;
152 static const char *opt_pam_winbind_conf;
153
154 /**
155  * A limited set of features are defined with text strings as needed
156  * by ntlm_auth
157  *
158  */
159 static void gensec_want_feature_list(struct gensec_security *state, char* feature_list)
160 {
161         if (in_list("NTLMSSP_FEATURE_SESSION_KEY", feature_list, true)) {
162                 DEBUG(10, ("want GENSEC_FEATURE_SESSION_KEY\n"));
163                 gensec_want_feature(state, GENSEC_FEATURE_SESSION_KEY);
164         }
165         if (in_list("NTLMSSP_FEATURE_SIGN", feature_list, true)) {
166                 DEBUG(10, ("want GENSEC_FEATURE_SIGN\n"));
167                 gensec_want_feature(state, GENSEC_FEATURE_SIGN);
168         }
169         if (in_list("NTLMSSP_FEATURE_SEAL", feature_list, true)) {
170                 DEBUG(10, ("want GENSEC_FEATURE_SEAL\n"));
171                 gensec_want_feature(state, GENSEC_FEATURE_SEAL);
172         }
173 }
174
175 static char winbind_separator(void)
176 {
177         struct winbindd_response response;
178         static bool got_sep;
179         static char sep;
180
181         if (got_sep)
182                 return sep;
183
184         ZERO_STRUCT(response);
185
186         /* Send off request */
187
188         if (winbindd_request_response(WINBINDD_INFO, NULL, &response) !=
189             NSS_STATUS_SUCCESS) {
190                 d_printf("could not obtain winbind separator!\n");
191                 return *lp_winbind_separator();
192         }
193
194         sep = response.data.info.winbind_separator;
195         got_sep = True;
196
197         if (!sep) {
198                 d_printf("winbind separator was NULL!\n");
199                 return *lp_winbind_separator();
200         }
201
202         return sep;
203 }
204
205 const char *get_winbind_domain(void)
206 {
207         struct winbindd_response response;
208
209         static fstring winbind_domain;
210         if (*winbind_domain) {
211                 return winbind_domain;
212         }
213
214         ZERO_STRUCT(response);
215
216         /* Send off request */
217
218         if (winbindd_request_response(WINBINDD_DOMAIN_NAME, NULL, &response) !=
219             NSS_STATUS_SUCCESS) {
220                 DEBUG(0, ("could not obtain winbind domain name!\n"));
221                 return lp_workgroup();
222         }
223
224         fstrcpy(winbind_domain, response.data.domain_name);
225
226         return winbind_domain;
227
228 }
229
230 const char *get_winbind_netbios_name(void)
231 {
232         struct winbindd_response response;
233
234         static fstring winbind_netbios_name;
235
236         if (*winbind_netbios_name) {
237                 return winbind_netbios_name;
238         }
239
240         ZERO_STRUCT(response);
241
242         /* Send off request */
243
244         if (winbindd_request_response(WINBINDD_NETBIOS_NAME, NULL, &response) !=
245             NSS_STATUS_SUCCESS) {
246                 DEBUG(0, ("could not obtain winbind netbios name!\n"));
247                 return lp_netbios_name();
248         }
249
250         fstrcpy(winbind_netbios_name, response.data.netbios_name);
251
252         return winbind_netbios_name;
253
254 }
255
256 DATA_BLOB get_challenge(void) 
257 {
258         static DATA_BLOB chal;
259         if (opt_challenge.length)
260                 return opt_challenge;
261
262         chal = data_blob(NULL, 8);
263
264         generate_random_buffer(chal.data, chal.length);
265         return chal;
266 }
267
268 /* Copy of parse_domain_user from winbindd_util.c.  Parse a string of the
269    form DOMAIN/user into a domain and a user */
270
271 static bool parse_ntlm_auth_domain_user(const char *domuser, fstring domain, 
272                                      fstring user)
273 {
274
275         char *p = strchr(domuser,winbind_separator());
276
277         if (!p) {
278                 return False;
279         }
280
281         fstrcpy(user, p+1);
282         fstrcpy(domain, domuser);
283         domain[PTR_DIFF(p, domuser)] = 0;
284         strupper_m(domain);
285
286         return True;
287 }
288
289 static bool get_require_membership_sid(void) {
290         struct winbindd_request request;
291         struct winbindd_response response;
292
293         if (!require_membership_of) {
294                 return True;
295         }
296
297         if (require_membership_of_sid) {
298                 return True;
299         }
300
301         /* Otherwise, ask winbindd for the name->sid request */
302
303         ZERO_STRUCT(request);
304         ZERO_STRUCT(response);
305
306         if (!parse_ntlm_auth_domain_user(require_membership_of, 
307                                          request.data.name.dom_name, 
308                                          request.data.name.name)) {
309                 DEBUG(0, ("Could not parse %s into seperate domain/name parts!\n", 
310                           require_membership_of));
311                 return False;
312         }
313
314         if (winbindd_request_response(WINBINDD_LOOKUPNAME, &request, &response) !=
315             NSS_STATUS_SUCCESS) {
316                 DEBUG(0, ("Winbindd lookupname failed to resolve %s into a SID!\n", 
317                           require_membership_of));
318                 return False;
319         }
320
321         require_membership_of_sid = SMB_STRDUP(response.data.sid.sid);
322
323         if (require_membership_of_sid)
324                 return True;
325
326         return False;
327 }
328
329 /* 
330  * Get some configuration from pam_winbind.conf to see if we 
331  * need to contact trusted domain
332  */
333
334 int get_pam_winbind_config()
335 {
336         int ctrl = 0;
337         dictionary *d = NULL;
338
339         if (!opt_pam_winbind_conf || !*opt_pam_winbind_conf) {
340                 opt_pam_winbind_conf = PAM_WINBIND_CONFIG_FILE;
341         }
342
343         d = iniparser_load(discard_const_p(char, opt_pam_winbind_conf));
344
345         if (!d) {
346                 return 0;
347         }
348
349         if (iniparser_getboolean(d, discard_const_p(char, "global:krb5_auth"), false)) {
350                 ctrl |= WINBIND_KRB5_AUTH;
351         }
352
353         iniparser_freedict(d);
354
355         return ctrl;
356 }
357
358 /* Authenticate a user with a plaintext password */
359
360 static bool check_plaintext_auth(const char *user, const char *pass,
361                                  bool stdout_diagnostics)
362 {
363         struct winbindd_request request;
364         struct winbindd_response response;
365         NSS_STATUS result;
366
367         if (!get_require_membership_sid()) {
368                 return False;
369         }
370
371         /* Send off request */
372
373         ZERO_STRUCT(request);
374         ZERO_STRUCT(response);
375
376         fstrcpy(request.data.auth.user, user);
377         fstrcpy(request.data.auth.pass, pass);
378         if (require_membership_of_sid) {
379                 strlcpy(request.data.auth.require_membership_of_sid,
380                         require_membership_of_sid,
381                         sizeof(request.data.auth.require_membership_of_sid));
382         }
383
384         result = winbindd_request_response(WINBINDD_PAM_AUTH, &request, &response);
385
386         /* Display response */
387
388         if (stdout_diagnostics) {
389                 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
390                         d_printf("Reading winbind reply failed! (0x01)\n");
391                 }
392
393                 d_printf("%s: %s (0x%x)\n",
394                          response.data.auth.nt_status_string,
395                          response.data.auth.error_string,
396                          response.data.auth.nt_status);
397         } else {
398                 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
399                         DEBUG(1, ("Reading winbind reply failed! (0x01)\n"));
400                 }
401
402                 DEBUG(3, ("%s: %s (0x%x)\n",
403                           response.data.auth.nt_status_string,
404                           response.data.auth.error_string,
405                           response.data.auth.nt_status));
406         }
407
408         return (result == NSS_STATUS_SUCCESS);
409 }
410
411 /* authenticate a user with an encrypted username/password */
412
413 NTSTATUS contact_winbind_auth_crap(const char *username,
414                                    const char *domain,
415                                    const char *workstation,
416                                    const DATA_BLOB *challenge,
417                                    const DATA_BLOB *lm_response,
418                                    const DATA_BLOB *nt_response,
419                                    uint32 flags,
420                                    uint32 extra_logon_parameters,
421                                    uint8 lm_key[8],
422                                    uint8 user_session_key[16],
423                                    char **error_string,
424                                    char **unix_name)
425 {
426         NTSTATUS nt_status;
427         NSS_STATUS result;
428         struct winbindd_request request;
429         struct winbindd_response response;
430
431         if (!get_require_membership_sid()) {
432                 return NT_STATUS_INVALID_PARAMETER;
433         }
434
435         ZERO_STRUCT(request);
436         ZERO_STRUCT(response);
437
438         request.flags = flags;
439
440         request.data.auth_crap.logon_parameters = extra_logon_parameters
441                 | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT | MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT;
442
443         if (require_membership_of_sid)
444                 fstrcpy(request.data.auth_crap.require_membership_of_sid, require_membership_of_sid);
445
446         fstrcpy(request.data.auth_crap.user, username);
447         fstrcpy(request.data.auth_crap.domain, domain);
448
449         fstrcpy(request.data.auth_crap.workstation, 
450                 workstation);
451
452         memcpy(request.data.auth_crap.chal, challenge->data, MIN(challenge->length, 8));
453
454         if (lm_response && lm_response->length) {
455                 memcpy(request.data.auth_crap.lm_resp, 
456                        lm_response->data, 
457                        MIN(lm_response->length, sizeof(request.data.auth_crap.lm_resp)));
458                 request.data.auth_crap.lm_resp_len = lm_response->length;
459         }
460
461         if (nt_response && nt_response->length) {
462                 if (nt_response->length > sizeof(request.data.auth_crap.nt_resp)) {
463                         request.flags = request.flags | WBFLAG_BIG_NTLMV2_BLOB;
464                         request.extra_len = nt_response->length;
465                         request.extra_data.data = SMB_MALLOC_ARRAY(char, request.extra_len);
466                         if (request.extra_data.data == NULL) {
467                                 return NT_STATUS_NO_MEMORY;
468                         }
469                         memcpy(request.extra_data.data, nt_response->data,
470                                nt_response->length);
471
472                 } else {
473                         memcpy(request.data.auth_crap.nt_resp,
474                                nt_response->data, nt_response->length);
475                 }
476                 request.data.auth_crap.nt_resp_len = nt_response->length;
477         }
478
479         result = winbindd_request_response(WINBINDD_PAM_AUTH_CRAP, &request, &response);
480         SAFE_FREE(request.extra_data.data);
481
482         /* Display response */
483
484         if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
485                 nt_status = NT_STATUS_UNSUCCESSFUL;
486                 if (error_string)
487                         *error_string = smb_xstrdup("Reading winbind reply failed!");
488                 winbindd_free_response(&response);
489                 return nt_status;
490         }
491
492         nt_status = (NT_STATUS(response.data.auth.nt_status));
493         if (!NT_STATUS_IS_OK(nt_status)) {
494                 if (error_string) 
495                         *error_string = smb_xstrdup(response.data.auth.error_string);
496                 winbindd_free_response(&response);
497                 return nt_status;
498         }
499
500         if ((flags & WBFLAG_PAM_LMKEY) && lm_key) {
501                 memcpy(lm_key, response.data.auth.first_8_lm_hash, 
502                        sizeof(response.data.auth.first_8_lm_hash));
503         }
504         if ((flags & WBFLAG_PAM_USER_SESSION_KEY) && user_session_key) {
505                 memcpy(user_session_key, response.data.auth.user_session_key, 
506                         sizeof(response.data.auth.user_session_key));
507         }
508
509         if (flags & WBFLAG_PAM_UNIX_NAME) {
510                 *unix_name = SMB_STRDUP(response.data.auth.unix_username);
511                 if (!*unix_name) {
512                         winbindd_free_response(&response);
513                         return NT_STATUS_NO_MEMORY;
514                 }
515         }
516
517         winbindd_free_response(&response);
518         return nt_status;
519 }
520
521 /* contact server to change user password using auth crap */
522 static NTSTATUS contact_winbind_change_pswd_auth_crap(const char *username,
523                                                       const char *domain,
524                                                       const DATA_BLOB new_nt_pswd,
525                                                       const DATA_BLOB old_nt_hash_enc,
526                                                       const DATA_BLOB new_lm_pswd,
527                                                       const DATA_BLOB old_lm_hash_enc,
528                                                       char  **error_string)
529 {
530         NTSTATUS nt_status;
531         NSS_STATUS result;
532         struct winbindd_request request;
533         struct winbindd_response response;
534
535         if (!get_require_membership_sid())
536         {
537                 if(error_string)
538                         *error_string = smb_xstrdup("Can't get membership sid.");
539                 return NT_STATUS_INVALID_PARAMETER;
540         }
541
542         ZERO_STRUCT(request);
543         ZERO_STRUCT(response);
544
545         if(username != NULL)
546                 fstrcpy(request.data.chng_pswd_auth_crap.user, username);
547         if(domain != NULL)
548                 fstrcpy(request.data.chng_pswd_auth_crap.domain,domain);
549
550         if(new_nt_pswd.length)
551         {
552                 memcpy(request.data.chng_pswd_auth_crap.new_nt_pswd, new_nt_pswd.data, sizeof(request.data.chng_pswd_auth_crap.new_nt_pswd));
553                 request.data.chng_pswd_auth_crap.new_nt_pswd_len = new_nt_pswd.length;
554         }
555
556         if(old_nt_hash_enc.length)
557         {
558                 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));
559                 request.data.chng_pswd_auth_crap.old_nt_hash_enc_len = old_nt_hash_enc.length;
560         }
561
562         if(new_lm_pswd.length)
563         {
564                 memcpy(request.data.chng_pswd_auth_crap.new_lm_pswd, new_lm_pswd.data, sizeof(request.data.chng_pswd_auth_crap.new_lm_pswd));
565                 request.data.chng_pswd_auth_crap.new_lm_pswd_len = new_lm_pswd.length;
566         }
567
568         if(old_lm_hash_enc.length)
569         {
570                 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));
571                 request.data.chng_pswd_auth_crap.old_lm_hash_enc_len = old_lm_hash_enc.length;
572         }
573
574         result = winbindd_request_response(WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP, &request, &response);
575
576         /* Display response */
577
578         if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0))
579         {
580                 nt_status = NT_STATUS_UNSUCCESSFUL;
581                 if (error_string)
582                         *error_string = smb_xstrdup("Reading winbind reply failed!");
583                 winbindd_free_response(&response);
584                 return nt_status;
585         }
586
587         nt_status = (NT_STATUS(response.data.auth.nt_status));
588         if (!NT_STATUS_IS_OK(nt_status))
589         {
590                 if (error_string) 
591                         *error_string = smb_xstrdup(response.data.auth.error_string);
592                 winbindd_free_response(&response);
593                 return nt_status;
594         }
595
596         winbindd_free_response(&response);
597
598     return nt_status;
599 }
600
601 static NTSTATUS ntlm_auth_generate_session_info(struct auth4_context *auth_context,
602                                                 TALLOC_CTX *mem_ctx,
603                                                 void *server_returned_info,
604                                                 const char *original_user_name,
605                                                 uint32_t session_info_flags,
606                                                 struct auth_session_info **session_info_out)
607 {
608         char *unix_username = (char *)server_returned_info;
609         struct auth_session_info *session_info = talloc_zero(mem_ctx, struct auth_session_info);
610         if (!session_info) {
611                 return NT_STATUS_NO_MEMORY;
612         }
613
614         session_info->unix_info = talloc_zero(session_info, struct auth_user_info_unix);
615         if (!session_info->unix_info) {
616                 TALLOC_FREE(session_info);
617                 return NT_STATUS_NO_MEMORY;
618         }
619         session_info->unix_info->unix_name = talloc_steal(session_info->unix_info, unix_username);
620
621         *session_info_out = session_info;
622
623         return NT_STATUS_OK;
624 }
625
626 /**
627  * Return the challenge as determined by the authentication subsystem 
628  * @return an 8 byte random challenge
629  */
630
631 static NTSTATUS ntlm_auth_get_challenge(struct auth4_context *auth_ctx,
632                                         uint8_t chal[8])
633 {
634         if (auth_ctx->challenge.data.length == 8) {
635                 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n", 
636                           auth_ctx->challenge.set_by));
637                 memcpy(chal, auth_ctx->challenge.data.data, 8);
638                 return NT_STATUS_OK;
639         }
640
641         if (!auth_ctx->challenge.set_by) {
642                 generate_random_buffer(chal, 8);
643
644                 auth_ctx->challenge.data                = data_blob_talloc(auth_ctx, chal, 8);
645                 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
646                 auth_ctx->challenge.set_by              = "random";
647
648                 auth_ctx->challenge.may_be_modified     = true;
649         }
650
651         DEBUG(10,("auth_get_challenge: challenge set by %s\n",
652                  auth_ctx->challenge.set_by));
653
654         return NT_STATUS_OK;
655 }
656
657 /**
658  * Some authentication methods 'fix' the challenge, so we may not be able to set it
659  *
660  * @return If the effective challenge used by the auth subsystem may be modified
661  */
662 static bool ntlm_auth_may_set_challenge(struct auth4_context *auth_ctx)
663 {
664         return auth_ctx->challenge.may_be_modified;
665 }
666
667 /**
668  * NTLM2 authentication modifies the effective challenge, 
669  * @param challenge The new challenge value
670  */
671 static NTSTATUS ntlm_auth_set_challenge(struct auth4_context *auth_ctx, const uint8_t chal[8], const char *set_by) 
672 {
673         auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
674         NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
675
676         auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
677         NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
678
679         return NT_STATUS_OK;
680 }
681
682 /**
683  * Check the password on an NTLMSSP login.  
684  *
685  * Return the session keys used on the connection.
686  */
687
688 static NTSTATUS winbind_pw_check(struct auth4_context *auth4_context, 
689                                  TALLOC_CTX *mem_ctx,
690                                  const struct auth_usersupplied_info *user_info, 
691                                  void **server_returned_info,
692                                  DATA_BLOB *session_key, DATA_BLOB *lm_session_key)
693 {
694         static const char zeros[16] = { 0, };
695         NTSTATUS nt_status;
696         char *error_string = NULL;
697         uint8 lm_key[8]; 
698         uint8 user_sess_key[16]; 
699         char *unix_name = NULL;
700
701         nt_status = contact_winbind_auth_crap(user_info->client.account_name, user_info->client.domain_name, 
702                                               user_info->workstation_name, 
703                                               &auth4_context->challenge.data,
704                                               &user_info->password.response.lanman,
705                                               &user_info->password.response.nt,
706                                               WBFLAG_PAM_LMKEY | WBFLAG_PAM_USER_SESSION_KEY | WBFLAG_PAM_UNIX_NAME,
707                                               0,
708                                               lm_key, user_sess_key, 
709                                               &error_string, &unix_name);
710
711         if (NT_STATUS_IS_OK(nt_status)) {
712                 if (memcmp(lm_key, zeros, 8) != 0) {
713                         *lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
714                         memcpy(lm_session_key->data, lm_key, 8);
715                         memset(lm_session_key->data+8, '\0', 8);
716                 }
717
718                 if (memcmp(user_sess_key, zeros, 16) != 0) {
719                         *session_key = data_blob_talloc(mem_ctx, user_sess_key, 16);
720                 }
721                 *server_returned_info = talloc_strdup(mem_ctx,
722                                                       unix_name);
723         } else {
724                 DEBUG(NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED) ? 0 : 3, 
725                       ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n", 
726                        user_info->client.domain_name, user_info->client.account_name,
727                        user_info->workstation_name, 
728                        error_string ? error_string : "unknown error (NULL)"));
729         }
730
731         SAFE_FREE(error_string);
732         SAFE_FREE(unix_name);
733         return nt_status;
734 }
735
736 static NTSTATUS local_pw_check(struct auth4_context *auth4_context, 
737                                 TALLOC_CTX *mem_ctx,
738                                 const struct auth_usersupplied_info *user_info, 
739                                 void **server_returned_info,
740                                 DATA_BLOB *session_key, DATA_BLOB *lm_session_key)
741 {
742         NTSTATUS nt_status;
743         struct samr_Password lm_pw, nt_pw;
744
745         nt_lm_owf_gen (opt_password, nt_pw.hash, lm_pw.hash);
746
747         nt_status = ntlm_password_check(mem_ctx,
748                                         true, true, 0,
749                                         &auth4_context->challenge.data,
750                                         &user_info->password.response.lanman,
751                                         &user_info->password.response.nt,
752                                         user_info->client.account_name,
753                                         user_info->client.account_name,
754                                         user_info->client.domain_name, 
755                                         &lm_pw, &nt_pw, session_key, lm_session_key);
756
757         if (NT_STATUS_IS_OK(nt_status)) {
758                 *server_returned_info = talloc_asprintf(mem_ctx,
759                                                         "%s%c%s", user_info->client.domain_name,
760                                                         *lp_winbind_separator(), 
761                                                         user_info->client.account_name);
762         } else {
763                 DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n", 
764                           user_info->client.domain_name, user_info->client.account_name,
765                           user_info->workstation_name, 
766                           nt_errstr(nt_status)));
767         }
768         return nt_status;
769 }
770
771 static NTSTATUS ntlm_auth_start_ntlmssp_client(struct ntlmssp_state **client_ntlmssp_state)
772 {
773         NTSTATUS status;
774         if ( (opt_username == NULL) || (opt_domain == NULL) ) {
775                 status = NT_STATUS_UNSUCCESSFUL;
776                 DEBUG(1, ("Need username and domain for NTLMSSP\n"));
777                 return NT_STATUS_INVALID_PARAMETER;
778         }
779
780         status = ntlmssp_client_start(NULL,
781                                       lp_netbios_name(),
782                                       lp_workgroup(),
783                                       lp_client_ntlmv2_auth(),
784                                       client_ntlmssp_state);
785
786         if (!NT_STATUS_IS_OK(status)) {
787                 DEBUG(1, ("Could not start NTLMSSP client: %s\n",
788                           nt_errstr(status)));
789                 TALLOC_FREE(*client_ntlmssp_state);
790                 return status;
791         }
792
793         status = ntlmssp_set_username(*client_ntlmssp_state, opt_username);
794
795         if (!NT_STATUS_IS_OK(status)) {
796                 DEBUG(1, ("Could not set username: %s\n",
797                           nt_errstr(status)));
798                 TALLOC_FREE(*client_ntlmssp_state);
799                 return status;
800         }
801
802         status = ntlmssp_set_domain(*client_ntlmssp_state, opt_domain);
803
804         if (!NT_STATUS_IS_OK(status)) {
805                 DEBUG(1, ("Could not set domain: %s\n",
806                           nt_errstr(status)));
807                 TALLOC_FREE(*client_ntlmssp_state);
808                 return status;
809         }
810
811         if (opt_password) {
812                 status = ntlmssp_set_password(*client_ntlmssp_state, opt_password);
813
814                 if (!NT_STATUS_IS_OK(status)) {
815                         DEBUG(1, ("Could not set password: %s\n",
816                                   nt_errstr(status)));
817                         TALLOC_FREE(*client_ntlmssp_state);
818                         return status;
819                 }
820         }
821
822         return NT_STATUS_OK;
823 }
824
825 static struct auth4_context *make_auth4_context_ntlm_auth(TALLOC_CTX *mem_ctx, bool local_pw)
826 {
827         struct auth4_context *auth4_context = talloc_zero(mem_ctx, struct auth4_context);
828         if (auth4_context == NULL) {
829                 DEBUG(10, ("failed to allocate auth4_context failed\n"));
830                 return NULL;
831         }
832         auth4_context->generate_session_info = ntlm_auth_generate_session_info;
833         auth4_context->get_ntlm_challenge = ntlm_auth_get_challenge;
834         auth4_context->set_ntlm_challenge = ntlm_auth_set_challenge;
835         auth4_context->challenge_may_be_modified = ntlm_auth_may_set_challenge;
836         if (local_pw) {
837                 auth4_context->check_ntlm_password = local_pw_check;
838         } else {
839                 auth4_context->check_ntlm_password = winbind_pw_check;
840         }
841         auth4_context->private_data = NULL;
842         return auth4_context;
843 }
844
845 static NTSTATUS ntlm_auth_start_ntlmssp_server(TALLOC_CTX *mem_ctx,
846                                                struct gensec_security **gensec_security_out)
847 {
848         struct gensec_security *gensec_security;
849         NTSTATUS nt_status;
850
851         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
852         NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
853
854         struct gensec_settings *gensec_settings;
855         struct loadparm_context *lp_ctx;
856         size_t idx = 0;
857         struct cli_credentials *server_credentials;
858         
859         struct auth4_context *auth4_context = make_auth4_context_ntlm_auth(tmp_ctx, opt_password);
860         if (auth4_context == NULL) {
861                 TALLOC_FREE(tmp_ctx);
862                 return NT_STATUS_NO_MEMORY;
863         }
864         
865         lp_ctx = loadparm_init_s3(tmp_ctx, loadparm_s3_context());
866         if (lp_ctx == NULL) {
867                 DEBUG(10, ("loadparm_init_s3 failed\n"));
868                 TALLOC_FREE(tmp_ctx);
869                 return NT_STATUS_INVALID_SERVER_STATE;
870         }
871         
872         gensec_settings = lpcfg_gensec_settings(tmp_ctx, lp_ctx);
873         if (lp_ctx == NULL) {
874                 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
875                 TALLOC_FREE(tmp_ctx);
876                 return NT_STATUS_NO_MEMORY;
877         }
878         
879         /* 
880          * This should be a 'netbios domain -> DNS domain'
881          * mapping, and can currently validly return NULL on
882          * poorly configured systems.
883          *
884          * This is used for the NTLMSSP server
885          *
886          */
887         if (opt_password) {
888                 gensec_settings->server_netbios_name = lp_netbios_name();
889                 gensec_settings->server_netbios_domain = lp_workgroup();
890         } else {
891                 gensec_settings->server_netbios_name = get_winbind_netbios_name();
892                 gensec_settings->server_netbios_domain = get_winbind_domain();
893         }
894         
895         gensec_settings->server_dns_domain = strlower_talloc(gensec_settings,
896                                                              get_mydnsdomname(talloc_tos()));
897         gensec_settings->server_dns_name = strlower_talloc(gensec_settings,
898                                                            get_mydnsfullname());
899         
900         gensec_settings->backends = talloc_zero_array(gensec_settings,
901                                                       struct gensec_security_ops *, 4);
902         
903         if (gensec_settings->backends == NULL) {
904                 TALLOC_FREE(tmp_ctx);
905                 return NT_STATUS_NO_MEMORY;
906         }
907         
908         gensec_init();
909         
910         gensec_settings->backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_NTLMSSP);
911         
912 #if defined(HAVE_KRB5) && defined(HAVE_GSS_WRAP_IOV)
913         gensec_settings->backends[idx++] = &gensec_gse_krb5_security_ops;
914 #endif
915         
916         gensec_settings->backends[idx++] = gensec_security_by_oid(NULL,
917                                                                   GENSEC_OID_SPNEGO);
918         
919         /*
920          * This is anonymous for now, because we just use it
921          * to set the kerberos state at the moment
922          */
923         server_credentials = cli_credentials_init_anon(tmp_ctx);
924         if (!server_credentials) {
925                 DEBUG(0, ("auth_generic_prepare: Failed to init server credentials\n"));
926                 return NT_STATUS_NO_MEMORY;
927         }
928         
929         cli_credentials_set_conf(server_credentials, lp_ctx);
930         
931         if (lp_security() == SEC_ADS || USE_KERBEROS_KEYTAB) {
932                 cli_credentials_set_kerberos_state(server_credentials, CRED_AUTO_USE_KERBEROS);
933         } else {
934                 cli_credentials_set_kerberos_state(server_credentials, CRED_DONT_USE_KERBEROS);
935         }
936         
937         nt_status = gensec_server_start(tmp_ctx, gensec_settings,
938                                         auth4_context, &gensec_security);
939         
940         if (!NT_STATUS_IS_OK(nt_status)) {
941                 TALLOC_FREE(tmp_ctx);
942                 return nt_status;
943         }
944         
945         gensec_set_credentials(gensec_security, server_credentials);
946         
947         gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
948         gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
949
950         talloc_unlink(tmp_ctx, lp_ctx);
951         talloc_unlink(tmp_ctx, server_credentials);
952         talloc_unlink(tmp_ctx, gensec_settings);
953         talloc_unlink(tmp_ctx, auth4_context);
954
955         nt_status = gensec_start_mech_by_oid(gensec_security, GENSEC_OID_NTLMSSP);
956         if (!NT_STATUS_IS_OK(nt_status)) {
957                 TALLOC_FREE(tmp_ctx);
958                 return nt_status;
959         }
960         
961         *gensec_security_out = talloc_steal(mem_ctx, gensec_security);
962         TALLOC_FREE(tmp_ctx);
963         return NT_STATUS_OK;
964 }
965
966 /*******************************************************************
967  Used by firefox to drive NTLM auth to IIS servers.
968 *******************************************************************/
969
970 static NTSTATUS do_ccache_ntlm_auth(DATA_BLOB initial_msg, DATA_BLOB challenge_msg,
971                                 DATA_BLOB *reply)
972 {
973         struct winbindd_request wb_request;
974         struct winbindd_response wb_response;
975         int ctrl = 0;
976         NSS_STATUS result;
977
978         /* get winbindd to do the ntlmssp step on our behalf */
979         ZERO_STRUCT(wb_request);
980         ZERO_STRUCT(wb_response);
981
982         /*
983          * This is tricky here. If we set krb5_auth in pam_winbind.conf
984          * creds for users in trusted domain will be stored the winbindd
985          * child of the trusted domain. If we ask the primary domain for
986          * ntlm_ccache_auth, it will fail. So, we have to ask the trusted
987          * domain's child for ccache_ntlm_auth. that is to say, we have to 
988          * set WBFLAG_PAM_CONTACT_TRUSTDOM in request.flags.
989          */
990         ctrl = get_pam_winbind_config();
991
992         if (ctrl & WINBIND_KRB5_AUTH) {
993                 wb_request.flags |= WBFLAG_PAM_CONTACT_TRUSTDOM;
994         }
995
996         fstr_sprintf(wb_request.data.ccache_ntlm_auth.user,
997                 "%s%c%s", opt_domain, winbind_separator(), opt_username);
998         wb_request.data.ccache_ntlm_auth.uid = geteuid();
999         wb_request.data.ccache_ntlm_auth.initial_blob_len = initial_msg.length;
1000         wb_request.data.ccache_ntlm_auth.challenge_blob_len = challenge_msg.length;
1001         wb_request.extra_len = initial_msg.length + challenge_msg.length;
1002
1003         if (wb_request.extra_len > 0) {
1004                 wb_request.extra_data.data = SMB_MALLOC_ARRAY(char, wb_request.extra_len);
1005                 if (wb_request.extra_data.data == NULL) {
1006                         return NT_STATUS_NO_MEMORY;
1007                 }
1008
1009                 memcpy(wb_request.extra_data.data, initial_msg.data, initial_msg.length);
1010                 memcpy(wb_request.extra_data.data + initial_msg.length,
1011                         challenge_msg.data, challenge_msg.length);
1012         }
1013
1014         result = winbindd_request_response(WINBINDD_CCACHE_NTLMAUTH, &wb_request, &wb_response);
1015         SAFE_FREE(wb_request.extra_data.data);
1016
1017         if (result != NSS_STATUS_SUCCESS) {
1018                 winbindd_free_response(&wb_response);
1019                 return NT_STATUS_UNSUCCESSFUL;
1020         }
1021
1022         if (reply) {
1023                 *reply = data_blob(wb_response.extra_data.data,
1024                                 wb_response.data.ccache_ntlm_auth.auth_blob_len);
1025                 if (wb_response.data.ccache_ntlm_auth.auth_blob_len > 0 &&
1026                                 reply->data == NULL) {
1027                         winbindd_free_response(&wb_response);
1028                         return NT_STATUS_NO_MEMORY;
1029                 }
1030         }
1031
1032         winbindd_free_response(&wb_response);
1033         return NT_STATUS_MORE_PROCESSING_REQUIRED;
1034 }
1035
1036 static void manage_squid_ntlmssp_request_int(struct ntlm_auth_state *state,
1037                                              char *buf, int length,
1038                                              TALLOC_CTX *mem_ctx,
1039                                              char **response)
1040 {
1041         DATA_BLOB request, reply;
1042         NTSTATUS nt_status;
1043
1044         if (strlen(buf) < 2) {
1045                 DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf));
1046                 *response = talloc_strdup(mem_ctx, "BH NTLMSSP query invalid");
1047                 return;
1048         }
1049
1050         if (strlen(buf) > 3) {
1051                 if(strncmp(buf, "SF ", 3) == 0){
1052                         DEBUG(10, ("Setting flags to negotioate\n"));
1053                         TALLOC_FREE(state->want_feature_list);
1054                         state->want_feature_list = talloc_strdup(state->mem_ctx,
1055                                         buf+3);
1056                         *response = talloc_strdup(mem_ctx, "OK");
1057                         return;
1058                 }
1059                 request = base64_decode_data_blob(buf + 3);
1060         } else {
1061                 request = data_blob_null;
1062         }
1063
1064         if ((strncmp(buf, "PW ", 3) == 0)) {
1065                 /* The calling application wants us to use a local password
1066                  * (rather than winbindd) */
1067
1068                 opt_password = SMB_STRNDUP((const char *)request.data,
1069                                 request.length);
1070
1071                 if (opt_password == NULL) {
1072                         DEBUG(1, ("Out of memory\n"));
1073                         *response = talloc_strdup(mem_ctx, "BH Out of memory");
1074                         data_blob_free(&request);
1075                         return;
1076                 }
1077
1078                 *response = talloc_strdup(mem_ctx, "OK");
1079                 data_blob_free(&request);
1080                 return;
1081         }
1082
1083         if (strncmp(buf, "YR", 2) == 0) {
1084                 TALLOC_FREE(state->gensec_security);
1085                 state->svr_state = SERVER_INITIAL;
1086         } else if (strncmp(buf, "KK", 2) == 0) {
1087                 /* No special preprocessing required */
1088         } else if (strncmp(buf, "GF", 2) == 0) {
1089                 DEBUG(10, ("Requested negotiated NTLMSSP flags\n"));
1090
1091                 if (state->svr_state == SERVER_FINISHED) {
1092                         *response = talloc_asprintf(mem_ctx, "GF 0x%08x",
1093                                                     gensec_ntlmssp_neg_flags(state->gensec_security));
1094                 }
1095                 else {
1096                         *response = talloc_strdup(mem_ctx, "BH\n");
1097                 }
1098                 data_blob_free(&request);
1099                 return;
1100         } else if (strncmp(buf, "GK", 2) == 0) {
1101                 DEBUG(10, ("Requested NTLMSSP session key\n"));
1102                 if(state->have_session_key) {
1103                         DATA_BLOB session_key;
1104                         char *key64;
1105                         nt_status = gensec_session_key(state->gensec_security, talloc_tos(), &session_key);
1106                         if (!NT_STATUS_IS_OK(nt_status)) {
1107                                 *response = talloc_asprintf(
1108                                         mem_ctx, "BH %s", nt_errstr(nt_status));
1109                                 return;
1110                         }
1111                         key64 = base64_encode_data_blob(state->mem_ctx, session_key);
1112                         data_blob_free(&session_key);
1113                         *response = talloc_asprintf(mem_ctx, "GK %s",
1114                                                  key64 ? key64 : "<NULL>");
1115                         TALLOC_FREE(key64);
1116                 } else {
1117                         *response = talloc_strdup(mem_ctx, "BH");
1118                 }
1119
1120                 data_blob_free(&request);
1121                 return;
1122         } else {
1123                 DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf));
1124                 *response = talloc_strdup(mem_ctx, "BH NTLMSSP query invalid");
1125                 return;
1126         }
1127
1128         if (!state->gensec_security) {
1129                 nt_status = ntlm_auth_start_ntlmssp_server(state, 
1130                                 &state->gensec_security);
1131                 if (!NT_STATUS_IS_OK(nt_status)) {
1132                         *response = talloc_asprintf(
1133                                 mem_ctx, "BH %s", nt_errstr(nt_status));
1134                         return;
1135                 }
1136                 gensec_want_feature_list(state->gensec_security,
1137                                          state->want_feature_list);
1138         }
1139
1140         DEBUG(10, ("got NTLMSSP packet:\n"));
1141         dump_data(10, request.data, request.length);
1142
1143         nt_status = gensec_update(state->gensec_security, talloc_tos(), NULL, request, &reply);
1144
1145         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1146                 char *reply_base64 = base64_encode_data_blob(state->mem_ctx,
1147                                 reply);
1148                 *response = talloc_asprintf(mem_ctx, "TT %s", reply_base64);
1149                 TALLOC_FREE(reply_base64);
1150                 data_blob_free(&reply);
1151                 state->svr_state = SERVER_CHALLENGE;
1152                 DEBUG(10, ("NTLMSSP challenge\n"));
1153         } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) {
1154                 *response = talloc_asprintf(mem_ctx, "BH %s",
1155                                          nt_errstr(nt_status));
1156                 DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status)));
1157
1158                 TALLOC_FREE(state->gensec_security);
1159         } else if (!NT_STATUS_IS_OK(nt_status)) {
1160                 *response = talloc_asprintf(mem_ctx, "NA %s",
1161                                          nt_errstr(nt_status));
1162                 DEBUG(10, ("NTLMSSP %s\n", nt_errstr(nt_status)));
1163         } else {
1164                 struct auth_session_info *session_info;
1165                 nt_status = gensec_session_info(state->gensec_security, state->gensec_security, &session_info);
1166                 if (!NT_STATUS_IS_OK(nt_status)) {
1167                         DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status)));
1168                         TALLOC_FREE(state->gensec_security);
1169                         return;
1170                 }
1171                 *response = talloc_asprintf(
1172                         mem_ctx, "AF %s",
1173                         session_info->unix_info->unix_name);
1174                 DEBUG(10, ("NTLMSSP OK!\n"));
1175
1176                 state->have_session_key = true;
1177                 state->svr_state = SERVER_FINISHED;
1178         }
1179
1180         data_blob_free(&request);
1181 }
1182
1183 static void manage_squid_ntlmssp_request(struct ntlm_auth_state *state,
1184                                          char *buf, int length)
1185 {
1186         char *response;
1187
1188         manage_squid_ntlmssp_request_int(state, buf, length,
1189                                          talloc_tos(), &response);
1190
1191         if (response == NULL) {
1192                 x_fprintf(x_stdout, "BH Out of memory\n");
1193                 return;
1194         }
1195         x_fprintf(x_stdout, "%s\n", response);
1196         TALLOC_FREE(response);
1197 }
1198
1199 static void manage_client_ntlmssp_request(struct ntlm_auth_state *state,
1200                                                 char *buf, int length)
1201 {
1202         DATA_BLOB request, reply;
1203         NTSTATUS nt_status;
1204
1205         if (!opt_username || !*opt_username) {
1206                 x_fprintf(x_stderr, "username must be specified!\n\n");
1207                 exit(1);
1208         }
1209
1210         if (strlen(buf) < 2) {
1211                 DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf));
1212                 x_fprintf(x_stdout, "BH NTLMSSP query invalid\n");
1213                 return;
1214         }
1215
1216         if (strlen(buf) > 3) {
1217                 if(strncmp(buf, "SF ", 3) == 0) {
1218                         DEBUG(10, ("Looking for flags to negotiate\n"));
1219                         talloc_free(state->want_feature_list);
1220                         state->want_feature_list = talloc_strdup(state->mem_ctx,
1221                                         buf+3);
1222                         x_fprintf(x_stdout, "OK\n");
1223                         return;
1224                 }
1225                 request = base64_decode_data_blob(buf + 3);
1226         } else {
1227                 request = data_blob_null;
1228         }
1229
1230         if (strncmp(buf, "PW ", 3) == 0) {
1231                 /* We asked for a password and obviously got it :-) */
1232
1233                 opt_password = SMB_STRNDUP((const char *)request.data,
1234                                 request.length);
1235
1236                 if (opt_password == NULL) {
1237                         DEBUG(1, ("Out of memory\n"));
1238                         x_fprintf(x_stdout, "BH Out of memory\n");
1239                         data_blob_free(&request);
1240                         return;
1241                 }
1242
1243                 x_fprintf(x_stdout, "OK\n");
1244                 data_blob_free(&request);
1245                 return;
1246         }
1247
1248         if (!state->ntlmssp_state && use_cached_creds) {
1249                 /* check whether cached credentials are usable. */
1250                 DATA_BLOB empty_blob = data_blob_null;
1251
1252                 nt_status = do_ccache_ntlm_auth(empty_blob, empty_blob, NULL);
1253                 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1254                         /* failed to use cached creds */
1255                         use_cached_creds = False;
1256                 }
1257         }
1258
1259         if (opt_password == NULL && !use_cached_creds) {
1260                 /* Request a password from the calling process.  After
1261                    sending it, the calling process should retry asking for the
1262                    negotiate. */
1263
1264                 DEBUG(10, ("Requesting password\n"));
1265                 x_fprintf(x_stdout, "PW\n");
1266                 return;
1267         }
1268
1269         if (strncmp(buf, "YR", 2) == 0) {
1270                 TALLOC_FREE(state->ntlmssp_state);
1271                 state->cli_state = CLIENT_INITIAL;
1272         } else if (strncmp(buf, "TT", 2) == 0) {
1273                 /* No special preprocessing required */
1274         } else if (strncmp(buf, "GF", 2) == 0) {
1275                 DEBUG(10, ("Requested negotiated NTLMSSP flags\n"));
1276
1277                 if(state->cli_state == CLIENT_FINISHED) {
1278                         x_fprintf(x_stdout, "GF 0x%08x\n", state->neg_flags);
1279                 }
1280                 else {
1281                         x_fprintf(x_stdout, "BH\n");
1282                 }
1283
1284                 data_blob_free(&request);
1285                 return;
1286         } else if (strncmp(buf, "GK", 2) == 0 ) {
1287                 DEBUG(10, ("Requested session key\n"));
1288
1289                 if(state->cli_state == CLIENT_FINISHED) {
1290                         char *key64 = base64_encode_data_blob(state->mem_ctx,
1291                                         state->session_key);
1292                         x_fprintf(x_stdout, "GK %s\n", key64?key64:"<NULL>");
1293                         TALLOC_FREE(key64);
1294                 }
1295                 else {
1296                         x_fprintf(x_stdout, "BH\n");
1297                 }
1298
1299                 data_blob_free(&request);
1300                 return;
1301         } else {
1302                 DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf));
1303                 x_fprintf(x_stdout, "BH NTLMSSP query invalid\n");
1304                 return;
1305         }
1306
1307         if (!state->ntlmssp_state) {
1308                 nt_status = ntlm_auth_start_ntlmssp_client(
1309                                 &state->ntlmssp_state);
1310                 if (!NT_STATUS_IS_OK(nt_status)) {
1311                         x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
1312                         return;
1313                 }
1314                 ntlmssp_want_feature_list(state->ntlmssp_state,
1315                                 state->want_feature_list);
1316                 state->initial_message = data_blob_null;
1317         }
1318
1319         DEBUG(10, ("got NTLMSSP packet:\n"));
1320         dump_data(10, request.data, request.length);
1321
1322         if (use_cached_creds && !opt_password &&
1323                         (state->cli_state == CLIENT_RESPONSE)) {
1324                 nt_status = do_ccache_ntlm_auth(state->initial_message, request,
1325                                 &reply);
1326         } else {
1327                 nt_status = ntlmssp_update(state->ntlmssp_state, request,
1328                                 &reply);
1329         }
1330
1331         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1332                 char *reply_base64 = base64_encode_data_blob(state->mem_ctx,
1333                                 reply);
1334                 if (state->cli_state == CLIENT_INITIAL) {
1335                         x_fprintf(x_stdout, "YR %s\n", reply_base64);
1336                         state->initial_message = reply;
1337                         state->cli_state = CLIENT_RESPONSE;
1338                 } else {
1339                         x_fprintf(x_stdout, "KK %s\n", reply_base64);
1340                         data_blob_free(&reply);
1341                 }
1342                 TALLOC_FREE(reply_base64);
1343                 DEBUG(10, ("NTLMSSP challenge\n"));
1344         } else if (NT_STATUS_IS_OK(nt_status)) {
1345                 char *reply_base64 = base64_encode_data_blob(talloc_tos(),
1346                                 reply);
1347                 x_fprintf(x_stdout, "AF %s\n", reply_base64);
1348                 TALLOC_FREE(reply_base64);
1349
1350                 if(state->have_session_key)
1351                         data_blob_free(&state->session_key);
1352
1353                 state->session_key = data_blob(
1354                                 state->ntlmssp_state->session_key.data,
1355                                 state->ntlmssp_state->session_key.length);
1356                 state->neg_flags = state->ntlmssp_state->neg_flags;
1357                 state->have_session_key = true;
1358
1359                 DEBUG(10, ("NTLMSSP OK!\n"));
1360                 state->cli_state = CLIENT_FINISHED;
1361                 TALLOC_FREE(state->ntlmssp_state);
1362         } else {
1363                 x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
1364                 DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status)));
1365                 state->cli_state = CLIENT_ERROR;
1366                 TALLOC_FREE(state->ntlmssp_state);
1367         }
1368
1369         data_blob_free(&request);
1370 }
1371
1372 static void manage_squid_basic_request(struct ntlm_auth_state *state,
1373                                         char *buf, int length)
1374 {
1375         char *user, *pass;      
1376         user=buf;
1377
1378         pass=(char *)memchr(buf,' ',length);
1379         if (!pass) {
1380                 DEBUG(2, ("Password not found. Denying access\n"));
1381                 x_fprintf(x_stdout, "ERR\n");
1382                 return;
1383         }
1384         *pass='\0';
1385         pass++;
1386
1387         if (state->helper_mode == SQUID_2_5_BASIC) {
1388                 rfc1738_unescape(user);
1389                 rfc1738_unescape(pass);
1390         }
1391
1392         if (check_plaintext_auth(user, pass, False)) {
1393                 x_fprintf(x_stdout, "OK\n");
1394         } else {
1395                 x_fprintf(x_stdout, "ERR\n");
1396         }
1397 }
1398
1399 static void offer_gss_spnego_mechs(void) {
1400
1401         DATA_BLOB token;
1402         struct spnego_data spnego;
1403         ssize_t len;
1404         char *reply_base64;
1405         TALLOC_CTX *ctx = talloc_tos();
1406         char *principal;
1407         char *myname_lower;
1408
1409         ZERO_STRUCT(spnego);
1410
1411         myname_lower = talloc_strdup(ctx, lp_netbios_name());
1412         if (!myname_lower) {
1413                 return;
1414         }
1415         strlower_m(myname_lower);
1416
1417         principal = talloc_asprintf(ctx, "%s$@%s", myname_lower, lp_realm());
1418         if (!principal) {
1419                 return;
1420         }
1421
1422         /* Server negTokenInit (mech offerings) */
1423         spnego.type = SPNEGO_NEG_TOKEN_INIT;
1424         spnego.negTokenInit.mechTypes = talloc_array(ctx, const char *, 4);
1425 #ifdef HAVE_KRB5
1426         spnego.negTokenInit.mechTypes[0] = talloc_strdup(ctx, OID_KERBEROS5_OLD);
1427         spnego.negTokenInit.mechTypes[1] = talloc_strdup(ctx, OID_KERBEROS5);
1428         spnego.negTokenInit.mechTypes[2] = talloc_strdup(ctx, OID_NTLMSSP);
1429         spnego.negTokenInit.mechTypes[3] = NULL;
1430 #else
1431         spnego.negTokenInit.mechTypes[0] = talloc_strdup(ctx, OID_NTLMSSP);
1432         spnego.negTokenInit.mechTypes[1] = NULL;
1433 #endif
1434
1435
1436         spnego.negTokenInit.mechListMIC = data_blob_talloc(ctx, principal,
1437                                                     strlen(principal));
1438
1439         len = spnego_write_data(ctx, &token, &spnego);
1440         spnego_free_data(&spnego);
1441
1442         if (len == -1) {
1443                 DEBUG(1, ("Could not write SPNEGO data blob\n"));
1444                 x_fprintf(x_stdout, "BH Could not write SPNEGO data blob\n");
1445                 return;
1446         }
1447
1448         reply_base64 = base64_encode_data_blob(talloc_tos(), token);
1449         x_fprintf(x_stdout, "TT %s *\n", reply_base64);
1450
1451         TALLOC_FREE(reply_base64);
1452         data_blob_free(&token);
1453         DEBUG(10, ("sent SPNEGO negTokenInit\n"));
1454         return;
1455 }
1456
1457 static void manage_gss_spnego_request(struct ntlm_auth_state *state,
1458                                         char *buf, int length)
1459 {
1460         struct spnego_data request, response;
1461         DATA_BLOB token;
1462         DATA_BLOB raw_in_token = data_blob_null;
1463         DATA_BLOB raw_out_token = data_blob_null;
1464         NTSTATUS status;
1465         ssize_t len;
1466         TALLOC_CTX *ctx = talloc_tos();
1467
1468         const char *unix_username = NULL;
1469
1470         const char *reply_code;
1471         char       *reply_base64;
1472         char *reply_argument = NULL;
1473         char *supportedMech = NULL;
1474
1475         if (strlen(buf) < 2) {
1476                 DEBUG(1, ("SPENGO query [%s] invalid\n", buf));
1477                 x_fprintf(x_stdout, "BH SPENGO query invalid\n");
1478                 return;
1479         }
1480
1481         if (strncmp(buf, "YR", 2) == 0) {
1482                 TALLOC_FREE(state->gensec_security);
1483                 TALLOC_FREE(state->spnego_mech);
1484                 TALLOC_FREE(state->spnego_mech_oid);
1485         } else if (strncmp(buf, "KK", 2) == 0) {
1486                 ;
1487         } else {
1488                 DEBUG(1, ("SPENGO query [%s] invalid\n", buf));
1489                 x_fprintf(x_stdout, "BH SPENGO query invalid\n");
1490                 return;
1491         }
1492
1493         if ( (strlen(buf) == 2)) {
1494
1495                 /* no client data, get the negTokenInit offering
1496                    mechanisms */
1497
1498                 offer_gss_spnego_mechs();
1499                 return;
1500         }
1501
1502         /* All subsequent requests have a blob. This might be negTokenInit or negTokenTarg */
1503
1504         if (strlen(buf) <= 3) {
1505                 DEBUG(1, ("GSS-SPNEGO query [%s] invalid\n", buf));
1506                 x_fprintf(x_stdout, "BH GSS-SPNEGO query invalid\n");
1507                 return;
1508         }
1509
1510         token = base64_decode_data_blob(buf + 3);
1511
1512         if ((token.length >= 7)
1513             && (strncmp((char *)token.data, "NTLMSSP", 7) == 0)) {
1514                 char *reply;
1515
1516                 data_blob_free(&token);
1517
1518                 DEBUG(10, ("Could not parse GSS-SPNEGO, trying raw "
1519                            "ntlmssp\n"));
1520
1521                 manage_squid_ntlmssp_request_int(state, buf, length,
1522                                                  talloc_tos(), &reply);
1523                 if (reply == NULL) {
1524                         x_fprintf(x_stdout, "BH Out of memory\n");
1525                         return;
1526                 }
1527
1528                 if (strncmp(reply, "AF ", 3) == 0) {
1529                         x_fprintf(x_stdout, "AF * %s\n", reply+3);
1530                 } else {
1531                         x_fprintf(x_stdout, "%s *\n", reply);
1532                 }
1533
1534                 TALLOC_FREE(reply);
1535                 return;
1536         }
1537
1538         ZERO_STRUCT(request);
1539         len = spnego_read_data(ctx, token, &request);
1540         data_blob_free(&token);
1541
1542         if (len == -1) {
1543                 DEBUG(1, ("GSS-SPNEGO query [%s] invalid\n", buf));
1544                 x_fprintf(x_stdout, "BH GSS-SPNEGO query invalid\n");
1545                 return;
1546         }
1547
1548         if (request.type == SPNEGO_NEG_TOKEN_INIT) {
1549 #ifdef HAVE_KRB5
1550                 int krb5_idx = -1;
1551 #endif
1552                 int ntlm_idx = -1;
1553                 int used_idx = -1;
1554                 int i;
1555
1556                 if (state->spnego_mech) {
1557                         DEBUG(1, ("Client restarted SPNEGO with NegTokenInit "
1558                                   "while mech[%s] was already negotiated\n",
1559                                   state->spnego_mech));
1560                         x_fprintf(x_stdout, "BH Client send NegTokenInit twice\n");
1561                         return;
1562                 }
1563
1564                 /* Second request from Client. This is where the
1565                    client offers its mechanism to use. */
1566
1567                 if ( (request.negTokenInit.mechTypes == NULL) ||
1568                      (request.negTokenInit.mechTypes[0] == NULL) ) {
1569                         DEBUG(1, ("Client did not offer any mechanism\n"));
1570                         x_fprintf(x_stdout, "BH Client did not offer any "
1571                                             "mechanism\n");
1572                         return;
1573                 }
1574
1575                 status = NT_STATUS_UNSUCCESSFUL;
1576                 for (i = 0; request.negTokenInit.mechTypes[i] != NULL; i++) {
1577                         DEBUG(10,("got mech[%d][%s]\n",
1578                                 i, request.negTokenInit.mechTypes[i]));
1579 #ifdef HAVE_KRB5
1580                         if (strcmp(request.negTokenInit.mechTypes[i], OID_KERBEROS5_OLD) == 0) {
1581                                 krb5_idx = i;
1582                                 break;
1583                         }
1584                         if (strcmp(request.negTokenInit.mechTypes[i], OID_KERBEROS5) == 0) {
1585                                 krb5_idx = i;
1586                                 break;
1587                         }
1588 #endif
1589                         if (strcmp(request.negTokenInit.mechTypes[i], OID_NTLMSSP) == 0) {
1590                                 ntlm_idx = i;
1591                                 break;
1592                         }
1593                 }
1594
1595                 used_idx = ntlm_idx;
1596 #ifdef HAVE_KRB5
1597                 if (krb5_idx != -1) {
1598                         ntlm_idx = -1;
1599                         used_idx = krb5_idx;
1600                 }
1601 #endif
1602                 if (ntlm_idx > -1) {
1603                         state->spnego_mech = talloc_strdup(state, "ntlmssp");
1604                         if (state->spnego_mech == NULL) {
1605                                 x_fprintf(x_stdout, "BH Out of memory\n");
1606                                 return;
1607                         }
1608
1609                         if (state->gensec_security) {
1610                                 DEBUG(1, ("Client wants a new NTLMSSP challenge, but "
1611                                           "already got one\n"));
1612                                 x_fprintf(x_stdout, "BH Client wants a new "
1613                                                     "NTLMSSP challenge, but "
1614                                                     "already got one\n");
1615                                 TALLOC_FREE(state->gensec_security);
1616                                 return;
1617                         }
1618
1619                         status = ntlm_auth_start_ntlmssp_server(state, &state->gensec_security);
1620                         if (!NT_STATUS_IS_OK(status)) {
1621                                 x_fprintf(x_stdout, "BH %s\n", nt_errstr(status));
1622                                 return;
1623                         }
1624                 }
1625
1626 #ifdef HAVE_KRB5
1627                 if (krb5_idx > -1) {
1628                         state->spnego_mech = talloc_strdup(state, "krb5");
1629                         if (state->spnego_mech == NULL) {
1630                                 x_fprintf(x_stdout, "BH Out of memory\n");
1631                                 return;
1632                         }
1633                 }
1634 #endif
1635                 if (used_idx > -1) {
1636                         state->spnego_mech_oid = talloc_strdup(state,
1637                                 request.negTokenInit.mechTypes[used_idx]);
1638                         if (state->spnego_mech_oid == NULL) {
1639                                 x_fprintf(x_stdout, "BH Out of memory\n");
1640                                 return;
1641                         }
1642                         supportedMech = talloc_strdup(ctx, state->spnego_mech_oid);
1643                         if (supportedMech == NULL) {
1644                                 x_fprintf(x_stdout, "BH Out of memory\n");
1645                                 return;
1646                         }
1647
1648                         status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1649                 } else {
1650                         status = NT_STATUS_NOT_SUPPORTED;
1651                 }
1652                 if (used_idx == 0) {
1653                         status = NT_STATUS_OK;
1654                         raw_in_token = request.negTokenInit.mechToken;
1655                 }
1656         } else {
1657                 if (state->spnego_mech == NULL) {
1658                         DEBUG(1,("Got netTokenTarg without negTokenInit\n"));
1659                         x_fprintf(x_stdout, "BH Got a negTokenTarg without "
1660                                             "negTokenInit\n");
1661                         return;
1662                 }
1663
1664                 if ((request.negTokenTarg.supportedMech != NULL) &&
1665                      (strcmp(request.negTokenTarg.supportedMech, state->spnego_mech_oid) != 0 ) ) {
1666                         DEBUG(1, ("Got a negTokenTarg with mech[%s] while [%s] was already negotiated\n",
1667                                   request.negTokenTarg.supportedMech,
1668                                   state->spnego_mech_oid));
1669                         x_fprintf(x_stdout, "BH Got a negTokenTarg with speficied mech\n");
1670                         return;
1671                 }
1672
1673                 status = NT_STATUS_OK;
1674                 raw_in_token = request.negTokenTarg.responseToken;
1675         }
1676
1677         if (!NT_STATUS_IS_OK(status)) {
1678                 /* error or more processing */
1679         } else if (strcmp(state->spnego_mech, "ntlmssp") == 0) {
1680
1681                 DEBUG(10, ("got NTLMSSP packet:\n"));
1682                 dump_data(10, raw_in_token.data, raw_in_token.length);
1683
1684                 status = gensec_update(state->gensec_security,
1685                                        talloc_tos(), NULL,
1686                                        raw_in_token,
1687                                        &raw_out_token);
1688                 if (NT_STATUS_IS_OK(status)) {
1689                         struct auth_session_info *session_info;
1690                         status = gensec_session_info(state->gensec_security, state->gensec_security, &session_info);
1691                         if (!NT_STATUS_IS_OK(status)) {
1692                                 DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(status)));
1693                                 TALLOC_FREE(state->gensec_security);
1694                                 return;
1695                         }
1696                         unix_username = session_info->unix_info->unix_name;
1697                         DEBUG(10, ("NTLMSSP OK!\n"));
1698                 }
1699                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1700                         TALLOC_FREE(state->ntlmssp_state);
1701                 }
1702 #ifdef HAVE_KRB5
1703         } else if (strcmp(state->spnego_mech, "krb5") == 0) {
1704                 char *principal;
1705                 DATA_BLOB ap_rep;
1706                 DATA_BLOB session_key;
1707                 struct PAC_LOGON_INFO *logon_info = NULL;
1708                 DATA_BLOB ticket;
1709                 uint8_t tok_id[2];
1710
1711                 if (!spnego_parse_krb5_wrap(ctx, raw_in_token,
1712                                             &ticket, tok_id)) {
1713                         DEBUG(1, ("spnego_parse_krb5_wrap failed\n"));
1714                         x_fprintf(x_stdout, "BH spnego_parse_krb5_wrap failed\n");
1715                         return;
1716                 }
1717
1718                 status = ads_verify_ticket(ctx, lp_realm(), 0,
1719                                            &ticket,
1720                                            &principal, &logon_info, &ap_rep,
1721                                            &session_key, True);
1722
1723                 /* Now in "principal" we have the name we are authenticated as. */
1724
1725                 if (NT_STATUS_IS_OK(status)) {
1726                         char *domain;
1727                         char *user;
1728                         domain = strchr_m(principal, '@');
1729
1730                         if (domain == NULL) {
1731                                 DEBUG(1, ("Did not get a valid principal "
1732                                           "from ads_verify_ticket\n"));
1733                                 x_fprintf(x_stdout, "BH Did not get a "
1734                                           "valid principal from "
1735                                           "ads_verify_ticket\n");
1736                                 return;
1737                         }
1738
1739                         *domain++ = '\0';
1740                         domain = talloc_strdup(ctx, domain);
1741                         user = talloc_strdup(ctx, principal);
1742
1743                         if (logon_info) {
1744                                 netsamlogon_cache_store(
1745                                         user, &logon_info->info3);
1746                         }
1747
1748                         data_blob_free(&ap_rep);
1749                         data_blob_free(&session_key);
1750                         unix_username = talloc_asprintf(ctx, "%s\\%s", domain, user);
1751                 }
1752                 data_blob_free(&ticket);
1753 #endif
1754         }
1755
1756         spnego_free_data(&request);
1757         ZERO_STRUCT(response);
1758         response.type = SPNEGO_NEG_TOKEN_TARG;
1759
1760         if (NT_STATUS_IS_OK(status)) {
1761                 TALLOC_FREE(state->spnego_mech);
1762                 TALLOC_FREE(state->spnego_mech_oid);
1763                 response.negTokenTarg.negResult = SPNEGO_ACCEPT_COMPLETED;
1764                 response.negTokenTarg.responseToken = raw_out_token;
1765                 reply_code = "AF";
1766                 reply_argument = unix_username;
1767         } else if (NT_STATUS_EQUAL(status,
1768                                    NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1769                 response.negTokenTarg.supportedMech = supportedMech;
1770                 response.negTokenTarg.responseToken = raw_out_token;
1771                 response.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
1772                 reply_code = "TT";
1773                 reply_argument = talloc_strdup(ctx, "*");
1774         } else {
1775                 TALLOC_FREE(state->spnego_mech);
1776                 TALLOC_FREE(state->spnego_mech_oid);
1777                 data_blob_free(&raw_out_token);
1778                 response.negTokenTarg.negResult = SPNEGO_REJECT;
1779                 reply_code = "NA";
1780                 reply_argument = talloc_strdup(ctx, nt_errstr(status));
1781         }
1782
1783         if (!reply_argument) {
1784                 DEBUG(1, ("Could not write SPNEGO data blob\n"));
1785                 x_fprintf(x_stdout, "BH Could not write SPNEGO data blob\n");
1786                 spnego_free_data(&response);
1787                 return;
1788         }
1789
1790         len = spnego_write_data(ctx, &token, &response);
1791         spnego_free_data(&response);
1792
1793         if (len == -1) {
1794                 DEBUG(1, ("Could not write SPNEGO data blob\n"));
1795                 x_fprintf(x_stdout, "BH Could not write SPNEGO data blob\n");
1796                 return;
1797         }
1798
1799         reply_base64 = base64_encode_data_blob(talloc_tos(), token);
1800
1801         x_fprintf(x_stdout, "%s %s %s\n",
1802                   reply_code, reply_base64, reply_argument);
1803
1804         TALLOC_FREE(reply_base64);
1805         data_blob_free(&token);
1806
1807         return;
1808 }
1809
1810 static struct ntlmssp_state *client_ntlmssp_state = NULL;
1811
1812 static bool manage_client_ntlmssp_init(struct spnego_data spnego)
1813 {
1814         NTSTATUS status;
1815         DATA_BLOB null_blob = data_blob_null;
1816         DATA_BLOB to_server;
1817         char *to_server_base64;
1818         const char *my_mechs[] = {OID_NTLMSSP, NULL};
1819         TALLOC_CTX *ctx = talloc_tos();
1820
1821         DEBUG(10, ("Got spnego negTokenInit with NTLMSSP\n"));
1822
1823         if (client_ntlmssp_state != NULL) {
1824                 DEBUG(1, ("Request for initial SPNEGO request where "
1825                           "we already have a state\n"));
1826                 return False;
1827         }
1828
1829         if (!client_ntlmssp_state) {
1830                 if (!NT_STATUS_IS_OK(status = ntlm_auth_start_ntlmssp_client(&client_ntlmssp_state))) {
1831                         x_fprintf(x_stdout, "BH %s\n", nt_errstr(status));
1832                         return False;
1833                 }
1834         }
1835
1836
1837         if (opt_password == NULL) {
1838
1839                 /* Request a password from the calling process.  After
1840                    sending it, the calling process should retry with
1841                    the negTokenInit. */
1842
1843                 DEBUG(10, ("Requesting password\n"));
1844                 x_fprintf(x_stdout, "PW\n");
1845                 return True;
1846         }
1847
1848         spnego.type = SPNEGO_NEG_TOKEN_INIT;
1849         spnego.negTokenInit.mechTypes = my_mechs;
1850         spnego.negTokenInit.reqFlags = data_blob_null;
1851         spnego.negTokenInit.reqFlagsPadding = 0;
1852         spnego.negTokenInit.mechListMIC = null_blob;
1853
1854         status = ntlmssp_update(client_ntlmssp_state, null_blob,
1855                                        &spnego.negTokenInit.mechToken);
1856
1857         if ( !(NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) ||
1858                         NT_STATUS_IS_OK(status)) ) {
1859                 DEBUG(1, ("Expected OK or MORE_PROCESSING_REQUIRED, got: %s\n",
1860                           nt_errstr(status)));
1861                 TALLOC_FREE(client_ntlmssp_state);
1862                 return False;
1863         }
1864
1865         spnego_write_data(ctx, &to_server, &spnego);
1866         data_blob_free(&spnego.negTokenInit.mechToken);
1867
1868         to_server_base64 = base64_encode_data_blob(talloc_tos(), to_server);
1869         data_blob_free(&to_server);
1870         x_fprintf(x_stdout, "KK %s\n", to_server_base64);
1871         TALLOC_FREE(to_server_base64);
1872         return True;
1873 }
1874
1875 static void manage_client_ntlmssp_targ(struct spnego_data spnego)
1876 {
1877         NTSTATUS status;
1878         DATA_BLOB null_blob = data_blob_null;
1879         DATA_BLOB request;
1880         DATA_BLOB to_server;
1881         char *to_server_base64;
1882         TALLOC_CTX *ctx = talloc_tos();
1883
1884         DEBUG(10, ("Got spnego negTokenTarg with NTLMSSP\n"));
1885
1886         if (client_ntlmssp_state == NULL) {
1887                 DEBUG(1, ("Got NTLMSSP tArg without a client state\n"));
1888                 x_fprintf(x_stdout, "BH Got NTLMSSP tArg without a client state\n");
1889                 return;
1890         }
1891
1892         if (spnego.negTokenTarg.negResult == SPNEGO_REJECT) {
1893                 x_fprintf(x_stdout, "NA\n");
1894                 TALLOC_FREE(client_ntlmssp_state);
1895                 return;
1896         }
1897
1898         if (spnego.negTokenTarg.negResult == SPNEGO_ACCEPT_COMPLETED) {
1899                 x_fprintf(x_stdout, "AF\n");
1900                 TALLOC_FREE(client_ntlmssp_state);
1901                 return;
1902         }
1903
1904         status = ntlmssp_update(client_ntlmssp_state,
1905                                        spnego.negTokenTarg.responseToken,
1906                                        &request);
1907
1908         if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1909                 DEBUG(1, ("Expected MORE_PROCESSING_REQUIRED from "
1910                           "ntlmssp_client_update, got: %s\n",
1911                           nt_errstr(status)));
1912                 x_fprintf(x_stdout, "BH Expected MORE_PROCESSING_REQUIRED from "
1913                                     "ntlmssp_client_update\n");
1914                 data_blob_free(&request);
1915                 TALLOC_FREE(client_ntlmssp_state);
1916                 return;
1917         }
1918
1919         spnego.type = SPNEGO_NEG_TOKEN_TARG;
1920         spnego.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
1921         spnego.negTokenTarg.supportedMech = (const char *)OID_NTLMSSP;
1922         spnego.negTokenTarg.responseToken = request;
1923         spnego.negTokenTarg.mechListMIC = null_blob;
1924
1925         spnego_write_data(ctx, &to_server, &spnego);
1926         data_blob_free(&request);
1927
1928         to_server_base64 = base64_encode_data_blob(talloc_tos(), to_server);
1929         data_blob_free(&to_server);
1930         x_fprintf(x_stdout, "KK %s\n", to_server_base64);
1931         TALLOC_FREE(to_server_base64);
1932         return;
1933 }
1934
1935 #ifdef HAVE_KRB5
1936
1937 static bool manage_client_krb5_init(struct spnego_data spnego)
1938 {
1939         char *principal;
1940         DATA_BLOB tkt, to_server;
1941         DATA_BLOB session_key_krb5 = data_blob_null;
1942         struct spnego_data reply;
1943         char *reply_base64;
1944         int retval;
1945
1946         const char *my_mechs[] = {OID_KERBEROS5_OLD, NULL};
1947         ssize_t len;
1948         TALLOC_CTX *ctx = talloc_tos();
1949
1950         if ( (spnego.negTokenInit.mechListMIC.data == NULL) ||
1951              (spnego.negTokenInit.mechListMIC.length == 0) ) {
1952                 DEBUG(1, ("Did not get a principal for krb5\n"));
1953                 return False;
1954         }
1955
1956         principal = (char *)SMB_MALLOC(
1957                 spnego.negTokenInit.mechListMIC.length+1);
1958
1959         if (principal == NULL) {
1960                 DEBUG(1, ("Could not malloc principal\n"));
1961                 return False;
1962         }
1963
1964         memcpy(principal, spnego.negTokenInit.mechListMIC.data,
1965                spnego.negTokenInit.mechListMIC.length);
1966         principal[spnego.negTokenInit.mechListMIC.length] = '\0';
1967
1968         retval = cli_krb5_get_ticket(ctx, principal, 0,
1969                                           &tkt, &session_key_krb5,
1970                                           0, NULL, NULL, NULL);
1971         if (retval) {
1972                 char *user = NULL;
1973
1974                 /* Let's try to first get the TGT, for that we need a
1975                    password. */
1976
1977                 if (opt_password == NULL) {
1978                         DEBUG(10, ("Requesting password\n"));
1979                         x_fprintf(x_stdout, "PW\n");
1980                         return True;
1981                 }
1982
1983                 user = talloc_asprintf(talloc_tos(), "%s@%s", opt_username, opt_domain);
1984                 if (!user) {
1985                         return false;
1986                 }
1987
1988                 if ((retval = kerberos_kinit_password(user, opt_password, 0, NULL))) {
1989                         DEBUG(10, ("Requesting TGT failed: %s\n", error_message(retval)));
1990                         return False;
1991                 }
1992
1993                 retval = cli_krb5_get_ticket(ctx, principal, 0,
1994                                                   &tkt, &session_key_krb5,
1995                                                   0, NULL, NULL, NULL);
1996                 if (retval) {
1997                         DEBUG(10, ("Kinit suceeded, but getting a ticket failed: %s\n", error_message(retval)));
1998                         return False;
1999                 }
2000         }
2001
2002         data_blob_free(&session_key_krb5);
2003
2004         ZERO_STRUCT(reply);
2005
2006         reply.type = SPNEGO_NEG_TOKEN_INIT;
2007         reply.negTokenInit.mechTypes = my_mechs;
2008         reply.negTokenInit.reqFlags = data_blob_null;
2009         reply.negTokenInit.reqFlagsPadding = 0;
2010         reply.negTokenInit.mechToken = tkt;
2011         reply.negTokenInit.mechListMIC = data_blob_null;
2012
2013         len = spnego_write_data(ctx, &to_server, &reply);
2014         data_blob_free(&tkt);
2015
2016         if (len == -1) {
2017                 DEBUG(1, ("Could not write SPNEGO data blob\n"));
2018                 return False;
2019         }
2020
2021         reply_base64 = base64_encode_data_blob(talloc_tos(), to_server);
2022         x_fprintf(x_stdout, "KK %s *\n", reply_base64);
2023
2024         TALLOC_FREE(reply_base64);
2025         data_blob_free(&to_server);
2026         DEBUG(10, ("sent GSS-SPNEGO KERBEROS5 negTokenInit\n"));
2027         return True;
2028 }
2029
2030 static void manage_client_krb5_targ(struct spnego_data spnego)
2031 {
2032         switch (spnego.negTokenTarg.negResult) {
2033         case SPNEGO_ACCEPT_INCOMPLETE:
2034                 DEBUG(1, ("Got a Kerberos negTokenTarg with ACCEPT_INCOMPLETE\n"));
2035                 x_fprintf(x_stdout, "BH Got a Kerberos negTokenTarg with "
2036                                     "ACCEPT_INCOMPLETE\n");
2037                 break;
2038         case SPNEGO_ACCEPT_COMPLETED:
2039                 DEBUG(10, ("Accept completed\n"));
2040                 x_fprintf(x_stdout, "AF\n");
2041                 break;
2042         case SPNEGO_REJECT:
2043                 DEBUG(10, ("Rejected\n"));
2044                 x_fprintf(x_stdout, "NA\n");
2045                 break;
2046         default:
2047                 DEBUG(1, ("Got an invalid negTokenTarg\n"));
2048                 x_fprintf(x_stdout, "AF\n");
2049         }
2050 }
2051
2052 #endif
2053
2054 static void manage_gss_spnego_client_request(struct ntlm_auth_state *state,
2055                                                 char *buf, int length)
2056 {
2057         DATA_BLOB request;
2058         struct spnego_data spnego;
2059         ssize_t len;
2060         TALLOC_CTX *ctx = talloc_tos();
2061
2062         if (!opt_username || !*opt_username) {
2063                 x_fprintf(x_stderr, "username must be specified!\n\n");
2064                 exit(1);
2065         }
2066
2067         if (strlen(buf) <= 3) {
2068                 DEBUG(1, ("SPNEGO query [%s] too short\n", buf));
2069                 x_fprintf(x_stdout, "BH SPNEGO query too short\n");
2070                 return;
2071         }
2072
2073         request = base64_decode_data_blob(buf+3);
2074
2075         if (strncmp(buf, "PW ", 3) == 0) {
2076
2077                 /* We asked for a password and obviously got it :-) */
2078
2079                 opt_password = SMB_STRNDUP((const char *)request.data, request.length);
2080
2081                 if (opt_password == NULL) {
2082                         DEBUG(1, ("Out of memory\n"));
2083                         x_fprintf(x_stdout, "BH Out of memory\n");
2084                         data_blob_free(&request);
2085                         return;
2086                 }
2087
2088                 x_fprintf(x_stdout, "OK\n");
2089                 data_blob_free(&request);
2090                 return;
2091         }
2092
2093         if ( (strncmp(buf, "TT ", 3) != 0) &&
2094              (strncmp(buf, "AF ", 3) != 0) &&
2095              (strncmp(buf, "NA ", 3) != 0) ) {
2096                 DEBUG(1, ("SPNEGO request [%s] invalid\n", buf));
2097                 x_fprintf(x_stdout, "BH SPNEGO request invalid\n");
2098                 data_blob_free(&request);
2099                 return;
2100         }
2101
2102         /* So we got a server challenge to generate a SPNEGO
2103            client-to-server request... */
2104
2105         len = spnego_read_data(ctx, request, &spnego);
2106         data_blob_free(&request);
2107
2108         if (len == -1) {
2109                 DEBUG(1, ("Could not read SPNEGO data for [%s]\n", buf));
2110                 x_fprintf(x_stdout, "BH Could not read SPNEGO data\n");
2111                 return;
2112         }
2113
2114         if (spnego.type == SPNEGO_NEG_TOKEN_INIT) {
2115
2116                 /* The server offers a list of mechanisms */
2117
2118                 const char **mechType = (const char **)spnego.negTokenInit.mechTypes;
2119
2120                 while (*mechType != NULL) {
2121
2122 #ifdef HAVE_KRB5
2123                         if ( (strcmp(*mechType, OID_KERBEROS5_OLD) == 0) ||
2124                              (strcmp(*mechType, OID_KERBEROS5) == 0) ) {
2125                                 if (manage_client_krb5_init(spnego))
2126                                         goto out;
2127                         }
2128 #endif
2129
2130                         if (strcmp(*mechType, OID_NTLMSSP) == 0) {
2131                                 if (manage_client_ntlmssp_init(spnego))
2132                                         goto out;
2133                         }
2134
2135                         mechType++;
2136                 }
2137
2138                 DEBUG(1, ("Server offered no compatible mechanism\n"));
2139                 x_fprintf(x_stdout, "BH Server offered no compatible mechanism\n");
2140                 return;
2141         }
2142
2143         if (spnego.type == SPNEGO_NEG_TOKEN_TARG) {
2144
2145                 if (spnego.negTokenTarg.supportedMech == NULL) {
2146                         /* On accept/reject Windows does not send the
2147                            mechanism anymore. Handle that here and
2148                            shut down the mechanisms. */
2149
2150                         switch (spnego.negTokenTarg.negResult) {
2151                         case SPNEGO_ACCEPT_COMPLETED:
2152                                 x_fprintf(x_stdout, "AF\n");
2153                                 break;
2154                         case SPNEGO_REJECT:
2155                                 x_fprintf(x_stdout, "NA\n");
2156                                 break;
2157                         default:
2158                                 DEBUG(1, ("Got a negTokenTarg with no mech and an "
2159                                           "unknown negResult: %d\n",
2160                                           spnego.negTokenTarg.negResult));
2161                                 x_fprintf(x_stdout, "BH Got a negTokenTarg with"
2162                                                     " no mech and an unknown "
2163                                                     "negResult\n");
2164                         }
2165
2166                         TALLOC_FREE(client_ntlmssp_state);
2167                         goto out;
2168                 }
2169
2170                 if (strcmp(spnego.negTokenTarg.supportedMech,
2171                            OID_NTLMSSP) == 0) {
2172                         manage_client_ntlmssp_targ(spnego);
2173                         goto out;
2174                 }
2175
2176 #if HAVE_KRB5
2177                 if (strcmp(spnego.negTokenTarg.supportedMech,
2178                            OID_KERBEROS5_OLD) == 0) {
2179                         manage_client_krb5_targ(spnego);
2180                         goto out;
2181                 }
2182 #endif
2183
2184         }
2185
2186         DEBUG(1, ("Got an SPNEGO token I could not handle [%s]!\n", buf));
2187         x_fprintf(x_stdout, "BH Got an SPNEGO token I could not handle\n");
2188         return;
2189
2190  out:
2191         spnego_free_data(&spnego);
2192         return;
2193 }
2194
2195 static void manage_ntlm_server_1_request(struct ntlm_auth_state *state,
2196                                                 char *buf, int length)
2197 {
2198         char *request, *parameter;      
2199         static DATA_BLOB challenge;
2200         static DATA_BLOB lm_response;
2201         static DATA_BLOB nt_response;
2202         static char *full_username;
2203         static char *username;
2204         static char *domain;
2205         static char *plaintext_password;
2206         static bool ntlm_server_1_user_session_key;
2207         static bool ntlm_server_1_lm_session_key;
2208
2209         if (strequal(buf, ".")) {
2210                 if (!full_username && !username) {      
2211                         x_fprintf(x_stdout, "Error: No username supplied!\n");
2212                 } else if (plaintext_password) {
2213                         /* handle this request as plaintext */
2214                         if (!full_username) {
2215                                 if (asprintf(&full_username, "%s%c%s", domain, winbind_separator(), username) == -1) {
2216                                         x_fprintf(x_stdout, "Error: Out of memory in asprintf!\n.\n");
2217                                         return;
2218                                 }
2219                         }
2220                         if (check_plaintext_auth(full_username, plaintext_password, False)) {
2221                                 x_fprintf(x_stdout, "Authenticated: Yes\n");
2222                         } else {
2223                                 x_fprintf(x_stdout, "Authenticated: No\n");
2224                         }
2225                 } else if (!lm_response.data && !nt_response.data) {
2226                         x_fprintf(x_stdout, "Error: No password supplied!\n");
2227                 } else if (!challenge.data) {   
2228                         x_fprintf(x_stdout, "Error: No lanman-challenge supplied!\n");
2229                 } else {
2230                         char *error_string = NULL;
2231                         uchar lm_key[8];
2232                         uchar user_session_key[16];
2233                         uint32 flags = 0;
2234
2235                         if (full_username && !username) {
2236                                 fstring fstr_user;
2237                                 fstring fstr_domain;
2238
2239                                 if (!parse_ntlm_auth_domain_user(full_username, fstr_user, fstr_domain)) {
2240                                         /* username might be 'tainted', don't print into our new-line deleimianted stream */
2241                                         x_fprintf(x_stdout, "Error: Could not parse into domain and username\n");
2242                                 }
2243                                 SAFE_FREE(username);
2244                                 SAFE_FREE(domain);
2245                                 username = smb_xstrdup(fstr_user);
2246                                 domain = smb_xstrdup(fstr_domain);
2247                         }
2248
2249                         if (!domain) {
2250                                 domain = smb_xstrdup(get_winbind_domain());
2251                         }
2252
2253                         if (ntlm_server_1_lm_session_key) 
2254                                 flags |= WBFLAG_PAM_LMKEY;
2255
2256                         if (ntlm_server_1_user_session_key) 
2257                                 flags |= WBFLAG_PAM_USER_SESSION_KEY;
2258
2259                         if (!NT_STATUS_IS_OK(
2260                                     contact_winbind_auth_crap(username, 
2261                                                               domain, 
2262                                                               lp_netbios_name(),
2263                                                               &challenge, 
2264                                                               &lm_response, 
2265                                                               &nt_response, 
2266                                                               flags, 0,
2267                                                               lm_key, 
2268                                                               user_session_key,
2269                                                               &error_string,
2270                                                               NULL))) {
2271
2272                                 x_fprintf(x_stdout, "Authenticated: No\n");
2273                                 x_fprintf(x_stdout, "Authentication-Error: %s\n.\n", error_string);
2274                         } else {
2275                                 static char zeros[16];
2276                                 char *hex_lm_key;
2277                                 char *hex_user_session_key;
2278
2279                                 x_fprintf(x_stdout, "Authenticated: Yes\n");
2280
2281                                 if (ntlm_server_1_lm_session_key 
2282                                     && (memcmp(zeros, lm_key, 
2283                                                sizeof(lm_key)) != 0)) {
2284                                         hex_lm_key = hex_encode_talloc(NULL,
2285                                                                 (const unsigned char *)lm_key,
2286                                                                 sizeof(lm_key));
2287                                         x_fprintf(x_stdout, "LANMAN-Session-Key: %s\n", hex_lm_key);
2288                                         TALLOC_FREE(hex_lm_key);
2289                                 }
2290
2291                                 if (ntlm_server_1_user_session_key 
2292                                     && (memcmp(zeros, user_session_key, 
2293                                                sizeof(user_session_key)) != 0)) {
2294                                         hex_user_session_key = hex_encode_talloc(NULL,
2295                                                                           (const unsigned char *)user_session_key, 
2296                                                                           sizeof(user_session_key));
2297                                         x_fprintf(x_stdout, "User-Session-Key: %s\n", hex_user_session_key);
2298                                         TALLOC_FREE(hex_user_session_key);
2299                                 }
2300                         }
2301                         SAFE_FREE(error_string);
2302                 }
2303                 /* clear out the state */
2304                 challenge = data_blob_null;
2305                 nt_response = data_blob_null;
2306                 lm_response = data_blob_null;
2307                 SAFE_FREE(full_username);
2308                 SAFE_FREE(username);
2309                 SAFE_FREE(domain);
2310                 SAFE_FREE(plaintext_password);
2311                 ntlm_server_1_user_session_key = False;
2312                 ntlm_server_1_lm_session_key = False;
2313                 x_fprintf(x_stdout, ".\n");
2314
2315                 return;
2316         }
2317
2318         request = buf;
2319
2320         /* Indicates a base64 encoded structure */
2321         parameter = strstr_m(request, ":: ");
2322         if (!parameter) {
2323                 parameter = strstr_m(request, ": ");
2324
2325                 if (!parameter) {
2326                         DEBUG(0, ("Parameter not found!\n"));
2327                         x_fprintf(x_stdout, "Error: Parameter not found!\n.\n");
2328                         return;
2329                 }
2330
2331                 parameter[0] ='\0';
2332                 parameter++;
2333                 parameter[0] ='\0';
2334                 parameter++;
2335
2336         } else {
2337                 parameter[0] ='\0';
2338                 parameter++;
2339                 parameter[0] ='\0';
2340                 parameter++;
2341                 parameter[0] ='\0';
2342                 parameter++;
2343
2344                 base64_decode_inplace(parameter);
2345         }
2346
2347         if (strequal(request, "LANMAN-Challenge")) {
2348                 challenge = strhex_to_data_blob(NULL, parameter);
2349                 if (challenge.length != 8) {
2350                         x_fprintf(x_stdout, "Error: hex decode of %s failed! (got %d bytes, expected 8)\n.\n", 
2351                                   parameter,
2352                                   (int)challenge.length);
2353                         challenge = data_blob_null;
2354                 }
2355         } else if (strequal(request, "NT-Response")) {
2356                 nt_response = strhex_to_data_blob(NULL, parameter);
2357                 if (nt_response.length < 24) {
2358                         x_fprintf(x_stdout, "Error: hex decode of %s failed! (only got %d bytes, needed at least 24)\n.\n", 
2359                                   parameter,
2360                                   (int)nt_response.length);
2361                         nt_response = data_blob_null;
2362                 }
2363         } else if (strequal(request, "LANMAN-Response")) {
2364                 lm_response = strhex_to_data_blob(NULL, parameter);
2365                 if (lm_response.length != 24) {
2366                         x_fprintf(x_stdout, "Error: hex decode of %s failed! (got %d bytes, expected 24)\n.\n", 
2367                                   parameter,
2368                                   (int)lm_response.length);
2369                         lm_response = data_blob_null;
2370                 }
2371         } else if (strequal(request, "Password")) {
2372                 plaintext_password = smb_xstrdup(parameter);
2373         } else if (strequal(request, "NT-Domain")) {
2374                 domain = smb_xstrdup(parameter);
2375         } else if (strequal(request, "Username")) {
2376                 username = smb_xstrdup(parameter);
2377         } else if (strequal(request, "Full-Username")) {
2378                 full_username = smb_xstrdup(parameter);
2379         } else if (strequal(request, "Request-User-Session-Key")) {
2380                 ntlm_server_1_user_session_key = strequal(parameter, "Yes");
2381         } else if (strequal(request, "Request-LanMan-Session-Key")) {
2382                 ntlm_server_1_lm_session_key = strequal(parameter, "Yes");
2383         } else {
2384                 x_fprintf(x_stdout, "Error: Unknown request %s\n.\n", request);
2385         }
2386 }
2387
2388 static void manage_ntlm_change_password_1_request(struct ntlm_auth_state *state,
2389                                                         char *buf, int length)
2390 {
2391         char *request, *parameter;      
2392         static DATA_BLOB new_nt_pswd;
2393         static DATA_BLOB old_nt_hash_enc;
2394         static DATA_BLOB new_lm_pswd;
2395         static DATA_BLOB old_lm_hash_enc;
2396         static char *full_username = NULL;
2397         static char *username = NULL;
2398         static char *domain = NULL;
2399         static char *newpswd =  NULL;
2400         static char *oldpswd = NULL;
2401
2402         if (strequal(buf, ".")) {
2403                 if(newpswd && oldpswd) {
2404                         uchar old_nt_hash[16];
2405                         uchar old_lm_hash[16];
2406                         uchar new_nt_hash[16];
2407                         uchar new_lm_hash[16];
2408
2409                         new_nt_pswd = data_blob(NULL, 516);
2410                         old_nt_hash_enc = data_blob(NULL, 16);
2411
2412                         /* Calculate the MD4 hash (NT compatible) of the
2413                          * password */
2414                         E_md4hash(oldpswd, old_nt_hash);
2415                         E_md4hash(newpswd, new_nt_hash);
2416
2417                         /* E_deshash returns false for 'long'
2418                            passwords (> 14 DOS chars).  
2419
2420                            Therefore, don't send a buffer
2421                            encrypted with the truncated hash
2422                            (it could allow an even easier
2423                            attack on the password)
2424
2425                            Likewise, obey the admin's restriction
2426                         */
2427
2428                         if (lp_client_lanman_auth() &&
2429                             E_deshash(newpswd, new_lm_hash) &&
2430                             E_deshash(oldpswd, old_lm_hash)) {
2431                                 new_lm_pswd = data_blob(NULL, 516);
2432                                 old_lm_hash_enc = data_blob(NULL, 16);
2433                                 encode_pw_buffer(new_lm_pswd.data, newpswd,
2434                                                  STR_UNICODE);
2435
2436                                 arcfour_crypt(new_lm_pswd.data, old_nt_hash, 516);
2437                                 E_old_pw_hash(new_nt_hash, old_lm_hash,
2438                                               old_lm_hash_enc.data);
2439                         } else {
2440                                 new_lm_pswd.data = NULL;
2441                                 new_lm_pswd.length = 0;
2442                                 old_lm_hash_enc.data = NULL;
2443                                 old_lm_hash_enc.length = 0;
2444                         }
2445
2446                         encode_pw_buffer(new_nt_pswd.data, newpswd,
2447                                          STR_UNICODE);
2448
2449                         arcfour_crypt(new_nt_pswd.data, old_nt_hash, 516);
2450                         E_old_pw_hash(new_nt_hash, old_nt_hash,
2451                                       old_nt_hash_enc.data);
2452                 }
2453
2454                 if (!full_username && !username) {      
2455                         x_fprintf(x_stdout, "Error: No username supplied!\n");
2456                 } else if ((!new_nt_pswd.data || !old_nt_hash_enc.data) &&
2457                            (!new_lm_pswd.data || old_lm_hash_enc.data) ) {
2458                         x_fprintf(x_stdout, "Error: No NT or LM password "
2459                                   "blobs supplied!\n");
2460                 } else {
2461                         char *error_string = NULL;
2462
2463                         if (full_username && !username) {
2464                                 fstring fstr_user;
2465                                 fstring fstr_domain;
2466
2467                                 if (!parse_ntlm_auth_domain_user(full_username,
2468                                                                  fstr_user,
2469                                                                  fstr_domain)) {
2470                                         /* username might be 'tainted', don't
2471                                          * print into our new-line
2472                                          * deleimianted stream */
2473                                         x_fprintf(x_stdout, "Error: Could not "
2474                                                   "parse into domain and "
2475                                                   "username\n");
2476                                         SAFE_FREE(username);
2477                                         username = smb_xstrdup(full_username);
2478                                 } else {
2479                                         SAFE_FREE(username);
2480                                         SAFE_FREE(domain);
2481                                         username = smb_xstrdup(fstr_user);
2482                                         domain = smb_xstrdup(fstr_domain);
2483                                 }
2484
2485                         }
2486
2487                         if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
2488                                                     username, domain,
2489                                                     new_nt_pswd,
2490                                                     old_nt_hash_enc,
2491                                                     new_lm_pswd,
2492                                                     old_lm_hash_enc,
2493                                                     &error_string))) {
2494                                 x_fprintf(x_stdout, "Password-Change: No\n");
2495                                 x_fprintf(x_stdout, "Password-Change-Error: "
2496                                           "%s\n.\n", error_string);
2497                         } else {
2498                                 x_fprintf(x_stdout, "Password-Change: Yes\n");
2499                         }
2500
2501                         SAFE_FREE(error_string);
2502                 }
2503                 /* clear out the state */
2504                 new_nt_pswd = data_blob_null;
2505                 old_nt_hash_enc = data_blob_null;
2506                 new_lm_pswd = data_blob_null;
2507                 old_nt_hash_enc = data_blob_null;
2508                 SAFE_FREE(full_username);
2509                 SAFE_FREE(username);
2510                 SAFE_FREE(domain);
2511                 SAFE_FREE(newpswd);
2512                 SAFE_FREE(oldpswd);
2513                 x_fprintf(x_stdout, ".\n");
2514
2515                 return;
2516         }
2517
2518         request = buf;
2519
2520         /* Indicates a base64 encoded structure */
2521         parameter = strstr_m(request, ":: ");
2522         if (!parameter) {
2523                 parameter = strstr_m(request, ": ");
2524
2525                 if (!parameter) {
2526                         DEBUG(0, ("Parameter not found!\n"));
2527                         x_fprintf(x_stdout, "Error: Parameter not found!\n.\n");
2528                         return;
2529                 }
2530
2531                 parameter[0] ='\0';
2532                 parameter++;
2533                 parameter[0] ='\0';
2534                 parameter++;
2535         } else {
2536                 parameter[0] ='\0';
2537                 parameter++;
2538                 parameter[0] ='\0';
2539                 parameter++;
2540                 parameter[0] ='\0';
2541                 parameter++;
2542
2543                 base64_decode_inplace(parameter);
2544         }
2545
2546         if (strequal(request, "new-nt-password-blob")) {
2547                 new_nt_pswd = strhex_to_data_blob(NULL, parameter);
2548                 if (new_nt_pswd.length != 516) {
2549                         x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2550                                   "(got %d bytes, expected 516)\n.\n", 
2551                                   parameter,
2552                                   (int)new_nt_pswd.length);
2553                         new_nt_pswd = data_blob_null;
2554                 }
2555         } else if (strequal(request, "old-nt-hash-blob")) {
2556                 old_nt_hash_enc = strhex_to_data_blob(NULL, parameter);
2557                 if (old_nt_hash_enc.length != 16) {
2558                         x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2559                                   "(got %d bytes, expected 16)\n.\n", 
2560                                   parameter,
2561                                   (int)old_nt_hash_enc.length);
2562                         old_nt_hash_enc = data_blob_null;
2563                 }
2564         } else if (strequal(request, "new-lm-password-blob")) {
2565                 new_lm_pswd = strhex_to_data_blob(NULL, parameter);
2566                 if (new_lm_pswd.length != 516) {
2567                         x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2568                                   "(got %d bytes, expected 516)\n.\n", 
2569                                   parameter,
2570                                   (int)new_lm_pswd.length);
2571                         new_lm_pswd = data_blob_null;
2572                 }
2573         }
2574         else if (strequal(request, "old-lm-hash-blob")) {
2575                 old_lm_hash_enc = strhex_to_data_blob(NULL, parameter);
2576                 if (old_lm_hash_enc.length != 16)
2577                 {
2578                         x_fprintf(x_stdout, "Error: hex decode of %s failed! "
2579                                   "(got %d bytes, expected 16)\n.\n", 
2580                                   parameter,
2581                                   (int)old_lm_hash_enc.length);
2582                         old_lm_hash_enc = data_blob_null;
2583                 }
2584         } else if (strequal(request, "nt-domain")) {
2585                 domain = smb_xstrdup(parameter);
2586         } else if(strequal(request, "username")) {
2587                 username = smb_xstrdup(parameter);
2588         } else if(strequal(request, "full-username")) {
2589                 username = smb_xstrdup(parameter);
2590         } else if(strequal(request, "new-password")) {
2591                 newpswd = smb_xstrdup(parameter);
2592         } else if (strequal(request, "old-password")) {
2593                 oldpswd = smb_xstrdup(parameter);
2594         } else {
2595                 x_fprintf(x_stdout, "Error: Unknown request %s\n.\n", request);
2596         }
2597 }
2598
2599 static void manage_squid_request(struct ntlm_auth_state *state,
2600                 stdio_helper_function fn)
2601 {
2602         char *buf;
2603         char tmp[INITIAL_BUFFER_SIZE+1];
2604         int length, buf_size = 0;
2605         char *c;
2606
2607         buf = talloc_strdup(state->mem_ctx, "");
2608         if (!buf) {
2609                 DEBUG(0, ("Failed to allocate input buffer.\n"));
2610                 x_fprintf(x_stderr, "ERR\n");
2611                 exit(1);
2612         }
2613
2614         do {
2615
2616                 /* this is not a typo - x_fgets doesn't work too well under
2617                  * squid */
2618                 if (fgets(tmp, sizeof(tmp)-1, stdin) == NULL) {
2619                         if (ferror(stdin)) {
2620                                 DEBUG(1, ("fgets() failed! dying..... errno=%d "
2621                                           "(%s)\n", ferror(stdin),
2622                                           strerror(ferror(stdin))));
2623
2624                                 exit(1);
2625                         }
2626                         exit(0);
2627                 }
2628
2629                 buf = talloc_strdup_append_buffer(buf, tmp);
2630                 buf_size += INITIAL_BUFFER_SIZE;
2631
2632                 if (buf_size > MAX_BUFFER_SIZE) {
2633                         DEBUG(2, ("Oversized message\n"));
2634                         x_fprintf(x_stderr, "ERR\n");
2635                         talloc_free(buf);
2636                         return;
2637                 }
2638
2639                 c = strchr(buf, '\n');
2640         } while (c == NULL);
2641
2642         *c = '\0';
2643         length = c-buf;
2644
2645         DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf,length));
2646
2647         if (buf[0] == '\0') {
2648                 DEBUG(2, ("Invalid Request\n"));
2649                 x_fprintf(x_stderr, "ERR\n");
2650                 talloc_free(buf);
2651                 return;
2652         }
2653
2654         fn(state, buf, length);
2655         talloc_free(buf);
2656 }
2657
2658
2659 static void squid_stream(enum stdio_helper_mode stdio_mode, stdio_helper_function fn) {
2660         TALLOC_CTX *mem_ctx;
2661         struct ntlm_auth_state *state;
2662
2663         /* initialize FDescs */
2664         x_setbuf(x_stdout, NULL);
2665         x_setbuf(x_stderr, NULL);
2666
2667         mem_ctx = talloc_init("ntlm_auth");
2668         if (!mem_ctx) {
2669                 DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
2670                 x_fprintf(x_stderr, "ERR\n");
2671                 exit(1);
2672         }
2673
2674         state = talloc_zero(mem_ctx, struct ntlm_auth_state);
2675         if (!state) {
2676                 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
2677                 x_fprintf(x_stderr, "ERR\n");
2678                 exit(1);
2679         }
2680
2681         state->mem_ctx = mem_ctx;
2682         state->helper_mode = stdio_mode;
2683
2684         while(1) {
2685                 TALLOC_CTX *frame = talloc_stackframe();
2686                 manage_squid_request(state, fn);
2687                 TALLOC_FREE(frame);
2688         }
2689 }
2690
2691
2692 /* Authenticate a user with a challenge/response */
2693
2694 static bool check_auth_crap(void)
2695 {
2696         NTSTATUS nt_status;
2697         uint32 flags = 0;
2698         char lm_key[8];
2699         char user_session_key[16];
2700         char *hex_lm_key;
2701         char *hex_user_session_key;
2702         char *error_string;
2703         static uint8 zeros[16];
2704
2705         x_setbuf(x_stdout, NULL);
2706
2707         if (request_lm_key) 
2708                 flags |= WBFLAG_PAM_LMKEY;
2709
2710         if (request_user_session_key) 
2711                 flags |= WBFLAG_PAM_USER_SESSION_KEY;
2712
2713         flags |= WBFLAG_PAM_NT_STATUS_SQUASH;
2714
2715         nt_status = contact_winbind_auth_crap(opt_username, opt_domain, 
2716                                               opt_workstation,
2717                                               &opt_challenge, 
2718                                               &opt_lm_response, 
2719                                               &opt_nt_response, 
2720                                               flags, 0,
2721                                               (unsigned char *)lm_key, 
2722                                               (unsigned char *)user_session_key, 
2723                                               &error_string, NULL);
2724
2725         if (!NT_STATUS_IS_OK(nt_status)) {
2726                 x_fprintf(x_stdout, "%s (0x%x)\n", 
2727                           error_string,
2728                           NT_STATUS_V(nt_status));
2729                 SAFE_FREE(error_string);
2730                 return False;
2731         }
2732
2733         if (request_lm_key 
2734             && (memcmp(zeros, lm_key, 
2735                        sizeof(lm_key)) != 0)) {
2736                 hex_lm_key = hex_encode_talloc(talloc_tos(), (const unsigned char *)lm_key,
2737                                         sizeof(lm_key));
2738                 x_fprintf(x_stdout, "LM_KEY: %s\n", hex_lm_key);
2739                 TALLOC_FREE(hex_lm_key);
2740         }
2741         if (request_user_session_key 
2742             && (memcmp(zeros, user_session_key, 
2743                        sizeof(user_session_key)) != 0)) {
2744                 hex_user_session_key = hex_encode_talloc(talloc_tos(), (const unsigned char *)user_session_key, 
2745                                                   sizeof(user_session_key));
2746                 x_fprintf(x_stdout, "NT_KEY: %s\n", hex_user_session_key);
2747                 TALLOC_FREE(hex_user_session_key);
2748         }
2749
2750         return True;
2751 }
2752
2753 /* Main program */
2754
2755 enum {
2756         OPT_USERNAME = 1000,
2757         OPT_DOMAIN,
2758         OPT_WORKSTATION,
2759         OPT_CHALLENGE,
2760         OPT_RESPONSE,
2761         OPT_LM,
2762         OPT_NT,
2763         OPT_PASSWORD,
2764         OPT_LM_KEY,
2765         OPT_USER_SESSION_KEY,
2766         OPT_DIAGNOSTICS,
2767         OPT_REQUIRE_MEMBERSHIP,
2768         OPT_USE_CACHED_CREDS,
2769         OPT_PAM_WINBIND_CONF
2770 };
2771
2772  int main(int argc, const char **argv)
2773 {
2774         TALLOC_CTX *frame = talloc_stackframe();
2775         int opt;
2776         static const char *helper_protocol;
2777         static int diagnostics;
2778
2779         static const char *hex_challenge;
2780         static const char *hex_lm_response;
2781         static const char *hex_nt_response;
2782
2783         poptContext pc;
2784
2785         /* NOTE: DO NOT change this interface without considering the implications!
2786            This is an external interface, which other programs will use to interact 
2787            with this helper.
2788         */
2789
2790         /* We do not use single-letter command abbreviations, because they harm future 
2791            interface stability. */
2792
2793         struct poptOption long_options[] = {
2794                 POPT_AUTOHELP
2795                 { "helper-protocol", 0, POPT_ARG_STRING, &helper_protocol, OPT_DOMAIN, "operate as a stdio-based helper", "helper protocol to use"},
2796                 { "username", 0, POPT_ARG_STRING, &opt_username, OPT_USERNAME, "username"},
2797                 { "domain", 0, POPT_ARG_STRING, &opt_domain, OPT_DOMAIN, "domain name"},
2798                 { "workstation", 0, POPT_ARG_STRING, &opt_workstation, OPT_WORKSTATION, "workstation"},
2799                 { "challenge", 0, POPT_ARG_STRING, &hex_challenge, OPT_CHALLENGE, "challenge (HEX encoded)"},
2800                 { "lm-response", 0, POPT_ARG_STRING, &hex_lm_response, OPT_LM, "LM Response to the challenge (HEX encoded)"},
2801                 { "nt-response", 0, POPT_ARG_STRING, &hex_nt_response, OPT_NT, "NT or NTLMv2 Response to the challenge (HEX encoded)"},
2802                 { "password", 0, POPT_ARG_STRING, &opt_password, OPT_PASSWORD, "User's plaintext password"},            
2803                 { "request-lm-key", 0, POPT_ARG_NONE, &request_lm_key, OPT_LM_KEY, "Retrieve LM session key"},
2804                 { "request-nt-key", 0, POPT_ARG_NONE, &request_user_session_key, OPT_USER_SESSION_KEY, "Retrieve User (NT) session key"},
2805                 { "use-cached-creds", 0, POPT_ARG_NONE, &use_cached_creds, OPT_USE_CACHED_CREDS, "Use cached credentials if no password is given"},
2806                 { "diagnostics", 0, POPT_ARG_NONE, &diagnostics,
2807                   OPT_DIAGNOSTICS,
2808                   "Perform diagnostics on the authentication chain"},
2809                 { "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" },
2810                 { "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" },
2811                 POPT_COMMON_CONFIGFILE
2812                 POPT_COMMON_VERSION
2813                 POPT_TABLEEND
2814         };
2815
2816         /* Samba client initialisation */
2817         load_case_tables();
2818
2819         setup_logging("ntlm_auth", DEBUG_STDERR);
2820
2821         /* Parse options */
2822
2823         pc = poptGetContext("ntlm_auth", argc, argv, long_options, 0);
2824
2825         /* Parse command line options */
2826
2827         if (argc == 1) {
2828                 poptPrintHelp(pc, stderr, 0);
2829                 return 1;
2830         }
2831
2832         while((opt = poptGetNextOpt(pc)) != -1) {
2833                 /* Get generic config options like --configfile */
2834         }
2835
2836         poptFreeContext(pc);
2837
2838         if (!lp_load_global(get_dyn_CONFIGFILE())) {
2839                 d_fprintf(stderr, "ntlm_auth: error opening config file %s. Error was %s\n",
2840                         get_dyn_CONFIGFILE(), strerror(errno));
2841                 exit(1);
2842         }
2843
2844         pc = poptGetContext(NULL, argc, (const char **)argv, long_options, 
2845                             POPT_CONTEXT_KEEP_FIRST);
2846
2847         while((opt = poptGetNextOpt(pc)) != -1) {
2848                 switch (opt) {
2849                 case OPT_CHALLENGE:
2850                         opt_challenge = strhex_to_data_blob(NULL, hex_challenge);
2851                         if (opt_challenge.length != 8) {
2852                                 x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n", 
2853                                           hex_challenge,
2854                                           (int)opt_challenge.length);
2855                                 exit(1);
2856                         }
2857                         break;
2858                 case OPT_LM: 
2859                         opt_lm_response = strhex_to_data_blob(NULL, hex_lm_response);
2860                         if (opt_lm_response.length != 24) {
2861                                 x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n", 
2862                                           hex_lm_response,
2863                                           (int)opt_lm_response.length);
2864                                 exit(1);
2865                         }
2866                         break;
2867
2868                 case OPT_NT: 
2869                         opt_nt_response = strhex_to_data_blob(NULL, hex_nt_response);
2870                         if (opt_nt_response.length < 24) {
2871                                 x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n", 
2872                                           hex_nt_response,
2873                                           (int)opt_nt_response.length);
2874                                 exit(1);
2875                         }
2876                         break;
2877
2878                 case OPT_REQUIRE_MEMBERSHIP:
2879                         if (strncasecmp_m("S-", require_membership_of, 2) == 0) {
2880                                 require_membership_of_sid = require_membership_of;
2881                         }
2882                         break;
2883                 }
2884         }
2885
2886         if (opt_username) {
2887                 char *domain = SMB_STRDUP(opt_username);
2888                 char *p = strchr_m(domain, *lp_winbind_separator());
2889                 if (p) {
2890                         opt_username = p+1;
2891                         *p = '\0';
2892                         if (opt_domain && !strequal(opt_domain, domain)) {
2893                                 x_fprintf(x_stderr, "Domain specified in username (%s) "
2894                                         "doesn't match specified domain (%s)!\n\n",
2895                                         domain, opt_domain);
2896                                 poptPrintHelp(pc, stderr, 0);
2897                                 exit(1);
2898                         }
2899                         opt_domain = domain;
2900                 } else {
2901                         SAFE_FREE(domain);
2902                 }
2903         }
2904
2905         /* Note: if opt_domain is "" then send no domain */
2906         if (opt_domain == NULL) {
2907                 opt_domain = get_winbind_domain();
2908         }
2909
2910         if (opt_workstation == NULL) {
2911                 opt_workstation = "";
2912         }
2913
2914         if (helper_protocol) {
2915                 int i;
2916                 for (i=0; i<NUM_HELPER_MODES; i++) {
2917                         if (strcmp(helper_protocol, stdio_helper_protocols[i].name) == 0) {
2918                                 squid_stream(stdio_helper_protocols[i].mode, stdio_helper_protocols[i].fn);
2919                                 exit(0);
2920                         }
2921                 }
2922                 x_fprintf(x_stderr, "unknown helper protocol [%s]\n\nValid helper protools:\n\n", helper_protocol);
2923
2924                 for (i=0; i<NUM_HELPER_MODES; i++) {
2925                         x_fprintf(x_stderr, "%s\n", stdio_helper_protocols[i].name);
2926                 }
2927
2928                 exit(1);
2929         }
2930
2931         if (!opt_username || !*opt_username) {
2932                 x_fprintf(x_stderr, "username must be specified!\n\n");
2933                 poptPrintHelp(pc, stderr, 0);
2934                 exit(1);
2935         }
2936
2937         if (opt_challenge.length) {
2938                 if (!check_auth_crap()) {
2939                         exit(1);
2940                 }
2941                 exit(0);
2942         } 
2943
2944         if (!opt_password) {
2945                 opt_password = getpass("password: ");
2946         }
2947
2948         if (diagnostics) {
2949                 if (!diagnose_ntlm_auth()) {
2950                         return 1;
2951                 }
2952         } else {
2953                 fstring user;
2954
2955                 fstr_sprintf(user, "%s%c%s", opt_domain, winbind_separator(), opt_username);
2956                 if (!check_plaintext_auth(user, opt_password, True)) {
2957                         return 1;
2958                 }
2959         }
2960
2961         /* Exit code */
2962
2963         poptFreeContext(pc);
2964         TALLOC_FREE(frame);
2965         return 0;
2966 }