00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "includes.h"
00027 #include "utils/ntlm_auth.h"
00028
00029 #undef DBGC_CLASS
00030 #define DBGC_CLASS DBGC_WINBIND
00031
00032 #define SQUID_BUFFER_SIZE 2010
00033
00034 enum stdio_helper_mode {
00035 SQUID_2_4_BASIC,
00036 SQUID_2_5_BASIC,
00037 SQUID_2_5_NTLMSSP,
00038 NTLMSSP_CLIENT_1,
00039 GSS_SPNEGO,
00040 GSS_SPNEGO_CLIENT,
00041 NTLM_SERVER_1,
00042 NTLM_CHANGE_PASSWORD_1,
00043 NUM_HELPER_MODES
00044 };
00045
00046 typedef void (*stdio_helper_function)(enum stdio_helper_mode stdio_helper_mode,
00047 char *buf, int length);
00048
00049 static void manage_squid_basic_request (enum stdio_helper_mode stdio_helper_mode,
00050 char *buf, int length);
00051
00052 static void manage_squid_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode,
00053 char *buf, int length);
00054
00055 static void manage_client_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode,
00056 char *buf, int length);
00057
00058 static void manage_gss_spnego_request (enum stdio_helper_mode stdio_helper_mode,
00059 char *buf, int length);
00060
00061 static void manage_gss_spnego_client_request (enum stdio_helper_mode stdio_helper_mode,
00062 char *buf, int length);
00063
00064 static void manage_ntlm_server_1_request (enum stdio_helper_mode stdio_helper_mode,
00065 char *buf, int length);
00066
00067 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode helper_mode, char *buf, int length);
00068
00069 static const struct {
00070 enum stdio_helper_mode mode;
00071 const char *name;
00072 stdio_helper_function fn;
00073 } stdio_helper_protocols[] = {
00074 { SQUID_2_4_BASIC, "squid-2.4-basic", manage_squid_basic_request},
00075 { SQUID_2_5_BASIC, "squid-2.5-basic", manage_squid_basic_request},
00076 { SQUID_2_5_NTLMSSP, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request},
00077 { NTLMSSP_CLIENT_1, "ntlmssp-client-1", manage_client_ntlmssp_request},
00078 { GSS_SPNEGO, "gss-spnego", manage_gss_spnego_request},
00079 { GSS_SPNEGO_CLIENT, "gss-spnego-client", manage_gss_spnego_client_request},
00080 { NTLM_SERVER_1, "ntlm-server-1", manage_ntlm_server_1_request},
00081 { NTLM_CHANGE_PASSWORD_1, "ntlm-change-password-1", manage_ntlm_change_password_1_request},
00082 { NUM_HELPER_MODES, NULL, NULL}
00083 };
00084
00085 extern int winbindd_fd;
00086
00087 const char *opt_username;
00088 const char *opt_domain;
00089 const char *opt_workstation;
00090 const char *opt_password;
00091 static DATA_BLOB opt_challenge;
00092 static DATA_BLOB opt_lm_response;
00093 static DATA_BLOB opt_nt_response;
00094 static int request_lm_key;
00095 static int request_user_session_key;
00096 static int use_cached_creds;
00097
00098 static const char *require_membership_of;
00099 static const char *require_membership_of_sid;
00100
00101 static char winbind_separator(void)
00102 {
00103 struct winbindd_response response;
00104 static BOOL got_sep;
00105 static char sep;
00106
00107 if (got_sep)
00108 return sep;
00109
00110 ZERO_STRUCT(response);
00111
00112
00113
00114 if (winbindd_request_response(WINBINDD_INFO, NULL, &response) !=
00115 NSS_STATUS_SUCCESS) {
00116 d_printf("could not obtain winbind separator!\n");
00117 return *lp_winbind_separator();
00118 }
00119
00120 sep = response.data.info.winbind_separator;
00121 got_sep = True;
00122
00123 if (!sep) {
00124 d_printf("winbind separator was NULL!\n");
00125 return *lp_winbind_separator();
00126 }
00127
00128 return sep;
00129 }
00130
00131 const char *get_winbind_domain(void)
00132 {
00133 struct winbindd_response response;
00134
00135 static fstring winbind_domain;
00136 if (*winbind_domain) {
00137 return winbind_domain;
00138 }
00139
00140 ZERO_STRUCT(response);
00141
00142
00143
00144 if (winbindd_request_response(WINBINDD_DOMAIN_NAME, NULL, &response) !=
00145 NSS_STATUS_SUCCESS) {
00146 DEBUG(0, ("could not obtain winbind domain name!\n"));
00147 return lp_workgroup();
00148 }
00149
00150 fstrcpy(winbind_domain, response.data.domain_name);
00151
00152 return winbind_domain;
00153
00154 }
00155
00156 const char *get_winbind_netbios_name(void)
00157 {
00158 struct winbindd_response response;
00159
00160 static fstring winbind_netbios_name;
00161
00162 if (*winbind_netbios_name) {
00163 return winbind_netbios_name;
00164 }
00165
00166 ZERO_STRUCT(response);
00167
00168
00169
00170 if (winbindd_request_response(WINBINDD_NETBIOS_NAME, NULL, &response) !=
00171 NSS_STATUS_SUCCESS) {
00172 DEBUG(0, ("could not obtain winbind netbios name!\n"));
00173 return global_myname();
00174 }
00175
00176 fstrcpy(winbind_netbios_name, response.data.netbios_name);
00177
00178 return winbind_netbios_name;
00179
00180 }
00181
00182 DATA_BLOB get_challenge(void)
00183 {
00184 static DATA_BLOB chal;
00185 if (opt_challenge.length)
00186 return opt_challenge;
00187
00188 chal = data_blob(NULL, 8);
00189
00190 generate_random_buffer(chal.data, chal.length);
00191 return chal;
00192 }
00193
00194
00195
00196
00197 static BOOL parse_ntlm_auth_domain_user(const char *domuser, fstring domain,
00198 fstring user)
00199 {
00200
00201 char *p = strchr(domuser,winbind_separator());
00202
00203 if (!p) {
00204 return False;
00205 }
00206
00207 fstrcpy(user, p+1);
00208 fstrcpy(domain, domuser);
00209 domain[PTR_DIFF(p, domuser)] = 0;
00210 strupper_m(domain);
00211
00212 return True;
00213 }
00214
00215 static BOOL get_require_membership_sid(void) {
00216 struct winbindd_request request;
00217 struct winbindd_response response;
00218
00219 if (!require_membership_of) {
00220 return True;
00221 }
00222
00223 if (require_membership_of_sid) {
00224 return True;
00225 }
00226
00227
00228
00229 ZERO_STRUCT(request);
00230 ZERO_STRUCT(response);
00231
00232 if (!parse_ntlm_auth_domain_user(require_membership_of,
00233 request.data.name.dom_name,
00234 request.data.name.name)) {
00235 DEBUG(0, ("Could not parse %s into seperate domain/name parts!\n",
00236 require_membership_of));
00237 return False;
00238 }
00239
00240 if (winbindd_request_response(WINBINDD_LOOKUPNAME, &request, &response) !=
00241 NSS_STATUS_SUCCESS) {
00242 DEBUG(0, ("Winbindd lookupname failed to resolve %s into a SID!\n",
00243 require_membership_of));
00244 return False;
00245 }
00246
00247 require_membership_of_sid = SMB_STRDUP(response.data.sid.sid);
00248
00249 if (require_membership_of_sid)
00250 return True;
00251
00252 return False;
00253 }
00254
00255
00256 static BOOL check_plaintext_auth(const char *user, const char *pass,
00257 BOOL stdout_diagnostics)
00258 {
00259 struct winbindd_request request;
00260 struct winbindd_response response;
00261 NSS_STATUS result;
00262
00263 if (!get_require_membership_sid()) {
00264 return False;
00265 }
00266
00267
00268
00269 ZERO_STRUCT(request);
00270 ZERO_STRUCT(response);
00271
00272 fstrcpy(request.data.auth.user, user);
00273 fstrcpy(request.data.auth.pass, pass);
00274 if (require_membership_of_sid)
00275 pstrcpy(request.data.auth.require_membership_of_sid, require_membership_of_sid);
00276
00277 result = winbindd_request_response(WINBINDD_PAM_AUTH, &request, &response);
00278
00279
00280
00281 if (stdout_diagnostics) {
00282 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
00283 d_printf("Reading winbind reply failed! (0x01)\n");
00284 }
00285
00286 d_printf("%s: %s (0x%x)\n",
00287 response.data.auth.nt_status_string,
00288 response.data.auth.error_string,
00289 response.data.auth.nt_status);
00290 } else {
00291 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
00292 DEBUG(1, ("Reading winbind reply failed! (0x01)\n"));
00293 }
00294
00295 DEBUG(3, ("%s: %s (0x%x)\n",
00296 response.data.auth.nt_status_string,
00297 response.data.auth.error_string,
00298 response.data.auth.nt_status));
00299 }
00300
00301 return (result == NSS_STATUS_SUCCESS);
00302 }
00303
00304
00305
00306 NTSTATUS contact_winbind_auth_crap(const char *username,
00307 const char *domain,
00308 const char *workstation,
00309 const DATA_BLOB *challenge,
00310 const DATA_BLOB *lm_response,
00311 const DATA_BLOB *nt_response,
00312 uint32 flags,
00313 uint8 lm_key[8],
00314 uint8 user_session_key[16],
00315 char **error_string,
00316 char **unix_name)
00317 {
00318 NTSTATUS nt_status;
00319 NSS_STATUS result;
00320 struct winbindd_request request;
00321 struct winbindd_response response;
00322
00323 if (!get_require_membership_sid()) {
00324 return NT_STATUS_INVALID_PARAMETER;
00325 }
00326
00327 ZERO_STRUCT(request);
00328 ZERO_STRUCT(response);
00329
00330 request.flags = flags;
00331
00332 request.data.auth_crap.logon_parameters = MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT | MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT;
00333
00334 if (require_membership_of_sid)
00335 fstrcpy(request.data.auth_crap.require_membership_of_sid, require_membership_of_sid);
00336
00337 fstrcpy(request.data.auth_crap.user, username);
00338 fstrcpy(request.data.auth_crap.domain, domain);
00339
00340 fstrcpy(request.data.auth_crap.workstation,
00341 workstation);
00342
00343 memcpy(request.data.auth_crap.chal, challenge->data, MIN(challenge->length, 8));
00344
00345 if (lm_response && lm_response->length) {
00346 memcpy(request.data.auth_crap.lm_resp,
00347 lm_response->data,
00348 MIN(lm_response->length, sizeof(request.data.auth_crap.lm_resp)));
00349 request.data.auth_crap.lm_resp_len = lm_response->length;
00350 }
00351
00352 if (nt_response && nt_response->length) {
00353 memcpy(request.data.auth_crap.nt_resp,
00354 nt_response->data,
00355 MIN(nt_response->length, sizeof(request.data.auth_crap.nt_resp)));
00356 request.data.auth_crap.nt_resp_len = nt_response->length;
00357 }
00358
00359 result = winbindd_request_response(WINBINDD_PAM_AUTH_CRAP, &request, &response);
00360
00361
00362
00363 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
00364 nt_status = NT_STATUS_UNSUCCESSFUL;
00365 if (error_string)
00366 *error_string = smb_xstrdup("Reading winbind reply failed!");
00367 free_response(&response);
00368 return nt_status;
00369 }
00370
00371 nt_status = (NT_STATUS(response.data.auth.nt_status));
00372 if (!NT_STATUS_IS_OK(nt_status)) {
00373 if (error_string)
00374 *error_string = smb_xstrdup(response.data.auth.error_string);
00375 free_response(&response);
00376 return nt_status;
00377 }
00378
00379 if ((flags & WBFLAG_PAM_LMKEY) && lm_key) {
00380 memcpy(lm_key, response.data.auth.first_8_lm_hash,
00381 sizeof(response.data.auth.first_8_lm_hash));
00382 }
00383 if ((flags & WBFLAG_PAM_USER_SESSION_KEY) && user_session_key) {
00384 memcpy(user_session_key, response.data.auth.user_session_key,
00385 sizeof(response.data.auth.user_session_key));
00386 }
00387
00388 if (flags & WBFLAG_PAM_UNIX_NAME) {
00389 *unix_name = SMB_STRDUP((char *)response.extra_data.data);
00390 if (!*unix_name) {
00391 free_response(&response);
00392 return NT_STATUS_NO_MEMORY;
00393 }
00394 }
00395
00396 free_response(&response);
00397 return nt_status;
00398 }
00399
00400
00401 static NTSTATUS contact_winbind_change_pswd_auth_crap(const char *username,
00402 const char *domain,
00403 const DATA_BLOB new_nt_pswd,
00404 const DATA_BLOB old_nt_hash_enc,
00405 const DATA_BLOB new_lm_pswd,
00406 const DATA_BLOB old_lm_hash_enc,
00407 char **error_string)
00408 {
00409 NTSTATUS nt_status;
00410 NSS_STATUS result;
00411 struct winbindd_request request;
00412 struct winbindd_response response;
00413
00414 if (!get_require_membership_sid())
00415 {
00416 if(error_string)
00417 *error_string = smb_xstrdup("Can't get membership sid.");
00418 return NT_STATUS_INVALID_PARAMETER;
00419 }
00420
00421 ZERO_STRUCT(request);
00422 ZERO_STRUCT(response);
00423
00424 if(username != NULL)
00425 fstrcpy(request.data.chng_pswd_auth_crap.user, username);
00426 if(domain != NULL)
00427 fstrcpy(request.data.chng_pswd_auth_crap.domain,domain);
00428
00429 if(new_nt_pswd.length)
00430 {
00431 memcpy(request.data.chng_pswd_auth_crap.new_nt_pswd, new_nt_pswd.data, sizeof(request.data.chng_pswd_auth_crap.new_nt_pswd));
00432 request.data.chng_pswd_auth_crap.new_nt_pswd_len = new_nt_pswd.length;
00433 }
00434
00435 if(old_nt_hash_enc.length)
00436 {
00437 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));
00438 request.data.chng_pswd_auth_crap.old_nt_hash_enc_len = old_nt_hash_enc.length;
00439 }
00440
00441 if(new_lm_pswd.length)
00442 {
00443 memcpy(request.data.chng_pswd_auth_crap.new_lm_pswd, new_lm_pswd.data, sizeof(request.data.chng_pswd_auth_crap.new_lm_pswd));
00444 request.data.chng_pswd_auth_crap.new_lm_pswd_len = new_lm_pswd.length;
00445 }
00446
00447 if(old_lm_hash_enc.length)
00448 {
00449 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));
00450 request.data.chng_pswd_auth_crap.old_lm_hash_enc_len = old_lm_hash_enc.length;
00451 }
00452
00453 result = winbindd_request_response(WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP, &request, &response);
00454
00455
00456
00457 if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0))
00458 {
00459 nt_status = NT_STATUS_UNSUCCESSFUL;
00460 if (error_string)
00461 *error_string = smb_xstrdup("Reading winbind reply failed!");
00462 free_response(&response);
00463 return nt_status;
00464 }
00465
00466 nt_status = (NT_STATUS(response.data.auth.nt_status));
00467 if (!NT_STATUS_IS_OK(nt_status))
00468 {
00469 if (error_string)
00470 *error_string = smb_xstrdup(response.data.auth.error_string);
00471 free_response(&response);
00472 return nt_status;
00473 }
00474
00475 free_response(&response);
00476
00477 return nt_status;
00478 }
00479
00480 static NTSTATUS winbind_pw_check(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
00481 {
00482 static const char zeros[16] = { 0, };
00483 NTSTATUS nt_status;
00484 char *error_string;
00485 uint8 lm_key[8];
00486 uint8 user_sess_key[16];
00487 char *unix_name;
00488
00489 nt_status = contact_winbind_auth_crap(ntlmssp_state->user, ntlmssp_state->domain,
00490 ntlmssp_state->workstation,
00491 &ntlmssp_state->chal,
00492 &ntlmssp_state->lm_resp,
00493 &ntlmssp_state->nt_resp,
00494 WBFLAG_PAM_LMKEY | WBFLAG_PAM_USER_SESSION_KEY | WBFLAG_PAM_UNIX_NAME,
00495 lm_key, user_sess_key,
00496 &error_string, &unix_name);
00497
00498 if (NT_STATUS_IS_OK(nt_status)) {
00499 if (memcmp(lm_key, zeros, 8) != 0) {
00500 *lm_session_key = data_blob(NULL, 16);
00501 memcpy(lm_session_key->data, lm_key, 8);
00502 memset(lm_session_key->data+8, '\0', 8);
00503 }
00504
00505 if (memcmp(user_sess_key, zeros, 16) != 0) {
00506 *user_session_key = data_blob(user_sess_key, 16);
00507 }
00508 ntlmssp_state->auth_context = talloc_strdup(ntlmssp_state->mem_ctx, unix_name);
00509 SAFE_FREE(unix_name);
00510 } else {
00511 DEBUG(NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED) ? 0 : 3,
00512 ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
00513 ntlmssp_state->domain, ntlmssp_state->user,
00514 ntlmssp_state->workstation,
00515 error_string ? error_string : "unknown error (NULL)"));
00516 ntlmssp_state->auth_context = NULL;
00517 }
00518 return nt_status;
00519 }
00520
00521 static NTSTATUS local_pw_check(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
00522 {
00523 NTSTATUS nt_status;
00524 uint8 lm_pw[16], nt_pw[16];
00525
00526 nt_lm_owf_gen (opt_password, nt_pw, lm_pw);
00527
00528 nt_status = ntlm_password_check(ntlmssp_state->mem_ctx,
00529 &ntlmssp_state->chal,
00530 &ntlmssp_state->lm_resp,
00531 &ntlmssp_state->nt_resp,
00532 NULL, NULL,
00533 ntlmssp_state->user,
00534 ntlmssp_state->user,
00535 ntlmssp_state->domain,
00536 lm_pw, nt_pw, user_session_key, lm_session_key);
00537
00538 if (NT_STATUS_IS_OK(nt_status)) {
00539 ntlmssp_state->auth_context = talloc_asprintf(ntlmssp_state->mem_ctx,
00540 "%s%c%s", ntlmssp_state->domain,
00541 *lp_winbind_separator(),
00542 ntlmssp_state->user);
00543 } else {
00544 DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
00545 ntlmssp_state->domain, ntlmssp_state->user, ntlmssp_state->workstation,
00546 nt_errstr(nt_status)));
00547 ntlmssp_state->auth_context = NULL;
00548 }
00549 return nt_status;
00550 }
00551
00552 static NTSTATUS ntlm_auth_start_ntlmssp_client(NTLMSSP_STATE **client_ntlmssp_state)
00553 {
00554 NTSTATUS status;
00555 if ( (opt_username == NULL) || (opt_domain == NULL) ) {
00556 status = NT_STATUS_UNSUCCESSFUL;
00557 DEBUG(1, ("Need username and domain for NTLMSSP\n"));
00558 return NT_STATUS_INVALID_PARAMETER;
00559 }
00560
00561 status = ntlmssp_client_start(client_ntlmssp_state);
00562
00563 if (!NT_STATUS_IS_OK(status)) {
00564 DEBUG(1, ("Could not start NTLMSSP client: %s\n",
00565 nt_errstr(status)));
00566 ntlmssp_end(client_ntlmssp_state);
00567 return status;
00568 }
00569
00570 status = ntlmssp_set_username(*client_ntlmssp_state, opt_username);
00571
00572 if (!NT_STATUS_IS_OK(status)) {
00573 DEBUG(1, ("Could not set username: %s\n",
00574 nt_errstr(status)));
00575 ntlmssp_end(client_ntlmssp_state);
00576 return status;
00577 }
00578
00579 status = ntlmssp_set_domain(*client_ntlmssp_state, opt_domain);
00580
00581 if (!NT_STATUS_IS_OK(status)) {
00582 DEBUG(1, ("Could not set domain: %s\n",
00583 nt_errstr(status)));
00584 ntlmssp_end(client_ntlmssp_state);
00585 return status;
00586 }
00587
00588 if (opt_password) {
00589 status = ntlmssp_set_password(*client_ntlmssp_state, opt_password);
00590
00591 if (!NT_STATUS_IS_OK(status)) {
00592 DEBUG(1, ("Could not set password: %s\n",
00593 nt_errstr(status)));
00594 ntlmssp_end(client_ntlmssp_state);
00595 return status;
00596 }
00597 }
00598
00599 return NT_STATUS_OK;
00600 }
00601
00602 static NTSTATUS ntlm_auth_start_ntlmssp_server(NTLMSSP_STATE **ntlmssp_state)
00603 {
00604 NTSTATUS status = ntlmssp_server_start(ntlmssp_state);
00605
00606 if (!NT_STATUS_IS_OK(status)) {
00607 DEBUG(1, ("Could not start NTLMSSP server: %s\n",
00608 nt_errstr(status)));
00609 return status;
00610 }
00611
00612
00613 if (opt_password) {
00614 (*ntlmssp_state)->check_password = local_pw_check;
00615 (*ntlmssp_state)->get_domain = lp_workgroup;
00616 (*ntlmssp_state)->get_global_myname = global_myname;
00617 } else {
00618 (*ntlmssp_state)->check_password = winbind_pw_check;
00619 (*ntlmssp_state)->get_domain = get_winbind_domain;
00620 (*ntlmssp_state)->get_global_myname = get_winbind_netbios_name;
00621 }
00622 return NT_STATUS_OK;
00623 }
00624
00625
00626
00627
00628
00629 static NTSTATUS do_ccache_ntlm_auth(DATA_BLOB initial_msg, DATA_BLOB challenge_msg,
00630 DATA_BLOB *reply)
00631 {
00632 struct winbindd_request wb_request;
00633 struct winbindd_response wb_response;
00634 NSS_STATUS result;
00635
00636
00637 ZERO_STRUCT(wb_request);
00638 ZERO_STRUCT(wb_response);
00639
00640 fstr_sprintf(wb_request.data.ccache_ntlm_auth.user,
00641 "%s%c%s", opt_domain, winbind_separator(), opt_username);
00642 wb_request.data.ccache_ntlm_auth.uid = geteuid();
00643 wb_request.data.ccache_ntlm_auth.initial_blob_len = initial_msg.length;
00644 wb_request.data.ccache_ntlm_auth.challenge_blob_len = challenge_msg.length;
00645 wb_request.extra_len = initial_msg.length + challenge_msg.length;
00646
00647 if (wb_request.extra_len > 0) {
00648 wb_request.extra_data.data = SMB_MALLOC_ARRAY(char, wb_request.extra_len);
00649 if (wb_request.extra_data.data == NULL) {
00650 return NT_STATUS_NO_MEMORY;
00651 }
00652
00653 memcpy(wb_request.extra_data.data, initial_msg.data, initial_msg.length);
00654 memcpy(wb_request.extra_data.data + initial_msg.length,
00655 challenge_msg.data, challenge_msg.length);
00656 }
00657
00658 result = winbindd_request_response(WINBINDD_CCACHE_NTLMAUTH, &wb_request, &wb_response);
00659 SAFE_FREE(wb_request.extra_data.data);
00660
00661 if (result != NSS_STATUS_SUCCESS) {
00662 free_response(&wb_response);
00663 return NT_STATUS_UNSUCCESSFUL;
00664 }
00665
00666 if (reply) {
00667 *reply = data_blob(wb_response.extra_data.data,
00668 wb_response.data.ccache_ntlm_auth.auth_blob_len);
00669 if (wb_response.data.ccache_ntlm_auth.auth_blob_len > 0 &&
00670 reply->data == NULL) {
00671 free_response(&wb_response);
00672 return NT_STATUS_NO_MEMORY;
00673 }
00674 }
00675
00676 free_response(&wb_response);
00677 return NT_STATUS_MORE_PROCESSING_REQUIRED;
00678 }
00679
00680 static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode,
00681 char *buf, int length)
00682 {
00683 static NTLMSSP_STATE *ntlmssp_state = NULL;
00684 static char* want_feature_list = NULL;
00685 static uint32 neg_flags = 0;
00686 static BOOL have_session_key = False;
00687 static DATA_BLOB session_key;
00688 DATA_BLOB request, reply;
00689 NTSTATUS nt_status;
00690
00691 if (strlen(buf) < 2) {
00692 DEBUG(1, ("NTLMSSP query [%s] invalid", buf));
00693 x_fprintf(x_stdout, "BH NTLMSSP query invalid\n");
00694 return;
00695 }
00696
00697 if (strlen(buf) > 3) {
00698 if(strncmp(buf, "SF ", 3) == 0){
00699 DEBUG(10, ("Setting flags to negotioate\n"));
00700 SAFE_FREE(want_feature_list);
00701 want_feature_list = SMB_STRNDUP(buf+3, strlen(buf)-3);
00702 x_fprintf(x_stdout, "OK\n");
00703 return;
00704 }
00705 request = base64_decode_data_blob(buf + 3);
00706 } else {
00707 request = data_blob(NULL, 0);
00708 }
00709
00710 if ((strncmp(buf, "PW ", 3) == 0)) {
00711
00712
00713 opt_password = SMB_STRNDUP((const char *)request.data, request.length);
00714
00715 if (opt_password == NULL) {
00716 DEBUG(1, ("Out of memory\n"));
00717 x_fprintf(x_stdout, "BH Out of memory\n");
00718 data_blob_free(&request);
00719 return;
00720 }
00721
00722 x_fprintf(x_stdout, "OK\n");
00723 data_blob_free(&request);
00724 return;
00725 }
00726
00727 if (strncmp(buf, "YR", 2) == 0) {
00728 if (ntlmssp_state)
00729 ntlmssp_end(&ntlmssp_state);
00730 } else if (strncmp(buf, "KK", 2) == 0) {
00731
00732 } else if (strncmp(buf, "GF", 2) == 0) {
00733 DEBUG(10, ("Requested negotiated NTLMSSP flags\n"));
00734 x_fprintf(x_stdout, "GF 0x%08lx\n", have_session_key?neg_flags:0l);
00735 data_blob_free(&request);
00736 return;
00737 } else if (strncmp(buf, "GK", 2) == 0) {
00738 DEBUG(10, ("Requested NTLMSSP session key\n"));
00739 if(have_session_key) {
00740 char *key64 = base64_encode_data_blob(session_key);
00741 x_fprintf(x_stdout, "GK %s\n", key64?key64:"<NULL>");
00742 SAFE_FREE(key64);
00743 } else {
00744 x_fprintf(x_stdout, "BH No session key available\n");
00745 }
00746
00747 data_blob_free(&request);
00748 return;
00749 } else {
00750 DEBUG(1, ("NTLMSSP query [%s] invalid", buf));
00751 x_fprintf(x_stdout, "BH NTLMSSP query invalid\n");
00752 return;
00753 }
00754
00755 if (!ntlmssp_state) {
00756 if (!NT_STATUS_IS_OK(nt_status = ntlm_auth_start_ntlmssp_server(&ntlmssp_state))) {
00757 x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
00758 return;
00759 }
00760 ntlmssp_want_feature_list(ntlmssp_state, want_feature_list);
00761 }
00762
00763 DEBUG(10, ("got NTLMSSP packet:\n"));
00764 dump_data(10, (const char *)request.data, request.length);
00765
00766 nt_status = ntlmssp_update(ntlmssp_state, request, &reply);
00767
00768 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
00769 char *reply_base64 = base64_encode_data_blob(reply);
00770 x_fprintf(x_stdout, "TT %s\n", reply_base64);
00771 SAFE_FREE(reply_base64);
00772 data_blob_free(&reply);
00773 DEBUG(10, ("NTLMSSP challenge\n"));
00774 } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) {
00775 x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
00776 DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status)));
00777
00778 ntlmssp_end(&ntlmssp_state);
00779 } else if (!NT_STATUS_IS_OK(nt_status)) {
00780 x_fprintf(x_stdout, "NA %s\n", nt_errstr(nt_status));
00781 DEBUG(10, ("NTLMSSP %s\n", nt_errstr(nt_status)));
00782 } else {
00783 x_fprintf(x_stdout, "AF %s\n", (char *)ntlmssp_state->auth_context);
00784 DEBUG(10, ("NTLMSSP OK!\n"));
00785
00786 if(have_session_key)
00787 data_blob_free(&session_key);
00788 session_key = data_blob(ntlmssp_state->session_key.data,
00789 ntlmssp_state->session_key.length);
00790 neg_flags = ntlmssp_state->neg_flags;
00791 have_session_key = True;
00792 }
00793
00794 data_blob_free(&request);
00795 }
00796
00797 static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode,
00798 char *buf, int length)
00799 {
00800
00801
00802
00803
00804 static NTLMSSP_STATE *ntlmssp_state = NULL;
00805 static DATA_BLOB initial_message;
00806 static char* want_feature_list = NULL;
00807 static uint32 neg_flags = 0;
00808 static BOOL have_session_key = False;
00809 static DATA_BLOB session_key;
00810 DATA_BLOB request, reply;
00811 NTSTATUS nt_status;
00812 BOOL first = False;
00813
00814 if (!opt_username || !*opt_username) {
00815 x_fprintf(x_stderr, "username must be specified!\n\n");
00816 exit(1);
00817 }
00818
00819 if (strlen(buf) < 2) {
00820 DEBUG(1, ("NTLMSSP query [%s] invalid", buf));
00821 x_fprintf(x_stdout, "BH NTLMSSP query invalid\n");
00822 return;
00823 }
00824
00825 if (strlen(buf) > 3) {
00826 if(strncmp(buf, "SF ", 3) == 0) {
00827 DEBUG(10, ("Looking for flags to negotiate\n"));
00828 SAFE_FREE(want_feature_list);
00829 want_feature_list = SMB_STRNDUP(buf+3, strlen(buf)-3);
00830 x_fprintf(x_stdout, "OK\n");
00831 return;
00832 }
00833 request = base64_decode_data_blob(buf + 3);
00834 } else {
00835 request = data_blob(NULL, 0);
00836 }
00837
00838 if (strncmp(buf, "PW ", 3) == 0) {
00839
00840
00841 opt_password = SMB_STRNDUP((const char *)request.data, request.length);
00842
00843 if (opt_password == NULL) {
00844 DEBUG(1, ("Out of memory\n"));
00845 x_fprintf(x_stdout, "BH Out of memory\n");
00846 data_blob_free(&request);
00847 return;
00848 }
00849
00850 x_fprintf(x_stdout, "OK\n");
00851 data_blob_free(&request);
00852 return;
00853 }
00854
00855 if (!ntlmssp_state && use_cached_creds) {
00856
00857 DATA_BLOB empty_blob = data_blob(NULL, 0);
00858
00859 nt_status = do_ccache_ntlm_auth(empty_blob, empty_blob, NULL);
00860 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
00861
00862 use_cached_creds = False;
00863 }
00864 }
00865
00866 if (opt_password == NULL && !use_cached_creds) {
00867
00868
00869
00870
00871 DEBUG(10, ("Requesting password\n"));
00872 x_fprintf(x_stdout, "PW\n");
00873 return;
00874 }
00875
00876 if (strncmp(buf, "YR", 2) == 0) {
00877 if (ntlmssp_state)
00878 ntlmssp_end(&ntlmssp_state);
00879 } else if (strncmp(buf, "TT", 2) == 0) {
00880
00881 } else if (strncmp(buf, "GF", 2) == 0) {
00882 DEBUG(10, ("Requested negotiated NTLMSSP flags\n"));
00883 x_fprintf(x_stdout, "GF 0x%08lx\n", have_session_key?neg_flags:0l);
00884 data_blob_free(&request);
00885 return;
00886 } else if (strncmp(buf, "GK", 2) == 0 ) {
00887 DEBUG(10, ("Requested session key\n"));
00888
00889 if(have_session_key) {
00890 char *key64 = base64_encode_data_blob(session_key);
00891 x_fprintf(x_stdout, "GK %s\n", key64?key64:"<NULL>");
00892 SAFE_FREE(key64);
00893 }
00894 else {
00895 x_fprintf(x_stdout, "BH No session key available\n");
00896 }
00897
00898 data_blob_free(&request);
00899 return;
00900 } else {
00901 DEBUG(1, ("NTLMSSP query [%s] invalid", buf));
00902 x_fprintf(x_stdout, "BH NTLMSSP query invalid\n");
00903 return;
00904 }
00905
00906 if (!ntlmssp_state) {
00907 if (!NT_STATUS_IS_OK(nt_status = ntlm_auth_start_ntlmssp_client(&ntlmssp_state))) {
00908 x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
00909 return;
00910 }
00911 ntlmssp_want_feature_list(ntlmssp_state, want_feature_list);
00912 first = True;
00913 initial_message = data_blob(NULL, 0);
00914 }
00915
00916 DEBUG(10, ("got NTLMSSP packet:\n"));
00917 dump_data(10, (const char *)request.data, request.length);
00918
00919 if (use_cached_creds && !opt_password && !first) {
00920 nt_status = do_ccache_ntlm_auth(initial_message, request, &reply);
00921 } else {
00922 nt_status = ntlmssp_update(ntlmssp_state, request, &reply);
00923 }
00924
00925 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
00926 char *reply_base64 = base64_encode_data_blob(reply);
00927 if (first) {
00928 x_fprintf(x_stdout, "YR %s\n", reply_base64);
00929 } else {
00930 x_fprintf(x_stdout, "KK %s\n", reply_base64);
00931 }
00932 SAFE_FREE(reply_base64);
00933 if (first) {
00934 initial_message = reply;
00935 } else {
00936 data_blob_free(&reply);
00937 }
00938 DEBUG(10, ("NTLMSSP challenge\n"));
00939 } else if (NT_STATUS_IS_OK(nt_status)) {
00940 char *reply_base64 = base64_encode_data_blob(reply);
00941 x_fprintf(x_stdout, "AF %s\n", reply_base64);
00942 SAFE_FREE(reply_base64);
00943
00944 if(have_session_key)
00945 data_blob_free(&session_key);
00946
00947 session_key = data_blob(ntlmssp_state->session_key.data,
00948 ntlmssp_state->session_key.length);
00949 neg_flags = ntlmssp_state->neg_flags;
00950 have_session_key = True;
00951
00952 DEBUG(10, ("NTLMSSP OK!\n"));
00953 if (ntlmssp_state)
00954 ntlmssp_end(&ntlmssp_state);
00955 } else {
00956 x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
00957 DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status)));
00958 if (ntlmssp_state)
00959 ntlmssp_end(&ntlmssp_state);
00960 }
00961
00962 data_blob_free(&request);
00963 }
00964
00965 static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode,
00966 char *buf, int length)
00967 {
00968 char *user, *pass;
00969 user=buf;
00970
00971 pass=(char *)memchr(buf,' ',length);
00972 if (!pass) {
00973 DEBUG(2, ("Password not found. Denying access\n"));
00974 x_fprintf(x_stdout, "ERR\n");
00975 return;
00976 }
00977 *pass='\0';
00978 pass++;
00979
00980 if (stdio_helper_mode == SQUID_2_5_BASIC) {
00981 rfc1738_unescape(user);
00982 rfc1738_unescape(pass);
00983 }
00984
00985 if (check_plaintext_auth(user, pass, False)) {
00986 x_fprintf(x_stdout, "OK\n");
00987 } else {
00988 x_fprintf(x_stdout, "ERR\n");
00989 }
00990 }
00991
00992 static void offer_gss_spnego_mechs(void) {
00993
00994 DATA_BLOB token;
00995 SPNEGO_DATA spnego;
00996 ssize_t len;
00997 char *reply_base64;
00998
00999 pstring principal;
01000 pstring myname_lower;
01001
01002 ZERO_STRUCT(spnego);
01003
01004 pstrcpy(myname_lower, global_myname());
01005 strlower_m(myname_lower);
01006
01007 pstr_sprintf(principal, "%s$@%s", myname_lower, lp_realm());
01008
01009
01010 spnego.type = SPNEGO_NEG_TOKEN_INIT;
01011 spnego.negTokenInit.mechTypes = SMB_XMALLOC_ARRAY(const char *, 2);
01012 #ifdef HAVE_KRB5
01013 spnego.negTokenInit.mechTypes[0] = smb_xstrdup(OID_KERBEROS5_OLD);
01014 spnego.negTokenInit.mechTypes[1] = smb_xstrdup(OID_NTLMSSP);
01015 spnego.negTokenInit.mechTypes[2] = NULL;
01016 #else
01017 spnego.negTokenInit.mechTypes[0] = smb_xstrdup(OID_NTLMSSP);
01018 spnego.negTokenInit.mechTypes[1] = NULL;
01019 #endif
01020
01021
01022 spnego.negTokenInit.mechListMIC = data_blob(principal,
01023 strlen(principal));
01024
01025 len = write_spnego_data(&token, &spnego);
01026 free_spnego_data(&spnego);
01027
01028 if (len == -1) {
01029 DEBUG(1, ("Could not write SPNEGO data blob\n"));
01030 x_fprintf(x_stdout, "BH Could not write SPNEGO data blob\n");
01031 return;
01032 }
01033
01034 reply_base64 = base64_encode_data_blob(token);
01035 x_fprintf(x_stdout, "TT %s *\n", reply_base64);
01036
01037 SAFE_FREE(reply_base64);
01038 data_blob_free(&token);
01039 DEBUG(10, ("sent SPNEGO negTokenInit\n"));
01040 return;
01041 }
01042
01043 static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode,
01044 char *buf, int length)
01045 {
01046 static NTLMSSP_STATE *ntlmssp_state = NULL;
01047 SPNEGO_DATA request, response;
01048 DATA_BLOB token;
01049 NTSTATUS status;
01050 ssize_t len;
01051
01052 char *user = NULL;
01053 char *domain = NULL;
01054
01055 const char *reply_code;
01056 char *reply_base64;
01057 pstring reply_argument;
01058
01059 if (strlen(buf) < 2) {
01060 DEBUG(1, ("SPENGO query [%s] invalid", buf));
01061 x_fprintf(x_stdout, "BH SPENGO query invalid\n");
01062 return;
01063 }
01064
01065 if (strncmp(buf, "YR", 2) == 0) {
01066 if (ntlmssp_state)
01067 ntlmssp_end(&ntlmssp_state);
01068 } else if (strncmp(buf, "KK", 2) == 0) {
01069
01070 } else {
01071 DEBUG(1, ("SPENGO query [%s] invalid", buf));
01072 x_fprintf(x_stdout, "BH SPENGO query invalid\n");
01073 return;
01074 }
01075
01076 if ( (strlen(buf) == 2)) {
01077
01078
01079
01080
01081 offer_gss_spnego_mechs();
01082 return;
01083 }
01084
01085
01086
01087 if (strlen(buf) <= 3) {
01088 DEBUG(1, ("GSS-SPNEGO query [%s] invalid\n", buf));
01089 x_fprintf(x_stdout, "BH GSS-SPNEGO query invalid\n");
01090 return;
01091 }
01092
01093 token = base64_decode_data_blob(buf + 3);
01094 len = read_spnego_data(token, &request);
01095 data_blob_free(&token);
01096
01097 if (len == -1) {
01098 DEBUG(1, ("GSS-SPNEGO query [%s] invalid", buf));
01099 x_fprintf(x_stdout, "BH GSS-SPNEGO query invalid\n");
01100 return;
01101 }
01102
01103 if (request.type == SPNEGO_NEG_TOKEN_INIT) {
01104
01105
01106
01107
01108 if ( (request.negTokenInit.mechTypes == NULL) ||
01109 (request.negTokenInit.mechTypes[0] == NULL) ) {
01110 DEBUG(1, ("Client did not offer any mechanism"));
01111 x_fprintf(x_stdout, "BH Client did not offer any mechanism\n");
01112 return;
01113 }
01114
01115 status = NT_STATUS_UNSUCCESSFUL;
01116 if (strcmp(request.negTokenInit.mechTypes[0], OID_NTLMSSP) == 0) {
01117
01118 if ( request.negTokenInit.mechToken.data == NULL ) {
01119 DEBUG(1, ("Client did not provide NTLMSSP data\n"));
01120 x_fprintf(x_stdout, "BH Client did not provide NTLMSSP data\n");
01121 return;
01122 }
01123
01124 if ( ntlmssp_state != NULL ) {
01125 DEBUG(1, ("Client wants a new NTLMSSP challenge, but "
01126 "already got one\n"));
01127 x_fprintf(x_stdout, "BH Client wants a new NTLMSSP challenge, but already got one\n");
01128 ntlmssp_end(&ntlmssp_state);
01129 return;
01130 }
01131
01132 if (!NT_STATUS_IS_OK(status = ntlm_auth_start_ntlmssp_server(&ntlmssp_state))) {
01133 x_fprintf(x_stdout, "BH %s\n", nt_errstr(status));
01134 return;
01135 }
01136
01137 DEBUG(10, ("got NTLMSSP packet:\n"));
01138 dump_data(10, (const char *)request.negTokenInit.mechToken.data,
01139 request.negTokenInit.mechToken.length);
01140
01141 response.type = SPNEGO_NEG_TOKEN_TARG;
01142 response.negTokenTarg.supportedMech = SMB_STRDUP(OID_NTLMSSP);
01143 response.negTokenTarg.mechListMIC = data_blob(NULL, 0);
01144
01145 status = ntlmssp_update(ntlmssp_state,
01146 request.negTokenInit.mechToken,
01147 &response.negTokenTarg.responseToken);
01148 }
01149
01150 #ifdef HAVE_KRB5
01151 if (strcmp(request.negTokenInit.mechTypes[0], OID_KERBEROS5_OLD) == 0) {
01152
01153 TALLOC_CTX *mem_ctx = talloc_init("manage_gss_spnego_request");
01154 char *principal;
01155 DATA_BLOB ap_rep;
01156 DATA_BLOB session_key;
01157
01158 if ( request.negTokenInit.mechToken.data == NULL ) {
01159 DEBUG(1, ("Client did not provide Kerberos data\n"));
01160 x_fprintf(x_stdout, "BH Client did not provide Kerberos data\n");
01161 return;
01162 }
01163
01164 response.type = SPNEGO_NEG_TOKEN_TARG;
01165 response.negTokenTarg.supportedMech = SMB_STRDUP(OID_KERBEROS5_OLD);
01166 response.negTokenTarg.mechListMIC = data_blob(NULL, 0);
01167 response.negTokenTarg.responseToken = data_blob(NULL, 0);
01168
01169 status = ads_verify_ticket(mem_ctx, lp_realm(), 0,
01170 &request.negTokenInit.mechToken,
01171 &principal, NULL, &ap_rep,
01172 &session_key);
01173
01174 talloc_destroy(mem_ctx);
01175
01176
01177
01178
01179 if (NT_STATUS_IS_OK(status)) {
01180
01181 domain = strchr_m(principal, '@');
01182
01183 if (domain == NULL) {
01184 DEBUG(1, ("Did not get a valid principal "
01185 "from ads_verify_ticket\n"));
01186 x_fprintf(x_stdout, "BH Did not get a valid principal from ads_verify_ticket\n");
01187 return;
01188 }
01189
01190 *domain++ = '\0';
01191 domain = SMB_STRDUP(domain);
01192 user = SMB_STRDUP(principal);
01193
01194 data_blob_free(&ap_rep);
01195
01196 SAFE_FREE(principal);
01197 }
01198 }
01199 #endif
01200
01201 } else {
01202
01203 if ( (request.negTokenTarg.supportedMech == NULL) ||
01204 ( strcmp(request.negTokenTarg.supportedMech, OID_NTLMSSP) != 0 ) ) {
01205
01206
01207 DEBUG(1, ("Got a negTokenTarg for something non-NTLMSSP: %s\n",
01208 request.negTokenTarg.supportedMech));
01209 x_fprintf(x_stdout, "BH Got a negTokenTarg for something non-NTLMSSP\n");
01210 return;
01211 }
01212
01213 if (request.negTokenTarg.responseToken.data == NULL) {
01214 DEBUG(1, ("Got a negTokenTarg without a responseToken!\n"));
01215 x_fprintf(x_stdout, "BH Got a negTokenTarg without a responseToken!\n");
01216 return;
01217 }
01218
01219 status = ntlmssp_update(ntlmssp_state,
01220 request.negTokenTarg.responseToken,
01221 &response.negTokenTarg.responseToken);
01222
01223 response.type = SPNEGO_NEG_TOKEN_TARG;
01224 response.negTokenTarg.supportedMech = SMB_STRDUP(OID_NTLMSSP);
01225 response.negTokenTarg.mechListMIC = data_blob(NULL, 0);
01226
01227 if (NT_STATUS_IS_OK(status)) {
01228 user = SMB_STRDUP(ntlmssp_state->user);
01229 domain = SMB_STRDUP(ntlmssp_state->domain);
01230 ntlmssp_end(&ntlmssp_state);
01231 }
01232 }
01233
01234 free_spnego_data(&request);
01235
01236 if (NT_STATUS_IS_OK(status)) {
01237 response.negTokenTarg.negResult = SPNEGO_ACCEPT_COMPLETED;
01238 reply_code = "AF";
01239 pstr_sprintf(reply_argument, "%s\\%s", domain, user);
01240 } else if (NT_STATUS_EQUAL(status,
01241 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
01242 response.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
01243 reply_code = "TT";
01244 pstr_sprintf(reply_argument, "*");
01245 } else {
01246 response.negTokenTarg.negResult = SPNEGO_REJECT;
01247 reply_code = "NA";
01248 pstrcpy(reply_argument, nt_errstr(status));
01249 }
01250
01251 SAFE_FREE(user);
01252 SAFE_FREE(domain);
01253
01254 len = write_spnego_data(&token, &response);
01255 free_spnego_data(&response);
01256
01257 if (len == -1) {
01258 DEBUG(1, ("Could not write SPNEGO data blob\n"));
01259 x_fprintf(x_stdout, "BH Could not write SPNEGO data blob\n");
01260 return;
01261 }
01262
01263 reply_base64 = base64_encode_data_blob(token);
01264
01265 x_fprintf(x_stdout, "%s %s %s\n",
01266 reply_code, reply_base64, reply_argument);
01267
01268 SAFE_FREE(reply_base64);
01269 data_blob_free(&token);
01270
01271 return;
01272 }
01273
01274 static NTLMSSP_STATE *client_ntlmssp_state = NULL;
01275
01276 static BOOL manage_client_ntlmssp_init(SPNEGO_DATA spnego)
01277 {
01278 NTSTATUS status;
01279 DATA_BLOB null_blob = data_blob(NULL, 0);
01280 DATA_BLOB to_server;
01281 char *to_server_base64;
01282 const char *my_mechs[] = {OID_NTLMSSP, NULL};
01283
01284 DEBUG(10, ("Got spnego negTokenInit with NTLMSSP\n"));
01285
01286 if (client_ntlmssp_state != NULL) {
01287 DEBUG(1, ("Request for initial SPNEGO request where "
01288 "we already have a state\n"));
01289 return False;
01290 }
01291
01292 if (!client_ntlmssp_state) {
01293 if (!NT_STATUS_IS_OK(status = ntlm_auth_start_ntlmssp_client(&client_ntlmssp_state))) {
01294 x_fprintf(x_stdout, "BH %s\n", nt_errstr(status));
01295 return False;
01296 }
01297 }
01298
01299
01300 if (opt_password == NULL) {
01301
01302
01303
01304
01305
01306 DEBUG(10, ("Requesting password\n"));
01307 x_fprintf(x_stdout, "PW\n");
01308 return True;
01309 }
01310
01311 spnego.type = SPNEGO_NEG_TOKEN_INIT;
01312 spnego.negTokenInit.mechTypes = my_mechs;
01313 spnego.negTokenInit.reqFlags = 0;
01314 spnego.negTokenInit.mechListMIC = null_blob;
01315
01316 status = ntlmssp_update(client_ntlmssp_state, null_blob,
01317 &spnego.negTokenInit.mechToken);
01318
01319 if ( !(NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) ||
01320 NT_STATUS_IS_OK(status)) ) {
01321 DEBUG(1, ("Expected OK or MORE_PROCESSING_REQUIRED, got: %s\n",
01322 nt_errstr(status)));
01323 ntlmssp_end(&client_ntlmssp_state);
01324 return False;
01325 }
01326
01327 write_spnego_data(&to_server, &spnego);
01328 data_blob_free(&spnego.negTokenInit.mechToken);
01329
01330 to_server_base64 = base64_encode_data_blob(to_server);
01331 data_blob_free(&to_server);
01332 x_fprintf(x_stdout, "KK %s\n", to_server_base64);
01333 SAFE_FREE(to_server_base64);
01334 return True;
01335 }
01336
01337 static void manage_client_ntlmssp_targ(SPNEGO_DATA spnego)
01338 {
01339 NTSTATUS status;
01340 DATA_BLOB null_blob = data_blob(NULL, 0);
01341 DATA_BLOB request;
01342 DATA_BLOB to_server;
01343 char *to_server_base64;
01344
01345 DEBUG(10, ("Got spnego negTokenTarg with NTLMSSP\n"));
01346
01347 if (client_ntlmssp_state == NULL) {
01348 DEBUG(1, ("Got NTLMSSP tArg without a client state\n"));
01349 x_fprintf(x_stdout, "BH Got NTLMSSP tArg without a client state\n");
01350 return;
01351 }
01352
01353 if (spnego.negTokenTarg.negResult == SPNEGO_REJECT) {
01354 x_fprintf(x_stdout, "NA\n");
01355 ntlmssp_end(&client_ntlmssp_state);
01356 return;
01357 }
01358
01359 if (spnego.negTokenTarg.negResult == SPNEGO_ACCEPT_COMPLETED) {
01360 x_fprintf(x_stdout, "AF\n");
01361 ntlmssp_end(&client_ntlmssp_state);
01362 return;
01363 }
01364
01365 status = ntlmssp_update(client_ntlmssp_state,
01366 spnego.negTokenTarg.responseToken,
01367 &request);
01368
01369 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
01370 DEBUG(1, ("Expected MORE_PROCESSING_REQUIRED from "
01371 "ntlmssp_client_update, got: %s\n",
01372 nt_errstr(status)));
01373 x_fprintf(x_stdout, "BH Expected MORE_PROCESSING_REQUIRED from ntlmssp_client_update\n");
01374 data_blob_free(&request);
01375 ntlmssp_end(&client_ntlmssp_state);
01376 return;
01377 }
01378
01379 spnego.type = SPNEGO_NEG_TOKEN_TARG;
01380 spnego.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
01381 spnego.negTokenTarg.supportedMech = (char *)OID_NTLMSSP;
01382 spnego.negTokenTarg.responseToken = request;
01383 spnego.negTokenTarg.mechListMIC = null_blob;
01384
01385 write_spnego_data(&to_server, &spnego);
01386 data_blob_free(&request);
01387
01388 to_server_base64 = base64_encode_data_blob(to_server);
01389 data_blob_free(&to_server);
01390 x_fprintf(x_stdout, "KK %s\n", to_server_base64);
01391 SAFE_FREE(to_server_base64);
01392 return;
01393 }
01394
01395 #ifdef HAVE_KRB5
01396
01397 static BOOL manage_client_krb5_init(SPNEGO_DATA spnego)
01398 {
01399 char *principal;
01400 DATA_BLOB tkt, to_server;
01401 DATA_BLOB session_key_krb5 = data_blob(NULL, 0);
01402 SPNEGO_DATA reply;
01403 char *reply_base64;
01404 int retval;
01405
01406 const char *my_mechs[] = {OID_KERBEROS5_OLD, NULL};
01407 ssize_t len;
01408
01409 if ( (spnego.negTokenInit.mechListMIC.data == NULL) ||
01410 (spnego.negTokenInit.mechListMIC.length == 0) ) {
01411 DEBUG(1, ("Did not get a principal for krb5\n"));
01412 return False;
01413 }
01414
01415 principal = (char *)SMB_MALLOC(
01416 spnego.negTokenInit.mechListMIC.length+1);
01417
01418 if (principal == NULL) {
01419 DEBUG(1, ("Could not malloc principal\n"));
01420 return False;
01421 }
01422
01423 memcpy(principal, spnego.negTokenInit.mechListMIC.data,
01424 spnego.negTokenInit.mechListMIC.length);
01425 principal[spnego.negTokenInit.mechListMIC.length] = '\0';
01426
01427 retval = cli_krb5_get_ticket(principal, 0, &tkt, &session_key_krb5, 0, NULL, NULL);
01428
01429 if (retval) {
01430
01431 pstring user;
01432
01433
01434
01435
01436 if (opt_password == NULL) {
01437 DEBUG(10, ("Requesting password\n"));
01438 x_fprintf(x_stdout, "PW\n");
01439 return True;
01440 }
01441
01442 pstr_sprintf(user, "%s@%s", opt_username, opt_domain);
01443
01444 if ((retval = kerberos_kinit_password(user, opt_password, 0, NULL))) {
01445 DEBUG(10, ("Requesting TGT failed: %s\n", error_message(retval)));
01446 return False;
01447 }
01448
01449 retval = cli_krb5_get_ticket(principal, 0, &tkt, &session_key_krb5, 0, NULL, NULL);
01450
01451 if (retval) {
01452 DEBUG(10, ("Kinit suceeded, but getting a ticket failed: %s\n", error_message(retval)));
01453 return False;
01454 }
01455 }
01456
01457 data_blob_free(&session_key_krb5);
01458
01459 ZERO_STRUCT(reply);
01460
01461 reply.type = SPNEGO_NEG_TOKEN_INIT;
01462 reply.negTokenInit.mechTypes = my_mechs;
01463 reply.negTokenInit.reqFlags = 0;
01464 reply.negTokenInit.mechToken = tkt;
01465 reply.negTokenInit.mechListMIC = data_blob(NULL, 0);
01466
01467 len = write_spnego_data(&to_server, &reply);
01468 data_blob_free(&tkt);
01469
01470 if (len == -1) {
01471 DEBUG(1, ("Could not write SPNEGO data blob\n"));
01472 return False;
01473 }
01474
01475 reply_base64 = base64_encode_data_blob(to_server);
01476 x_fprintf(x_stdout, "KK %s *\n", reply_base64);
01477
01478 SAFE_FREE(reply_base64);
01479 data_blob_free(&to_server);
01480 DEBUG(10, ("sent GSS-SPNEGO KERBEROS5 negTokenInit\n"));
01481 return True;
01482 }
01483
01484 static void manage_client_krb5_targ(SPNEGO_DATA spnego)
01485 {
01486 switch (spnego.negTokenTarg.negResult) {
01487 case SPNEGO_ACCEPT_INCOMPLETE:
01488 DEBUG(1, ("Got a Kerberos negTokenTarg with ACCEPT_INCOMPLETE\n"));
01489 x_fprintf(x_stdout, "BH Got a Kerberos negTokenTarg with ACCEPT_INCOMPLETE\n");
01490 break;
01491 case SPNEGO_ACCEPT_COMPLETED:
01492 DEBUG(10, ("Accept completed\n"));
01493 x_fprintf(x_stdout, "AF\n");
01494 break;
01495 case SPNEGO_REJECT:
01496 DEBUG(10, ("Rejected\n"));
01497 x_fprintf(x_stdout, "NA\n");
01498 break;
01499 default:
01500 DEBUG(1, ("Got an invalid negTokenTarg\n"));
01501 x_fprintf(x_stdout, "AF\n");
01502 }
01503 }
01504
01505 #endif
01506
01507 static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode,
01508 char *buf, int length)
01509 {
01510 DATA_BLOB request;
01511 SPNEGO_DATA spnego;
01512 ssize_t len;
01513
01514 if (!opt_username || !*opt_username) {
01515 x_fprintf(x_stderr, "username must be specified!\n\n");
01516 exit(1);
01517 }
01518
01519 if (strlen(buf) <= 3) {
01520 DEBUG(1, ("SPNEGO query [%s] too short\n", buf));
01521 x_fprintf(x_stdout, "BH SPNEGO query too short\n");
01522 return;
01523 }
01524
01525 request = base64_decode_data_blob(buf+3);
01526
01527 if (strncmp(buf, "PW ", 3) == 0) {
01528
01529
01530
01531 opt_password = SMB_STRNDUP((const char *)request.data, request.length);
01532
01533 if (opt_password == NULL) {
01534 DEBUG(1, ("Out of memory\n"));
01535 x_fprintf(x_stdout, "BH Out of memory\n");
01536 data_blob_free(&request);
01537 return;
01538 }
01539
01540 x_fprintf(x_stdout, "OK\n");
01541 data_blob_free(&request);
01542 return;
01543 }
01544
01545 if ( (strncmp(buf, "TT ", 3) != 0) &&
01546 (strncmp(buf, "AF ", 3) != 0) &&
01547 (strncmp(buf, "NA ", 3) != 0) ) {
01548 DEBUG(1, ("SPNEGO request [%s] invalid\n", buf));
01549 x_fprintf(x_stdout, "BH SPNEGO request invalid\n");
01550 data_blob_free(&request);
01551 return;
01552 }
01553
01554
01555
01556
01557 len = read_spnego_data(request, &spnego);
01558 data_blob_free(&request);
01559
01560 if (len == -1) {
01561 DEBUG(1, ("Could not read SPNEGO data for [%s]\n", buf));
01562 x_fprintf(x_stdout, "BH Could not read SPNEGO data\n");
01563 return;
01564 }
01565
01566 if (spnego.type == SPNEGO_NEG_TOKEN_INIT) {
01567
01568
01569
01570 const char **mechType = (const char **)spnego.negTokenInit.mechTypes;
01571
01572 while (*mechType != NULL) {
01573
01574 #ifdef HAVE_KRB5
01575 if ( (strcmp(*mechType, OID_KERBEROS5_OLD) == 0) ||
01576 (strcmp(*mechType, OID_KERBEROS5) == 0) ) {
01577 if (manage_client_krb5_init(spnego))
01578 goto out;
01579 }
01580 #endif
01581
01582 if (strcmp(*mechType, OID_NTLMSSP) == 0) {
01583 if (manage_client_ntlmssp_init(spnego))
01584 goto out;
01585 }
01586
01587 mechType++;
01588 }
01589
01590 DEBUG(1, ("Server offered no compatible mechanism\n"));
01591 x_fprintf(x_stdout, "BH Server offered no compatible mechanism\n");
01592 return;
01593 }
01594
01595 if (spnego.type == SPNEGO_NEG_TOKEN_TARG) {
01596
01597 if (spnego.negTokenTarg.supportedMech == NULL) {
01598
01599
01600
01601
01602 switch (spnego.negTokenTarg.negResult) {
01603 case SPNEGO_ACCEPT_COMPLETED:
01604 x_fprintf(x_stdout, "AF\n");
01605 break;
01606 case SPNEGO_REJECT:
01607 x_fprintf(x_stdout, "NA\n");
01608 break;
01609 default:
01610 DEBUG(1, ("Got a negTokenTarg with no mech and an "
01611 "unknown negResult: %d\n",
01612 spnego.negTokenTarg.negResult));
01613 x_fprintf(x_stdout, "BH Got a negTokenTarg with no mech and an unknown negResult\n");
01614 }
01615
01616 ntlmssp_end(&client_ntlmssp_state);
01617 goto out;
01618 }
01619
01620 if (strcmp(spnego.negTokenTarg.supportedMech,
01621 OID_NTLMSSP) == 0) {
01622 manage_client_ntlmssp_targ(spnego);
01623 goto out;
01624 }
01625
01626 #if HAVE_KRB5
01627 if (strcmp(spnego.negTokenTarg.supportedMech,
01628 OID_KERBEROS5_OLD) == 0) {
01629 manage_client_krb5_targ(spnego);
01630 goto out;
01631 }
01632 #endif
01633
01634 }
01635
01636 DEBUG(1, ("Got an SPNEGO token I could not handle [%s]!\n", buf));
01637 x_fprintf(x_stdout, "BH Got an SPNEGO token I could not handle\n");
01638 return;
01639
01640 out:
01641 free_spnego_data(&spnego);
01642 return;
01643 }
01644
01645 static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode,
01646 char *buf, int length)
01647 {
01648 char *request, *parameter;
01649 static DATA_BLOB challenge;
01650 static DATA_BLOB lm_response;
01651 static DATA_BLOB nt_response;
01652 static char *full_username;
01653 static char *username;
01654 static char *domain;
01655 static char *plaintext_password;
01656 static BOOL ntlm_server_1_user_session_key;
01657 static BOOL ntlm_server_1_lm_session_key;
01658
01659 if (strequal(buf, ".")) {
01660 if (!full_username && !username) {
01661 x_fprintf(x_stdout, "Error: No username supplied!\n");
01662 } else if (plaintext_password) {
01663
01664 if (!full_username) {
01665 if (asprintf(&full_username, "%s%c%s", domain, winbind_separator(), username) == -1) {
01666 x_fprintf(x_stdout, "Error: Out of memory in asprintf!\n.\n");
01667 return;
01668 }
01669 }
01670 if (check_plaintext_auth(full_username, plaintext_password, False)) {
01671 x_fprintf(x_stdout, "Authenticated: Yes\n");
01672 } else {
01673 x_fprintf(x_stdout, "Authenticated: No\n");
01674 }
01675 } else if (!lm_response.data && !nt_response.data) {
01676 x_fprintf(x_stdout, "Error: No password supplied!\n");
01677 } else if (!challenge.data) {
01678 x_fprintf(x_stdout, "Error: No lanman-challenge supplied!\n");
01679 } else {
01680 char *error_string = NULL;
01681 uchar lm_key[8];
01682 uchar user_session_key[16];
01683 uint32 flags = 0;
01684
01685 if (full_username && !username) {
01686 fstring fstr_user;
01687 fstring fstr_domain;
01688
01689 if (!parse_ntlm_auth_domain_user(full_username, fstr_user, fstr_domain)) {
01690
01691 x_fprintf(x_stdout, "Error: Could not parse into domain and username\n");
01692 }
01693 SAFE_FREE(username);
01694 SAFE_FREE(domain);
01695 username = smb_xstrdup(fstr_user);
01696 domain = smb_xstrdup(fstr_domain);
01697 }
01698
01699 if (!domain) {
01700 domain = smb_xstrdup(get_winbind_domain());
01701 }
01702
01703 if (ntlm_server_1_lm_session_key)
01704 flags |= WBFLAG_PAM_LMKEY;
01705
01706 if (ntlm_server_1_user_session_key)
01707 flags |= WBFLAG_PAM_USER_SESSION_KEY;
01708
01709 if (!NT_STATUS_IS_OK(
01710 contact_winbind_auth_crap(username,
01711 domain,
01712 global_myname(),
01713 &challenge,
01714 &lm_response,
01715 &nt_response,
01716 flags,
01717 lm_key,
01718 user_session_key,
01719 &error_string,
01720 NULL))) {
01721
01722 x_fprintf(x_stdout, "Authenticated: No\n");
01723 x_fprintf(x_stdout, "Authentication-Error: %s\n.\n", error_string);
01724 SAFE_FREE(error_string);
01725 } else {
01726 static char zeros[16];
01727 char *hex_lm_key;
01728 char *hex_user_session_key;
01729
01730 x_fprintf(x_stdout, "Authenticated: Yes\n");
01731
01732 if (ntlm_server_1_lm_session_key
01733 && (memcmp(zeros, lm_key,
01734 sizeof(lm_key)) != 0)) {
01735 hex_lm_key = hex_encode(NULL,
01736 (const unsigned char *)lm_key,
01737 sizeof(lm_key));
01738 x_fprintf(x_stdout, "LANMAN-Session-Key: %s\n", hex_lm_key);
01739 TALLOC_FREE(hex_lm_key);
01740 }
01741
01742 if (ntlm_server_1_user_session_key
01743 && (memcmp(zeros, user_session_key,
01744 sizeof(user_session_key)) != 0)) {
01745 hex_user_session_key = hex_encode(NULL,
01746 (const unsigned char *)user_session_key,
01747 sizeof(user_session_key));
01748 x_fprintf(x_stdout, "User-Session-Key: %s\n", hex_user_session_key);
01749 TALLOC_FREE(hex_user_session_key);
01750 }
01751 }
01752 }
01753
01754 challenge = data_blob(NULL, 0);
01755 nt_response = data_blob(NULL, 0);
01756 lm_response = data_blob(NULL, 0);
01757 SAFE_FREE(full_username);
01758 SAFE_FREE(username);
01759 SAFE_FREE(domain);
01760 SAFE_FREE(plaintext_password);
01761 ntlm_server_1_user_session_key = False;
01762 ntlm_server_1_lm_session_key = False;
01763 x_fprintf(x_stdout, ".\n");
01764
01765 return;
01766 }
01767
01768 request = buf;
01769
01770
01771 parameter = strstr_m(request, ":: ");
01772 if (!parameter) {
01773 parameter = strstr_m(request, ": ");
01774
01775 if (!parameter) {
01776 DEBUG(0, ("Parameter not found!\n"));
01777 x_fprintf(x_stdout, "Error: Parameter not found!\n.\n");
01778 return;
01779 }
01780
01781 parameter[0] ='\0';
01782 parameter++;
01783 parameter[0] ='\0';
01784 parameter++;
01785
01786 } else {
01787 parameter[0] ='\0';
01788 parameter++;
01789 parameter[0] ='\0';
01790 parameter++;
01791 parameter[0] ='\0';
01792 parameter++;
01793
01794 base64_decode_inplace(parameter);
01795 }
01796
01797 if (strequal(request, "LANMAN-Challenge")) {
01798 challenge = strhex_to_data_blob(NULL, parameter);
01799 if (challenge.length != 8) {
01800 x_fprintf(x_stdout, "Error: hex decode of %s failed! (got %d bytes, expected 8)\n.\n",
01801 parameter,
01802 (int)challenge.length);
01803 challenge = data_blob(NULL, 0);
01804 }
01805 } else if (strequal(request, "NT-Response")) {
01806 nt_response = strhex_to_data_blob(NULL, parameter);
01807 if (nt_response.length < 24) {
01808 x_fprintf(x_stdout, "Error: hex decode of %s failed! (only got %d bytes, needed at least 24)\n.\n",
01809 parameter,
01810 (int)nt_response.length);
01811 nt_response = data_blob(NULL, 0);
01812 }
01813 } else if (strequal(request, "LANMAN-Response")) {
01814 lm_response = strhex_to_data_blob(NULL, parameter);
01815 if (lm_response.length != 24) {
01816 x_fprintf(x_stdout, "Error: hex decode of %s failed! (got %d bytes, expected 24)\n.\n",
01817 parameter,
01818 (int)lm_response.length);
01819 lm_response = data_blob(NULL, 0);
01820 }
01821 } else if (strequal(request, "Password")) {
01822 plaintext_password = smb_xstrdup(parameter);
01823 } else if (strequal(request, "NT-Domain")) {
01824 domain = smb_xstrdup(parameter);
01825 } else if (strequal(request, "Username")) {
01826 username = smb_xstrdup(parameter);
01827 } else if (strequal(request, "Full-Username")) {
01828 full_username = smb_xstrdup(parameter);
01829 } else if (strequal(request, "Request-User-Session-Key")) {
01830 ntlm_server_1_user_session_key = strequal(parameter, "Yes");
01831 } else if (strequal(request, "Request-LanMan-Session-Key")) {
01832 ntlm_server_1_lm_session_key = strequal(parameter, "Yes");
01833 } else {
01834 x_fprintf(x_stdout, "Error: Unknown request %s\n.\n", request);
01835 }
01836 }
01837
01838 static void manage_ntlm_change_password_1_request(enum stdio_helper_mode helper_mode, char *buf, int length)
01839 {
01840 char *request, *parameter;
01841 static DATA_BLOB new_nt_pswd;
01842 static DATA_BLOB old_nt_hash_enc;
01843 static DATA_BLOB new_lm_pswd;
01844 static DATA_BLOB old_lm_hash_enc;
01845 static char *full_username = NULL;
01846 static char *username = NULL;
01847 static char *domain = NULL;
01848 static char *newpswd = NULL;
01849 static char *oldpswd = NULL;
01850
01851 if (strequal(buf, ".")) {
01852 if(newpswd && oldpswd) {
01853 uchar old_nt_hash[16];
01854 uchar old_lm_hash[16];
01855 uchar new_nt_hash[16];
01856 uchar new_lm_hash[16];
01857
01858 new_nt_pswd = data_blob(NULL, 516);
01859 old_nt_hash_enc = data_blob(NULL, 16);
01860
01861
01862
01863 E_md4hash(oldpswd, old_nt_hash);
01864 E_md4hash(newpswd, new_nt_hash);
01865
01866
01867
01868
01869
01870
01871
01872
01873
01874
01875
01876
01877 if (lp_client_lanman_auth() &&
01878 E_deshash(newpswd, new_lm_hash) &&
01879 E_deshash(oldpswd, old_lm_hash)) {
01880 new_lm_pswd = data_blob(NULL, 516);
01881 old_lm_hash_enc = data_blob(NULL, 16);
01882 encode_pw_buffer(new_lm_pswd.data, newpswd,
01883 STR_UNICODE);
01884
01885 SamOEMhash(new_lm_pswd.data, old_nt_hash, 516);
01886 E_old_pw_hash(new_nt_hash, old_lm_hash,
01887 old_lm_hash_enc.data);
01888 } else {
01889 new_lm_pswd.data = NULL;
01890 new_lm_pswd.length = 0;
01891 old_lm_hash_enc.data = NULL;
01892 old_lm_hash_enc.length = 0;
01893 }
01894
01895 encode_pw_buffer(new_nt_pswd.data, newpswd,
01896 STR_UNICODE);
01897
01898 SamOEMhash(new_nt_pswd.data, old_nt_hash, 516);
01899 E_old_pw_hash(new_nt_hash, old_nt_hash,
01900 old_nt_hash_enc.data);
01901 }
01902
01903 if (!full_username && !username) {
01904 x_fprintf(x_stdout, "Error: No username supplied!\n");
01905 } else if ((!new_nt_pswd.data || !old_nt_hash_enc.data) &&
01906 (!new_lm_pswd.data || old_lm_hash_enc.data) ) {
01907 x_fprintf(x_stdout, "Error: No NT or LM password "
01908 "blobs supplied!\n");
01909 } else {
01910 char *error_string = NULL;
01911
01912 if (full_username && !username) {
01913 fstring fstr_user;
01914 fstring fstr_domain;
01915
01916 if (!parse_ntlm_auth_domain_user(full_username,
01917 fstr_user,
01918 fstr_domain)) {
01919
01920
01921
01922 x_fprintf(x_stdout, "Error: Could not "
01923 "parse into domain and "
01924 "username\n");
01925 SAFE_FREE(username);
01926 username = smb_xstrdup(full_username);
01927 } else {
01928 SAFE_FREE(username);
01929 SAFE_FREE(domain);
01930 username = smb_xstrdup(fstr_user);
01931 domain = smb_xstrdup(fstr_domain);
01932 }
01933
01934 }
01935
01936 if(!NT_STATUS_IS_OK(contact_winbind_change_pswd_auth_crap(
01937 username, domain,
01938 new_nt_pswd,
01939 old_nt_hash_enc,
01940 new_lm_pswd,
01941 old_lm_hash_enc,
01942 &error_string))) {
01943 x_fprintf(x_stdout, "Password-Change: No\n");
01944 x_fprintf(x_stdout, "Password-Change-Error: "
01945 "%s\n.\n", error_string);
01946 } else {
01947 x_fprintf(x_stdout, "Password-Change: Yes\n");
01948 }
01949
01950 SAFE_FREE(error_string);
01951 }
01952
01953 new_nt_pswd = data_blob(NULL, 0);
01954 old_nt_hash_enc = data_blob(NULL, 0);
01955 new_lm_pswd = data_blob(NULL, 0);
01956 old_nt_hash_enc = data_blob(NULL, 0);
01957 SAFE_FREE(full_username);
01958 SAFE_FREE(username);
01959 SAFE_FREE(domain);
01960 SAFE_FREE(newpswd);
01961 SAFE_FREE(oldpswd);
01962 x_fprintf(x_stdout, ".\n");
01963
01964 return;
01965 }
01966
01967 request = buf;
01968
01969
01970 parameter = strstr_m(request, ":: ");
01971 if (!parameter) {
01972 parameter = strstr_m(request, ": ");
01973
01974 if (!parameter) {
01975 DEBUG(0, ("Parameter not found!\n"));
01976 x_fprintf(x_stdout, "Error: Parameter not found!\n.\n");
01977 return;
01978 }
01979
01980 parameter[0] ='\0';
01981 parameter++;
01982 parameter[0] ='\0';
01983 parameter++;
01984 } else {
01985 parameter[0] ='\0';
01986 parameter++;
01987 parameter[0] ='\0';
01988 parameter++;
01989 parameter[0] ='\0';
01990 parameter++;
01991
01992 base64_decode_inplace(parameter);
01993 }
01994
01995 if (strequal(request, "new-nt-password-blob")) {
01996 new_nt_pswd = strhex_to_data_blob(NULL, parameter);
01997 if (new_nt_pswd.length != 516) {
01998 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
01999 "(got %d bytes, expected 516)\n.\n",
02000 parameter,
02001 (int)new_nt_pswd.length);
02002 new_nt_pswd = data_blob(NULL, 0);
02003 }
02004 } else if (strequal(request, "old-nt-hash-blob")) {
02005 old_nt_hash_enc = strhex_to_data_blob(NULL, parameter);
02006 if (old_nt_hash_enc.length != 16) {
02007 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
02008 "(got %d bytes, expected 16)\n.\n",
02009 parameter,
02010 (int)old_nt_hash_enc.length);
02011 old_nt_hash_enc = data_blob(NULL, 0);
02012 }
02013 } else if (strequal(request, "new-lm-password-blob")) {
02014 new_lm_pswd = strhex_to_data_blob(NULL, parameter);
02015 if (new_lm_pswd.length != 516) {
02016 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
02017 "(got %d bytes, expected 516)\n.\n",
02018 parameter,
02019 (int)new_lm_pswd.length);
02020 new_lm_pswd = data_blob(NULL, 0);
02021 }
02022 }
02023 else if (strequal(request, "old-lm-hash-blob")) {
02024 old_lm_hash_enc = strhex_to_data_blob(NULL, parameter);
02025 if (old_lm_hash_enc.length != 16)
02026 {
02027 x_fprintf(x_stdout, "Error: hex decode of %s failed! "
02028 "(got %d bytes, expected 16)\n.\n",
02029 parameter,
02030 (int)old_lm_hash_enc.length);
02031 old_lm_hash_enc = data_blob(NULL, 0);
02032 }
02033 } else if (strequal(request, "nt-domain")) {
02034 domain = smb_xstrdup(parameter);
02035 } else if(strequal(request, "username")) {
02036 username = smb_xstrdup(parameter);
02037 } else if(strequal(request, "full-username")) {
02038 username = smb_xstrdup(parameter);
02039 } else if(strequal(request, "new-password")) {
02040 newpswd = smb_xstrdup(parameter);
02041 } else if (strequal(request, "old-password")) {
02042 oldpswd = smb_xstrdup(parameter);
02043 } else {
02044 x_fprintf(x_stdout, "Error: Unknown request %s\n.\n", request);
02045 }
02046 }
02047
02048 static void manage_squid_request(enum stdio_helper_mode helper_mode, stdio_helper_function fn)
02049 {
02050 char buf[SQUID_BUFFER_SIZE+1];
02051 int length;
02052 char *c;
02053 static BOOL err;
02054
02055
02056 if (fgets(buf, sizeof(buf)-1, stdin) == NULL) {
02057 if (ferror(stdin)) {
02058 DEBUG(1, ("fgets() failed! dying..... errno=%d (%s)\n", ferror(stdin),
02059 strerror(ferror(stdin))));
02060
02061 exit(1);
02062 }
02063 exit(0);
02064 }
02065
02066 c=(char *)memchr(buf,'\n',sizeof(buf)-1);
02067 if (c) {
02068 *c = '\0';
02069 length = c-buf;
02070 } else {
02071 err = 1;
02072 return;
02073 }
02074 if (err) {
02075 DEBUG(2, ("Oversized message\n"));
02076 x_fprintf(x_stderr, "ERR\n");
02077 err = 0;
02078 return;
02079 }
02080
02081 DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf,length));
02082
02083 if (buf[0] == '\0') {
02084 DEBUG(2, ("Invalid Request\n"));
02085 x_fprintf(x_stderr, "ERR\n");
02086 return;
02087 }
02088
02089 fn(helper_mode, buf, length);
02090 }
02091
02092
02093 static void squid_stream(enum stdio_helper_mode stdio_mode, stdio_helper_function fn) {
02094
02095 x_setbuf(x_stdout, NULL);
02096 x_setbuf(x_stderr, NULL);
02097 while(1) {
02098 manage_squid_request(stdio_mode, fn);
02099 }
02100 }
02101
02102
02103
02104
02105 static BOOL check_auth_crap(void)
02106 {
02107 NTSTATUS nt_status;
02108 uint32 flags = 0;
02109 char lm_key[8];
02110 char user_session_key[16];
02111 char *hex_lm_key;
02112 char *hex_user_session_key;
02113 char *error_string;
02114 static uint8 zeros[16];
02115
02116 x_setbuf(x_stdout, NULL);
02117
02118 if (request_lm_key)
02119 flags |= WBFLAG_PAM_LMKEY;
02120
02121 if (request_user_session_key)
02122 flags |= WBFLAG_PAM_USER_SESSION_KEY;
02123
02124 flags |= WBFLAG_PAM_NT_STATUS_SQUASH;
02125
02126 nt_status = contact_winbind_auth_crap(opt_username, opt_domain,
02127 opt_workstation,
02128 &opt_challenge,
02129 &opt_lm_response,
02130 &opt_nt_response,
02131 flags,
02132 (unsigned char *)lm_key,
02133 (unsigned char *)user_session_key,
02134 &error_string, NULL);
02135
02136 if (!NT_STATUS_IS_OK(nt_status)) {
02137 x_fprintf(x_stdout, "%s (0x%x)\n",
02138 error_string,
02139 NT_STATUS_V(nt_status));
02140 SAFE_FREE(error_string);
02141 return False;
02142 }
02143
02144 if (request_lm_key
02145 && (memcmp(zeros, lm_key,
02146 sizeof(lm_key)) != 0)) {
02147 hex_lm_key = hex_encode(NULL, (const unsigned char *)lm_key,
02148 sizeof(lm_key));
02149 x_fprintf(x_stdout, "LM_KEY: %s\n", hex_lm_key);
02150 TALLOC_FREE(hex_lm_key);
02151 }
02152 if (request_user_session_key
02153 && (memcmp(zeros, user_session_key,
02154 sizeof(user_session_key)) != 0)) {
02155 hex_user_session_key = hex_encode(NULL, (const unsigned char *)user_session_key,
02156 sizeof(user_session_key));
02157 x_fprintf(x_stdout, "NT_KEY: %s\n", hex_user_session_key);
02158 TALLOC_FREE(hex_user_session_key);
02159 }
02160
02161 return True;
02162 }
02163
02164
02165
02166 enum {
02167 OPT_USERNAME = 1000,
02168 OPT_DOMAIN,
02169 OPT_WORKSTATION,
02170 OPT_CHALLENGE,
02171 OPT_RESPONSE,
02172 OPT_LM,
02173 OPT_NT,
02174 OPT_PASSWORD,
02175 OPT_LM_KEY,
02176 OPT_USER_SESSION_KEY,
02177 OPT_DIAGNOSTICS,
02178 OPT_REQUIRE_MEMBERSHIP,
02179 OPT_USE_CACHED_CREDS
02180 };
02181
02182 int main(int argc, const char **argv)
02183 {
02184 int opt;
02185 static const char *helper_protocol;
02186 static int diagnostics;
02187
02188 static const char *hex_challenge;
02189 static const char *hex_lm_response;
02190 static const char *hex_nt_response;
02191
02192 poptContext pc;
02193
02194
02195
02196
02197
02198
02199
02200
02201
02202 struct poptOption long_options[] = {
02203 POPT_AUTOHELP
02204 { "helper-protocol", 0, POPT_ARG_STRING, &helper_protocol, OPT_DOMAIN, "operate as a stdio-based helper", "helper protocol to use"},
02205 { "username", 0, POPT_ARG_STRING, &opt_username, OPT_USERNAME, "username"},
02206 { "domain", 0, POPT_ARG_STRING, &opt_domain, OPT_DOMAIN, "domain name"},
02207 { "workstation", 0, POPT_ARG_STRING, &opt_workstation, OPT_WORKSTATION, "workstation"},
02208 { "challenge", 0, POPT_ARG_STRING, &hex_challenge, OPT_CHALLENGE, "challenge (HEX encoded)"},
02209 { "lm-response", 0, POPT_ARG_STRING, &hex_lm_response, OPT_LM, "LM Response to the challenge (HEX encoded)"},
02210 { "nt-response", 0, POPT_ARG_STRING, &hex_nt_response, OPT_NT, "NT or NTLMv2 Response to the challenge (HEX encoded)"},
02211 { "password", 0, POPT_ARG_STRING, &opt_password, OPT_PASSWORD, "User's plaintext password"},
02212 { "request-lm-key", 0, POPT_ARG_NONE, &request_lm_key, OPT_LM_KEY, "Retrieve LM session key"},
02213 { "request-nt-key", 0, POPT_ARG_NONE, &request_user_session_key, OPT_USER_SESSION_KEY, "Retrieve User (NT) session key"},
02214 { "use-cached-creds", 0, POPT_ARG_NONE, &use_cached_creds, OPT_USE_CACHED_CREDS, "Use cached credentials if no password is given"},
02215 { "diagnostics", 0, POPT_ARG_NONE, &diagnostics, OPT_DIAGNOSTICS, "Perform diagnostics on the authentictaion chain"},
02216 { "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" },
02217 POPT_COMMON_SAMBA
02218 POPT_TABLEEND
02219 };
02220
02221
02222 load_case_tables();
02223
02224 dbf = x_stderr;
02225
02226
02227
02228 if (!lp_load(dyn_CONFIGFILE, True, False, False, True)) {
02229 d_fprintf(stderr, "ntlm_auth: error opening config file %s. Error was %s\n",
02230 dyn_CONFIGFILE, strerror(errno));
02231 exit(1);
02232 }
02233
02234
02235
02236 pc = poptGetContext("ntlm_auth", argc, argv, long_options, 0);
02237
02238
02239
02240 if (argc == 1) {
02241 poptPrintHelp(pc, stderr, 0);
02242 return 1;
02243 }
02244
02245 pc = poptGetContext(NULL, argc, (const char **)argv, long_options,
02246 POPT_CONTEXT_KEEP_FIRST);
02247
02248 while((opt = poptGetNextOpt(pc)) != -1) {
02249 switch (opt) {
02250 case OPT_CHALLENGE:
02251 opt_challenge = strhex_to_data_blob(NULL, hex_challenge);
02252 if (opt_challenge.length != 8) {
02253 x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n",
02254 hex_challenge,
02255 (int)opt_challenge.length);
02256 exit(1);
02257 }
02258 break;
02259 case OPT_LM:
02260 opt_lm_response = strhex_to_data_blob(NULL, hex_lm_response);
02261 if (opt_lm_response.length != 24) {
02262 x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n",
02263 hex_lm_response,
02264 (int)opt_lm_response.length);
02265 exit(1);
02266 }
02267 break;
02268
02269 case OPT_NT:
02270 opt_nt_response = strhex_to_data_blob(NULL, hex_nt_response);
02271 if (opt_nt_response.length < 24) {
02272 x_fprintf(x_stderr, "hex decode of %s failed! (only got %d bytes)\n",
02273 hex_nt_response,
02274 (int)opt_nt_response.length);
02275 exit(1);
02276 }
02277 break;
02278
02279 case OPT_REQUIRE_MEMBERSHIP:
02280 if (StrnCaseCmp("S-", require_membership_of, 2) == 0) {
02281 require_membership_of_sid = require_membership_of;
02282 }
02283 break;
02284 }
02285 }
02286
02287 if (opt_username) {
02288 char *domain = SMB_STRDUP(opt_username);
02289 char *p = strchr_m(domain, *lp_winbind_separator());
02290 if (p) {
02291 opt_username = p+1;
02292 *p = '\0';
02293 if (opt_domain && !strequal(opt_domain, domain)) {
02294 x_fprintf(x_stderr, "Domain specified in username (%s) "
02295 "doesn't match specified domain (%s)!\n\n",
02296 domain, opt_domain);
02297 poptPrintHelp(pc, stderr, 0);
02298 exit(1);
02299 }
02300 opt_domain = domain;
02301 } else {
02302 SAFE_FREE(domain);
02303 }
02304 }
02305
02306
02307 if (opt_domain == NULL) {
02308 opt_domain = get_winbind_domain();
02309 }
02310
02311 if (opt_workstation == NULL) {
02312 opt_workstation = "";
02313 }
02314
02315 if (helper_protocol) {
02316 int i;
02317 for (i=0; i<NUM_HELPER_MODES; i++) {
02318 if (strcmp(helper_protocol, stdio_helper_protocols[i].name) == 0) {
02319 squid_stream(stdio_helper_protocols[i].mode, stdio_helper_protocols[i].fn);
02320 exit(0);
02321 }
02322 }
02323 x_fprintf(x_stderr, "unknown helper protocol [%s]\n\nValid helper protools:\n\n", helper_protocol);
02324
02325 for (i=0; i<NUM_HELPER_MODES; i++) {
02326 x_fprintf(x_stderr, "%s\n", stdio_helper_protocols[i].name);
02327 }
02328
02329 exit(1);
02330 }
02331
02332 if (!opt_username || !*opt_username) {
02333 x_fprintf(x_stderr, "username must be specified!\n\n");
02334 poptPrintHelp(pc, stderr, 0);
02335 exit(1);
02336 }
02337
02338 if (opt_challenge.length) {
02339 if (!check_auth_crap()) {
02340 exit(1);
02341 }
02342 exit(0);
02343 }
02344
02345 if (!opt_password) {
02346 opt_password = getpass("password: ");
02347 }
02348
02349 if (diagnostics) {
02350 if (!diagnose_ntlm_auth()) {
02351 return 1;
02352 }
02353 } else {
02354 fstring user;
02355
02356 fstr_sprintf(user, "%s%c%s", opt_domain, winbind_separator(), opt_username);
02357 if (!check_plaintext_auth(user, opt_password, True)) {
02358 return 1;
02359 }
02360 }
02361
02362
02363
02364 poptFreeContext(pc);
02365 return 0;
02366 }