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