2 Unix SMB/CIFS implementation.
4 Winbind status program.
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
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 3 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include "utils/ntlm_auth.h"
28 #include "../libcli/auth/libcli_auth.h"
29 #include "../libcli/auth/spnego.h"
32 #include <iniparser.h>
34 #ifndef PAM_WINBIND_CONFIG_FILE
35 #define PAM_WINBIND_CONFIG_FILE "/etc/security/pam_winbind.conf"
38 #define WINBIND_KRB5_AUTH 0x00000080
41 #define DBGC_CLASS DBGC_WINBIND
43 #define INITIAL_BUFFER_SIZE 300
44 #define MAX_BUFFER_SIZE 630000
46 enum stdio_helper_mode
{
54 NTLM_CHANGE_PASSWORD_1
,
58 enum ntlm_auth_cli_state
{
65 enum ntlm_auth_svr_state
{
72 struct ntlm_auth_state
{
74 enum stdio_helper_mode helper_mode
;
75 enum ntlm_auth_cli_state cli_state
;
76 enum ntlm_auth_svr_state svr_state
;
77 struct ntlmssp_state
*ntlmssp_state
;
79 char *want_feature_list
;
80 bool have_session_key
;
81 DATA_BLOB session_key
;
82 DATA_BLOB initial_message
;
85 typedef void (*stdio_helper_function
)(struct ntlm_auth_state
*state
, char *buf
,
88 static void manage_squid_basic_request (struct ntlm_auth_state
*state
,
89 char *buf
, int length
);
91 static void manage_squid_ntlmssp_request (struct ntlm_auth_state
*state
,
92 char *buf
, int length
);
94 static void manage_client_ntlmssp_request (struct ntlm_auth_state
*state
,
95 char *buf
, int length
);
97 static void manage_gss_spnego_request (struct ntlm_auth_state
*state
,
98 char *buf
, int length
);
100 static void manage_gss_spnego_client_request (struct ntlm_auth_state
*state
,
101 char *buf
, int length
);
103 static void manage_ntlm_server_1_request (struct ntlm_auth_state
*state
,
104 char *buf
, int length
);
106 static void manage_ntlm_change_password_1_request(struct ntlm_auth_state
*state
,
107 char *buf
, int length
);
109 static const struct {
110 enum stdio_helper_mode mode
;
112 stdio_helper_function fn
;
113 } stdio_helper_protocols
[] = {
114 { SQUID_2_4_BASIC
, "squid-2.4-basic", manage_squid_basic_request
},
115 { SQUID_2_5_BASIC
, "squid-2.5-basic", manage_squid_basic_request
},
116 { SQUID_2_5_NTLMSSP
, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request
},
117 { NTLMSSP_CLIENT_1
, "ntlmssp-client-1", manage_client_ntlmssp_request
},
118 { GSS_SPNEGO
, "gss-spnego", manage_gss_spnego_request
},
119 { GSS_SPNEGO_CLIENT
, "gss-spnego-client", manage_gss_spnego_client_request
},
120 { NTLM_SERVER_1
, "ntlm-server-1", manage_ntlm_server_1_request
},
121 { NTLM_CHANGE_PASSWORD_1
, "ntlm-change-password-1", manage_ntlm_change_password_1_request
},
122 { NUM_HELPER_MODES
, NULL
, NULL
}
125 const char *opt_username
;
126 const char *opt_domain
;
127 const char *opt_workstation
;
128 const char *opt_password
;
129 static DATA_BLOB opt_challenge
;
130 static DATA_BLOB opt_lm_response
;
131 static DATA_BLOB opt_nt_response
;
132 static int request_lm_key
;
133 static int request_user_session_key
;
134 static int use_cached_creds
;
136 static const char *require_membership_of
;
137 static const char *require_membership_of_sid
;
138 static const char *opt_pam_winbind_conf
;
140 static char winbind_separator(void)
142 struct winbindd_response response
;
149 ZERO_STRUCT(response
);
151 /* Send off request */
153 if (winbindd_request_response(WINBINDD_INFO
, NULL
, &response
) !=
154 NSS_STATUS_SUCCESS
) {
155 d_printf("could not obtain winbind separator!\n");
156 return *lp_winbind_separator();
159 sep
= response
.data
.info
.winbind_separator
;
163 d_printf("winbind separator was NULL!\n");
164 return *lp_winbind_separator();
170 const char *get_winbind_domain(void)
172 struct winbindd_response response
;
174 static fstring winbind_domain
;
175 if (*winbind_domain
) {
176 return winbind_domain
;
179 ZERO_STRUCT(response
);
181 /* Send off request */
183 if (winbindd_request_response(WINBINDD_DOMAIN_NAME
, NULL
, &response
) !=
184 NSS_STATUS_SUCCESS
) {
185 DEBUG(0, ("could not obtain winbind domain name!\n"));
186 return lp_workgroup();
189 fstrcpy(winbind_domain
, response
.data
.domain_name
);
191 return winbind_domain
;
195 const char *get_winbind_netbios_name(void)
197 struct winbindd_response response
;
199 static fstring winbind_netbios_name
;
201 if (*winbind_netbios_name
) {
202 return winbind_netbios_name
;
205 ZERO_STRUCT(response
);
207 /* Send off request */
209 if (winbindd_request_response(WINBINDD_NETBIOS_NAME
, NULL
, &response
) !=
210 NSS_STATUS_SUCCESS
) {
211 DEBUG(0, ("could not obtain winbind netbios name!\n"));
212 return global_myname();
215 fstrcpy(winbind_netbios_name
, response
.data
.netbios_name
);
217 return winbind_netbios_name
;
221 DATA_BLOB
get_challenge(void)
223 static DATA_BLOB chal
;
224 if (opt_challenge
.length
)
225 return opt_challenge
;
227 chal
= data_blob(NULL
, 8);
229 generate_random_buffer(chal
.data
, chal
.length
);
233 /* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
234 form DOMAIN/user into a domain and a user */
236 static bool parse_ntlm_auth_domain_user(const char *domuser
, fstring domain
,
240 char *p
= strchr(domuser
,winbind_separator());
247 fstrcpy(domain
, domuser
);
248 domain
[PTR_DIFF(p
, domuser
)] = 0;
254 static bool get_require_membership_sid(void) {
255 struct winbindd_request request
;
256 struct winbindd_response response
;
258 if (!require_membership_of
) {
262 if (require_membership_of_sid
) {
266 /* Otherwise, ask winbindd for the name->sid request */
268 ZERO_STRUCT(request
);
269 ZERO_STRUCT(response
);
271 if (!parse_ntlm_auth_domain_user(require_membership_of
,
272 request
.data
.name
.dom_name
,
273 request
.data
.name
.name
)) {
274 DEBUG(0, ("Could not parse %s into seperate domain/name parts!\n",
275 require_membership_of
));
279 if (winbindd_request_response(WINBINDD_LOOKUPNAME
, &request
, &response
) !=
280 NSS_STATUS_SUCCESS
) {
281 DEBUG(0, ("Winbindd lookupname failed to resolve %s into a SID!\n",
282 require_membership_of
));
286 require_membership_of_sid
= SMB_STRDUP(response
.data
.sid
.sid
);
288 if (require_membership_of_sid
)
295 * Get some configuration from pam_winbind.conf to see if we
296 * need to contact trusted domain
299 int get_pam_winbind_config()
302 dictionary
*d
= NULL
;
304 if (!opt_pam_winbind_conf
|| !*opt_pam_winbind_conf
) {
305 opt_pam_winbind_conf
= PAM_WINBIND_CONFIG_FILE
;
308 d
= iniparser_load(CONST_DISCARD(char *, opt_pam_winbind_conf
));
314 if (iniparser_getboolean(d
, CONST_DISCARD(char *, "global:krb5_auth"), false)) {
315 ctrl
|= WINBIND_KRB5_AUTH
;
318 iniparser_freedict(d
);
323 /* Authenticate a user with a plaintext password */
325 static bool check_plaintext_auth(const char *user
, const char *pass
,
326 bool stdout_diagnostics
)
328 struct winbindd_request request
;
329 struct winbindd_response response
;
332 if (!get_require_membership_sid()) {
336 /* Send off request */
338 ZERO_STRUCT(request
);
339 ZERO_STRUCT(response
);
341 fstrcpy(request
.data
.auth
.user
, user
);
342 fstrcpy(request
.data
.auth
.pass
, pass
);
343 if (require_membership_of_sid
) {
344 strlcpy(request
.data
.auth
.require_membership_of_sid
,
345 require_membership_of_sid
,
346 sizeof(request
.data
.auth
.require_membership_of_sid
));
349 result
= winbindd_request_response(WINBINDD_PAM_AUTH
, &request
, &response
);
351 /* Display response */
353 if (stdout_diagnostics
) {
354 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
355 d_printf("Reading winbind reply failed! (0x01)\n");
358 d_printf("%s: %s (0x%x)\n",
359 response
.data
.auth
.nt_status_string
,
360 response
.data
.auth
.error_string
,
361 response
.data
.auth
.nt_status
);
363 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
364 DEBUG(1, ("Reading winbind reply failed! (0x01)\n"));
367 DEBUG(3, ("%s: %s (0x%x)\n",
368 response
.data
.auth
.nt_status_string
,
369 response
.data
.auth
.error_string
,
370 response
.data
.auth
.nt_status
));
373 return (result
== NSS_STATUS_SUCCESS
);
376 /* authenticate a user with an encrypted username/password */
378 NTSTATUS
contact_winbind_auth_crap(const char *username
,
380 const char *workstation
,
381 const DATA_BLOB
*challenge
,
382 const DATA_BLOB
*lm_response
,
383 const DATA_BLOB
*nt_response
,
386 uint8 user_session_key
[16],
392 struct winbindd_request request
;
393 struct winbindd_response response
;
395 if (!get_require_membership_sid()) {
396 return NT_STATUS_INVALID_PARAMETER
;
399 ZERO_STRUCT(request
);
400 ZERO_STRUCT(response
);
402 request
.flags
= flags
;
404 request
.data
.auth_crap
.logon_parameters
= MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
| MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT
;
406 if (require_membership_of_sid
)
407 fstrcpy(request
.data
.auth_crap
.require_membership_of_sid
, require_membership_of_sid
);
409 fstrcpy(request
.data
.auth_crap
.user
, username
);
410 fstrcpy(request
.data
.auth_crap
.domain
, domain
);
412 fstrcpy(request
.data
.auth_crap
.workstation
,
415 memcpy(request
.data
.auth_crap
.chal
, challenge
->data
, MIN(challenge
->length
, 8));
417 if (lm_response
&& lm_response
->length
) {
418 memcpy(request
.data
.auth_crap
.lm_resp
,
420 MIN(lm_response
->length
, sizeof(request
.data
.auth_crap
.lm_resp
)));
421 request
.data
.auth_crap
.lm_resp_len
= lm_response
->length
;
424 if (nt_response
&& nt_response
->length
) {
425 if (nt_response
->length
> sizeof(request
.data
.auth_crap
.nt_resp
)) {
426 request
.flags
= request
.flags
| WBFLAG_BIG_NTLMV2_BLOB
;
427 request
.extra_len
= nt_response
->length
;
428 request
.extra_data
.data
= SMB_MALLOC_ARRAY(char, request
.extra_len
);
429 if (request
.extra_data
.data
== NULL
) {
430 return NT_STATUS_NO_MEMORY
;
432 memcpy(request
.extra_data
.data
, nt_response
->data
,
433 nt_response
->length
);
436 memcpy(request
.data
.auth_crap
.nt_resp
,
437 nt_response
->data
, nt_response
->length
);
439 request
.data
.auth_crap
.nt_resp_len
= nt_response
->length
;
442 result
= winbindd_request_response(WINBINDD_PAM_AUTH_CRAP
, &request
, &response
);
443 SAFE_FREE(request
.extra_data
.data
);
445 /* Display response */
447 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
448 nt_status
= NT_STATUS_UNSUCCESSFUL
;
450 *error_string
= smb_xstrdup("Reading winbind reply failed!");
451 winbindd_free_response(&response
);
455 nt_status
= (NT_STATUS(response
.data
.auth
.nt_status
));
456 if (!NT_STATUS_IS_OK(nt_status
)) {
458 *error_string
= smb_xstrdup(response
.data
.auth
.error_string
);
459 winbindd_free_response(&response
);
463 if ((flags
& WBFLAG_PAM_LMKEY
) && lm_key
) {
464 memcpy(lm_key
, response
.data
.auth
.first_8_lm_hash
,
465 sizeof(response
.data
.auth
.first_8_lm_hash
));
467 if ((flags
& WBFLAG_PAM_USER_SESSION_KEY
) && user_session_key
) {
468 memcpy(user_session_key
, response
.data
.auth
.user_session_key
,
469 sizeof(response
.data
.auth
.user_session_key
));
472 if (flags
& WBFLAG_PAM_UNIX_NAME
) {
473 *unix_name
= SMB_STRDUP(response
.data
.auth
.unix_username
);
475 winbindd_free_response(&response
);
476 return NT_STATUS_NO_MEMORY
;
480 winbindd_free_response(&response
);
484 /* contact server to change user password using auth crap */
485 static NTSTATUS
contact_winbind_change_pswd_auth_crap(const char *username
,
487 const DATA_BLOB new_nt_pswd
,
488 const DATA_BLOB old_nt_hash_enc
,
489 const DATA_BLOB new_lm_pswd
,
490 const DATA_BLOB old_lm_hash_enc
,
495 struct winbindd_request request
;
496 struct winbindd_response response
;
498 if (!get_require_membership_sid())
501 *error_string
= smb_xstrdup("Can't get membership sid.");
502 return NT_STATUS_INVALID_PARAMETER
;
505 ZERO_STRUCT(request
);
506 ZERO_STRUCT(response
);
509 fstrcpy(request
.data
.chng_pswd_auth_crap
.user
, username
);
511 fstrcpy(request
.data
.chng_pswd_auth_crap
.domain
,domain
);
513 if(new_nt_pswd
.length
)
515 memcpy(request
.data
.chng_pswd_auth_crap
.new_nt_pswd
, new_nt_pswd
.data
, sizeof(request
.data
.chng_pswd_auth_crap
.new_nt_pswd
));
516 request
.data
.chng_pswd_auth_crap
.new_nt_pswd_len
= new_nt_pswd
.length
;
519 if(old_nt_hash_enc
.length
)
521 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
));
522 request
.data
.chng_pswd_auth_crap
.old_nt_hash_enc_len
= old_nt_hash_enc
.length
;
525 if(new_lm_pswd
.length
)
527 memcpy(request
.data
.chng_pswd_auth_crap
.new_lm_pswd
, new_lm_pswd
.data
, sizeof(request
.data
.chng_pswd_auth_crap
.new_lm_pswd
));
528 request
.data
.chng_pswd_auth_crap
.new_lm_pswd_len
= new_lm_pswd
.length
;
531 if(old_lm_hash_enc
.length
)
533 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
));
534 request
.data
.chng_pswd_auth_crap
.old_lm_hash_enc_len
= old_lm_hash_enc
.length
;
537 result
= winbindd_request_response(WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP
, &request
, &response
);
539 /* Display response */
541 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0))
543 nt_status
= NT_STATUS_UNSUCCESSFUL
;
545 *error_string
= smb_xstrdup("Reading winbind reply failed!");
546 winbindd_free_response(&response
);
550 nt_status
= (NT_STATUS(response
.data
.auth
.nt_status
));
551 if (!NT_STATUS_IS_OK(nt_status
))
554 *error_string
= smb_xstrdup(response
.data
.auth
.error_string
);
555 winbindd_free_response(&response
);
559 winbindd_free_response(&response
);
564 static NTSTATUS
winbind_pw_check(struct ntlmssp_state
*ntlmssp_state
, DATA_BLOB
*user_session_key
, DATA_BLOB
*lm_session_key
)
566 static const char zeros
[16] = { 0, };
568 char *error_string
= NULL
;
570 uint8 user_sess_key
[16];
571 char *unix_name
= NULL
;
573 nt_status
= contact_winbind_auth_crap(ntlmssp_state
->user
, ntlmssp_state
->domain
,
574 ntlmssp_state
->workstation
,
575 &ntlmssp_state
->chal
,
576 &ntlmssp_state
->lm_resp
,
577 &ntlmssp_state
->nt_resp
,
578 WBFLAG_PAM_LMKEY
| WBFLAG_PAM_USER_SESSION_KEY
| WBFLAG_PAM_UNIX_NAME
,
579 lm_key
, user_sess_key
,
580 &error_string
, &unix_name
);
582 if (NT_STATUS_IS_OK(nt_status
)) {
583 if (memcmp(lm_key
, zeros
, 8) != 0) {
584 *lm_session_key
= data_blob_talloc(ntlmssp_state
, NULL
, 16);
585 memcpy(lm_session_key
->data
, lm_key
, 8);
586 memset(lm_session_key
->data
+8, '\0', 8);
589 if (memcmp(user_sess_key
, zeros
, 16) != 0) {
590 *user_session_key
= data_blob_talloc(ntlmssp_state
, user_sess_key
, 16);
592 ntlmssp_state
->auth_context
= talloc_strdup(ntlmssp_state
,
595 DEBUG(NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCESS_DENIED
) ? 0 : 3,
596 ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
597 ntlmssp_state
->domain
, ntlmssp_state
->user
,
598 ntlmssp_state
->workstation
,
599 error_string
? error_string
: "unknown error (NULL)"));
600 ntlmssp_state
->auth_context
= NULL
;
603 SAFE_FREE(error_string
);
604 SAFE_FREE(unix_name
);
608 static NTSTATUS
local_pw_check(struct ntlmssp_state
*ntlmssp_state
, DATA_BLOB
*user_session_key
, DATA_BLOB
*lm_session_key
)
611 struct samr_Password lm_pw
, nt_pw
;
613 nt_lm_owf_gen (opt_password
, nt_pw
.hash
, lm_pw
.hash
);
615 nt_status
= ntlm_password_check(ntlmssp_state
,
617 &ntlmssp_state
->chal
,
618 &ntlmssp_state
->lm_resp
,
619 &ntlmssp_state
->nt_resp
,
622 ntlmssp_state
->domain
,
623 &lm_pw
, &nt_pw
, user_session_key
, lm_session_key
);
625 if (NT_STATUS_IS_OK(nt_status
)) {
626 ntlmssp_state
->auth_context
= talloc_asprintf(ntlmssp_state
,
627 "%s%c%s", ntlmssp_state
->domain
,
628 *lp_winbind_separator(),
629 ntlmssp_state
->user
);
631 DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
632 ntlmssp_state
->domain
, ntlmssp_state
->user
, ntlmssp_state
->workstation
,
633 nt_errstr(nt_status
)));
634 ntlmssp_state
->auth_context
= NULL
;
639 static NTSTATUS
ntlm_auth_start_ntlmssp_client(struct ntlmssp_state
**client_ntlmssp_state
)
642 if ( (opt_username
== NULL
) || (opt_domain
== NULL
) ) {
643 status
= NT_STATUS_UNSUCCESSFUL
;
644 DEBUG(1, ("Need username and domain for NTLMSSP\n"));
645 return NT_STATUS_INVALID_PARAMETER
;
648 status
= ntlmssp_client_start(client_ntlmssp_state
);
650 if (!NT_STATUS_IS_OK(status
)) {
651 DEBUG(1, ("Could not start NTLMSSP client: %s\n",
653 ntlmssp_end(client_ntlmssp_state
);
657 status
= ntlmssp_set_username(*client_ntlmssp_state
, opt_username
);
659 if (!NT_STATUS_IS_OK(status
)) {
660 DEBUG(1, ("Could not set username: %s\n",
662 ntlmssp_end(client_ntlmssp_state
);
666 status
= ntlmssp_set_domain(*client_ntlmssp_state
, opt_domain
);
668 if (!NT_STATUS_IS_OK(status
)) {
669 DEBUG(1, ("Could not set domain: %s\n",
671 ntlmssp_end(client_ntlmssp_state
);
676 status
= ntlmssp_set_password(*client_ntlmssp_state
, opt_password
);
678 if (!NT_STATUS_IS_OK(status
)) {
679 DEBUG(1, ("Could not set password: %s\n",
681 ntlmssp_end(client_ntlmssp_state
);
689 static NTSTATUS
ntlm_auth_start_ntlmssp_server(struct ntlmssp_state
**ntlmssp_state
)
691 NTSTATUS status
= ntlmssp_server_start(ntlmssp_state
);
693 if (!NT_STATUS_IS_OK(status
)) {
694 DEBUG(1, ("Could not start NTLMSSP server: %s\n",
699 /* Have we been given a local password, or should we ask winbind? */
701 (*ntlmssp_state
)->check_password
= local_pw_check
;
702 (*ntlmssp_state
)->get_domain
= lp_workgroup
;
703 (*ntlmssp_state
)->get_global_myname
= global_myname
;
705 (*ntlmssp_state
)->check_password
= winbind_pw_check
;
706 (*ntlmssp_state
)->get_domain
= get_winbind_domain
;
707 (*ntlmssp_state
)->get_global_myname
= get_winbind_netbios_name
;
712 /*******************************************************************
713 Used by firefox to drive NTLM auth to IIS servers.
714 *******************************************************************/
716 static NTSTATUS
do_ccache_ntlm_auth(DATA_BLOB initial_msg
, DATA_BLOB challenge_msg
,
719 struct winbindd_request wb_request
;
720 struct winbindd_response wb_response
;
724 /* get winbindd to do the ntlmssp step on our behalf */
725 ZERO_STRUCT(wb_request
);
726 ZERO_STRUCT(wb_response
);
729 * This is tricky here. If we set krb5_auth in pam_winbind.conf
730 * creds for users in trusted domain will be stored the winbindd
731 * child of the trusted domain. If we ask the primary domain for
732 * ntlm_ccache_auth, it will fail. So, we have to ask the trusted
733 * domain's child for ccache_ntlm_auth. that is to say, we have to
734 * set WBFALG_PAM_CONTACT_TRUSTDOM in request.flags.
736 ctrl
= get_pam_winbind_config();
738 if (ctrl
| WINBIND_KRB5_AUTH
) {
739 wb_request
.flags
|= WBFLAG_PAM_CONTACT_TRUSTDOM
;
742 fstr_sprintf(wb_request
.data
.ccache_ntlm_auth
.user
,
743 "%s%c%s", opt_domain
, winbind_separator(), opt_username
);
744 wb_request
.data
.ccache_ntlm_auth
.uid
= geteuid();
745 wb_request
.data
.ccache_ntlm_auth
.initial_blob_len
= initial_msg
.length
;
746 wb_request
.data
.ccache_ntlm_auth
.challenge_blob_len
= challenge_msg
.length
;
747 wb_request
.extra_len
= initial_msg
.length
+ challenge_msg
.length
;
749 if (wb_request
.extra_len
> 0) {
750 wb_request
.extra_data
.data
= SMB_MALLOC_ARRAY(char, wb_request
.extra_len
);
751 if (wb_request
.extra_data
.data
== NULL
) {
752 return NT_STATUS_NO_MEMORY
;
755 memcpy(wb_request
.extra_data
.data
, initial_msg
.data
, initial_msg
.length
);
756 memcpy(wb_request
.extra_data
.data
+ initial_msg
.length
,
757 challenge_msg
.data
, challenge_msg
.length
);
760 result
= winbindd_request_response(WINBINDD_CCACHE_NTLMAUTH
, &wb_request
, &wb_response
);
761 SAFE_FREE(wb_request
.extra_data
.data
);
763 if (result
!= NSS_STATUS_SUCCESS
) {
764 winbindd_free_response(&wb_response
);
765 return NT_STATUS_UNSUCCESSFUL
;
769 *reply
= data_blob(wb_response
.extra_data
.data
,
770 wb_response
.data
.ccache_ntlm_auth
.auth_blob_len
);
771 if (wb_response
.data
.ccache_ntlm_auth
.auth_blob_len
> 0 &&
772 reply
->data
== NULL
) {
773 winbindd_free_response(&wb_response
);
774 return NT_STATUS_NO_MEMORY
;
778 winbindd_free_response(&wb_response
);
779 return NT_STATUS_MORE_PROCESSING_REQUIRED
;
782 static void manage_squid_ntlmssp_request(struct ntlm_auth_state
*state
,
783 char *buf
, int length
)
785 DATA_BLOB request
, reply
;
788 if (strlen(buf
) < 2) {
789 DEBUG(1, ("NTLMSSP query [%s] invalid", buf
));
790 x_fprintf(x_stdout
, "BH NTLMSSP query invalid\n");
794 if (strlen(buf
) > 3) {
795 if(strncmp(buf
, "SF ", 3) == 0){
796 DEBUG(10, ("Setting flags to negotioate\n"));
797 TALLOC_FREE(state
->want_feature_list
);
798 state
->want_feature_list
= talloc_strdup(state
->mem_ctx
,
800 x_fprintf(x_stdout
, "OK\n");
803 request
= base64_decode_data_blob(buf
+ 3);
805 request
= data_blob_null
;
808 if ((strncmp(buf
, "PW ", 3) == 0)) {
809 /* The calling application wants us to use a local password
810 * (rather than winbindd) */
812 opt_password
= SMB_STRNDUP((const char *)request
.data
,
815 if (opt_password
== NULL
) {
816 DEBUG(1, ("Out of memory\n"));
817 x_fprintf(x_stdout
, "BH Out of memory\n");
818 data_blob_free(&request
);
822 x_fprintf(x_stdout
, "OK\n");
823 data_blob_free(&request
);
827 if (strncmp(buf
, "YR", 2) == 0) {
828 if (state
->ntlmssp_state
)
829 ntlmssp_end(&state
->ntlmssp_state
);
830 state
->svr_state
= SERVER_INITIAL
;
831 } else if (strncmp(buf
, "KK", 2) == 0) {
832 /* No special preprocessing required */
833 } else if (strncmp(buf
, "GF", 2) == 0) {
834 DEBUG(10, ("Requested negotiated NTLMSSP flags\n"));
836 if (state
->svr_state
== SERVER_FINISHED
) {
837 x_fprintf(x_stdout
, "GF 0x%08x\n", state
->neg_flags
);
840 x_fprintf(x_stdout
, "BH\n");
842 data_blob_free(&request
);
844 } else if (strncmp(buf
, "GK", 2) == 0) {
845 DEBUG(10, ("Requested NTLMSSP session key\n"));
846 if(state
->have_session_key
) {
847 char *key64
= base64_encode_data_blob(state
->mem_ctx
,
849 x_fprintf(x_stdout
, "GK %s\n", key64
?key64
:"<NULL>");
852 x_fprintf(x_stdout
, "BH\n");
855 data_blob_free(&request
);
858 DEBUG(1, ("NTLMSSP query [%s] invalid", buf
));
859 x_fprintf(x_stdout
, "BH NTLMSSP query invalid\n");
863 if (!state
->ntlmssp_state
) {
864 nt_status
= ntlm_auth_start_ntlmssp_server(
865 &state
->ntlmssp_state
);
866 if (!NT_STATUS_IS_OK(nt_status
)) {
867 x_fprintf(x_stdout
, "BH %s\n", nt_errstr(nt_status
));
870 ntlmssp_want_feature_list(state
->ntlmssp_state
,
871 state
->want_feature_list
);
874 DEBUG(10, ("got NTLMSSP packet:\n"));
875 dump_data(10, request
.data
, request
.length
);
877 nt_status
= ntlmssp_update(state
->ntlmssp_state
, request
, &reply
);
879 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
880 char *reply_base64
= base64_encode_data_blob(state
->mem_ctx
,
882 x_fprintf(x_stdout
, "TT %s\n", reply_base64
);
883 TALLOC_FREE(reply_base64
);
884 data_blob_free(&reply
);
885 state
->svr_state
= SERVER_CHALLENGE
;
886 DEBUG(10, ("NTLMSSP challenge\n"));
887 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCESS_DENIED
)) {
888 x_fprintf(x_stdout
, "BH %s\n", nt_errstr(nt_status
));
889 DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status
)));
891 ntlmssp_end(&state
->ntlmssp_state
);
892 } else if (!NT_STATUS_IS_OK(nt_status
)) {
893 x_fprintf(x_stdout
, "NA %s\n", nt_errstr(nt_status
));
894 DEBUG(10, ("NTLMSSP %s\n", nt_errstr(nt_status
)));
896 x_fprintf(x_stdout
, "AF %s\n",
897 (char *)state
->ntlmssp_state
->auth_context
);
898 DEBUG(10, ("NTLMSSP OK!\n"));
900 if(state
->have_session_key
)
901 data_blob_free(&state
->session_key
);
902 state
->session_key
= data_blob(
903 state
->ntlmssp_state
->session_key
.data
,
904 state
->ntlmssp_state
->session_key
.length
);
905 state
->neg_flags
= state
->ntlmssp_state
->neg_flags
;
906 state
->have_session_key
= true;
907 state
->svr_state
= SERVER_FINISHED
;
910 data_blob_free(&request
);
913 static void manage_client_ntlmssp_request(struct ntlm_auth_state
*state
,
914 char *buf
, int length
)
916 DATA_BLOB request
, reply
;
919 if (!opt_username
|| !*opt_username
) {
920 x_fprintf(x_stderr
, "username must be specified!\n\n");
924 if (strlen(buf
) < 2) {
925 DEBUG(1, ("NTLMSSP query [%s] invalid", buf
));
926 x_fprintf(x_stdout
, "BH NTLMSSP query invalid\n");
930 if (strlen(buf
) > 3) {
931 if(strncmp(buf
, "SF ", 3) == 0) {
932 DEBUG(10, ("Looking for flags to negotiate\n"));
933 talloc_free(state
->want_feature_list
);
934 state
->want_feature_list
= talloc_strdup(state
->mem_ctx
,
936 x_fprintf(x_stdout
, "OK\n");
939 request
= base64_decode_data_blob(buf
+ 3);
941 request
= data_blob_null
;
944 if (strncmp(buf
, "PW ", 3) == 0) {
945 /* We asked for a password and obviously got it :-) */
947 opt_password
= SMB_STRNDUP((const char *)request
.data
,
950 if (opt_password
== NULL
) {
951 DEBUG(1, ("Out of memory\n"));
952 x_fprintf(x_stdout
, "BH Out of memory\n");
953 data_blob_free(&request
);
957 x_fprintf(x_stdout
, "OK\n");
958 data_blob_free(&request
);
962 if (!state
->ntlmssp_state
&& use_cached_creds
) {
963 /* check whether cached credentials are usable. */
964 DATA_BLOB empty_blob
= data_blob_null
;
966 nt_status
= do_ccache_ntlm_auth(empty_blob
, empty_blob
, NULL
);
967 if (!NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
968 /* failed to use cached creds */
969 use_cached_creds
= False
;
973 if (opt_password
== NULL
&& !use_cached_creds
) {
974 /* Request a password from the calling process. After
975 sending it, the calling process should retry asking for the
978 DEBUG(10, ("Requesting password\n"));
979 x_fprintf(x_stdout
, "PW\n");
983 if (strncmp(buf
, "YR", 2) == 0) {
984 if (state
->ntlmssp_state
)
985 ntlmssp_end(&state
->ntlmssp_state
);
986 state
->cli_state
= CLIENT_INITIAL
;
987 } else if (strncmp(buf
, "TT", 2) == 0) {
988 /* No special preprocessing required */
989 } else if (strncmp(buf
, "GF", 2) == 0) {
990 DEBUG(10, ("Requested negotiated NTLMSSP flags\n"));
992 if(state
->cli_state
== CLIENT_FINISHED
) {
993 x_fprintf(x_stdout
, "GF 0x%08x\n", state
->neg_flags
);
996 x_fprintf(x_stdout
, "BH\n");
999 data_blob_free(&request
);
1001 } else if (strncmp(buf
, "GK", 2) == 0 ) {
1002 DEBUG(10, ("Requested session key\n"));
1004 if(state
->cli_state
== CLIENT_FINISHED
) {
1005 char *key64
= base64_encode_data_blob(state
->mem_ctx
,
1006 state
->session_key
);
1007 x_fprintf(x_stdout
, "GK %s\n", key64
?key64
:"<NULL>");
1011 x_fprintf(x_stdout
, "BH\n");
1014 data_blob_free(&request
);
1017 DEBUG(1, ("NTLMSSP query [%s] invalid", buf
));
1018 x_fprintf(x_stdout
, "BH NTLMSSP query invalid\n");
1022 if (!state
->ntlmssp_state
) {
1023 nt_status
= ntlm_auth_start_ntlmssp_client(
1024 &state
->ntlmssp_state
);
1025 if (!NT_STATUS_IS_OK(nt_status
)) {
1026 x_fprintf(x_stdout
, "BH %s\n", nt_errstr(nt_status
));
1029 ntlmssp_want_feature_list(state
->ntlmssp_state
,
1030 state
->want_feature_list
);
1031 state
->initial_message
= data_blob_null
;
1034 DEBUG(10, ("got NTLMSSP packet:\n"));
1035 dump_data(10, request
.data
, request
.length
);
1037 if (use_cached_creds
&& !opt_password
&&
1038 (state
->cli_state
== CLIENT_RESPONSE
)) {
1039 nt_status
= do_ccache_ntlm_auth(state
->initial_message
, request
,
1042 nt_status
= ntlmssp_update(state
->ntlmssp_state
, request
,
1046 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1047 char *reply_base64
= base64_encode_data_blob(state
->mem_ctx
,
1049 if (state
->cli_state
== CLIENT_INITIAL
) {
1050 x_fprintf(x_stdout
, "YR %s\n", reply_base64
);
1051 state
->initial_message
= reply
;
1052 state
->cli_state
= CLIENT_RESPONSE
;
1054 x_fprintf(x_stdout
, "KK %s\n", reply_base64
);
1055 data_blob_free(&reply
);
1057 TALLOC_FREE(reply_base64
);
1058 DEBUG(10, ("NTLMSSP challenge\n"));
1059 } else if (NT_STATUS_IS_OK(nt_status
)) {
1060 char *reply_base64
= base64_encode_data_blob(talloc_tos(),
1062 x_fprintf(x_stdout
, "AF %s\n", reply_base64
);
1063 TALLOC_FREE(reply_base64
);
1065 if(state
->have_session_key
)
1066 data_blob_free(&state
->session_key
);
1068 state
->session_key
= data_blob(
1069 state
->ntlmssp_state
->session_key
.data
,
1070 state
->ntlmssp_state
->session_key
.length
);
1071 state
->neg_flags
= state
->ntlmssp_state
->neg_flags
;
1072 state
->have_session_key
= true;
1074 DEBUG(10, ("NTLMSSP OK!\n"));
1075 state
->cli_state
= CLIENT_FINISHED
;
1076 if (state
->ntlmssp_state
)
1077 ntlmssp_end(&state
->ntlmssp_state
);
1079 x_fprintf(x_stdout
, "BH %s\n", nt_errstr(nt_status
));
1080 DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status
)));
1081 state
->cli_state
= CLIENT_ERROR
;
1082 if (state
->ntlmssp_state
)
1083 ntlmssp_end(&state
->ntlmssp_state
);
1086 data_blob_free(&request
);
1089 static void manage_squid_basic_request(struct ntlm_auth_state
*state
,
1090 char *buf
, int length
)
1095 pass
=(char *)memchr(buf
,' ',length
);
1097 DEBUG(2, ("Password not found. Denying access\n"));
1098 x_fprintf(x_stdout
, "ERR\n");
1104 if (state
->helper_mode
== SQUID_2_5_BASIC
) {
1105 rfc1738_unescape(user
);
1106 rfc1738_unescape(pass
);
1109 if (check_plaintext_auth(user
, pass
, False
)) {
1110 x_fprintf(x_stdout
, "OK\n");
1112 x_fprintf(x_stdout
, "ERR\n");
1116 static void offer_gss_spnego_mechs(void) {
1119 struct spnego_data spnego
;
1122 TALLOC_CTX
*ctx
= talloc_tos();
1126 ZERO_STRUCT(spnego
);
1128 myname_lower
= talloc_strdup(ctx
, global_myname());
1129 if (!myname_lower
) {
1132 strlower_m(myname_lower
);
1134 principal
= talloc_asprintf(ctx
, "%s$@%s", myname_lower
, lp_realm());
1139 /* Server negTokenInit (mech offerings) */
1140 spnego
.type
= SPNEGO_NEG_TOKEN_INIT
;
1141 spnego
.negTokenInit
.mechTypes
= SMB_XMALLOC_ARRAY(const char *, 2);
1143 spnego
.negTokenInit
.mechTypes
[0] = smb_xstrdup(OID_KERBEROS5_OLD
);
1144 spnego
.negTokenInit
.mechTypes
[1] = smb_xstrdup(OID_NTLMSSP
);
1145 spnego
.negTokenInit
.mechTypes
[2] = NULL
;
1147 spnego
.negTokenInit
.mechTypes
[0] = smb_xstrdup(OID_NTLMSSP
);
1148 spnego
.negTokenInit
.mechTypes
[1] = NULL
;
1152 spnego
.negTokenInit
.mechListMIC
= data_blob(principal
,
1155 len
= spnego_write_data(ctx
, &token
, &spnego
);
1156 spnego_free_data(&spnego
);
1159 DEBUG(1, ("Could not write SPNEGO data blob\n"));
1160 x_fprintf(x_stdout
, "BH Could not write SPNEGO data blob\n");
1164 reply_base64
= base64_encode_data_blob(talloc_tos(), token
);
1165 x_fprintf(x_stdout
, "TT %s *\n", reply_base64
);
1167 TALLOC_FREE(reply_base64
);
1168 data_blob_free(&token
);
1169 DEBUG(10, ("sent SPNEGO negTokenInit\n"));
1173 static void manage_gss_spnego_request(struct ntlm_auth_state
*state
,
1174 char *buf
, int length
)
1176 static struct ntlmssp_state
*ntlmssp_state
= NULL
;
1177 struct spnego_data request
, response
;
1181 TALLOC_CTX
*ctx
= talloc_tos();
1184 char *domain
= NULL
;
1186 const char *reply_code
;
1188 char *reply_argument
= NULL
;
1190 if (strlen(buf
) < 2) {
1191 DEBUG(1, ("SPENGO query [%s] invalid", buf
));
1192 x_fprintf(x_stdout
, "BH SPENGO query invalid\n");
1196 if (strncmp(buf
, "YR", 2) == 0) {
1198 ntlmssp_end(&ntlmssp_state
);
1199 } else if (strncmp(buf
, "KK", 2) == 0) {
1202 DEBUG(1, ("SPENGO query [%s] invalid", buf
));
1203 x_fprintf(x_stdout
, "BH SPENGO query invalid\n");
1207 if ( (strlen(buf
) == 2)) {
1209 /* no client data, get the negTokenInit offering
1212 offer_gss_spnego_mechs();
1216 /* All subsequent requests have a blob. This might be negTokenInit or negTokenTarg */
1218 if (strlen(buf
) <= 3) {
1219 DEBUG(1, ("GSS-SPNEGO query [%s] invalid\n", buf
));
1220 x_fprintf(x_stdout
, "BH GSS-SPNEGO query invalid\n");
1224 token
= base64_decode_data_blob(buf
+ 3);
1225 len
= spnego_read_data(ctx
, token
, &request
);
1226 data_blob_free(&token
);
1229 DEBUG(1, ("GSS-SPNEGO query [%s] invalid", buf
));
1230 x_fprintf(x_stdout
, "BH GSS-SPNEGO query invalid\n");
1234 if (request
.type
== SPNEGO_NEG_TOKEN_INIT
) {
1236 /* Second request from Client. This is where the
1237 client offers its mechanism to use. */
1239 if ( (request
.negTokenInit
.mechTypes
== NULL
) ||
1240 (request
.negTokenInit
.mechTypes
[0] == NULL
) ) {
1241 DEBUG(1, ("Client did not offer any mechanism"));
1242 x_fprintf(x_stdout
, "BH Client did not offer any "
1247 status
= NT_STATUS_UNSUCCESSFUL
;
1248 if (strcmp(request
.negTokenInit
.mechTypes
[0], OID_NTLMSSP
) == 0) {
1250 if ( request
.negTokenInit
.mechToken
.data
== NULL
) {
1251 DEBUG(1, ("Client did not provide NTLMSSP data\n"));
1252 x_fprintf(x_stdout
, "BH Client did not provide "
1257 if ( ntlmssp_state
!= NULL
) {
1258 DEBUG(1, ("Client wants a new NTLMSSP challenge, but "
1259 "already got one\n"));
1260 x_fprintf(x_stdout
, "BH Client wants a new "
1261 "NTLMSSP challenge, but "
1262 "already got one\n");
1263 ntlmssp_end(&ntlmssp_state
);
1267 if (!NT_STATUS_IS_OK(status
= ntlm_auth_start_ntlmssp_server(&ntlmssp_state
))) {
1268 x_fprintf(x_stdout
, "BH %s\n", nt_errstr(status
));
1272 DEBUG(10, ("got NTLMSSP packet:\n"));
1273 dump_data(10, request
.negTokenInit
.mechToken
.data
,
1274 request
.negTokenInit
.mechToken
.length
);
1276 response
.type
= SPNEGO_NEG_TOKEN_TARG
;
1277 response
.negTokenTarg
.supportedMech
= SMB_STRDUP(OID_NTLMSSP
);
1278 response
.negTokenTarg
.mechListMIC
= data_blob_null
;
1280 status
= ntlmssp_update(ntlmssp_state
,
1281 request
.negTokenInit
.mechToken
,
1282 &response
.negTokenTarg
.responseToken
);
1286 if (strcmp(request
.negTokenInit
.mechTypes
[0], OID_KERBEROS5_OLD
) == 0) {
1288 TALLOC_CTX
*mem_ctx
= talloc_init("manage_gss_spnego_request");
1291 DATA_BLOB session_key
;
1292 struct PAC_DATA
*pac_data
= NULL
;
1294 if ( request
.negTokenInit
.mechToken
.data
== NULL
) {
1295 DEBUG(1, ("Client did not provide Kerberos data\n"));
1296 x_fprintf(x_stdout
, "BH Client did not provide "
1301 response
.type
= SPNEGO_NEG_TOKEN_TARG
;
1302 response
.negTokenTarg
.supportedMech
= SMB_STRDUP(OID_KERBEROS5_OLD
);
1303 response
.negTokenTarg
.mechListMIC
= data_blob_null
;
1304 response
.negTokenTarg
.responseToken
= data_blob_null
;
1306 status
= ads_verify_ticket(mem_ctx
, lp_realm(), 0,
1307 &request
.negTokenInit
.mechToken
,
1308 &principal
, &pac_data
, &ap_rep
,
1309 &session_key
, True
);
1311 /* Now in "principal" we have the name we are
1312 authenticated as. */
1314 if (NT_STATUS_IS_OK(status
)) {
1316 domain
= strchr_m(principal
, '@');
1318 if (domain
== NULL
) {
1319 DEBUG(1, ("Did not get a valid principal "
1320 "from ads_verify_ticket\n"));
1321 x_fprintf(x_stdout
, "BH Did not get a "
1322 "valid principal from "
1323 "ads_verify_ticket\n");
1328 domain
= SMB_STRDUP(domain
);
1329 user
= SMB_STRDUP(principal
);
1331 data_blob_free(&ap_rep
);
1334 TALLOC_FREE(mem_ctx
);
1340 if ( (request
.negTokenTarg
.supportedMech
== NULL
) ||
1341 ( strcmp(request
.negTokenTarg
.supportedMech
, OID_NTLMSSP
) != 0 ) ) {
1342 /* Kerberos should never send a negTokenTarg, OID_NTLMSSP
1343 is the only one we support that sends this stuff */
1344 DEBUG(1, ("Got a negTokenTarg for something non-NTLMSSP: %s\n",
1345 request
.negTokenTarg
.supportedMech
));
1346 x_fprintf(x_stdout
, "BH Got a negTokenTarg for "
1347 "something non-NTLMSSP\n");
1351 if (request
.negTokenTarg
.responseToken
.data
== NULL
) {
1352 DEBUG(1, ("Got a negTokenTarg without a responseToken!\n"));
1353 x_fprintf(x_stdout
, "BH Got a negTokenTarg without a "
1354 "responseToken!\n");
1358 status
= ntlmssp_update(ntlmssp_state
,
1359 request
.negTokenTarg
.responseToken
,
1360 &response
.negTokenTarg
.responseToken
);
1362 response
.type
= SPNEGO_NEG_TOKEN_TARG
;
1363 response
.negTokenTarg
.supportedMech
= SMB_STRDUP(OID_NTLMSSP
);
1364 response
.negTokenTarg
.mechListMIC
= data_blob_null
;
1366 if (NT_STATUS_IS_OK(status
)) {
1367 user
= SMB_STRDUP(ntlmssp_state
->user
);
1368 domain
= SMB_STRDUP(ntlmssp_state
->domain
);
1369 ntlmssp_end(&ntlmssp_state
);
1373 spnego_free_data(&request
);
1375 if (NT_STATUS_IS_OK(status
)) {
1376 response
.negTokenTarg
.negResult
= SPNEGO_ACCEPT_COMPLETED
;
1378 reply_argument
= talloc_asprintf(ctx
, "%s\\%s", domain
, user
);
1379 } else if (NT_STATUS_EQUAL(status
,
1380 NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1381 response
.negTokenTarg
.negResult
= SPNEGO_ACCEPT_INCOMPLETE
;
1383 reply_argument
= talloc_strdup(ctx
, "*");
1385 response
.negTokenTarg
.negResult
= SPNEGO_REJECT
;
1387 reply_argument
= talloc_strdup(ctx
, nt_errstr(status
));
1390 if (!reply_argument
) {
1391 DEBUG(1, ("Could not write SPNEGO data blob\n"));
1392 x_fprintf(x_stdout
, "BH Could not write SPNEGO data blob\n");
1399 len
= spnego_write_data(ctx
, &token
, &response
);
1400 spnego_free_data(&response
);
1403 DEBUG(1, ("Could not write SPNEGO data blob\n"));
1404 x_fprintf(x_stdout
, "BH Could not write SPNEGO data blob\n");
1408 reply_base64
= base64_encode_data_blob(talloc_tos(), token
);
1410 x_fprintf(x_stdout
, "%s %s %s\n",
1411 reply_code
, reply_base64
, reply_argument
);
1413 TALLOC_FREE(reply_base64
);
1414 data_blob_free(&token
);
1419 static struct ntlmssp_state
*client_ntlmssp_state
= NULL
;
1421 static bool manage_client_ntlmssp_init(struct spnego_data spnego
)
1424 DATA_BLOB null_blob
= data_blob_null
;
1425 DATA_BLOB to_server
;
1426 char *to_server_base64
;
1427 const char *my_mechs
[] = {OID_NTLMSSP
, NULL
};
1428 TALLOC_CTX
*ctx
= talloc_tos();
1430 DEBUG(10, ("Got spnego negTokenInit with NTLMSSP\n"));
1432 if (client_ntlmssp_state
!= NULL
) {
1433 DEBUG(1, ("Request for initial SPNEGO request where "
1434 "we already have a state\n"));
1438 if (!client_ntlmssp_state
) {
1439 if (!NT_STATUS_IS_OK(status
= ntlm_auth_start_ntlmssp_client(&client_ntlmssp_state
))) {
1440 x_fprintf(x_stdout
, "BH %s\n", nt_errstr(status
));
1446 if (opt_password
== NULL
) {
1448 /* Request a password from the calling process. After
1449 sending it, the calling process should retry with
1450 the negTokenInit. */
1452 DEBUG(10, ("Requesting password\n"));
1453 x_fprintf(x_stdout
, "PW\n");
1457 spnego
.type
= SPNEGO_NEG_TOKEN_INIT
;
1458 spnego
.negTokenInit
.mechTypes
= my_mechs
;
1459 spnego
.negTokenInit
.reqFlags
= data_blob_null
;
1460 spnego
.negTokenInit
.reqFlagsPadding
= 0;
1461 spnego
.negTokenInit
.mechListMIC
= null_blob
;
1463 status
= ntlmssp_update(client_ntlmssp_state
, null_blob
,
1464 &spnego
.negTokenInit
.mechToken
);
1466 if ( !(NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
) ||
1467 NT_STATUS_IS_OK(status
)) ) {
1468 DEBUG(1, ("Expected OK or MORE_PROCESSING_REQUIRED, got: %s\n",
1469 nt_errstr(status
)));
1470 ntlmssp_end(&client_ntlmssp_state
);
1474 spnego_write_data(ctx
, &to_server
, &spnego
);
1475 data_blob_free(&spnego
.negTokenInit
.mechToken
);
1477 to_server_base64
= base64_encode_data_blob(talloc_tos(), to_server
);
1478 data_blob_free(&to_server
);
1479 x_fprintf(x_stdout
, "KK %s\n", to_server_base64
);
1480 TALLOC_FREE(to_server_base64
);
1484 static void manage_client_ntlmssp_targ(struct spnego_data spnego
)
1487 DATA_BLOB null_blob
= data_blob_null
;
1489 DATA_BLOB to_server
;
1490 char *to_server_base64
;
1491 TALLOC_CTX
*ctx
= talloc_tos();
1493 DEBUG(10, ("Got spnego negTokenTarg with NTLMSSP\n"));
1495 if (client_ntlmssp_state
== NULL
) {
1496 DEBUG(1, ("Got NTLMSSP tArg without a client state\n"));
1497 x_fprintf(x_stdout
, "BH Got NTLMSSP tArg without a client state\n");
1501 if (spnego
.negTokenTarg
.negResult
== SPNEGO_REJECT
) {
1502 x_fprintf(x_stdout
, "NA\n");
1503 ntlmssp_end(&client_ntlmssp_state
);
1507 if (spnego
.negTokenTarg
.negResult
== SPNEGO_ACCEPT_COMPLETED
) {
1508 x_fprintf(x_stdout
, "AF\n");
1509 ntlmssp_end(&client_ntlmssp_state
);
1513 status
= ntlmssp_update(client_ntlmssp_state
,
1514 spnego
.negTokenTarg
.responseToken
,
1517 if (!NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1518 DEBUG(1, ("Expected MORE_PROCESSING_REQUIRED from "
1519 "ntlmssp_client_update, got: %s\n",
1520 nt_errstr(status
)));
1521 x_fprintf(x_stdout
, "BH Expected MORE_PROCESSING_REQUIRED from "
1522 "ntlmssp_client_update\n");
1523 data_blob_free(&request
);
1524 ntlmssp_end(&client_ntlmssp_state
);
1528 spnego
.type
= SPNEGO_NEG_TOKEN_TARG
;
1529 spnego
.negTokenTarg
.negResult
= SPNEGO_ACCEPT_INCOMPLETE
;
1530 spnego
.negTokenTarg
.supportedMech
= (char *)OID_NTLMSSP
;
1531 spnego
.negTokenTarg
.responseToken
= request
;
1532 spnego
.negTokenTarg
.mechListMIC
= null_blob
;
1534 spnego_write_data(ctx
, &to_server
, &spnego
);
1535 data_blob_free(&request
);
1537 to_server_base64
= base64_encode_data_blob(talloc_tos(), to_server
);
1538 data_blob_free(&to_server
);
1539 x_fprintf(x_stdout
, "KK %s\n", to_server_base64
);
1540 TALLOC_FREE(to_server_base64
);
1546 static bool manage_client_krb5_init(struct spnego_data spnego
)
1549 DATA_BLOB tkt
, to_server
;
1550 DATA_BLOB session_key_krb5
= data_blob_null
;
1551 struct spnego_data reply
;
1555 const char *my_mechs
[] = {OID_KERBEROS5_OLD
, NULL
};
1557 TALLOC_CTX
*ctx
= talloc_tos();
1559 if ( (spnego
.negTokenInit
.mechListMIC
.data
== NULL
) ||
1560 (spnego
.negTokenInit
.mechListMIC
.length
== 0) ) {
1561 DEBUG(1, ("Did not get a principal for krb5\n"));
1565 principal
= (char *)SMB_MALLOC(
1566 spnego
.negTokenInit
.mechListMIC
.length
+1);
1568 if (principal
== NULL
) {
1569 DEBUG(1, ("Could not malloc principal\n"));
1573 memcpy(principal
, spnego
.negTokenInit
.mechListMIC
.data
,
1574 spnego
.negTokenInit
.mechListMIC
.length
);
1575 principal
[spnego
.negTokenInit
.mechListMIC
.length
] = '\0';
1577 retval
= cli_krb5_get_ticket(principal
, 0, &tkt
, &session_key_krb5
, 0, NULL
, NULL
, NULL
);
1582 /* Let's try to first get the TGT, for that we need a
1585 if (opt_password
== NULL
) {
1586 DEBUG(10, ("Requesting password\n"));
1587 x_fprintf(x_stdout
, "PW\n");
1591 user
= talloc_asprintf(talloc_tos(), "%s@%s", opt_username
, opt_domain
);
1596 if ((retval
= kerberos_kinit_password(user
, opt_password
, 0, NULL
))) {
1597 DEBUG(10, ("Requesting TGT failed: %s\n", error_message(retval
)));
1601 retval
= cli_krb5_get_ticket(principal
, 0, &tkt
, &session_key_krb5
, 0, NULL
, NULL
, NULL
);
1604 DEBUG(10, ("Kinit suceeded, but getting a ticket failed: %s\n", error_message(retval
)));
1609 data_blob_free(&session_key_krb5
);
1613 reply
.type
= SPNEGO_NEG_TOKEN_INIT
;
1614 reply
.negTokenInit
.mechTypes
= my_mechs
;
1615 reply
.negTokenInit
.reqFlags
= data_blob_null
;
1616 reply
.negTokenInit
.reqFlagsPadding
= 0;
1617 reply
.negTokenInit
.mechToken
= tkt
;
1618 reply
.negTokenInit
.mechListMIC
= data_blob_null
;
1620 len
= spnego_write_data(ctx
, &to_server
, &reply
);
1621 data_blob_free(&tkt
);
1624 DEBUG(1, ("Could not write SPNEGO data blob\n"));
1628 reply_base64
= base64_encode_data_blob(talloc_tos(), to_server
);
1629 x_fprintf(x_stdout
, "KK %s *\n", reply_base64
);
1631 TALLOC_FREE(reply_base64
);
1632 data_blob_free(&to_server
);
1633 DEBUG(10, ("sent GSS-SPNEGO KERBEROS5 negTokenInit\n"));
1637 static void manage_client_krb5_targ(struct spnego_data spnego
)
1639 switch (spnego
.negTokenTarg
.negResult
) {
1640 case SPNEGO_ACCEPT_INCOMPLETE
:
1641 DEBUG(1, ("Got a Kerberos negTokenTarg with ACCEPT_INCOMPLETE\n"));
1642 x_fprintf(x_stdout
, "BH Got a Kerberos negTokenTarg with "
1643 "ACCEPT_INCOMPLETE\n");
1645 case SPNEGO_ACCEPT_COMPLETED
:
1646 DEBUG(10, ("Accept completed\n"));
1647 x_fprintf(x_stdout
, "AF\n");
1650 DEBUG(10, ("Rejected\n"));
1651 x_fprintf(x_stdout
, "NA\n");
1654 DEBUG(1, ("Got an invalid negTokenTarg\n"));
1655 x_fprintf(x_stdout
, "AF\n");
1661 static void manage_gss_spnego_client_request(struct ntlm_auth_state
*state
,
1662 char *buf
, int length
)
1665 struct spnego_data spnego
;
1667 TALLOC_CTX
*ctx
= talloc_tos();
1669 if (!opt_username
|| !*opt_username
) {
1670 x_fprintf(x_stderr
, "username must be specified!\n\n");
1674 if (strlen(buf
) <= 3) {
1675 DEBUG(1, ("SPNEGO query [%s] too short\n", buf
));
1676 x_fprintf(x_stdout
, "BH SPNEGO query too short\n");
1680 request
= base64_decode_data_blob(buf
+3);
1682 if (strncmp(buf
, "PW ", 3) == 0) {
1684 /* We asked for a password and obviously got it :-) */
1686 opt_password
= SMB_STRNDUP((const char *)request
.data
, request
.length
);
1688 if (opt_password
== NULL
) {
1689 DEBUG(1, ("Out of memory\n"));
1690 x_fprintf(x_stdout
, "BH Out of memory\n");
1691 data_blob_free(&request
);
1695 x_fprintf(x_stdout
, "OK\n");
1696 data_blob_free(&request
);
1700 if ( (strncmp(buf
, "TT ", 3) != 0) &&
1701 (strncmp(buf
, "AF ", 3) != 0) &&
1702 (strncmp(buf
, "NA ", 3) != 0) ) {
1703 DEBUG(1, ("SPNEGO request [%s] invalid\n", buf
));
1704 x_fprintf(x_stdout
, "BH SPNEGO request invalid\n");
1705 data_blob_free(&request
);
1709 /* So we got a server challenge to generate a SPNEGO
1710 client-to-server request... */
1712 len
= spnego_read_data(ctx
, request
, &spnego
);
1713 data_blob_free(&request
);
1716 DEBUG(1, ("Could not read SPNEGO data for [%s]\n", buf
));
1717 x_fprintf(x_stdout
, "BH Could not read SPNEGO data\n");
1721 if (spnego
.type
== SPNEGO_NEG_TOKEN_INIT
) {
1723 /* The server offers a list of mechanisms */
1725 const char **mechType
= (const char **)spnego
.negTokenInit
.mechTypes
;
1727 while (*mechType
!= NULL
) {
1730 if ( (strcmp(*mechType
, OID_KERBEROS5_OLD
) == 0) ||
1731 (strcmp(*mechType
, OID_KERBEROS5
) == 0) ) {
1732 if (manage_client_krb5_init(spnego
))
1737 if (strcmp(*mechType
, OID_NTLMSSP
) == 0) {
1738 if (manage_client_ntlmssp_init(spnego
))
1745 DEBUG(1, ("Server offered no compatible mechanism\n"));
1746 x_fprintf(x_stdout
, "BH Server offered no compatible mechanism\n");
1750 if (spnego
.type
== SPNEGO_NEG_TOKEN_TARG
) {
1752 if (spnego
.negTokenTarg
.supportedMech
== NULL
) {
1753 /* On accept/reject Windows does not send the
1754 mechanism anymore. Handle that here and
1755 shut down the mechanisms. */
1757 switch (spnego
.negTokenTarg
.negResult
) {
1758 case SPNEGO_ACCEPT_COMPLETED
:
1759 x_fprintf(x_stdout
, "AF\n");
1762 x_fprintf(x_stdout
, "NA\n");
1765 DEBUG(1, ("Got a negTokenTarg with no mech and an "
1766 "unknown negResult: %d\n",
1767 spnego
.negTokenTarg
.negResult
));
1768 x_fprintf(x_stdout
, "BH Got a negTokenTarg with"
1769 " no mech and an unknown "
1773 ntlmssp_end(&client_ntlmssp_state
);
1777 if (strcmp(spnego
.negTokenTarg
.supportedMech
,
1778 OID_NTLMSSP
) == 0) {
1779 manage_client_ntlmssp_targ(spnego
);
1784 if (strcmp(spnego
.negTokenTarg
.supportedMech
,
1785 OID_KERBEROS5_OLD
) == 0) {
1786 manage_client_krb5_targ(spnego
);
1793 DEBUG(1, ("Got an SPNEGO token I could not handle [%s]!\n", buf
));
1794 x_fprintf(x_stdout
, "BH Got an SPNEGO token I could not handle\n");
1798 spnego_free_data(&spnego
);
1802 static void manage_ntlm_server_1_request(struct ntlm_auth_state
*state
,
1803 char *buf
, int length
)
1805 char *request
, *parameter
;
1806 static DATA_BLOB challenge
;
1807 static DATA_BLOB lm_response
;
1808 static DATA_BLOB nt_response
;
1809 static char *full_username
;
1810 static char *username
;
1811 static char *domain
;
1812 static char *plaintext_password
;
1813 static bool ntlm_server_1_user_session_key
;
1814 static bool ntlm_server_1_lm_session_key
;
1816 if (strequal(buf
, ".")) {
1817 if (!full_username
&& !username
) {
1818 x_fprintf(x_stdout
, "Error: No username supplied!\n");
1819 } else if (plaintext_password
) {
1820 /* handle this request as plaintext */
1821 if (!full_username
) {
1822 if (asprintf(&full_username
, "%s%c%s", domain
, winbind_separator(), username
) == -1) {
1823 x_fprintf(x_stdout
, "Error: Out of memory in asprintf!\n.\n");
1827 if (check_plaintext_auth(full_username
, plaintext_password
, False
)) {
1828 x_fprintf(x_stdout
, "Authenticated: Yes\n");
1830 x_fprintf(x_stdout
, "Authenticated: No\n");
1832 } else if (!lm_response
.data
&& !nt_response
.data
) {
1833 x_fprintf(x_stdout
, "Error: No password supplied!\n");
1834 } else if (!challenge
.data
) {
1835 x_fprintf(x_stdout
, "Error: No lanman-challenge supplied!\n");
1837 char *error_string
= NULL
;
1839 uchar user_session_key
[16];
1842 if (full_username
&& !username
) {
1844 fstring fstr_domain
;
1846 if (!parse_ntlm_auth_domain_user(full_username
, fstr_user
, fstr_domain
)) {
1847 /* username might be 'tainted', don't print into our new-line deleimianted stream */
1848 x_fprintf(x_stdout
, "Error: Could not parse into domain and username\n");
1850 SAFE_FREE(username
);
1852 username
= smb_xstrdup(fstr_user
);
1853 domain
= smb_xstrdup(fstr_domain
);
1857 domain
= smb_xstrdup(get_winbind_domain());
1860 if (ntlm_server_1_lm_session_key
)
1861 flags
|= WBFLAG_PAM_LMKEY
;
1863 if (ntlm_server_1_user_session_key
)
1864 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
1866 if (!NT_STATUS_IS_OK(
1867 contact_winbind_auth_crap(username
,
1879 x_fprintf(x_stdout
, "Authenticated: No\n");
1880 x_fprintf(x_stdout
, "Authentication-Error: %s\n.\n", error_string
);
1882 static char zeros
[16];
1884 char *hex_user_session_key
;
1886 x_fprintf(x_stdout
, "Authenticated: Yes\n");
1888 if (ntlm_server_1_lm_session_key
1889 && (memcmp(zeros
, lm_key
,
1890 sizeof(lm_key
)) != 0)) {
1891 hex_lm_key
= hex_encode_talloc(NULL
,
1892 (const unsigned char *)lm_key
,
1894 x_fprintf(x_stdout
, "LANMAN-Session-Key: %s\n", hex_lm_key
);
1895 TALLOC_FREE(hex_lm_key
);
1898 if (ntlm_server_1_user_session_key
1899 && (memcmp(zeros
, user_session_key
,
1900 sizeof(user_session_key
)) != 0)) {
1901 hex_user_session_key
= hex_encode_talloc(NULL
,
1902 (const unsigned char *)user_session_key
,
1903 sizeof(user_session_key
));
1904 x_fprintf(x_stdout
, "User-Session-Key: %s\n", hex_user_session_key
);
1905 TALLOC_FREE(hex_user_session_key
);
1908 SAFE_FREE(error_string
);
1910 /* clear out the state */
1911 challenge
= data_blob_null
;
1912 nt_response
= data_blob_null
;
1913 lm_response
= data_blob_null
;
1914 SAFE_FREE(full_username
);
1915 SAFE_FREE(username
);
1917 SAFE_FREE(plaintext_password
);
1918 ntlm_server_1_user_session_key
= False
;
1919 ntlm_server_1_lm_session_key
= False
;
1920 x_fprintf(x_stdout
, ".\n");
1927 /* Indicates a base64 encoded structure */
1928 parameter
= strstr_m(request
, ":: ");
1930 parameter
= strstr_m(request
, ": ");
1933 DEBUG(0, ("Parameter not found!\n"));
1934 x_fprintf(x_stdout
, "Error: Parameter not found!\n.\n");
1951 base64_decode_inplace(parameter
);
1954 if (strequal(request
, "LANMAN-Challenge")) {
1955 challenge
= strhex_to_data_blob(NULL
, parameter
);
1956 if (challenge
.length
!= 8) {
1957 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (got %d bytes, expected 8)\n.\n",
1959 (int)challenge
.length
);
1960 challenge
= data_blob_null
;
1962 } else if (strequal(request
, "NT-Response")) {
1963 nt_response
= strhex_to_data_blob(NULL
, parameter
);
1964 if (nt_response
.length
< 24) {
1965 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (only got %d bytes, needed at least 24)\n.\n",
1967 (int)nt_response
.length
);
1968 nt_response
= data_blob_null
;
1970 } else if (strequal(request
, "LANMAN-Response")) {
1971 lm_response
= strhex_to_data_blob(NULL
, parameter
);
1972 if (lm_response
.length
!= 24) {
1973 x_fprintf(x_stdout
, "Error: hex decode of %s failed! (got %d bytes, expected 24)\n.\n",
1975 (int)lm_response
.length
);
1976 lm_response
= data_blob_null
;
1978 } else if (strequal(request
, "Password")) {
1979 plaintext_password
= smb_xstrdup(parameter
);
1980 } else if (strequal(request
, "NT-Domain")) {
1981 domain
= smb_xstrdup(parameter
);
1982 } else if (strequal(request
, "Username")) {
1983 username
= smb_xstrdup(parameter
);
1984 } else if (strequal(request
, "Full-Username")) {
1985 full_username
= smb_xstrdup(parameter
);
1986 } else if (strequal(request
, "Request-User-Session-Key")) {
1987 ntlm_server_1_user_session_key
= strequal(parameter
, "Yes");
1988 } else if (strequal(request
, "Request-LanMan-Session-Key")) {
1989 ntlm_server_1_lm_session_key
= strequal(parameter
, "Yes");
1991 x_fprintf(x_stdout
, "Error: Unknown request %s\n.\n", request
);
1995 static void manage_ntlm_change_password_1_request(struct ntlm_auth_state
*state
,
1996 char *buf
, int length
)
1998 char *request
, *parameter
;
1999 static DATA_BLOB new_nt_pswd
;
2000 static DATA_BLOB old_nt_hash_enc
;
2001 static DATA_BLOB new_lm_pswd
;
2002 static DATA_BLOB old_lm_hash_enc
;
2003 static char *full_username
= NULL
;
2004 static char *username
= NULL
;
2005 static char *domain
= NULL
;
2006 static char *newpswd
= NULL
;
2007 static char *oldpswd
= NULL
;
2009 if (strequal(buf
, ".")) {
2010 if(newpswd
&& oldpswd
) {
2011 uchar old_nt_hash
[16];
2012 uchar old_lm_hash
[16];
2013 uchar new_nt_hash
[16];
2014 uchar new_lm_hash
[16];
2016 new_nt_pswd
= data_blob(NULL
, 516);
2017 old_nt_hash_enc
= data_blob(NULL
, 16);
2019 /* Calculate the MD4 hash (NT compatible) of the
2021 E_md4hash(oldpswd
, old_nt_hash
);
2022 E_md4hash(newpswd
, new_nt_hash
);
2024 /* E_deshash returns false for 'long'
2025 passwords (> 14 DOS chars).
2027 Therefore, don't send a buffer
2028 encrypted with the truncated hash
2029 (it could allow an even easier
2030 attack on the password)
2032 Likewise, obey the admin's restriction
2035 if (lp_client_lanman_auth() &&
2036 E_deshash(newpswd
, new_lm_hash
) &&
2037 E_deshash(oldpswd
, old_lm_hash
)) {
2038 new_lm_pswd
= data_blob(NULL
, 516);
2039 old_lm_hash_enc
= data_blob(NULL
, 16);
2040 encode_pw_buffer(new_lm_pswd
.data
, newpswd
,
2043 arcfour_crypt(new_lm_pswd
.data
, old_nt_hash
, 516);
2044 E_old_pw_hash(new_nt_hash
, old_lm_hash
,
2045 old_lm_hash_enc
.data
);
2047 new_lm_pswd
.data
= NULL
;
2048 new_lm_pswd
.length
= 0;
2049 old_lm_hash_enc
.data
= NULL
;
2050 old_lm_hash_enc
.length
= 0;
2053 encode_pw_buffer(new_nt_pswd
.data
, newpswd
,
2056 arcfour_crypt(new_nt_pswd
.data
, old_nt_hash
, 516);
2057 E_old_pw_hash(new_nt_hash
, old_nt_hash
,
2058 old_nt_hash_enc
.data
);
2061 if (!full_username
&& !username
) {
2062 x_fprintf(x_stdout
, "Error: No username supplied!\n");
2063 } else if ((!new_nt_pswd
.data
|| !old_nt_hash_enc
.data
) &&
2064 (!new_lm_pswd
.data
|| old_lm_hash_enc
.data
) ) {
2065 x_fprintf(x_stdout
, "Error: No NT or LM password "
2066 "blobs supplied!\n");
2068 char *error_string
= NULL
;
2070 if (full_username
&& !username
) {
2072 fstring fstr_domain
;
2074 if (!parse_ntlm_auth_domain_user(full_username
,
2077 /* username might be 'tainted', don't
2078 * print into our new-line
2079 * deleimianted stream */
2080 x_fprintf(x_stdout
, "Error: Could not "
2081 "parse into domain and "
2083 SAFE_FREE(username
);
2084 username
= smb_xstrdup(full_username
);
2086 SAFE_FREE(username
);
2088 username
= smb_xstrdup(fstr_user
);
2089 domain
= smb_xstrdup(fstr_domain
);
2094 if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
2101 x_fprintf(x_stdout
, "Password-Change: No\n");
2102 x_fprintf(x_stdout
, "Password-Change-Error: "
2103 "%s\n.\n", error_string
);
2105 x_fprintf(x_stdout
, "Password-Change: Yes\n");
2108 SAFE_FREE(error_string
);
2110 /* clear out the state */
2111 new_nt_pswd
= data_blob_null
;
2112 old_nt_hash_enc
= data_blob_null
;
2113 new_lm_pswd
= data_blob_null
;
2114 old_nt_hash_enc
= data_blob_null
;
2115 SAFE_FREE(full_username
);
2116 SAFE_FREE(username
);
2120 x_fprintf(x_stdout
, ".\n");
2127 /* Indicates a base64 encoded structure */
2128 parameter
= strstr_m(request
, ":: ");
2130 parameter
= strstr_m(request
, ": ");
2133 DEBUG(0, ("Parameter not found!\n"));
2134 x_fprintf(x_stdout
, "Error: Parameter not found!\n.\n");
2150 base64_decode_inplace(parameter
);
2153 if (strequal(request
, "new-nt-password-blob")) {
2154 new_nt_pswd
= strhex_to_data_blob(NULL
, parameter
);
2155 if (new_nt_pswd
.length
!= 516) {
2156 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2157 "(got %d bytes, expected 516)\n.\n",
2159 (int)new_nt_pswd
.length
);
2160 new_nt_pswd
= data_blob_null
;
2162 } else if (strequal(request
, "old-nt-hash-blob")) {
2163 old_nt_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2164 if (old_nt_hash_enc
.length
!= 16) {
2165 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2166 "(got %d bytes, expected 16)\n.\n",
2168 (int)old_nt_hash_enc
.length
);
2169 old_nt_hash_enc
= data_blob_null
;
2171 } else if (strequal(request
, "new-lm-password-blob")) {
2172 new_lm_pswd
= strhex_to_data_blob(NULL
, parameter
);
2173 if (new_lm_pswd
.length
!= 516) {
2174 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2175 "(got %d bytes, expected 516)\n.\n",
2177 (int)new_lm_pswd
.length
);
2178 new_lm_pswd
= data_blob_null
;
2181 else if (strequal(request
, "old-lm-hash-blob")) {
2182 old_lm_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2183 if (old_lm_hash_enc
.length
!= 16)
2185 x_fprintf(x_stdout
, "Error: hex decode of %s failed! "
2186 "(got %d bytes, expected 16)\n.\n",
2188 (int)old_lm_hash_enc
.length
);
2189 old_lm_hash_enc
= data_blob_null
;
2191 } else if (strequal(request
, "nt-domain")) {
2192 domain
= smb_xstrdup(parameter
);
2193 } else if(strequal(request
, "username")) {
2194 username
= smb_xstrdup(parameter
);
2195 } else if(strequal(request
, "full-username")) {
2196 username
= smb_xstrdup(parameter
);
2197 } else if(strequal(request
, "new-password")) {
2198 newpswd
= smb_xstrdup(parameter
);
2199 } else if (strequal(request
, "old-password")) {
2200 oldpswd
= smb_xstrdup(parameter
);
2202 x_fprintf(x_stdout
, "Error: Unknown request %s\n.\n", request
);
2206 static void manage_squid_request(struct ntlm_auth_state
*state
,
2207 stdio_helper_function fn
)
2210 char tmp
[INITIAL_BUFFER_SIZE
+1];
2211 int length
, buf_size
= 0;
2214 buf
= talloc_strdup(state
->mem_ctx
, "");
2216 DEBUG(0, ("Failed to allocate input buffer.\n"));
2217 x_fprintf(x_stderr
, "ERR\n");
2223 /* this is not a typo - x_fgets doesn't work too well under
2225 if (fgets(tmp
, sizeof(tmp
)-1, stdin
) == NULL
) {
2226 if (ferror(stdin
)) {
2227 DEBUG(1, ("fgets() failed! dying..... errno=%d "
2228 "(%s)\n", ferror(stdin
),
2229 strerror(ferror(stdin
))));
2236 buf
= talloc_strdup_append_buffer(buf
, tmp
);
2237 buf_size
+= INITIAL_BUFFER_SIZE
;
2239 if (buf_size
> MAX_BUFFER_SIZE
) {
2240 DEBUG(2, ("Oversized message\n"));
2241 x_fprintf(x_stderr
, "ERR\n");
2246 c
= strchr(buf
, '\n');
2247 } while (c
== NULL
);
2252 DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf
,length
));
2254 if (buf
[0] == '\0') {
2255 DEBUG(2, ("Invalid Request\n"));
2256 x_fprintf(x_stderr
, "ERR\n");
2261 fn(state
, buf
, length
);
2266 static void squid_stream(enum stdio_helper_mode stdio_mode
, stdio_helper_function fn
) {
2267 TALLOC_CTX
*mem_ctx
;
2268 struct ntlm_auth_state
*state
;
2270 /* initialize FDescs */
2271 x_setbuf(x_stdout
, NULL
);
2272 x_setbuf(x_stderr
, NULL
);
2274 mem_ctx
= talloc_init("ntlm_auth");
2276 DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
2277 x_fprintf(x_stderr
, "ERR\n");
2281 state
= talloc_zero(mem_ctx
, struct ntlm_auth_state
);
2283 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
2284 x_fprintf(x_stderr
, "ERR\n");
2288 state
->mem_ctx
= mem_ctx
;
2289 state
->helper_mode
= stdio_mode
;
2292 manage_squid_request(state
, fn
);
2297 /* Authenticate a user with a challenge/response */
2299 static bool check_auth_crap(void)
2304 char user_session_key
[16];
2306 char *hex_user_session_key
;
2308 static uint8 zeros
[16];
2310 x_setbuf(x_stdout
, NULL
);
2313 flags
|= WBFLAG_PAM_LMKEY
;
2315 if (request_user_session_key
)
2316 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
2318 flags
|= WBFLAG_PAM_NT_STATUS_SQUASH
;
2320 nt_status
= contact_winbind_auth_crap(opt_username
, opt_domain
,
2326 (unsigned char *)lm_key
,
2327 (unsigned char *)user_session_key
,
2328 &error_string
, NULL
);
2330 if (!NT_STATUS_IS_OK(nt_status
)) {
2331 x_fprintf(x_stdout
, "%s (0x%x)\n",
2333 NT_STATUS_V(nt_status
));
2334 SAFE_FREE(error_string
);
2339 && (memcmp(zeros
, lm_key
,
2340 sizeof(lm_key
)) != 0)) {
2341 hex_lm_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)lm_key
,
2343 x_fprintf(x_stdout
, "LM_KEY: %s\n", hex_lm_key
);
2344 TALLOC_FREE(hex_lm_key
);
2346 if (request_user_session_key
2347 && (memcmp(zeros
, user_session_key
,
2348 sizeof(user_session_key
)) != 0)) {
2349 hex_user_session_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)user_session_key
,
2350 sizeof(user_session_key
));
2351 x_fprintf(x_stdout
, "NT_KEY: %s\n", hex_user_session_key
);
2352 TALLOC_FREE(hex_user_session_key
);
2361 OPT_USERNAME
= 1000,
2370 OPT_USER_SESSION_KEY
,
2372 OPT_REQUIRE_MEMBERSHIP
,
2373 OPT_USE_CACHED_CREDS
,
2374 OPT_PAM_WINBIND_CONF
2377 int main(int argc
, const char **argv
)
2379 TALLOC_CTX
*frame
= talloc_stackframe();
2381 static const char *helper_protocol
;
2382 static int diagnostics
;
2384 static const char *hex_challenge
;
2385 static const char *hex_lm_response
;
2386 static const char *hex_nt_response
;
2390 /* NOTE: DO NOT change this interface without considering the implications!
2391 This is an external interface, which other programs will use to interact
2395 /* We do not use single-letter command abbreviations, because they harm future
2396 interface stability. */
2398 struct poptOption long_options
[] = {
2400 { "helper-protocol", 0, POPT_ARG_STRING
, &helper_protocol
, OPT_DOMAIN
, "operate as a stdio-based helper", "helper protocol to use"},
2401 { "username", 0, POPT_ARG_STRING
, &opt_username
, OPT_USERNAME
, "username"},
2402 { "domain", 0, POPT_ARG_STRING
, &opt_domain
, OPT_DOMAIN
, "domain name"},
2403 { "workstation", 0, POPT_ARG_STRING
, &opt_workstation
, OPT_WORKSTATION
, "workstation"},
2404 { "challenge", 0, POPT_ARG_STRING
, &hex_challenge
, OPT_CHALLENGE
, "challenge (HEX encoded)"},
2405 { "lm-response", 0, POPT_ARG_STRING
, &hex_lm_response
, OPT_LM
, "LM Response to the challenge (HEX encoded)"},
2406 { "nt-response", 0, POPT_ARG_STRING
, &hex_nt_response
, OPT_NT
, "NT or NTLMv2 Response to the challenge (HEX encoded)"},
2407 { "password", 0, POPT_ARG_STRING
, &opt_password
, OPT_PASSWORD
, "User's plaintext password"},
2408 { "request-lm-key", 0, POPT_ARG_NONE
, &request_lm_key
, OPT_LM_KEY
, "Retrieve LM session key"},
2409 { "request-nt-key", 0, POPT_ARG_NONE
, &request_user_session_key
, OPT_USER_SESSION_KEY
, "Retrieve User (NT) session key"},
2410 { "use-cached-creds", 0, POPT_ARG_NONE
, &use_cached_creds
, OPT_USE_CACHED_CREDS
, "Use cached credentials if no password is given"},
2411 { "diagnostics", 0, POPT_ARG_NONE
, &diagnostics
, OPT_DIAGNOSTICS
, "Perform diagnostics on the authentictaion chain"},
2412 { "require-membership-of", 0, POPT_ARG_STRING
, &require_membership_of
, OPT_REQUIRE_MEMBERSHIP
, "Require that a user be a member of this group (either name or SID) for authentication to succeed" },
2413 { "pam-winbind-conf", 0, POPT_ARG_STRING
, &opt_pam_winbind_conf
, OPT_PAM_WINBIND_CONF
, "Require that request must set WBFLAG_PAM_CONTACT_TRUSTDOM when krb5 auth is required" },
2414 POPT_COMMON_CONFIGFILE
2419 /* Samba client initialisation */
2426 pc
= poptGetContext("ntlm_auth", argc
, argv
, long_options
, 0);
2428 /* Parse command line options */
2431 poptPrintHelp(pc
, stderr
, 0);
2435 while((opt
= poptGetNextOpt(pc
)) != -1) {
2436 /* Get generic config options like --configfile */
2439 poptFreeContext(pc
);
2441 if (!lp_load(get_dyn_CONFIGFILE(), True
, False
, False
, True
)) {
2442 d_fprintf(stderr
, "ntlm_auth: error opening config file %s. Error was %s\n",
2443 get_dyn_CONFIGFILE(), strerror(errno
));
2447 pc
= poptGetContext(NULL
, argc
, (const char **)argv
, long_options
,
2448 POPT_CONTEXT_KEEP_FIRST
);
2450 while((opt
= poptGetNextOpt(pc
)) != -1) {
2453 opt_challenge
= strhex_to_data_blob(NULL
, hex_challenge
);
2454 if (opt_challenge
.length
!= 8) {
2455 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2457 (int)opt_challenge
.length
);
2462 opt_lm_response
= strhex_to_data_blob(NULL
, hex_lm_response
);
2463 if (opt_lm_response
.length
!= 24) {
2464 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2466 (int)opt_lm_response
.length
);
2472 opt_nt_response
= strhex_to_data_blob(NULL
, hex_nt_response
);
2473 if (opt_nt_response
.length
< 24) {
2474 x_fprintf(x_stderr
, "hex decode of %s failed! (only got %d bytes)\n",
2476 (int)opt_nt_response
.length
);
2481 case OPT_REQUIRE_MEMBERSHIP
:
2482 if (StrnCaseCmp("S-", require_membership_of
, 2) == 0) {
2483 require_membership_of_sid
= require_membership_of
;
2490 char *domain
= SMB_STRDUP(opt_username
);
2491 char *p
= strchr_m(domain
, *lp_winbind_separator());
2495 if (opt_domain
&& !strequal(opt_domain
, domain
)) {
2496 x_fprintf(x_stderr
, "Domain specified in username (%s) "
2497 "doesn't match specified domain (%s)!\n\n",
2498 domain
, opt_domain
);
2499 poptPrintHelp(pc
, stderr
, 0);
2502 opt_domain
= domain
;
2508 /* Note: if opt_domain is "" then send no domain */
2509 if (opt_domain
== NULL
) {
2510 opt_domain
= get_winbind_domain();
2513 if (opt_workstation
== NULL
) {
2514 opt_workstation
= "";
2517 if (helper_protocol
) {
2519 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2520 if (strcmp(helper_protocol
, stdio_helper_protocols
[i
].name
) == 0) {
2521 squid_stream(stdio_helper_protocols
[i
].mode
, stdio_helper_protocols
[i
].fn
);
2525 x_fprintf(x_stderr
, "unknown helper protocol [%s]\n\nValid helper protools:\n\n", helper_protocol
);
2527 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2528 x_fprintf(x_stderr
, "%s\n", stdio_helper_protocols
[i
].name
);
2534 if (!opt_username
|| !*opt_username
) {
2535 x_fprintf(x_stderr
, "username must be specified!\n\n");
2536 poptPrintHelp(pc
, stderr
, 0);
2540 if (opt_challenge
.length
) {
2541 if (!check_auth_crap()) {
2547 if (!opt_password
) {
2548 opt_password
= getpass("password: ");
2552 if (!diagnose_ntlm_auth()) {
2558 fstr_sprintf(user
, "%s%c%s", opt_domain
, winbind_separator(), opt_username
);
2559 if (!check_plaintext_auth(user
, opt_password
, True
)) {
2566 poptFreeContext(pc
);