📄 cliconnect.c
字号:
capabilities |= CAP_EXTENDED_SECURITY; /* send a session setup command */ memset(cli->outbuf,'\0',smb_size); set_message(cli->outbuf,12,0,True); SCVAL(cli->outbuf,smb_com,SMBsesssetupX); cli_setup_packet(cli); SCVAL(cli->outbuf,smb_vwv0,0xFF); SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE); SSVAL(cli->outbuf,smb_vwv3,2); SSVAL(cli->outbuf,smb_vwv4,1); SIVAL(cli->outbuf,smb_vwv5,0); SSVAL(cli->outbuf,smb_vwv7,blob.length); SIVAL(cli->outbuf,smb_vwv10,capabilities); p = smb_buf(cli->outbuf); memcpy(p, blob.data, blob.length); p += blob.length; p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE); p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE); cli_setup_bcc(cli, p); return cli_send_smb(cli);}/**************************************************************************** Send a extended security session setup blob, returning a reply blob.****************************************************************************/static DATA_BLOB cli_session_setup_blob_receive(struct cli_state *cli){ DATA_BLOB blob2 = data_blob(NULL, 0); char *p; size_t len; if (!cli_receive_smb(cli)) return blob2; show_msg(cli->inbuf); if (cli_is_error(cli) && !NT_STATUS_EQUAL(cli_nt_error(cli), NT_STATUS_MORE_PROCESSING_REQUIRED)) { return blob2; } /* use the returned vuid from now on */ cli->vuid = SVAL(cli->inbuf,smb_uid); p = smb_buf(cli->inbuf); blob2 = data_blob(p, SVAL(cli->inbuf, smb_vwv3)); p += blob2.length; p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE); /* w2k with kerberos doesn't properly null terminate this field */ len = smb_buflen(cli->inbuf) - PTR_DIFF(p, smb_buf(cli->inbuf)); p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), len, 0); return blob2;}#ifdef HAVE_KRB5/**************************************************************************** Send a extended security session setup blob, returning a reply blob.****************************************************************************/static DATA_BLOB cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob){ DATA_BLOB blob2 = data_blob(NULL, 0); if (!cli_session_setup_blob_send(cli, blob)) { return blob2; } return cli_session_setup_blob_receive(cli);}/**************************************************************************** Use in-memory credentials cache****************************************************************************/static void use_in_memory_ccache(void) { setenv(KRB5_ENV_CCNAME, "MEMORY:cliconnect", 1);}/**************************************************************************** Do a spnego/kerberos encrypted session setup.****************************************************************************/static ADS_STATUS cli_session_setup_kerberos(struct cli_state *cli, const char *principal, const char *workgroup){ DATA_BLOB blob2, negTokenTarg; DATA_BLOB session_key_krb5; DATA_BLOB null_blob = data_blob(NULL, 0); int rc; DEBUG(2,("Doing kerberos session setup\n")); /* generate the encapsulated kerberos5 ticket */ rc = spnego_gen_negTokenTarg(principal, 0, &negTokenTarg, &session_key_krb5, 0); if (rc) { DEBUG(1, ("spnego_gen_negTokenTarg failed: %s\n", error_message(rc))); return ADS_ERROR_KRB5(rc); }#if 0 file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length);#endif cli_simple_set_signing(cli, session_key_krb5, null_blob); blob2 = cli_session_setup_blob(cli, negTokenTarg); /* we don't need this blob for kerberos */ data_blob_free(&blob2); cli_set_session_key(cli, session_key_krb5); data_blob_free(&negTokenTarg); data_blob_free(&session_key_krb5); if (cli_is_error(cli)) { if (NT_STATUS_IS_OK(cli_nt_error(cli))) { return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); } } return ADS_ERROR_NT(cli_nt_error(cli));}#endif /* HAVE_KRB5 *//**************************************************************************** Do a spnego/NTLMSSP encrypted session setup.****************************************************************************/static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *user, const char *pass, const char *domain){ struct ntlmssp_state *ntlmssp_state; NTSTATUS nt_status; int turn = 1; DATA_BLOB msg1; DATA_BLOB blob = data_blob(NULL, 0); DATA_BLOB blob_in = data_blob(NULL, 0); DATA_BLOB blob_out = data_blob(NULL, 0); cli_temp_set_signing(cli); if (!NT_STATUS_IS_OK(nt_status = ntlmssp_client_start(&ntlmssp_state))) { return nt_status; } if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, user))) { return nt_status; } if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, domain))) { return nt_status; } if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, pass))) { return nt_status; } do { nt_status = ntlmssp_update(ntlmssp_state, blob_in, &blob_out); data_blob_free(&blob_in); if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) || NT_STATUS_IS_OK(nt_status)) { if (turn == 1) { /* and wrap it in a SPNEGO wrapper */ msg1 = gen_negTokenInit(OID_NTLMSSP, blob_out); } else { /* wrap it in SPNEGO */ msg1 = spnego_gen_auth(blob_out); } /* now send that blob on its way */ if (!cli_session_setup_blob_send(cli, msg1)) { DEBUG(3, ("Failed to send NTLMSSP/SPNEGO blob to server!\n")); nt_status = NT_STATUS_UNSUCCESSFUL; } else { data_blob_free(&msg1); blob = cli_session_setup_blob_receive(cli); nt_status = cli_nt_error(cli); if (cli_is_error(cli) && NT_STATUS_IS_OK(nt_status)) { if (cli->smb_rw_error == READ_BAD_SIG) { nt_status = NT_STATUS_ACCESS_DENIED; } else { nt_status = NT_STATUS_UNSUCCESSFUL; } } } } if (!blob.length) { if (NT_STATUS_IS_OK(nt_status)) { nt_status = NT_STATUS_UNSUCCESSFUL; } } else if ((turn == 1) && NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { DATA_BLOB tmp_blob = data_blob(NULL, 0); /* the server might give us back two challenges */ if (!spnego_parse_challenge(blob, &blob_in, &tmp_blob)) { DEBUG(3,("Failed to parse challenges\n")); nt_status = NT_STATUS_INVALID_PARAMETER; } data_blob_free(&tmp_blob); } else { if (!spnego_parse_auth_response(blob, nt_status, &blob_in)) { DEBUG(3,("Failed to parse auth response\n")); if (NT_STATUS_IS_OK(nt_status) || NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) nt_status = NT_STATUS_INVALID_PARAMETER; } } data_blob_free(&blob); data_blob_free(&blob_out); turn++; } while (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)); if (NT_STATUS_IS_OK(nt_status)) { DATA_BLOB key = data_blob(ntlmssp_state->session_key.data, ntlmssp_state->session_key.length); DATA_BLOB null_blob = data_blob(NULL, 0); BOOL res; fstrcpy(cli->server_domain, ntlmssp_state->server_domain); cli_set_session_key(cli, ntlmssp_state->session_key); res = cli_simple_set_signing(cli, key, null_blob); data_blob_free(&key); if (res) { /* 'resign' the last message, so we get the right sequence numbers for checking the first reply from the server */ cli_calculate_sign_mac(cli); if (!cli_check_sign_mac(cli)) { nt_status = NT_STATUS_ACCESS_DENIED; } } } /* we have a reference conter on ntlmssp_state, if we are signing then the state will be kept by the signing engine */ ntlmssp_end(&ntlmssp_state); return nt_status;}/**************************************************************************** Do a spnego encrypted session setup.****************************************************************************/ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user, const char *pass, const char *domain){ char *principal; char *OIDs[ASN1_MAX_OIDS]; int i;#ifdef HAVE_KRB5 BOOL got_kerberos_mechanism = False;#endif DATA_BLOB blob; DEBUG(3,("Doing spnego session setup (blob length=%lu)\n", (unsigned long)cli->secblob.length)); /* the server might not even do spnego */ if (cli->secblob.length <= 16) { DEBUG(3,("server didn't supply a full spnego negprot\n")); goto ntlmssp; }#if 0 file_save("negprot.dat", cli->secblob.data, cli->secblob.length);#endif /* there is 16 bytes of GUID before the real spnego packet starts */ blob = data_blob(cli->secblob.data+16, cli->secblob.length-16); /* the server sent us the first part of the SPNEGO exchange in the negprot reply */ if (!spnego_parse_negTokenInit(blob, OIDs, &principal)) { data_blob_free(&blob); return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER); } data_blob_free(&blob); /* make sure the server understands kerberos */ for (i=0;OIDs[i];i++) { DEBUG(3,("got OID=%s\n", OIDs[i]));#ifdef HAVE_KRB5 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 || strcmp(OIDs[i], OID_KERBEROS5) == 0) { got_kerberos_mechanism = True; }#endif free(OIDs[i]); } DEBUG(3,("got principal=%s\n", principal)); fstrcpy(cli->user_name, user);#ifdef HAVE_KRB5 /* If password is set we reauthenticate to kerberos server * and do not store results */ if (got_kerberos_mechanism && cli->use_kerberos) { ADS_STATUS rc; if (pass && *pass) { int ret; use_in_memory_ccache(); ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */, NULL, NULL); if (ret){ SAFE_FREE(principal); DEBUG(0, ("Kinit failed: %s\n", error_message(ret))); if (cli->fallback_after_kerberos) goto ntlmssp; return ADS_ERROR_KRB5(ret); } } rc = cli_session_setup_kerberos(cli, principal, domain); if (ADS_ERR_OK(rc) || !cli->fallback_after_kerberos) { SAFE_FREE(principal); return rc; } }#endif SAFE_FREE(principal);ntlmssp: return ADS_ERROR_NT(cli_session_setup_ntlmssp(cli, user, pass, domain));}/**************************************************************************** Send a session setup. The username and workgroup is in UNIX character format and must be converted to DOS codepage format before sending. If the password is in plaintext, the same should be done.****************************************************************************/BOOL cli_session_setup(struct cli_state *cli, const char *user, const char *pass, int passlen, const char *ntpass, int ntpasslen, const char *workgroup){ char *p; fstring user2; /* allow for workgroups as part of the username */ fstrcpy(user2, user); if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/')) || (p=strchr_m(user2,*lp_winbind_separator()))) { *p = 0; user = p+1; workgroup = user2; } if (cli->protocol < PROTOCOL_LANMAN1) return True; /* now work out what sort of session setup we are going to do. I have split this into separate functions to make the flow a bit easier to understand (tridge) */ /* if its an older server then we have to use the older request format */ if (cli->protocol < PROTOCOL_NT1) { if (!lp_client_lanman_auth() && passlen != 24 && (*pass)) { DEBUG(1, ("Server requested LM password but 'client lanman auth'" " is disabled\n")); return False; } if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0 && !lp_client_plaintext_auth() && (*pass)) { DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'" " is disabled\n")); return False; } return cli_session_setup_lanman2(cli, user, pass, passlen, workgroup); } /* if no user is supplied then we have to do an anonymous connection. passwords are ignored */ if (!user || !*user) return cli_session_setup_guest(cli); /* if the server is share level then send a plaintext null password at this point. The password is sent in the tree connect */ if ((cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0) return cli_session_setup_plaintext(cli, user, "", workgroup); /* if the server doesn't support encryption then we have to use plaintext. The second password is ignored */ if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) { if (!lp_client_plaintext_auth() && (*pass)) { DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'" " is disabled\n")); return False; } return cli_session_setup_plaintext(cli, user, pass, workgroup); } /* if the server supports extended security then use SPNEGO */ if (cli->capabilities & CAP_EXTENDED_SECURITY) { ADS_STATUS status = cli_session_setup_spnego(cli, user, pass, workgroup); if (!ADS_ERR_OK(status)) { DEBUG(3, ("SPNEGO login failed: %s\n", ads_errstr(status))); return False;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -