r1200: Add 'gensec', our generic security layer.
[jelmer/samba4-debian.git] / source / 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
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include "includes.h"
26
27 #undef DBGC_CLASS
28 #define DBGC_CLASS DBGC_WINBIND
29
30 #define SQUID_BUFFER_SIZE 2010
31
32 enum stdio_helper_mode {
33         SQUID_2_4_BASIC,
34         SQUID_2_5_BASIC,
35         SQUID_2_5_NTLMSSP,
36         NTLMSSP_CLIENT_1,
37         GSS_SPNEGO_CLIENT,
38         NTLM_SERVER_1,
39         NUM_HELPER_MODES
40 };
41
42 #define NTLM_AUTH_FLAG_USER_SESSION_KEY     0x0004
43 #define NTLM_AUTH_FLAG_LMKEY                0x0008
44
45
46 typedef void (*stdio_helper_function)(enum stdio_helper_mode stdio_helper_mode, 
47                                      char *buf, int length);
48
49 static void manage_squid_basic_request (enum stdio_helper_mode stdio_helper_mode, 
50                                         char *buf, int length);
51
52 static void manage_squid_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode, 
53                                           char *buf, int length);
54
55 static void manage_gensec_client_request (enum stdio_helper_mode stdio_helper_mode, 
56                                           char *buf, int length);
57
58 static void manage_ntlm_server_1_request (enum stdio_helper_mode stdio_helper_mode, 
59                                           char *buf, int length);
60
61 static const struct {
62         enum stdio_helper_mode mode;
63         const char *name;
64         stdio_helper_function fn;
65 } stdio_helper_protocols[] = {
66         { SQUID_2_4_BASIC, "squid-2.4-basic", manage_squid_basic_request},
67         { SQUID_2_5_BASIC, "squid-2.5-basic", manage_squid_basic_request},
68         { SQUID_2_5_NTLMSSP, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request},
69         { NTLMSSP_CLIENT_1, "ntlmssp-client-1", manage_gensec_client_request},
70         { GSS_SPNEGO_CLIENT, "gss-spnego-client", manage_gensec_client_request},
71         { NTLM_SERVER_1, "ntlm-server-1", manage_ntlm_server_1_request},
72         { NUM_HELPER_MODES, NULL, NULL}
73 };
74
75 extern int winbindd_fd;
76
77 const char *opt_username;
78 const char *opt_domain;
79 const char *opt_workstation;
80 const char *opt_password;
81
82
83 /* Copy of parse_domain_user from winbindd_util.c.  Parse a string of the
84    form DOMAIN/user into a domain and a user */
85
86 static BOOL parse_ntlm_auth_domain_user(const char *domuser, fstring domain, 
87                                      fstring user)
88 {
89
90         char *p = strchr(domuser,*lp_winbind_separator());
91
92         if (!p) {
93                 return False;
94         }
95         
96         fstrcpy(user, p+1);
97         fstrcpy(domain, domuser);
98         domain[PTR_DIFF(p, domuser)] = 0;
99         strupper_m(domain);
100
101         return True;
102 }
103
104 /* Authenticate a user with a plaintext password */
105
106 static BOOL check_plaintext_auth(const char *user, const char *pass, 
107                                  BOOL stdout_diagnostics)
108 {
109         return (strcmp(pass, opt_password) == 0);
110 }
111
112 /* authenticate a user with an encrypted username/password */
113
114 static NTSTATUS local_pw_check_specified(const char *username, 
115                                          const char *domain, 
116                                          const char *workstation,
117                                          const DATA_BLOB *challenge, 
118                                          const DATA_BLOB *lm_response, 
119                                          const DATA_BLOB *nt_response, 
120                                          uint32 flags, 
121                                          DATA_BLOB *lm_session_key, 
122                                          DATA_BLOB *user_session_key, 
123                                          char **error_string, 
124                                          char **unix_name) 
125 {
126         NTSTATUS nt_status;
127         uint8_t lm_pw[16], nt_pw[16];
128         uint8_t *lm_pwd, *nt_pwd;
129         TALLOC_CTX *mem_ctx = talloc_init("local_pw_check_specified");
130         if (!mem_ctx) {
131                 nt_status = NT_STATUS_NO_MEMORY;
132         } else {
133                 
134                 E_md4hash(opt_password, nt_pw);
135                 if (E_deshash(opt_password, lm_pw)) {
136                         lm_pwd = lm_pw;
137                 } else {
138                         lm_pwd = NULL;
139                 }
140                 nt_pwd = nt_pw;
141                 
142                 
143                 nt_status = ntlm_password_check(mem_ctx, 
144                                                 challenge,
145                                                 lm_response,
146                                                 nt_response,
147                                                 NULL, NULL,
148                                                 username,
149                                                 username,
150                                                 domain,
151                                                 lm_pwd, nt_pwd, user_session_key, lm_session_key);
152                 
153                 if (NT_STATUS_IS_OK(nt_status)) {
154                         if (unix_name) {
155                                 asprintf(unix_name, 
156                                          "%s%c%s", domain,
157                                          *lp_winbind_separator(), 
158                                          username);
159                         }
160                 } else {
161                         DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n", 
162                                   domain, username, workstation, 
163                                   nt_errstr(nt_status)));
164                 }
165                 talloc_destroy(mem_ctx);
166         }
167         if (error_string) {
168                 *error_string = strdup(nt_errstr(nt_status));
169         }
170         return nt_status;
171         
172         
173 }
174
175 static NTSTATUS local_pw_check(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key) 
176 {
177         NTSTATUS nt_status;
178         uint8 lm_pw[16], nt_pw[16];
179         uint8_t *lm_pwd, *nt_pwd;
180
181         E_md4hash(opt_password, nt_pw);
182         if (E_deshash(opt_password, lm_pw)) {
183                 lm_pwd = lm_pw;
184         } else {
185                         lm_pwd = NULL;
186         }
187         nt_pwd = nt_pw;
188                 
189         nt_status = ntlm_password_check(ntlmssp_state->mem_ctx, 
190                                         &ntlmssp_state->chal,
191                                         &ntlmssp_state->lm_resp,
192                                         &ntlmssp_state->nt_resp, 
193                                         NULL, NULL,
194                                         ntlmssp_state->user, 
195                                         ntlmssp_state->user, 
196                                         ntlmssp_state->domain,
197                                         lm_pwd, nt_pwd, user_session_key, lm_session_key);
198         
199         if (NT_STATUS_IS_OK(nt_status)) {
200                 ntlmssp_state->auth_context = talloc_asprintf(ntlmssp_state->mem_ctx, 
201                                                               "%s%c%s", ntlmssp_state->domain, 
202                                                               *lp_winbind_separator(), 
203                                                               ntlmssp_state->user);
204         } else {
205                 DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n", 
206                           ntlmssp_state->domain, ntlmssp_state->user, ntlmssp_state->workstation, 
207                           nt_errstr(nt_status)));
208                 ntlmssp_state->auth_context = NULL;
209         }
210         return nt_status;
211 }
212
213 static NTSTATUS ntlm_auth_start_ntlmssp_server(struct ntlmssp_state **ntlmssp_state) 
214 {
215         NTSTATUS status = ntlmssp_server_start(ntlmssp_state);
216         
217         if (!NT_STATUS_IS_OK(status)) {
218                 DEBUG(1, ("Could not start NTLMSSP client: %s\n",
219                           nt_errstr(status)));
220                 return status;
221         }
222
223         /* Have we been given a local password, or should we ask winbind? */
224         if (opt_password) {
225                 (*ntlmssp_state)->check_password = local_pw_check;
226                 (*ntlmssp_state)->get_domain = lp_workgroup;
227                 (*ntlmssp_state)->get_global_myname = global_myname;
228         } else {
229                 DEBUG(0, ("Winbind not supported in Samba4 ntlm_auth yet, specify --password\n"));
230                 exit(1);
231         }
232         return NT_STATUS_OK;
233 }
234
235 static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode, 
236                                          char *buf, int length) 
237 {
238         static struct ntlmssp_state *ntlmssp_state = NULL;
239         DATA_BLOB request, reply;
240         NTSTATUS nt_status;
241
242         if (strlen(buf) < 2) {
243                 DEBUG(1, ("NTLMSSP query [%s] invalid", buf));
244                 x_fprintf(x_stdout, "BH\n");
245                 return;
246         }
247
248         if (strlen(buf) > 3) {
249                 request = base64_decode_data_blob(buf + 3);
250         } else {
251                 request = data_blob(NULL, 0);
252         }
253
254         if ((strncmp(buf, "PW ", 3) == 0)) {
255                 /* The calling application wants us to use a local password (rather than winbindd) */
256
257                 opt_password = strndup((const char *)request.data, request.length);
258
259                 if (opt_password == NULL) {
260                         DEBUG(1, ("Out of memory\n"));
261                         x_fprintf(x_stdout, "BH\n");
262                         data_blob_free(&request);
263                         return;
264                 }
265
266                 x_fprintf(x_stdout, "OK\n");
267                 data_blob_free(&request);
268                 return;
269         }
270
271         if (strncmp(buf, "YR", 2) == 0) {
272                 if (ntlmssp_state)
273                         ntlmssp_end(&ntlmssp_state);
274         } else if (strncmp(buf, "KK", 2) == 0) {
275                 
276         } else {
277                 DEBUG(1, ("NTLMSSP query [%s] invalid", buf));
278                 x_fprintf(x_stdout, "BH\n");
279                 return;
280         }
281
282         if (!ntlmssp_state) {
283                 if (!NT_STATUS_IS_OK(nt_status = ntlm_auth_start_ntlmssp_server(&ntlmssp_state))) {
284                         x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
285                         return;
286                 }
287         }
288
289         DEBUG(10, ("got NTLMSSP packet:\n"));
290         dump_data(10, (const char *)request.data, request.length);
291
292         nt_status = ntlmssp_update(ntlmssp_state, NULL, request, &reply);
293         
294         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
295                 char *reply_base64 = base64_encode_data_blob(reply);
296                 x_fprintf(x_stdout, "TT %s\n", reply_base64);
297                 SAFE_FREE(reply_base64);
298                 data_blob_free(&reply);
299                 DEBUG(10, ("NTLMSSP challenge\n"));
300         } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) {
301                 x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
302                 DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status)));
303
304                 ntlmssp_end(&ntlmssp_state);
305         } else if (!NT_STATUS_IS_OK(nt_status)) {
306                 x_fprintf(x_stdout, "NA %s\n", nt_errstr(nt_status));
307                 DEBUG(10, ("NTLMSSP %s\n", nt_errstr(nt_status)));
308         } else {
309                 x_fprintf(x_stdout, "AF %s\n", (char *)ntlmssp_state->auth_context);
310                 DEBUG(10, ("NTLMSSP OK!\n"));
311         }
312
313         data_blob_free(&request);
314 }
315
316 static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode, 
317                                        char *buf, int length) 
318 {
319         char *user, *pass;      
320         user=buf;
321         
322         pass=memchr(buf,' ',length);
323         if (!pass) {
324                 DEBUG(2, ("Password not found. Denying access\n"));
325                 x_fprintf(x_stdout, "ERR\n");
326                 return;
327         }
328         *pass='\0';
329         pass++;
330         
331         if (stdio_helper_mode == SQUID_2_5_BASIC) {
332                 rfc1738_unescape(user);
333                 rfc1738_unescape(pass);
334         }
335         
336         if (check_plaintext_auth(user, pass, False)) {
337                 x_fprintf(x_stdout, "OK\n");
338         } else {
339                 x_fprintf(x_stdout, "ERR\n");
340         }
341 }
342
343 static void manage_gensec_client_request(enum stdio_helper_mode stdio_helper_mode, 
344                                          char *buf, int length) 
345 {
346         DATA_BLOB in;
347         DATA_BLOB out;
348         char *out_base64;
349         static struct gensec_security gensec_state;
350         NTSTATUS nt_status;
351         BOOL first = False;
352
353         if (strlen(buf) < 2) {
354                 DEBUG(1, ("query [%s] invalid", buf));
355                 x_fprintf(x_stdout, "BH\n");
356                 return;
357         }
358
359         if (strlen(buf) > 3) {
360                 in = base64_decode_data_blob(buf + 3);
361         } else {
362                 in = data_blob(NULL, 0);
363         }
364
365         if (strncmp(buf, "PW ", 3) == 0) {
366
367                 /* We asked for a password and obviously got it :-) */
368
369                 opt_password = strndup((const char *)in.data, in.length);
370                 
371                 if (opt_password == NULL) {
372                         DEBUG(1, ("Out of memory\n"));
373                         x_fprintf(x_stdout, "BH\n");
374                         data_blob_free(&in);
375                         return;
376                 }
377
378                 x_fprintf(x_stdout, "OK\n");
379                 data_blob_free(&in);
380                 return;
381         }
382         if (strncmp(buf, "YR", 2) == 0) {
383                 if (gensec_state.ops) {
384                         gensec_state.ops->end(&gensec_state);
385                         gensec_state.ops = NULL;
386                 }
387         } else if ( (strncmp(buf, "TT ", 3) != 0) &&
388              (strncmp(buf, "AF ", 3) != 0) &&
389              (strncmp(buf, "NA ", 3) != 0) ) {
390                 DEBUG(1, ("SPNEGO request [%s] invalid\n", buf));
391                 x_fprintf(x_stdout, "BH\n");
392                 data_blob_free(&in);
393                 return;
394         }
395
396         if (!opt_password) {
397                 x_fprintf(x_stdout, "PW\n");
398                 data_blob_free(&in);
399                 return;
400         }
401
402         /* setup gensec */
403         if (!gensec_state.ops) {
404                 if (stdio_helper_mode == GSS_SPNEGO_CLIENT) {
405                         gensec_state.ops = gensec_security_by_oid(OID_SPNEGO);
406                 } else if (stdio_helper_mode == NTLMSSP_CLIENT_1) {
407                         gensec_state.ops = gensec_security_by_oid(OID_NTLMSSP);
408                 } else {
409                         exit(1);
410                 }
411                 gensec_state.user.name = opt_username;
412                 gensec_state.user.domain = opt_domain;
413                 gensec_state.user.password = opt_password;
414                 nt_status = gensec_state.ops->client_start(&gensec_state);
415
416                 if (!NT_STATUS_IS_OK(nt_status)) {
417                         DEBUG(1, ("SPENGO login failed to initialise: %s\n", nt_errstr(nt_status)));
418                         x_fprintf(x_stdout, "BH\n");
419                         return;
420                 }
421                 if (!in.length) {
422                         first = True;
423                 }
424         }
425         
426         /* update */
427
428         nt_status = gensec_state.ops->update(&gensec_state, NULL, in, &out);
429         
430         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
431
432                 out_base64 = base64_encode_data_blob(out);
433                 if (first) {
434                         x_fprintf(x_stdout, "YR %s\n", out_base64);
435                 } else { 
436                         x_fprintf(x_stdout, "KK %s\n", out_base64);
437                 }
438                 SAFE_FREE(out_base64);
439
440
441         } else if (!NT_STATUS_IS_OK(nt_status)) {
442                 DEBUG(1, ("SPENGO login failed: %s\n", nt_errstr(nt_status)));
443                 x_fprintf(x_stdout, "BH\n");
444         } else {
445                 x_fprintf(x_stdout, "AF\n");
446         }
447
448         return;
449 }
450
451 static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode, 
452                                          char *buf, int length) 
453 {
454         char *request, *parameter;      
455         static DATA_BLOB challenge;
456         static DATA_BLOB lm_response;
457         static DATA_BLOB nt_response;
458         static char *full_username;
459         static char *username;
460         static char *domain;
461         static char *plaintext_password;
462         static BOOL ntlm_server_1_user_session_key;
463         static BOOL ntlm_server_1_lm_session_key;
464         
465         if (strequal(buf, ".")) {
466                 if (!full_username && !username) {      
467                         x_fprintf(x_stdout, "Error: No username supplied!\n");
468                 } else if (plaintext_password) {
469                         /* handle this request as plaintext */
470                         if (!full_username) {
471                                 if (asprintf(&full_username, "%s%c%s", domain, *lp_winbind_separator(), username) == -1) {
472                                         x_fprintf(x_stdout, "Error: Out of memory in asprintf!\n.\n");
473                                         return;
474                                 }
475                         }
476                         if (check_plaintext_auth(full_username, plaintext_password, False)) {
477                                 x_fprintf(x_stdout, "Authenticated: Yes\n");
478                         } else {
479                                 x_fprintf(x_stdout, "Authenticated: No\n");
480                         }
481                 } else if (!lm_response.data && !nt_response.data) {
482                         x_fprintf(x_stdout, "Error: No password supplied!\n");
483                 } else if (!challenge.data) {   
484                         x_fprintf(x_stdout, "Error: No lanman-challenge supplied!\n");
485                 } else {
486                         char *error_string = NULL;
487                         DATA_BLOB lm_key;
488                         DATA_BLOB user_session_key;
489                         uint32 flags = 0;
490
491                         if (full_username && !username) {
492                                 fstring fstr_user;
493                                 fstring fstr_domain;
494                                 
495                                 if (!parse_ntlm_auth_domain_user(full_username, fstr_user, fstr_domain)) {
496                                         /* username might be 'tainted', don't print into our new-line deleimianted stream */
497                                         x_fprintf(x_stdout, "Error: Could not parse into domain and username\n");
498                                 }
499                                 SAFE_FREE(username);
500                                 SAFE_FREE(domain);
501                                 username = smb_xstrdup(fstr_user);
502                                 domain = smb_xstrdup(fstr_domain);
503                         }
504
505                         if (!domain) {
506                                 domain = smb_xstrdup(lp_workgroup());
507                         }
508
509                         if (ntlm_server_1_lm_session_key) 
510                                 flags |= NTLM_AUTH_FLAG_LMKEY;
511                         
512                         if (ntlm_server_1_user_session_key) 
513                                 flags |= NTLM_AUTH_FLAG_USER_SESSION_KEY;
514
515                         if (!NT_STATUS_IS_OK(
516                                     local_pw_check_specified(username, 
517                                                               domain, 
518                                                               global_myname(),
519                                                               &challenge, 
520                                                               &lm_response, 
521                                                               &nt_response, 
522                                                               flags, 
523                                                               &lm_key, 
524                                                               &user_session_key,
525                                                               &error_string,
526                                                               NULL))) {
527
528                                 x_fprintf(x_stdout, "Authenticated: No\n");
529                                 x_fprintf(x_stdout, "Authentication-Error: %s\n.\n", error_string);
530                                 SAFE_FREE(error_string);
531                         } else {
532                                 static char zeros[16];
533                                 char *hex_lm_key;
534                                 char *hex_user_session_key;
535
536                                 x_fprintf(x_stdout, "Authenticated: Yes\n");
537
538                                 if (ntlm_server_1_lm_session_key 
539                                     && lm_key.length 
540                                     && (memcmp(zeros, lm_key.data, 
541                                                                 lm_key.length) != 0)) {
542                                         hex_encode(lm_key.data,
543                                                    lm_key.length,
544                                                    &hex_lm_key);
545                                         x_fprintf(x_stdout, "LANMAN-Session-Key: %s\n", hex_lm_key);
546                                         SAFE_FREE(hex_lm_key);
547                                 }
548
549                                 if (ntlm_server_1_user_session_key 
550                                     && user_session_key.length 
551                                     && (memcmp(zeros, user_session_key.data, 
552                                                user_session_key.length) != 0)) {
553                                         hex_encode(user_session_key.data, 
554                                                    user_session_key.length, 
555                                                    &hex_user_session_key);
556                                         x_fprintf(x_stdout, "User-Session-Key: %s\n", hex_user_session_key);
557                                         SAFE_FREE(hex_user_session_key);
558                                 }
559                         }
560                 }
561                 /* clear out the state */
562                 challenge = data_blob(NULL, 0);
563                 nt_response = data_blob(NULL, 0);
564                 lm_response = data_blob(NULL, 0);
565                 SAFE_FREE(full_username);
566                 SAFE_FREE(username);
567                 SAFE_FREE(domain);
568                 SAFE_FREE(plaintext_password);
569                 ntlm_server_1_user_session_key = False;
570                 ntlm_server_1_lm_session_key = False;
571                 x_fprintf(x_stdout, ".\n");
572
573                 return;
574         }
575
576         request = buf;
577
578         /* Indicates a base64 encoded structure */
579         parameter = strstr(request, ":: ");
580         if (!parameter) {
581                 parameter = strstr(request, ": ");
582                 
583                 if (!parameter) {
584                         DEBUG(0, ("Parameter not found!\n"));
585                         x_fprintf(x_stdout, "Error: Parameter not found!\n.\n");
586                         return;
587                 }
588                 
589                 parameter[0] ='\0';
590                 parameter++;
591                 parameter[0] ='\0';
592                 parameter++;
593
594         } else {
595                 parameter[0] ='\0';
596                 parameter++;
597                 parameter[0] ='\0';
598                 parameter++;
599                 parameter[0] ='\0';
600                 parameter++;
601
602                 base64_decode_inplace(parameter);
603         }
604
605         if (strequal(request, "LANMAN-Challenge")) {
606                 challenge = strhex_to_data_blob(parameter);
607                 if (challenge.length != 8) {
608                         x_fprintf(x_stdout, "Error: hex decode of %s failed! (got %d bytes, expected 8)\n.\n", 
609                                   parameter,
610                                   (int)challenge.length);
611                         challenge = data_blob(NULL, 0);
612                 }
613         } else if (strequal(request, "NT-Response")) {
614                 nt_response = strhex_to_data_blob(parameter);
615                 if (nt_response.length < 24) {
616                         x_fprintf(x_stdout, "Error: hex decode of %s failed! (only got %d bytes, needed at least 24)\n.\n", 
617                                   parameter,
618                                   (int)nt_response.length);
619                         nt_response = data_blob(NULL, 0);
620                 }
621         } else if (strequal(request, "LANMAN-Response")) {
622                 lm_response = strhex_to_data_blob(parameter);
623                 if (lm_response.length != 24) {
624                         x_fprintf(x_stdout, "Error: hex decode of %s failed! (got %d bytes, expected 24)\n.\n", 
625                                   parameter,
626                                   (int)lm_response.length);
627                         lm_response = data_blob(NULL, 0);
628                 }
629         } else if (strequal(request, "Password")) {
630                 plaintext_password = smb_xstrdup(parameter);
631         } else if (strequal(request, "NT-Domain")) {
632                 domain = smb_xstrdup(parameter);
633         } else if (strequal(request, "Username")) {
634                 username = smb_xstrdup(parameter);
635         } else if (strequal(request, "Full-Username")) {
636                 full_username = smb_xstrdup(parameter);
637         } else if (strequal(request, "Request-User-Session-Key")) {
638                 ntlm_server_1_user_session_key = strequal(parameter, "Yes");
639         } else if (strequal(request, "Request-LanMan-Session-Key")) {
640                 ntlm_server_1_lm_session_key = strequal(parameter, "Yes");
641         } else {
642                 x_fprintf(x_stdout, "Error: Unknown request %s\n.\n", request);
643         }
644 }
645
646 static void manage_squid_request(enum stdio_helper_mode helper_mode, stdio_helper_function fn) 
647 {
648         char buf[SQUID_BUFFER_SIZE+1];
649         int length;
650         char *c;
651         static BOOL err;
652
653         /* this is not a typo - x_fgets doesn't work too well under squid */
654         if (fgets(buf, sizeof(buf)-1, stdin) == NULL) {
655                 if (ferror(stdin)) {
656                         DEBUG(1, ("fgets() failed! dying..... errno=%d (%s)\n", ferror(stdin),
657                                   strerror(ferror(stdin))));
658                         
659                         exit(1);    /* BIIG buffer */
660                 }
661                 exit(0);
662         }
663     
664         c=memchr(buf,'\n',sizeof(buf)-1);
665         if (c) {
666                 *c = '\0';
667                 length = c-buf;
668         } else {
669                 err = 1;
670                 return;
671         }
672         if (err) {
673                 DEBUG(2, ("Oversized message\n"));
674                 x_fprintf(x_stderr, "ERR\n");
675                 err = 0;
676                 return;
677         }
678
679         DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf,length));
680
681         if (buf[0] == '\0') {
682                 DEBUG(2, ("Invalid Request\n"));
683                 x_fprintf(x_stderr, "ERR\n");
684                 return;
685         }
686         
687         fn(helper_mode, buf, length);
688 }
689
690
691 static void squid_stream(enum stdio_helper_mode stdio_mode, stdio_helper_function fn) {
692         /* initialize FDescs */
693         x_setbuf(x_stdout, NULL);
694         x_setbuf(x_stderr, NULL);
695         while(1) {
696                 manage_squid_request(stdio_mode, fn);
697         }
698 }
699
700
701 /* Main program */
702
703 enum {
704         OPT_USERNAME = 1000,
705         OPT_DOMAIN,
706         OPT_WORKSTATION,
707         OPT_CHALLENGE,
708         OPT_RESPONSE,
709         OPT_LM,
710         OPT_NT,
711         OPT_PASSWORD,
712         OPT_LM_KEY,
713         OPT_USER_SESSION_KEY,
714         OPT_DIAGNOSTICS,
715         OPT_REQUIRE_MEMBERSHIP
716 };
717
718  int main(int argc, const char **argv)
719 {
720         static const char *helper_protocol;
721         int opt;
722
723         poptContext pc;
724
725         /* NOTE: DO NOT change this interface without considering the implications!
726            This is an external interface, which other programs will use to interact 
727            with this helper.
728         */
729
730         /* We do not use single-letter command abbreviations, because they harm future 
731            interface stability. */
732
733         struct poptOption long_options[] = {
734                 POPT_AUTOHELP
735                 { "helper-protocol", 0, POPT_ARG_STRING, &helper_protocol, OPT_DOMAIN, "operate as a stdio-based helper", "helper protocol to use"},
736                 { "domain", 0, POPT_ARG_STRING, &opt_domain, OPT_DOMAIN, "domain name"},
737                 { "workstation", 0, POPT_ARG_STRING, &opt_workstation, OPT_WORKSTATION, "workstation"},
738                 { "username", 0, POPT_ARG_STRING, &opt_username, OPT_PASSWORD, "Username"},             
739                 { "password", 0, POPT_ARG_STRING, &opt_password, OPT_PASSWORD, "User's plaintext password"},            
740                 POPT_COMMON_SAMBA
741                 POPT_TABLEEND
742         };
743
744         /* Samba client initialisation */
745
746         setup_logging("ntlm_auth", DEBUG_STDOUT);
747
748         if (!lp_load(dyn_CONFIGFILE, True, False, False)) {
749                 d_fprintf(stderr, "wbinfo: error opening config file %s. Error was %s\n",
750                         dyn_CONFIGFILE, strerror(errno));
751                 exit(1);
752         }
753
754         /* Parse options */
755
756         pc = poptGetContext("ntlm_auth", argc, argv, long_options, 0);
757
758         /* Parse command line options */
759
760         if (argc == 1) {
761                 poptPrintHelp(pc, stderr, 0);
762                 return 1;
763         }
764
765         pc = poptGetContext(NULL, argc, (const char **)argv, long_options, 
766                             POPT_CONTEXT_KEEP_FIRST);
767
768         while((opt = poptGetNextOpt(pc)) != -1) {
769                 if (opt < -1) {
770                         break;
771                 }
772         }
773         if (opt < -1) {
774                 fprintf(stderr, "%s: %s\n",
775                         poptBadOption(pc, POPT_BADOPTION_NOALIAS),
776                         poptStrerror(opt));
777                 return 1;
778         }
779
780         if (opt_domain == NULL) {
781                 opt_domain = lp_workgroup();
782         }
783
784         if (helper_protocol) {
785                 int i;
786                 for (i=0; i<NUM_HELPER_MODES; i++) {
787                         if (strcmp(helper_protocol, stdio_helper_protocols[i].name) == 0) {
788                                 squid_stream(stdio_helper_protocols[i].mode, stdio_helper_protocols[i].fn);
789                                 exit(0);
790                         }
791                 }
792                 x_fprintf(x_stderr, "unknown helper protocol [%s]\n\nValid helper protools:\n\n", helper_protocol);
793
794                 for (i=0; i<NUM_HELPER_MODES; i++) {
795                         x_fprintf(x_stderr, "%s\n", stdio_helper_protocols[i].name);
796                 }
797
798                 exit(1);
799         }
800
801         if (!opt_username) {
802                 x_fprintf(x_stderr, "username must be specified!\n\n");
803                 poptPrintHelp(pc, stderr, 0);
804                 exit(1);
805         }
806
807         if (opt_workstation == NULL) {
808                 opt_workstation = lp_netbios_name();
809         }
810
811         if (!opt_password) {
812                 opt_password = getpass("password: ");
813         }
814
815         {
816                 char *user;
817
818                 asprintf(&user, "%s%c%s", opt_domain, *lp_winbind_separator(), opt_username);
819                 if (!check_plaintext_auth(user, opt_password, True)) {
820                         return 1;
821                 }
822         }
823
824         /* Exit code */
825
826         poptFreeContext(pc);
827         return 0;
828 }