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
11 Copyright (C) Simo Sorce 2010
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.
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.
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/>.
28 #include "lib/param/param.h"
29 #include "popt_common.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"
39 #include "lib/util/tiniparser.h"
40 #include "../lib/crypto/arcfour.h"
41 #include "nsswitch/winbind_client.h"
42 #include "librpc/gen_ndr/krb5pac.h"
43 #include "../lib/util/asn1.h"
44 #include "auth/common_auth.h"
45 #include "source3/include/auth.h"
46 #include "source3/auth/proto.h"
47 #include "nsswitch/libwbclient/wbclient.h"
48 #include "lib/param/loadparm.h"
49 #include "lib/util/base64.h"
52 #include "auth/kerberos/pac_utils.h"
55 #ifndef PAM_WINBIND_CONFIG_FILE
56 #define PAM_WINBIND_CONFIG_FILE "/etc/security/pam_winbind.conf"
59 #define WINBIND_KRB5_AUTH 0x00000080
62 #define DBGC_CLASS DBGC_WINBIND
64 #define INITIAL_BUFFER_SIZE 300
65 #define MAX_BUFFER_SIZE 630000
67 enum stdio_helper_mode
{
75 NTLM_CHANGE_PASSWORD_1
,
79 enum ntlm_auth_cli_state
{
86 struct ntlm_auth_state
{
88 enum stdio_helper_mode helper_mode
;
89 enum ntlm_auth_cli_state cli_state
;
90 struct ntlmssp_state
*ntlmssp_state
;
92 char *want_feature_list
;
93 bool have_session_key
;
94 DATA_BLOB session_key
;
95 DATA_BLOB initial_message
;
96 void *gensec_private_1
;
98 typedef void (*stdio_helper_function
)(enum stdio_helper_mode stdio_helper_mode
,
99 struct loadparm_context
*lp_ctx
,
100 struct ntlm_auth_state
*state
, char *buf
,
101 int length
, void **private2
);
103 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode
,
104 struct loadparm_context
*lp_ctx
,
105 char *buf
, int length
, void **private1
);
107 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode
,
108 struct loadparm_context
*lp_ctx
,
109 struct ntlm_auth_state
*state
,
110 stdio_helper_function fn
, void **private2
);
112 static void manage_squid_basic_request (enum stdio_helper_mode stdio_helper_mode
,
113 struct loadparm_context
*lp_ctx
,
114 struct ntlm_auth_state
*state
,
115 char *buf
, int length
, void **private2
);
117 static void manage_squid_ntlmssp_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
);
122 static void manage_client_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
);
127 static void manage_gss_spnego_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
);
132 static void manage_gss_spnego_client_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
);
137 static void manage_ntlm_server_1_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
);
142 static void manage_ntlm_change_password_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
);
147 static const struct {
148 enum stdio_helper_mode mode
;
150 stdio_helper_function fn
;
151 } stdio_helper_protocols
[] = {
152 { SQUID_2_4_BASIC
, "squid-2.4-basic", manage_squid_basic_request
},
153 { SQUID_2_5_BASIC
, "squid-2.5-basic", manage_squid_basic_request
},
154 { SQUID_2_5_NTLMSSP
, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request
},
155 { NTLMSSP_CLIENT_1
, "ntlmssp-client-1", manage_client_ntlmssp_request
},
156 { GSS_SPNEGO_SERVER
, "gss-spnego", manage_gss_spnego_request
},
157 { GSS_SPNEGO_CLIENT
, "gss-spnego-client", manage_gss_spnego_client_request
},
158 { NTLM_SERVER_1
, "ntlm-server-1", manage_ntlm_server_1_request
},
159 { NTLM_CHANGE_PASSWORD_1
, "ntlm-change-password-1", manage_ntlm_change_password_1_request
},
160 { NUM_HELPER_MODES
, NULL
, NULL
}
163 const char *opt_username
;
164 const char *opt_domain
;
165 const char *opt_workstation
;
166 const char *opt_password
;
167 static DATA_BLOB opt_challenge
;
168 static DATA_BLOB opt_lm_response
;
169 static DATA_BLOB opt_nt_response
;
170 static int request_lm_key
;
171 static int request_user_session_key
;
172 static int use_cached_creds
;
173 static int offline_logon
;
174 static int opt_allow_mschapv2
;
176 static const char *require_membership_of
;
177 static const char *require_membership_of_sid
;
178 static const char *opt_pam_winbind_conf
;
180 const char *opt_target_service
;
181 const char *opt_target_hostname
;
184 /* This is a bit hairy, but the basic idea is to do a password callback
185 to the calling application. The callback comes from within gensec */
187 static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mode
,
188 struct loadparm_context
*lp_ctx
,
189 struct ntlm_auth_state
*state
, char *buf
, int length
,
193 if (strlen(buf
) < 2) {
194 DEBUG(1, ("query [%s] invalid", buf
));
195 printf("BH Query invalid\n");
199 if (strlen(buf
) > 3) {
200 in
= base64_decode_data_blob(buf
+ 3);
202 in
= data_blob(NULL
, 0);
205 if (strncmp(buf
, "PW ", 3) == 0) {
207 *password
= talloc_strndup(NULL
,
208 (const char *)in
.data
, in
.length
);
210 if (*password
== NULL
) {
211 DEBUG(1, ("Out of memory\n"));
212 printf("BH Out of memory\n");
221 DEBUG(1, ("Asked for (and expected) a password\n"));
222 printf("BH Expected a password\n");
227 * Callback for password credentials. This is not async, and when
228 * GENSEC and the credentials code is made async, it will look rather
232 static const char *get_password(struct cli_credentials
*credentials
)
234 TALLOC_CTX
*frame
= talloc_stackframe();
235 char *password
= NULL
;
236 struct ntlm_auth_state
*state
;
238 state
= talloc_zero(frame
, struct ntlm_auth_state
);
240 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
241 fprintf(stderr
, "ERR\n");
245 state
->mem_ctx
= state
;
247 /* Ask for a password */
250 manage_squid_request(NUM_HELPER_MODES
/* bogus */, NULL
, state
, manage_gensec_get_pw_request
, (void **)&password
);
251 talloc_steal(credentials
, password
);
257 * A limited set of features are defined with text strings as needed
261 static void gensec_want_feature_list(struct gensec_security
*state
, char* feature_list
)
263 if (in_list("NTLMSSP_FEATURE_SESSION_KEY", feature_list
, true)) {
264 DEBUG(10, ("want GENSEC_FEATURE_SESSION_KEY\n"));
265 gensec_want_feature(state
, GENSEC_FEATURE_SESSION_KEY
);
267 if (in_list("NTLMSSP_FEATURE_SIGN", feature_list
, true)) {
268 DEBUG(10, ("want GENSEC_FEATURE_SIGN\n"));
269 gensec_want_feature(state
, GENSEC_FEATURE_SIGN
);
271 if (in_list("NTLMSSP_FEATURE_SEAL", feature_list
, true)) {
272 DEBUG(10, ("want GENSEC_FEATURE_SEAL\n"));
273 gensec_want_feature(state
, GENSEC_FEATURE_SEAL
);
275 if (in_list("NTLMSSP_FEATURE_CCACHE", feature_list
, true)) {
276 DEBUG(10, ("want GENSEC_FEATURE_NTLM_CCACHE\n"));
277 gensec_want_feature(state
, GENSEC_FEATURE_NTLM_CCACHE
);
281 static char winbind_separator(void)
283 struct winbindd_response response
;
290 ZERO_STRUCT(response
);
292 /* Send off request */
294 if (winbindd_request_response(NULL
, WINBINDD_INFO
, NULL
, &response
) !=
295 NSS_STATUS_SUCCESS
) {
296 d_fprintf(stderr
, "could not obtain winbind separator!\n");
297 return *lp_winbind_separator();
300 sep
= response
.data
.info
.winbind_separator
;
304 d_fprintf(stderr
, "winbind separator was NULL!\n");
305 return *lp_winbind_separator();
311 const char *get_winbind_domain(void)
313 struct winbindd_response response
;
315 static fstring winbind_domain
;
316 if (*winbind_domain
) {
317 return winbind_domain
;
320 ZERO_STRUCT(response
);
322 /* Send off request */
324 if (winbindd_request_response(NULL
, WINBINDD_DOMAIN_NAME
, NULL
, &response
) !=
325 NSS_STATUS_SUCCESS
) {
326 DEBUG(1, ("could not obtain winbind domain name!\n"));
327 return lp_workgroup();
330 fstrcpy(winbind_domain
, response
.data
.domain_name
);
332 return winbind_domain
;
336 const char *get_winbind_netbios_name(void)
338 struct winbindd_response response
;
340 static fstring winbind_netbios_name
;
342 if (*winbind_netbios_name
) {
343 return winbind_netbios_name
;
346 ZERO_STRUCT(response
);
348 /* Send off request */
350 if (winbindd_request_response(NULL
, WINBINDD_NETBIOS_NAME
, NULL
, &response
) !=
351 NSS_STATUS_SUCCESS
) {
352 DEBUG(1, ("could not obtain winbind netbios name!\n"));
353 return lp_netbios_name();
356 fstrcpy(winbind_netbios_name
, response
.data
.netbios_name
);
358 return winbind_netbios_name
;
362 DATA_BLOB
get_challenge(void)
364 static DATA_BLOB chal
;
365 if (opt_challenge
.length
)
366 return opt_challenge
;
368 chal
= data_blob(NULL
, 8);
370 generate_random_buffer(chal
.data
, chal
.length
);
374 /* Copy of parse_domain_user from winbindd_util.c. Parse a string of the
375 form DOMAIN/user into a domain and a user */
377 static bool parse_ntlm_auth_domain_user(const char *domuser
, fstring domain
,
381 char *p
= strchr(domuser
,winbind_separator());
388 fstrcpy(domain
, domuser
);
389 domain
[PTR_DIFF(p
, domuser
)] = 0;
390 return strupper_m(domain
);
393 static bool get_require_membership_sid(void) {
394 struct winbindd_request request
;
395 struct winbindd_response response
;
397 if (!require_membership_of
) {
401 if (require_membership_of_sid
) {
405 /* Otherwise, ask winbindd for the name->sid request */
407 ZERO_STRUCT(request
);
408 ZERO_STRUCT(response
);
410 if (!parse_ntlm_auth_domain_user(require_membership_of
,
411 request
.data
.name
.dom_name
,
412 request
.data
.name
.name
)) {
413 DEBUG(0, ("Could not parse %s into separate domain/name parts!\n",
414 require_membership_of
));
418 if (winbindd_request_response(NULL
, WINBINDD_LOOKUPNAME
, &request
, &response
) !=
419 NSS_STATUS_SUCCESS
) {
420 DEBUG(0, ("Winbindd lookupname failed to resolve %s into a SID!\n",
421 require_membership_of
));
425 require_membership_of_sid
= SMB_STRDUP(response
.data
.sid
.sid
);
427 if (require_membership_of_sid
)
434 * Get some configuration from pam_winbind.conf to see if we
435 * need to contact trusted domain
438 int get_pam_winbind_config()
441 struct tiniparser_dictionary
*d
= NULL
;
443 if (!opt_pam_winbind_conf
|| !*opt_pam_winbind_conf
) {
444 opt_pam_winbind_conf
= PAM_WINBIND_CONFIG_FILE
;
447 d
= tiniparser_load(opt_pam_winbind_conf
);
453 if (tiniparser_getboolean(d
, "global:krb5_auth", false)) {
454 ctrl
|= WINBIND_KRB5_AUTH
;
457 tiniparser_freedict(d
);
462 /* Authenticate a user with a plaintext password */
464 static bool check_plaintext_auth(const char *user
, const char *pass
,
465 bool stdout_diagnostics
)
467 struct winbindd_request request
;
468 struct winbindd_response response
;
471 if (!get_require_membership_sid()) {
475 /* Send off request */
477 ZERO_STRUCT(request
);
478 ZERO_STRUCT(response
);
480 fstrcpy(request
.data
.auth
.user
, user
);
481 fstrcpy(request
.data
.auth
.pass
, pass
);
482 if (require_membership_of_sid
) {
483 strlcpy(request
.data
.auth
.require_membership_of_sid
,
484 require_membership_of_sid
,
485 sizeof(request
.data
.auth
.require_membership_of_sid
));
489 request
.flags
|= WBFLAG_PAM_CACHED_LOGIN
;
492 result
= winbindd_request_response(NULL
, WINBINDD_PAM_AUTH
, &request
, &response
);
494 /* Display response */
496 if (stdout_diagnostics
) {
497 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
498 d_fprintf(stderr
, "Reading winbind reply failed! (0x01)\n");
501 d_printf("%s: %s (0x%x)\n",
502 response
.data
.auth
.nt_status_string
,
503 response
.data
.auth
.error_string
,
504 response
.data
.auth
.nt_status
);
506 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
507 DEBUG(1, ("Reading winbind reply failed! (0x01)\n"));
510 DEBUG(3, ("%s: %s (0x%x)\n",
511 response
.data
.auth
.nt_status_string
,
512 response
.data
.auth
.error_string
,
513 response
.data
.auth
.nt_status
));
516 return (result
== NSS_STATUS_SUCCESS
);
519 /* authenticate a user with an encrypted username/password */
521 NTSTATUS
contact_winbind_auth_crap(const char *username
,
523 const char *workstation
,
524 const DATA_BLOB
*challenge
,
525 const DATA_BLOB
*lm_response
,
526 const DATA_BLOB
*nt_response
,
528 uint32_t extra_logon_parameters
,
530 uint8_t user_session_key
[16],
531 uint8_t *pauthoritative
,
537 struct winbindd_request request
;
538 struct winbindd_response response
;
542 if (!get_require_membership_sid()) {
543 return NT_STATUS_INVALID_PARAMETER
;
546 ZERO_STRUCT(request
);
547 ZERO_STRUCT(response
);
549 request
.flags
= flags
;
551 request
.data
.auth_crap
.logon_parameters
= extra_logon_parameters
552 | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
| MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT
;
554 if (opt_allow_mschapv2
) {
555 request
.data
.auth_crap
.logon_parameters
|= MSV1_0_ALLOW_MSVCHAPV2
;
558 if (require_membership_of_sid
)
559 fstrcpy(request
.data
.auth_crap
.require_membership_of_sid
, require_membership_of_sid
);
561 fstrcpy(request
.data
.auth_crap
.user
, username
);
562 fstrcpy(request
.data
.auth_crap
.domain
, domain
);
564 fstrcpy(request
.data
.auth_crap
.workstation
,
567 memcpy(request
.data
.auth_crap
.chal
, challenge
->data
, MIN(challenge
->length
, 8));
569 if (lm_response
&& lm_response
->length
) {
570 memcpy(request
.data
.auth_crap
.lm_resp
,
572 MIN(lm_response
->length
, sizeof(request
.data
.auth_crap
.lm_resp
)));
573 request
.data
.auth_crap
.lm_resp_len
= lm_response
->length
;
576 if (nt_response
&& nt_response
->length
) {
577 if (nt_response
->length
> sizeof(request
.data
.auth_crap
.nt_resp
)) {
578 request
.flags
= request
.flags
| WBFLAG_BIG_NTLMV2_BLOB
;
579 request
.extra_len
= nt_response
->length
;
580 request
.extra_data
.data
= SMB_MALLOC_ARRAY(char, request
.extra_len
);
581 if (request
.extra_data
.data
== NULL
) {
582 return NT_STATUS_NO_MEMORY
;
584 memcpy(request
.extra_data
.data
, nt_response
->data
,
585 nt_response
->length
);
588 memcpy(request
.data
.auth_crap
.nt_resp
,
589 nt_response
->data
, nt_response
->length
);
591 request
.data
.auth_crap
.nt_resp_len
= nt_response
->length
;
594 result
= winbindd_request_response(NULL
, WINBINDD_PAM_AUTH_CRAP
, &request
, &response
);
595 SAFE_FREE(request
.extra_data
.data
);
597 /* Display response */
599 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0)) {
600 nt_status
= NT_STATUS_UNSUCCESSFUL
;
602 *error_string
= smb_xstrdup("Reading winbind reply failed!");
603 winbindd_free_response(&response
);
607 nt_status
= (NT_STATUS(response
.data
.auth
.nt_status
));
608 if (!NT_STATUS_IS_OK(nt_status
)) {
610 *error_string
= smb_xstrdup(response
.data
.auth
.error_string
);
611 *pauthoritative
= response
.data
.auth
.authoritative
;
612 winbindd_free_response(&response
);
616 if ((flags
& WBFLAG_PAM_LMKEY
) && lm_key
) {
617 memcpy(lm_key
, response
.data
.auth
.first_8_lm_hash
,
618 sizeof(response
.data
.auth
.first_8_lm_hash
));
620 if ((flags
& WBFLAG_PAM_USER_SESSION_KEY
) && user_session_key
) {
621 memcpy(user_session_key
, response
.data
.auth
.user_session_key
,
622 sizeof(response
.data
.auth
.user_session_key
));
625 if (flags
& WBFLAG_PAM_UNIX_NAME
) {
626 *unix_name
= SMB_STRDUP(response
.data
.auth
.unix_username
);
628 winbindd_free_response(&response
);
629 return NT_STATUS_NO_MEMORY
;
633 winbindd_free_response(&response
);
637 /* contact server to change user password using auth crap */
638 static NTSTATUS
contact_winbind_change_pswd_auth_crap(const char *username
,
640 const DATA_BLOB new_nt_pswd
,
641 const DATA_BLOB old_nt_hash_enc
,
642 const DATA_BLOB new_lm_pswd
,
643 const DATA_BLOB old_lm_hash_enc
,
648 struct winbindd_request request
;
649 struct winbindd_response response
;
651 if (!get_require_membership_sid())
654 *error_string
= smb_xstrdup("Can't get membership sid.");
655 return NT_STATUS_INVALID_PARAMETER
;
658 ZERO_STRUCT(request
);
659 ZERO_STRUCT(response
);
662 fstrcpy(request
.data
.chng_pswd_auth_crap
.user
, username
);
664 fstrcpy(request
.data
.chng_pswd_auth_crap
.domain
,domain
);
666 if(new_nt_pswd
.length
)
668 memcpy(request
.data
.chng_pswd_auth_crap
.new_nt_pswd
, new_nt_pswd
.data
, sizeof(request
.data
.chng_pswd_auth_crap
.new_nt_pswd
));
669 request
.data
.chng_pswd_auth_crap
.new_nt_pswd_len
= new_nt_pswd
.length
;
672 if(old_nt_hash_enc
.length
)
674 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
));
675 request
.data
.chng_pswd_auth_crap
.old_nt_hash_enc_len
= old_nt_hash_enc
.length
;
678 if(new_lm_pswd
.length
)
680 memcpy(request
.data
.chng_pswd_auth_crap
.new_lm_pswd
, new_lm_pswd
.data
, sizeof(request
.data
.chng_pswd_auth_crap
.new_lm_pswd
));
681 request
.data
.chng_pswd_auth_crap
.new_lm_pswd_len
= new_lm_pswd
.length
;
684 if(old_lm_hash_enc
.length
)
686 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
));
687 request
.data
.chng_pswd_auth_crap
.old_lm_hash_enc_len
= old_lm_hash_enc
.length
;
690 result
= winbindd_request_response(NULL
, WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP
, &request
, &response
);
692 /* Display response */
694 if ((result
!= NSS_STATUS_SUCCESS
) && (response
.data
.auth
.nt_status
== 0))
696 nt_status
= NT_STATUS_UNSUCCESSFUL
;
698 *error_string
= smb_xstrdup("Reading winbind reply failed!");
699 winbindd_free_response(&response
);
703 nt_status
= (NT_STATUS(response
.data
.auth
.nt_status
));
704 if (!NT_STATUS_IS_OK(nt_status
))
707 *error_string
= smb_xstrdup(response
.data
.auth
.error_string
);
708 winbindd_free_response(&response
);
712 winbindd_free_response(&response
);
717 static NTSTATUS
ntlm_auth_generate_session_info(struct auth4_context
*auth_context
,
719 void *server_returned_info
,
720 const char *original_user_name
,
721 uint32_t session_info_flags
,
722 struct auth_session_info
**session_info_out
)
724 const char *unix_username
= (const char *)server_returned_info
;
726 struct dom_sid
*sids
= NULL
;
727 struct auth_session_info
*session_info
= NULL
;
729 session_info
= talloc_zero(mem_ctx
, struct auth_session_info
);
730 if (session_info
== NULL
) {
731 return NT_STATUS_NO_MEMORY
;
734 session_info
->unix_info
= talloc_zero(session_info
, struct auth_user_info_unix
);
735 if (session_info
->unix_info
== NULL
) {
736 TALLOC_FREE(session_info
);
737 return NT_STATUS_NO_MEMORY
;
739 session_info
->unix_info
->unix_name
= talloc_strdup(session_info
->unix_info
,
741 if (session_info
->unix_info
->unix_name
== NULL
) {
742 TALLOC_FREE(session_info
);
743 return NT_STATUS_NO_MEMORY
;
746 session_info
->security_token
= talloc_zero(session_info
, struct security_token
);
747 if (session_info
->security_token
== NULL
) {
748 TALLOC_FREE(session_info
);
749 return NT_STATUS_NO_MEMORY
;
752 sids
= talloc_zero_array(session_info
->security_token
,
755 TALLOC_FREE(session_info
);
756 return NT_STATUS_NO_MEMORY
;
758 ok
= dom_sid_parse(SID_WORLD
, &sids
[0]);
760 TALLOC_FREE(session_info
);
761 return NT_STATUS_INTERNAL_ERROR
;
763 ok
= dom_sid_parse(SID_NT_NETWORK
, &sids
[1]);
765 TALLOC_FREE(session_info
);
766 return NT_STATUS_INTERNAL_ERROR
;
768 ok
= dom_sid_parse(SID_NT_AUTHENTICATED_USERS
, &sids
[2]);
770 TALLOC_FREE(session_info
);
771 return NT_STATUS_INTERNAL_ERROR
;
774 session_info
->security_token
->num_sids
= talloc_array_length(sids
);
775 session_info
->security_token
->sids
= sids
;
777 *session_info_out
= session_info
;
782 static NTSTATUS
ntlm_auth_generate_session_info_pac(struct auth4_context
*auth_ctx
,
784 struct smb_krb5_context
*smb_krb5_context
,
786 const char *princ_name
,
787 const struct tsocket_address
*remote_address
,
788 uint32_t session_info_flags
,
789 struct auth_session_info
**session_info
)
792 struct PAC_LOGON_INFO
*logon_info
= NULL
;
800 tmp_ctx
= talloc_new(mem_ctx
);
802 return NT_STATUS_NO_MEMORY
;
807 status
= kerberos_pac_logon_info(tmp_ctx
, *pac_blob
, NULL
, NULL
,
808 NULL
, NULL
, 0, &logon_info
);
810 status
= NT_STATUS_ACCESS_DENIED
;
812 if (!NT_STATUS_IS_OK(status
)) {
817 DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name
));
819 p
= strchr_m(princ_name
, '@');
821 DEBUG(3, ("[%s] Doesn't look like a valid principal\n",
823 return NT_STATUS_LOGON_FAILURE
;
826 user
= talloc_strndup(mem_ctx
, princ_name
, p
- princ_name
);
828 return NT_STATUS_NO_MEMORY
;
831 realm
= talloc_strdup(talloc_tos(), p
+ 1);
833 return NT_STATUS_NO_MEMORY
;
836 if (!strequal(realm
, lp_realm())) {
837 DEBUG(3, ("Ticket for foreign realm %s@%s\n", user
, realm
));
838 if (!lp_allow_trusted_domains()) {
839 return NT_STATUS_LOGON_FAILURE
;
843 if (logon_info
&& logon_info
->info3
.base
.logon_domain
.string
) {
844 domain
= talloc_strdup(mem_ctx
,
845 logon_info
->info3
.base
.logon_domain
.string
);
847 return NT_STATUS_NO_MEMORY
;
849 DEBUG(10, ("Domain is [%s] (using PAC)\n", domain
));
852 /* If we have winbind running, we can (and must) shorten the
853 username by using the short netbios name. Otherwise we will
854 have inconsistent user names. With Kerberos, we get the
855 fully qualified realm, with ntlmssp we get the short
856 name. And even w2k3 does use ntlmssp if you for example
857 connect to an ip address. */
860 struct wbcDomainInfo
*info
= NULL
;
862 DEBUG(10, ("Mapping [%s] to short name using winbindd\n",
865 wbc_status
= wbcDomainInfo(realm
, &info
);
867 if (WBC_ERROR_IS_OK(wbc_status
)) {
868 domain
= talloc_strdup(mem_ctx
,
872 DEBUG(3, ("Could not find short name: %s\n",
873 wbcErrorString(wbc_status
)));
874 domain
= talloc_strdup(mem_ctx
, realm
);
877 return NT_STATUS_NO_MEMORY
;
879 DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain
));
882 unixuser
= talloc_asprintf(tmp_ctx
, "%s%c%s", domain
, winbind_separator(), user
);
884 status
= NT_STATUS_NO_MEMORY
;
888 status
= ntlm_auth_generate_session_info(auth_ctx
, mem_ctx
, unixuser
, NULL
, session_info_flags
, session_info
);
891 TALLOC_FREE(tmp_ctx
);
898 * Return the challenge as determined by the authentication subsystem
899 * @return an 8 byte random challenge
902 static NTSTATUS
ntlm_auth_get_challenge(struct auth4_context
*auth_ctx
,
905 if (auth_ctx
->challenge
.data
.length
== 8) {
906 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
907 auth_ctx
->challenge
.set_by
));
908 memcpy(chal
, auth_ctx
->challenge
.data
.data
, 8);
912 if (!auth_ctx
->challenge
.set_by
) {
913 generate_random_buffer(chal
, 8);
915 auth_ctx
->challenge
.data
= data_blob_talloc(auth_ctx
, chal
, 8);
916 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.data
.data
);
917 auth_ctx
->challenge
.set_by
= "random";
920 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
921 auth_ctx
->challenge
.set_by
));
927 * NTLM2 authentication modifies the effective challenge,
928 * @param challenge The new challenge value
930 static NTSTATUS
ntlm_auth_set_challenge(struct auth4_context
*auth_ctx
, const uint8_t chal
[8], const char *set_by
)
932 auth_ctx
->challenge
.set_by
= talloc_strdup(auth_ctx
, set_by
);
933 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.set_by
);
935 auth_ctx
->challenge
.data
= data_blob_talloc(auth_ctx
, chal
, 8);
936 NT_STATUS_HAVE_NO_MEMORY(auth_ctx
->challenge
.data
.data
);
942 * Check the password on an NTLMSSP login.
944 * Return the session keys used on the connection.
947 static NTSTATUS
winbind_pw_check(struct auth4_context
*auth4_context
,
949 const struct auth_usersupplied_info
*user_info
,
950 uint8_t *pauthoritative
,
951 void **server_returned_info
,
952 DATA_BLOB
*session_key
, DATA_BLOB
*lm_session_key
)
955 char *error_string
= NULL
;
957 uint8_t user_sess_key
[16];
958 char *unix_name
= NULL
;
960 nt_status
= contact_winbind_auth_crap(user_info
->client
.account_name
, user_info
->client
.domain_name
,
961 user_info
->workstation_name
,
962 &auth4_context
->challenge
.data
,
963 &user_info
->password
.response
.lanman
,
964 &user_info
->password
.response
.nt
,
965 WBFLAG_PAM_LMKEY
| WBFLAG_PAM_USER_SESSION_KEY
| WBFLAG_PAM_UNIX_NAME
,
967 lm_key
, user_sess_key
,
969 &error_string
, &unix_name
);
971 if (NT_STATUS_IS_OK(nt_status
)) {
972 if (!all_zero(lm_key
, 8)) {
973 *lm_session_key
= data_blob_talloc(mem_ctx
, NULL
, 16);
974 memcpy(lm_session_key
->data
, lm_key
, 8);
975 memset(lm_session_key
->data
+8, '\0', 8);
978 if (!all_zero(user_sess_key
, 16)) {
979 *session_key
= data_blob_talloc(mem_ctx
, user_sess_key
, 16);
981 *server_returned_info
= talloc_strdup(mem_ctx
,
984 DEBUG(NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCESS_DENIED
) ? 0 : 3,
985 ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
986 user_info
->client
.domain_name
, user_info
->client
.account_name
,
987 user_info
->workstation_name
,
988 error_string
? error_string
: "unknown error (NULL)"));
991 SAFE_FREE(error_string
);
992 SAFE_FREE(unix_name
);
996 static NTSTATUS
local_pw_check(struct auth4_context
*auth4_context
,
998 const struct auth_usersupplied_info
*user_info
,
999 uint8_t *pauthoritative
,
1000 void **server_returned_info
,
1001 DATA_BLOB
*session_key
, DATA_BLOB
*lm_session_key
)
1004 struct samr_Password lm_pw
, nt_pw
;
1006 nt_lm_owf_gen (opt_password
, nt_pw
.hash
, lm_pw
.hash
);
1008 *pauthoritative
= 1;
1010 nt_status
= ntlm_password_check(mem_ctx
,
1012 &auth4_context
->challenge
.data
,
1013 &user_info
->password
.response
.lanman
,
1014 &user_info
->password
.response
.nt
,
1015 user_info
->client
.account_name
,
1016 user_info
->client
.account_name
,
1017 user_info
->client
.domain_name
,
1018 &lm_pw
, &nt_pw
, session_key
, lm_session_key
);
1020 if (NT_STATUS_IS_OK(nt_status
)) {
1021 *server_returned_info
= talloc_asprintf(mem_ctx
,
1022 "%s%c%s", user_info
->client
.domain_name
,
1023 *lp_winbind_separator(),
1024 user_info
->client
.account_name
);
1026 DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
1027 user_info
->client
.domain_name
, user_info
->client
.account_name
,
1028 user_info
->workstation_name
,
1029 nt_errstr(nt_status
)));
1034 static NTSTATUS
ntlm_auth_prepare_gensec_client(TALLOC_CTX
*mem_ctx
,
1035 struct loadparm_context
*lp_ctx
,
1036 struct gensec_security
**gensec_security_out
)
1038 struct gensec_security
*gensec_security
= NULL
;
1040 TALLOC_CTX
*tmp_ctx
;
1041 const struct gensec_security_ops
**backends
= NULL
;
1042 struct gensec_settings
*gensec_settings
= NULL
;
1045 tmp_ctx
= talloc_new(mem_ctx
);
1046 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx
);
1048 gensec_settings
= lpcfg_gensec_settings(tmp_ctx
, lp_ctx
);
1049 if (gensec_settings
== NULL
) {
1050 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1051 TALLOC_FREE(tmp_ctx
);
1052 return NT_STATUS_NO_MEMORY
;
1055 backends
= talloc_zero_array(gensec_settings
,
1056 const struct gensec_security_ops
*, 4);
1057 if (backends
== NULL
) {
1058 TALLOC_FREE(tmp_ctx
);
1059 return NT_STATUS_NO_MEMORY
;
1061 gensec_settings
->backends
= backends
;
1065 /* These need to be in priority order, krb5 before NTLMSSP */
1066 #if defined(HAVE_KRB5)
1067 backends
[idx
++] = &gensec_gse_krb5_security_ops
;
1070 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_NTLMSSP
);
1072 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_SPNEGO
);
1074 nt_status
= gensec_client_start(NULL
, &gensec_security
,
1076 if (!NT_STATUS_IS_OK(nt_status
)) {
1077 TALLOC_FREE(tmp_ctx
);
1081 talloc_unlink(tmp_ctx
, gensec_settings
);
1083 if (opt_target_service
!= NULL
) {
1084 nt_status
= gensec_set_target_service(gensec_security
,
1085 opt_target_service
);
1086 if (!NT_STATUS_IS_OK(nt_status
)) {
1087 TALLOC_FREE(tmp_ctx
);
1092 if (opt_target_hostname
!= NULL
) {
1093 nt_status
= gensec_set_target_hostname(gensec_security
,
1094 opt_target_hostname
);
1095 if (!NT_STATUS_IS_OK(nt_status
)) {
1096 TALLOC_FREE(tmp_ctx
);
1101 *gensec_security_out
= talloc_steal(mem_ctx
, gensec_security
);
1102 TALLOC_FREE(tmp_ctx
);
1103 return NT_STATUS_OK
;
1106 static struct auth4_context
*make_auth4_context_ntlm_auth(TALLOC_CTX
*mem_ctx
, bool local_pw
)
1108 struct auth4_context
*auth4_context
= talloc_zero(mem_ctx
, struct auth4_context
);
1109 if (auth4_context
== NULL
) {
1110 DEBUG(10, ("failed to allocate auth4_context failed\n"));
1113 auth4_context
->generate_session_info
= ntlm_auth_generate_session_info
;
1114 auth4_context
->generate_session_info_pac
= ntlm_auth_generate_session_info_pac
;
1115 auth4_context
->get_ntlm_challenge
= ntlm_auth_get_challenge
;
1116 auth4_context
->set_ntlm_challenge
= ntlm_auth_set_challenge
;
1118 auth4_context
->check_ntlm_password
= local_pw_check
;
1120 auth4_context
->check_ntlm_password
= winbind_pw_check
;
1122 auth4_context
->private_data
= NULL
;
1123 return auth4_context
;
1126 static NTSTATUS
ntlm_auth_prepare_gensec_server(TALLOC_CTX
*mem_ctx
,
1127 struct loadparm_context
*lp_ctx
,
1128 struct gensec_security
**gensec_security_out
)
1130 struct gensec_security
*gensec_security
;
1133 TALLOC_CTX
*tmp_ctx
;
1134 const struct gensec_security_ops
**backends
;
1135 struct gensec_settings
*gensec_settings
;
1137 struct cli_credentials
*server_credentials
;
1139 struct auth4_context
*auth4_context
;
1141 tmp_ctx
= talloc_new(mem_ctx
);
1142 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx
);
1144 auth4_context
= make_auth4_context_ntlm_auth(tmp_ctx
, opt_password
);
1145 if (auth4_context
== NULL
) {
1146 TALLOC_FREE(tmp_ctx
);
1147 return NT_STATUS_NO_MEMORY
;
1150 gensec_settings
= lpcfg_gensec_settings(tmp_ctx
, lp_ctx
);
1151 if (lp_ctx
== NULL
) {
1152 DEBUG(10, ("lpcfg_gensec_settings failed\n"));
1153 TALLOC_FREE(tmp_ctx
);
1154 return NT_STATUS_NO_MEMORY
;
1158 * This should be a 'netbios domain -> DNS domain'
1159 * mapping, and can currently validly return NULL on
1160 * poorly configured systems.
1162 * This is used for the NTLMSSP server
1166 gensec_settings
->server_netbios_name
= lp_netbios_name();
1167 gensec_settings
->server_netbios_domain
= lp_workgroup();
1169 gensec_settings
->server_netbios_name
= get_winbind_netbios_name();
1170 gensec_settings
->server_netbios_domain
= get_winbind_domain();
1173 gensec_settings
->server_dns_domain
= strlower_talloc(gensec_settings
,
1174 get_mydnsdomname(talloc_tos()));
1175 gensec_settings
->server_dns_name
= strlower_talloc(gensec_settings
,
1176 get_mydnsfullname());
1178 backends
= talloc_zero_array(gensec_settings
,
1179 const struct gensec_security_ops
*, 4);
1181 if (backends
== NULL
) {
1182 TALLOC_FREE(tmp_ctx
);
1183 return NT_STATUS_NO_MEMORY
;
1185 gensec_settings
->backends
= backends
;
1189 /* These need to be in priority order, krb5 before NTLMSSP */
1190 #if defined(HAVE_KRB5)
1191 backends
[idx
++] = &gensec_gse_krb5_security_ops
;
1194 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_NTLMSSP
);
1196 backends
[idx
++] = gensec_security_by_oid(NULL
, GENSEC_OID_SPNEGO
);
1199 * This is anonymous for now, because we just use it
1200 * to set the kerberos state at the moment
1202 server_credentials
= cli_credentials_init_anon(tmp_ctx
);
1203 if (!server_credentials
) {
1204 DEBUG(0, ("auth_generic_prepare: Failed to init server credentials\n"));
1205 return NT_STATUS_NO_MEMORY
;
1208 cli_credentials_set_conf(server_credentials
, lp_ctx
);
1210 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC
|| lp_security() == SEC_ADS
|| USE_KERBEROS_KEYTAB
) {
1211 cli_credentials_set_kerberos_state(server_credentials
, CRED_AUTO_USE_KERBEROS
);
1213 cli_credentials_set_kerberos_state(server_credentials
, CRED_DONT_USE_KERBEROS
);
1216 nt_status
= gensec_server_start(tmp_ctx
, gensec_settings
,
1217 auth4_context
, &gensec_security
);
1219 if (!NT_STATUS_IS_OK(nt_status
)) {
1220 TALLOC_FREE(tmp_ctx
);
1224 gensec_set_credentials(gensec_security
, server_credentials
);
1227 * TODO: Allow the caller to pass their own description here
1228 * via a command-line option
1230 nt_status
= gensec_set_target_service_description(gensec_security
,
1232 if (!NT_STATUS_IS_OK(nt_status
)) {
1233 TALLOC_FREE(tmp_ctx
);
1237 talloc_unlink(tmp_ctx
, lp_ctx
);
1238 talloc_unlink(tmp_ctx
, server_credentials
);
1239 talloc_unlink(tmp_ctx
, gensec_settings
);
1240 talloc_unlink(tmp_ctx
, auth4_context
);
1242 *gensec_security_out
= talloc_steal(mem_ctx
, gensec_security
);
1243 TALLOC_FREE(tmp_ctx
);
1244 return NT_STATUS_OK
;
1247 static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode
,
1248 struct loadparm_context
*lp_ctx
,
1249 struct ntlm_auth_state
*state
,
1250 char *buf
, int length
, void **private2
)
1252 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1256 static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode
,
1257 struct loadparm_context
*lp_ctx
,
1258 struct ntlm_auth_state
*state
,
1259 char *buf
, int length
, void **private2
)
1264 pass
=(char *)memchr(buf
,' ',length
);
1266 DEBUG(2, ("Password not found. Denying access\n"));
1273 if (state
->helper_mode
== SQUID_2_5_BASIC
) {
1274 rfc1738_unescape(user
);
1275 rfc1738_unescape(pass
);
1278 if (check_plaintext_auth(user
, pass
, False
)) {
1285 static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode
,
1286 struct loadparm_context
*lp_ctx
,
1287 char *buf
, int length
, void **private1
)
1290 DATA_BLOB out
= data_blob(NULL
, 0);
1291 char *out_base64
= NULL
;
1292 const char *reply_arg
= NULL
;
1293 struct gensec_ntlm_state
{
1294 struct gensec_security
*gensec_state
;
1295 const char *set_password
;
1297 struct gensec_ntlm_state
*state
;
1301 const char *reply_code
;
1302 struct cli_credentials
*creds
;
1304 static char *want_feature_list
= NULL
;
1305 static DATA_BLOB session_key
;
1307 TALLOC_CTX
*mem_ctx
;
1310 state
= (struct gensec_ntlm_state
*)*private1
;
1312 state
= talloc_zero(NULL
, struct gensec_ntlm_state
);
1314 printf("BH No Memory\n");
1319 state
->set_password
= opt_password
;
1323 if (strlen(buf
) < 2) {
1324 DEBUG(1, ("query [%s] invalid", buf
));
1325 printf("BH Query invalid\n");
1329 if (strlen(buf
) > 3) {
1330 if(strncmp(buf
, "SF ", 3) == 0) {
1331 DEBUG(10, ("Setting flags to negotiate\n"));
1332 talloc_free(want_feature_list
);
1333 want_feature_list
= talloc_strndup(state
, buf
+3, strlen(buf
)-3);
1337 in
= base64_decode_data_blob(buf
+ 3);
1339 in
= data_blob(NULL
, 0);
1342 if (strncmp(buf
, "YR", 2) == 0) {
1343 if (state
->gensec_state
) {
1344 talloc_free(state
->gensec_state
);
1345 state
->gensec_state
= NULL
;
1347 } else if ( (strncmp(buf
, "OK", 2) == 0)) {
1348 /* Just return BH, like ntlm_auth from Samba 3 does. */
1349 printf("BH Command expected\n");
1350 data_blob_free(&in
);
1352 } else if ( (strncmp(buf
, "TT ", 3) != 0) &&
1353 (strncmp(buf
, "KK ", 3) != 0) &&
1354 (strncmp(buf
, "AF ", 3) != 0) &&
1355 (strncmp(buf
, "NA ", 3) != 0) &&
1356 (strncmp(buf
, "UG", 2) != 0) &&
1357 (strncmp(buf
, "PW ", 3) != 0) &&
1358 (strncmp(buf
, "GK", 2) != 0) &&
1359 (strncmp(buf
, "GF", 2) != 0)) {
1360 DEBUG(1, ("SPNEGO request [%s] invalid prefix\n", buf
));
1361 printf("BH SPNEGO request invalid prefix\n");
1362 data_blob_free(&in
);
1366 mem_ctx
= talloc_named(NULL
, 0, "manage_gensec_request internal mem_ctx");
1369 if (!(state
->gensec_state
)) {
1370 switch (stdio_helper_mode
) {
1371 case GSS_SPNEGO_CLIENT
:
1373 * cached credentials are only supported by
1374 * NTLMSSP_CLIENT_1 for now.
1376 use_cached_creds
= false;
1378 case NTLMSSP_CLIENT_1
:
1379 /* setup the client side */
1381 if (state
->set_password
!= NULL
) {
1382 use_cached_creds
= false;
1385 if (use_cached_creds
) {
1386 struct wbcCredentialCacheParams params
;
1387 struct wbcCredentialCacheInfo
*info
= NULL
;
1388 struct wbcAuthErrorInfo
*error
= NULL
;
1391 params
.account_name
= opt_username
;
1392 params
.domain_name
= opt_domain
;
1393 params
.level
= WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP
;
1394 params
.num_blobs
= 0;
1395 params
.blobs
= NULL
;
1397 wbc_status
= wbcCredentialCache(¶ms
, &info
,
1399 wbcFreeMemory(error
);
1400 if (!WBC_ERROR_IS_OK(wbc_status
)) {
1401 use_cached_creds
= false;
1403 wbcFreeMemory(info
);
1406 nt_status
= ntlm_auth_prepare_gensec_client(state
, lp_ctx
,
1407 &state
->gensec_state
);
1408 if (!NT_STATUS_IS_OK(nt_status
)) {
1409 printf("BH GENSEC mech failed to start: %s\n",
1410 nt_errstr(nt_status
));
1411 talloc_free(mem_ctx
);
1415 creds
= cli_credentials_init(state
->gensec_state
);
1416 cli_credentials_set_conf(creds
, lp_ctx
);
1418 cli_credentials_set_username(creds
, opt_username
, CRED_SPECIFIED
);
1421 cli_credentials_set_domain(creds
, opt_domain
, CRED_SPECIFIED
);
1423 if (use_cached_creds
) {
1424 gensec_want_feature(state
->gensec_state
,
1425 GENSEC_FEATURE_NTLM_CCACHE
);
1426 } else if (state
->set_password
) {
1427 cli_credentials_set_password(creds
, state
->set_password
, CRED_SPECIFIED
);
1429 cli_credentials_set_password_callback(creds
, get_password
);
1431 if (opt_workstation
) {
1432 cli_credentials_set_workstation(creds
, opt_workstation
, CRED_SPECIFIED
);
1435 gensec_set_credentials(state
->gensec_state
, creds
);
1438 case GSS_SPNEGO_SERVER
:
1439 case SQUID_2_5_NTLMSSP
:
1441 nt_status
= ntlm_auth_prepare_gensec_server(state
, lp_ctx
,
1442 &state
->gensec_state
);
1443 if (!NT_STATUS_IS_OK(nt_status
)) {
1444 printf("BH GENSEC mech failed to start: %s\n",
1445 nt_errstr(nt_status
));
1446 talloc_free(mem_ctx
);
1452 talloc_free(mem_ctx
);
1456 gensec_want_feature_list(state
->gensec_state
, want_feature_list
);
1458 /* Session info is not complete, do not pass to auth log */
1459 gensec_want_feature(state
->gensec_state
, GENSEC_FEATURE_NO_AUTHZ_LOG
);
1461 switch (stdio_helper_mode
) {
1462 case GSS_SPNEGO_CLIENT
:
1463 case GSS_SPNEGO_SERVER
:
1464 nt_status
= gensec_start_mech_by_oid(state
->gensec_state
, GENSEC_OID_SPNEGO
);
1469 case NTLMSSP_CLIENT_1
:
1474 case SQUID_2_5_NTLMSSP
:
1475 nt_status
= gensec_start_mech_by_oid(state
->gensec_state
, GENSEC_OID_NTLMSSP
);
1478 talloc_free(mem_ctx
);
1482 if (!NT_STATUS_IS_OK(nt_status
)) {
1483 DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status
)));
1484 printf("BH GENSEC mech failed to start\n");
1485 talloc_free(mem_ctx
);
1493 if (strncmp(buf
, "PW ", 3) == 0) {
1494 state
->set_password
= talloc_strndup(state
,
1495 (const char *)in
.data
,
1498 cli_credentials_set_password(gensec_get_credentials(state
->gensec_state
),
1499 state
->set_password
,
1502 data_blob_free(&in
);
1503 talloc_free(mem_ctx
);
1507 if (strncmp(buf
, "GK", 2) == 0) {
1509 DEBUG(10, ("Requested session key\n"));
1510 nt_status
= gensec_session_key(state
->gensec_state
, mem_ctx
, &session_key
);
1511 if(!NT_STATUS_IS_OK(nt_status
)) {
1512 DEBUG(1, ("gensec_session_key failed: %s\n", nt_errstr(nt_status
)));
1513 printf("BH No session key\n");
1514 talloc_free(mem_ctx
);
1517 base64_key
= base64_encode_data_blob(state
, session_key
);
1518 SMB_ASSERT(base64_key
!= NULL
);
1519 printf("GK %s\n", base64_key
);
1520 talloc_free(base64_key
);
1522 talloc_free(mem_ctx
);
1526 if (strncmp(buf
, "GF", 2) == 0) {
1529 DEBUG(10, ("Requested negotiated NTLMSSP feature flags\n"));
1531 neg_flags
= gensec_ntlmssp_neg_flags(state
->gensec_state
);
1532 if (neg_flags
== 0) {
1537 printf("GF 0x%08x\n", neg_flags
);
1541 nt_status
= gensec_update(state
->gensec_state
, mem_ctx
, in
, &out
);
1543 /* don't leak 'bad password'/'no such user' info to the network client */
1544 nt_status
= nt_status_squash(nt_status
);
1547 out_base64
= base64_encode_data_blob(mem_ctx
, out
);
1548 SMB_ASSERT(out_base64
!= NULL
);
1553 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
1555 if (first
&& state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1557 } else if (state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1559 } else if (state
->gensec_state
->gensec_role
== GENSEC_SERVER
) {
1566 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCESS_DENIED
)) {
1567 reply_code
= "BH NT_STATUS_ACCESS_DENIED";
1568 reply_arg
= nt_errstr(nt_status
);
1569 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1570 } else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_UNSUCCESSFUL
)) {
1571 reply_code
= "BH NT_STATUS_UNSUCCESSFUL";
1572 reply_arg
= nt_errstr(nt_status
);
1573 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1574 } else if (!NT_STATUS_IS_OK(nt_status
)) {
1576 reply_arg
= nt_errstr(nt_status
);
1577 DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status
)));
1578 } else if /* OK */ (state
->gensec_state
->gensec_role
== GENSEC_SERVER
) {
1579 struct auth_session_info
*session_info
;
1581 nt_status
= gensec_session_info(state
->gensec_state
, mem_ctx
, &session_info
);
1582 if (!NT_STATUS_IS_OK(nt_status
)) {
1583 reply_code
= "BH Failed to retrive session info";
1584 reply_arg
= nt_errstr(nt_status
);
1585 DEBUG(1, ("GENSEC failed to retrieve the session info: %s\n", nt_errstr(nt_status
)));
1589 reply_arg
= talloc_strdup(state
->gensec_state
, session_info
->unix_info
->unix_name
);
1590 if (reply_arg
== NULL
) {
1591 reply_code
= "BH out of memory";
1592 reply_arg
= nt_errstr(NT_STATUS_NO_MEMORY
);
1594 talloc_free(session_info
);
1596 } else if (state
->gensec_state
->gensec_role
== GENSEC_CLIENT
) {
1598 reply_arg
= out_base64
;
1603 switch (stdio_helper_mode
) {
1604 case GSS_SPNEGO_SERVER
:
1605 printf("%s %s %s\n", reply_code
,
1606 out_base64
? out_base64
: "*",
1607 reply_arg
? reply_arg
: "*");
1611 printf("%s %s\n", reply_code
, out_base64
);
1612 } else if (reply_arg
) {
1613 printf("%s %s\n", reply_code
, reply_arg
);
1615 printf("%s\n", reply_code
);
1619 talloc_free(mem_ctx
);
1623 static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode
,
1624 struct loadparm_context
*lp_ctx
,
1625 struct ntlm_auth_state
*state
,
1626 char *buf
, int length
, void **private2
)
1628 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1632 static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode
,
1633 struct loadparm_context
*lp_ctx
,
1634 struct ntlm_auth_state
*state
,
1635 char *buf
, int length
, void **private2
)
1637 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1641 static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode
,
1642 struct loadparm_context
*lp_ctx
,
1643 struct ntlm_auth_state
*state
,
1644 char *buf
, int length
, void **private2
)
1646 manage_gensec_request(stdio_helper_mode
, lp_ctx
, buf
, length
, &state
->gensec_private_1
);
1650 static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode
,
1651 struct loadparm_context
*lp_ctx
,
1652 struct ntlm_auth_state
*state
,
1653 char *buf
, int length
, void **private2
)
1655 char *request
, *parameter
;
1656 static DATA_BLOB challenge
;
1657 static DATA_BLOB lm_response
;
1658 static DATA_BLOB nt_response
;
1659 static char *full_username
;
1660 static char *username
;
1661 static char *domain
;
1662 static char *plaintext_password
;
1663 static bool ntlm_server_1_user_session_key
;
1664 static bool ntlm_server_1_lm_session_key
;
1666 if (strequal(buf
, ".")) {
1667 if (!full_username
&& !username
) {
1668 printf("Error: No username supplied!\n");
1669 } else if (plaintext_password
) {
1670 /* handle this request as plaintext */
1671 if (!full_username
) {
1672 if (asprintf(&full_username
, "%s%c%s", domain
, winbind_separator(), username
) == -1) {
1673 printf("Error: Out of memory in "
1678 if (check_plaintext_auth(full_username
, plaintext_password
, False
)) {
1679 printf("Authenticated: Yes\n");
1681 printf("Authenticated: No\n");
1683 } else if (!lm_response
.data
&& !nt_response
.data
) {
1684 printf("Error: No password supplied!\n");
1685 } else if (!challenge
.data
) {
1686 printf("Error: No lanman-challenge supplied!\n");
1688 char *error_string
= NULL
;
1690 uchar user_session_key
[16];
1693 if (full_username
&& !username
) {
1695 fstring fstr_domain
;
1697 if (!parse_ntlm_auth_domain_user(full_username
, fstr_user
, fstr_domain
)) {
1698 /* username might be 'tainted', don't print into our new-line deleimianted stream */
1699 printf("Error: Could not parse into "
1700 "domain and username\n");
1702 SAFE_FREE(username
);
1704 username
= smb_xstrdup(fstr_user
);
1705 domain
= smb_xstrdup(fstr_domain
);
1709 DATA_BLOB nt_session_key
, lm_session_key
;
1710 struct samr_Password lm_pw
, nt_pw
;
1711 TALLOC_CTX
*mem_ctx
= talloc_new(NULL
);
1712 ZERO_STRUCT(user_session_key
);
1713 ZERO_STRUCT(lm_key
);
1715 nt_lm_owf_gen (opt_password
, nt_pw
.hash
, lm_pw
.hash
);
1716 nt_status
= ntlm_password_check(mem_ctx
,
1727 error_string
= smb_xstrdup(get_friendly_nt_error_msg(nt_status
));
1728 if (ntlm_server_1_user_session_key
) {
1729 if (nt_session_key
.length
== sizeof(user_session_key
)) {
1730 memcpy(user_session_key
,
1731 nt_session_key
.data
,
1732 sizeof(user_session_key
));
1735 if (ntlm_server_1_lm_session_key
) {
1736 if (lm_session_key
.length
== sizeof(lm_key
)) {
1738 lm_session_key
.data
,
1742 TALLOC_FREE(mem_ctx
);
1745 uint8_t authoritative
= 0;
1748 domain
= smb_xstrdup(get_winbind_domain());
1751 if (ntlm_server_1_lm_session_key
)
1752 flags
|= WBFLAG_PAM_LMKEY
;
1754 if (ntlm_server_1_user_session_key
)
1755 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
1757 nt_status
= contact_winbind_auth_crap(username
,
1771 if (!NT_STATUS_IS_OK(nt_status
)) {
1772 printf("Authenticated: No\n");
1773 printf("Authentication-Error: %s\n.\n",
1777 char *hex_user_session_key
;
1779 printf("Authenticated: Yes\n");
1781 if (ntlm_server_1_lm_session_key
1782 && (!all_zero(lm_key
,
1784 hex_lm_key
= hex_encode_talloc(NULL
,
1785 (const unsigned char *)lm_key
,
1787 printf("LANMAN-Session-Key: %s\n",
1789 TALLOC_FREE(hex_lm_key
);
1792 if (ntlm_server_1_user_session_key
1793 && (!all_zero(user_session_key
,
1794 sizeof(user_session_key
)))) {
1795 hex_user_session_key
= hex_encode_talloc(NULL
,
1796 (const unsigned char *)user_session_key
,
1797 sizeof(user_session_key
));
1798 printf("User-Session-Key: %s\n",
1799 hex_user_session_key
);
1800 TALLOC_FREE(hex_user_session_key
);
1803 SAFE_FREE(error_string
);
1805 /* clear out the state */
1806 challenge
= data_blob_null
;
1807 nt_response
= data_blob_null
;
1808 lm_response
= data_blob_null
;
1809 SAFE_FREE(full_username
);
1810 SAFE_FREE(username
);
1812 SAFE_FREE(plaintext_password
);
1813 ntlm_server_1_user_session_key
= False
;
1814 ntlm_server_1_lm_session_key
= False
;
1822 /* Indicates a base64 encoded structure */
1823 parameter
= strstr_m(request
, ":: ");
1825 parameter
= strstr_m(request
, ": ");
1828 DEBUG(0, ("Parameter not found!\n"));
1829 printf("Error: Parameter not found!\n.\n");
1846 base64_decode_inplace(parameter
);
1849 if (strequal(request
, "LANMAN-Challenge")) {
1850 challenge
= strhex_to_data_blob(NULL
, parameter
);
1851 if (challenge
.length
!= 8) {
1852 printf("Error: hex decode of %s failed! "
1853 "(got %d bytes, expected 8)\n.\n",
1855 (int)challenge
.length
);
1856 challenge
= data_blob_null
;
1858 } else if (strequal(request
, "NT-Response")) {
1859 nt_response
= strhex_to_data_blob(NULL
, parameter
);
1860 if (nt_response
.length
< 24) {
1861 printf("Error: hex decode of %s failed! "
1862 "(only got %d bytes, needed at least 24)\n.\n",
1864 (int)nt_response
.length
);
1865 nt_response
= data_blob_null
;
1867 } else if (strequal(request
, "LANMAN-Response")) {
1868 lm_response
= strhex_to_data_blob(NULL
, parameter
);
1869 if (lm_response
.length
!= 24) {
1870 printf("Error: hex decode of %s failed! "
1871 "(got %d bytes, expected 24)\n.\n",
1873 (int)lm_response
.length
);
1874 lm_response
= data_blob_null
;
1876 } else if (strequal(request
, "Password")) {
1877 plaintext_password
= smb_xstrdup(parameter
);
1878 } else if (strequal(request
, "NT-Domain")) {
1879 domain
= smb_xstrdup(parameter
);
1880 } else if (strequal(request
, "Username")) {
1881 username
= smb_xstrdup(parameter
);
1882 } else if (strequal(request
, "Full-Username")) {
1883 full_username
= smb_xstrdup(parameter
);
1884 } else if (strequal(request
, "Request-User-Session-Key")) {
1885 ntlm_server_1_user_session_key
= strequal(parameter
, "Yes");
1886 } else if (strequal(request
, "Request-LanMan-Session-Key")) {
1887 ntlm_server_1_lm_session_key
= strequal(parameter
, "Yes");
1889 printf("Error: Unknown request %s\n.\n", request
);
1893 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode stdio_helper_mode
,
1894 struct loadparm_context
*lp_ctx
,
1895 struct ntlm_auth_state
*state
,
1896 char *buf
, int length
, void **private2
)
1898 char *request
, *parameter
;
1899 static DATA_BLOB new_nt_pswd
;
1900 static DATA_BLOB old_nt_hash_enc
;
1901 static DATA_BLOB new_lm_pswd
;
1902 static DATA_BLOB old_lm_hash_enc
;
1903 static char *full_username
= NULL
;
1904 static char *username
= NULL
;
1905 static char *domain
= NULL
;
1906 static char *newpswd
= NULL
;
1907 static char *oldpswd
= NULL
;
1909 if (strequal(buf
, ".")) {
1910 if(newpswd
&& oldpswd
) {
1911 uchar old_nt_hash
[16];
1912 uchar old_lm_hash
[16];
1913 uchar new_nt_hash
[16];
1914 uchar new_lm_hash
[16];
1916 new_nt_pswd
= data_blob(NULL
, 516);
1917 old_nt_hash_enc
= data_blob(NULL
, 16);
1919 /* Calculate the MD4 hash (NT compatible) of the
1921 E_md4hash(oldpswd
, old_nt_hash
);
1922 E_md4hash(newpswd
, new_nt_hash
);
1924 /* E_deshash returns false for 'long'
1925 passwords (> 14 DOS chars).
1927 Therefore, don't send a buffer
1928 encrypted with the truncated hash
1929 (it could allow an even easier
1930 attack on the password)
1932 Likewise, obey the admin's restriction
1935 if (lp_client_lanman_auth() &&
1936 E_deshash(newpswd
, new_lm_hash
) &&
1937 E_deshash(oldpswd
, old_lm_hash
)) {
1938 new_lm_pswd
= data_blob(NULL
, 516);
1939 old_lm_hash_enc
= data_blob(NULL
, 16);
1940 encode_pw_buffer(new_lm_pswd
.data
, newpswd
,
1943 arcfour_crypt(new_lm_pswd
.data
, old_nt_hash
, 516);
1944 E_old_pw_hash(new_nt_hash
, old_lm_hash
,
1945 old_lm_hash_enc
.data
);
1947 new_lm_pswd
.data
= NULL
;
1948 new_lm_pswd
.length
= 0;
1949 old_lm_hash_enc
.data
= NULL
;
1950 old_lm_hash_enc
.length
= 0;
1953 encode_pw_buffer(new_nt_pswd
.data
, newpswd
,
1956 arcfour_crypt(new_nt_pswd
.data
, old_nt_hash
, 516);
1957 E_old_pw_hash(new_nt_hash
, old_nt_hash
,
1958 old_nt_hash_enc
.data
);
1961 if (!full_username
&& !username
) {
1962 printf("Error: No username supplied!\n");
1963 } else if ((!new_nt_pswd
.data
|| !old_nt_hash_enc
.data
) &&
1964 (!new_lm_pswd
.data
|| old_lm_hash_enc
.data
) ) {
1965 printf("Error: No NT or LM password "
1966 "blobs supplied!\n");
1968 char *error_string
= NULL
;
1970 if (full_username
&& !username
) {
1972 fstring fstr_domain
;
1974 if (!parse_ntlm_auth_domain_user(full_username
,
1977 /* username might be 'tainted', don't
1978 * print into our new-line
1979 * deleimianted stream */
1980 printf("Error: Could not "
1981 "parse into domain and "
1983 SAFE_FREE(username
);
1984 username
= smb_xstrdup(full_username
);
1986 SAFE_FREE(username
);
1988 username
= smb_xstrdup(fstr_user
);
1989 domain
= smb_xstrdup(fstr_domain
);
1994 if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
2001 printf("Password-Change: No\n");
2002 printf("Password-Change-Error: %s\n.\n",
2005 printf("Password-Change: Yes\n");
2008 SAFE_FREE(error_string
);
2010 /* clear out the state */
2011 new_nt_pswd
= data_blob_null
;
2012 old_nt_hash_enc
= data_blob_null
;
2013 new_lm_pswd
= data_blob_null
;
2014 old_nt_hash_enc
= data_blob_null
;
2015 SAFE_FREE(full_username
);
2016 SAFE_FREE(username
);
2027 /* Indicates a base64 encoded structure */
2028 parameter
= strstr_m(request
, ":: ");
2030 parameter
= strstr_m(request
, ": ");
2033 DEBUG(0, ("Parameter not found!\n"));
2034 printf("Error: Parameter not found!\n.\n");
2050 base64_decode_inplace(parameter
);
2053 if (strequal(request
, "new-nt-password-blob")) {
2054 new_nt_pswd
= strhex_to_data_blob(NULL
, parameter
);
2055 if (new_nt_pswd
.length
!= 516) {
2056 printf("Error: hex decode of %s failed! "
2057 "(got %d bytes, expected 516)\n.\n",
2059 (int)new_nt_pswd
.length
);
2060 new_nt_pswd
= data_blob_null
;
2062 } else if (strequal(request
, "old-nt-hash-blob")) {
2063 old_nt_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2064 if (old_nt_hash_enc
.length
!= 16) {
2065 printf("Error: hex decode of %s failed! "
2066 "(got %d bytes, expected 16)\n.\n",
2068 (int)old_nt_hash_enc
.length
);
2069 old_nt_hash_enc
= data_blob_null
;
2071 } else if (strequal(request
, "new-lm-password-blob")) {
2072 new_lm_pswd
= strhex_to_data_blob(NULL
, parameter
);
2073 if (new_lm_pswd
.length
!= 516) {
2074 printf("Error: hex decode of %s failed! "
2075 "(got %d bytes, expected 516)\n.\n",
2077 (int)new_lm_pswd
.length
);
2078 new_lm_pswd
= data_blob_null
;
2081 else if (strequal(request
, "old-lm-hash-blob")) {
2082 old_lm_hash_enc
= strhex_to_data_blob(NULL
, parameter
);
2083 if (old_lm_hash_enc
.length
!= 16)
2085 printf("Error: hex decode of %s failed! "
2086 "(got %d bytes, expected 16)\n.\n",
2088 (int)old_lm_hash_enc
.length
);
2089 old_lm_hash_enc
= data_blob_null
;
2091 } else if (strequal(request
, "nt-domain")) {
2092 domain
= smb_xstrdup(parameter
);
2093 } else if(strequal(request
, "username")) {
2094 username
= smb_xstrdup(parameter
);
2095 } else if(strequal(request
, "full-username")) {
2096 username
= smb_xstrdup(parameter
);
2097 } else if(strequal(request
, "new-password")) {
2098 newpswd
= smb_xstrdup(parameter
);
2099 } else if (strequal(request
, "old-password")) {
2100 oldpswd
= smb_xstrdup(parameter
);
2102 printf("Error: Unknown request %s\n.\n", request
);
2106 static void manage_squid_request(enum stdio_helper_mode stdio_helper_mode
,
2107 struct loadparm_context
*lp_ctx
,
2108 struct ntlm_auth_state
*state
,
2109 stdio_helper_function fn
, void **private2
)
2112 char tmp
[INITIAL_BUFFER_SIZE
+1];
2113 int length
, buf_size
= 0;
2116 buf
= talloc_strdup(state
->mem_ctx
, "");
2118 DEBUG(0, ("Failed to allocate input buffer.\n"));
2119 fprintf(stderr
, "ERR\n");
2125 /* this is not a typo - x_fgets doesn't work too well under
2127 if (fgets(tmp
, sizeof(tmp
)-1, stdin
) == NULL
) {
2128 if (ferror(stdin
)) {
2129 DEBUG(1, ("fgets() failed! dying..... errno=%d "
2130 "(%s)\n", ferror(stdin
),
2131 strerror(ferror(stdin
))));
2138 buf
= talloc_strdup_append_buffer(buf
, tmp
);
2139 buf_size
+= INITIAL_BUFFER_SIZE
;
2141 if (buf_size
> MAX_BUFFER_SIZE
) {
2142 DEBUG(2, ("Oversized message\n"));
2143 fprintf(stderr
, "ERR\n");
2148 c
= strchr(buf
, '\n');
2149 } while (c
== NULL
);
2154 DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf
,length
));
2156 if (buf
[0] == '\0') {
2157 DEBUG(2, ("Invalid Request\n"));
2158 fprintf(stderr
, "ERR\n");
2163 fn(stdio_helper_mode
, lp_ctx
, state
, buf
, length
, private2
);
2168 static void squid_stream(enum stdio_helper_mode stdio_mode
,
2169 struct loadparm_context
*lp_ctx
,
2170 stdio_helper_function fn
) {
2171 TALLOC_CTX
*mem_ctx
;
2172 struct ntlm_auth_state
*state
;
2174 /* initialize FDescs */
2175 setbuf(stdout
, NULL
);
2176 setbuf(stderr
, NULL
);
2178 mem_ctx
= talloc_init("ntlm_auth");
2180 DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
2181 fprintf(stderr
, "ERR\n");
2185 state
= talloc_zero(mem_ctx
, struct ntlm_auth_state
);
2187 DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
2188 fprintf(stderr
, "ERR\n");
2192 state
->mem_ctx
= mem_ctx
;
2193 state
->helper_mode
= stdio_mode
;
2196 TALLOC_CTX
*frame
= talloc_stackframe();
2197 manage_squid_request(stdio_mode
, lp_ctx
, state
, fn
, NULL
);
2203 /* Authenticate a user with a challenge/response */
2205 static bool check_auth_crap(void)
2210 char user_session_key
[16];
2212 char *hex_user_session_key
;
2214 uint8_t authoritative
= 0;
2216 setbuf(stdout
, NULL
);
2219 flags
|= WBFLAG_PAM_LMKEY
;
2221 if (request_user_session_key
)
2222 flags
|= WBFLAG_PAM_USER_SESSION_KEY
;
2224 flags
|= WBFLAG_PAM_NT_STATUS_SQUASH
;
2226 nt_status
= contact_winbind_auth_crap(opt_username
, opt_domain
,
2232 (unsigned char *)lm_key
,
2233 (unsigned char *)user_session_key
,
2235 &error_string
, NULL
);
2237 if (!NT_STATUS_IS_OK(nt_status
)) {
2238 printf("%s (0x%x)\n", error_string
,
2239 NT_STATUS_V(nt_status
));
2240 SAFE_FREE(error_string
);
2245 && (!all_zero((uint8_t *)lm_key
, sizeof(lm_key
)))) {
2246 hex_lm_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)lm_key
,
2248 printf("LM_KEY: %s\n", hex_lm_key
);
2249 TALLOC_FREE(hex_lm_key
);
2251 if (request_user_session_key
2252 && (!all_zero((uint8_t *)user_session_key
,
2253 sizeof(user_session_key
)))) {
2254 hex_user_session_key
= hex_encode_talloc(talloc_tos(), (const unsigned char *)user_session_key
,
2255 sizeof(user_session_key
));
2256 printf("NT_KEY: %s\n", hex_user_session_key
);
2257 TALLOC_FREE(hex_user_session_key
);
2266 OPT_USERNAME
= 1000,
2275 OPT_USER_SESSION_KEY
,
2277 OPT_REQUIRE_MEMBERSHIP
,
2278 OPT_USE_CACHED_CREDS
,
2280 OPT_PAM_WINBIND_CONF
,
2282 OPT_TARGET_HOSTNAME
,
2286 int main(int argc
, const char **argv
)
2288 TALLOC_CTX
*frame
= talloc_stackframe();
2290 const char *helper_protocol
= NULL
;
2291 int diagnostics
= 0;
2293 const char *hex_challenge
= NULL
;
2294 const char *hex_lm_response
= NULL
;
2295 const char *hex_nt_response
= NULL
;
2296 struct loadparm_context
*lp_ctx
;
2299 /* NOTE: DO NOT change this interface without considering the implications!
2300 This is an external interface, which other programs will use to interact
2304 /* We do not use single-letter command abbreviations, because they harm future
2305 interface stability. */
2307 struct poptOption long_options
[] = {
2309 { "helper-protocol", 0, POPT_ARG_STRING
, &helper_protocol
, OPT_DOMAIN
, "operate as a stdio-based helper", "helper protocol to use"},
2310 { "username", 0, POPT_ARG_STRING
, &opt_username
, OPT_USERNAME
, "username"},
2311 { "domain", 0, POPT_ARG_STRING
, &opt_domain
, OPT_DOMAIN
, "domain name"},
2312 { "workstation", 0, POPT_ARG_STRING
, &opt_workstation
, OPT_WORKSTATION
, "workstation"},
2313 { "challenge", 0, POPT_ARG_STRING
, &hex_challenge
, OPT_CHALLENGE
, "challenge (HEX encoded)"},
2314 { "lm-response", 0, POPT_ARG_STRING
, &hex_lm_response
, OPT_LM
, "LM Response to the challenge (HEX encoded)"},
2315 { "nt-response", 0, POPT_ARG_STRING
, &hex_nt_response
, OPT_NT
, "NT or NTLMv2 Response to the challenge (HEX encoded)"},
2316 { "password", 0, POPT_ARG_STRING
, &opt_password
, OPT_PASSWORD
, "User's plaintext password"},
2317 { "request-lm-key", 0, POPT_ARG_NONE
, &request_lm_key
, OPT_LM_KEY
, "Retrieve LM session key"},
2318 { "request-nt-key", 0, POPT_ARG_NONE
, &request_user_session_key
, OPT_USER_SESSION_KEY
, "Retrieve User (NT) session key"},
2319 { "use-cached-creds", 0, POPT_ARG_NONE
, &use_cached_creds
, OPT_USE_CACHED_CREDS
, "Use cached credentials if no password is given"},
2320 { "allow-mschapv2", 0, POPT_ARG_NONE
, &opt_allow_mschapv2
, OPT_ALLOW_MSCHAPV2
, "Explicitly allow MSCHAPv2" },
2321 { "offline-logon", 0, POPT_ARG_NONE
, &offline_logon
,
2323 "Use cached passwords when DC is offline"},
2324 { "diagnostics", 0, POPT_ARG_NONE
, &diagnostics
,
2326 "Perform diagnostics on the authentication chain"},
2327 { "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" },
2328 { "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" },
2329 { "target-service", 0, POPT_ARG_STRING
, &opt_target_service
, OPT_TARGET_SERVICE
, "Target service (eg http)" },
2330 { "target-hostname", 0, POPT_ARG_STRING
, &opt_target_hostname
, OPT_TARGET_HOSTNAME
, "Target hostname" },
2331 POPT_COMMON_CONFIGFILE
2337 /* Samba client initialisation */
2340 setup_logging("ntlm_auth", DEBUG_STDERR
);
2345 pc
= poptGetContext("ntlm_auth", argc
, argv
, long_options
, 0);
2347 /* Parse command line options */
2350 poptPrintHelp(pc
, stderr
, 0);
2354 while((opt
= poptGetNextOpt(pc
)) != -1) {
2355 /* Get generic config options like --configfile */
2358 poptFreeContext(pc
);
2360 if (!lp_load_global(get_dyn_CONFIGFILE())) {
2361 d_fprintf(stderr
, "ntlm_auth: error opening config file %s. Error was %s\n",
2362 get_dyn_CONFIGFILE(), strerror(errno
));
2366 pc
= poptGetContext(NULL
, argc
, (const char **)argv
, long_options
,
2367 POPT_CONTEXT_KEEP_FIRST
);
2369 while((opt
= poptGetNextOpt(pc
)) != -1) {
2372 opt_challenge
= strhex_to_data_blob(NULL
, hex_challenge
);
2373 if (opt_challenge
.length
!= 8) {
2374 fprintf(stderr
, "hex decode of %s failed! "
2375 "(only got %d bytes)\n",
2377 (int)opt_challenge
.length
);
2382 opt_lm_response
= strhex_to_data_blob(NULL
, hex_lm_response
);
2383 if (opt_lm_response
.length
!= 24) {
2384 fprintf(stderr
, "hex decode of %s failed! "
2385 "(only got %d bytes)\n",
2387 (int)opt_lm_response
.length
);
2393 opt_nt_response
= strhex_to_data_blob(NULL
, hex_nt_response
);
2394 if (opt_nt_response
.length
< 24) {
2395 fprintf(stderr
, "hex decode of %s failed! "
2396 "(only got %d bytes)\n",
2398 (int)opt_nt_response
.length
);
2403 case OPT_REQUIRE_MEMBERSHIP
:
2404 if (strncasecmp_m("S-", require_membership_of
, 2) == 0) {
2405 require_membership_of_sid
= require_membership_of
;
2412 char *domain
= SMB_STRDUP(opt_username
);
2413 char *p
= strchr_m(domain
, *lp_winbind_separator());
2417 if (opt_domain
&& !strequal(opt_domain
, domain
)) {
2418 fprintf(stderr
, "Domain specified in username (%s) "
2419 "doesn't match specified domain (%s)!\n\n",
2420 domain
, opt_domain
);
2421 poptPrintHelp(pc
, stderr
, 0);
2424 opt_domain
= domain
;
2430 /* Note: if opt_domain is "" then send no domain */
2431 if (opt_domain
== NULL
) {
2432 opt_domain
= get_winbind_domain();
2435 if (opt_workstation
== NULL
) {
2436 opt_workstation
= "";
2439 lp_ctx
= loadparm_init_s3(NULL
, loadparm_s3_helpers());
2440 if (lp_ctx
== NULL
) {
2441 fprintf(stderr
, "loadparm_init_s3() failed!\n");
2445 if (helper_protocol
) {
2447 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2448 if (strcmp(helper_protocol
, stdio_helper_protocols
[i
].name
) == 0) {
2449 squid_stream(stdio_helper_protocols
[i
].mode
, lp_ctx
, stdio_helper_protocols
[i
].fn
);
2453 fprintf(stderr
, "unknown helper protocol [%s]\n\n"
2454 "Valid helper protools:\n\n", helper_protocol
);
2456 for (i
=0; i
<NUM_HELPER_MODES
; i
++) {
2457 fprintf(stderr
, "%s\n",
2458 stdio_helper_protocols
[i
].name
);
2464 if (!opt_username
|| !*opt_username
) {
2465 fprintf(stderr
, "username must be specified!\n\n");
2466 poptPrintHelp(pc
, stderr
, 0);
2470 if (opt_challenge
.length
) {
2471 if (!check_auth_crap()) {
2477 if (!opt_password
) {
2478 char pwd
[256] = {0};
2481 rc
= samba_getpass("Password: ", pwd
, sizeof(pwd
), false, false);
2483 opt_password
= SMB_STRDUP(pwd
);
2488 if (!diagnose_ntlm_auth()) {
2494 fstr_sprintf(user
, "%s%c%s", opt_domain
, winbind_separator(), opt_username
);
2495 if (!check_plaintext_auth(user
, opt_password
, True
)) {
2502 poptFreeContext(pc
);