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