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