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