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