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