cli_pipe.c
来自「samba-3.0.22.tar.gz 编译smb服务器的源码」· C语言 代码 · 共 2,128 行 · 第 1/5 页
C
2,128 行
/******************************************************************* Creates a DCE/RPC bind authentication response. This is the packet that is sent back to the server once we have received a BIND-ACK, to finish the third leg of the authentication handshake. ********************************************************************/static NTSTATUS create_rpc_bind_auth3(struct rpc_pipe_client *cli, uint32 rpc_call_id, enum pipe_auth_type auth_type, enum pipe_auth_level auth_level, DATA_BLOB *pauth_blob, prs_struct *rpc_out){ RPC_HDR hdr; RPC_HDR_AUTH hdr_auth; uint32 pad = 0; /* Create the request RPC_HDR */ init_rpc_hdr(&hdr, RPC_AUTH3, RPC_FLG_FIRST|RPC_FLG_LAST, rpc_call_id, RPC_HEADER_LEN + 4 /* pad */ + RPC_HDR_AUTH_LEN + pauth_blob->length, pauth_blob->length ); /* Marshall it. */ if(!smb_io_rpc_hdr("hdr", &hdr, rpc_out, 0)) { DEBUG(0,("create_rpc_bind_auth3: failed to marshall RPC_HDR.\n")); return NT_STATUS_NO_MEMORY; } /* I'm puzzled about this - seems to violate the DCE RPC auth rules, about padding - shouldn't this pad to length 8 ? JRA. */ /* 4 bytes padding. */ if (!prs_uint32("pad", rpc_out, 0, &pad)) { DEBUG(0,("create_rpc_bind_auth3: failed to marshall 4 byte pad.\n")); return NT_STATUS_NO_MEMORY; } /* Create the request RPC_HDR_AUTHA */ init_rpc_hdr_auth(&hdr_auth, map_pipe_auth_type_to_rpc_auth_type(auth_type), auth_level, 0, 1); if(!smb_io_rpc_hdr_auth("hdr_auth", &hdr_auth, rpc_out, 0)) { DEBUG(0,("create_rpc_bind_auth3: failed to marshall RPC_HDR_AUTHA.\n")); return NT_STATUS_NO_MEMORY; } /* * Append the auth data to the outgoing buffer. */ if(!prs_copy_data_in(rpc_out, (char *)pauth_blob->data, pauth_blob->length)) { DEBUG(0,("create_rpc_bind_auth3: failed to marshall auth blob.\n")); return NT_STATUS_NO_MEMORY; } return NT_STATUS_OK;}/**************************************************************************** Create and send the third packet in an RPC auth.****************************************************************************/static NTSTATUS rpc_finish_auth3_bind(struct rpc_pipe_client *cli, RPC_HDR *phdr, prs_struct *rbuf, uint32 rpc_call_id, enum pipe_auth_type auth_type, enum pipe_auth_level auth_level){ DATA_BLOB server_response = data_blob(NULL,0); DATA_BLOB client_reply = data_blob(NULL,0); RPC_HDR_AUTH hdr_auth; NTSTATUS nt_status; prs_struct rpc_out; ssize_t ret; if (!phdr->auth_len || (phdr->frag_len < phdr->auth_len + RPC_HDR_AUTH_LEN)) { return NT_STATUS_INVALID_PARAMETER; } /* Process the returned NTLMSSP blob first. */ if (!prs_set_offset(rbuf, phdr->frag_len - phdr->auth_len - RPC_HDR_AUTH_LEN)) { return NT_STATUS_INVALID_PARAMETER; } if(!smb_io_rpc_hdr_auth("hdr_auth", &hdr_auth, rbuf, 0)) { return NT_STATUS_INVALID_PARAMETER; } /* TODO - check auth_type/auth_level match. */ server_response = data_blob(NULL, phdr->auth_len); prs_copy_data_out((char *)server_response.data, rbuf, phdr->auth_len); nt_status = ntlmssp_update(cli->auth.a_u.ntlmssp_state, server_response, &client_reply); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(0,("rpc_finish_auth3_bind: NTLMSSP update using server blob failed.\n")); return nt_status; } prs_init(&rpc_out, 0, prs_get_mem_context(rbuf), MARSHALL); nt_status = create_rpc_bind_auth3(cli, rpc_call_id, auth_type, auth_level, &client_reply, &rpc_out); if (!NT_STATUS_IS_OK(nt_status)) { prs_mem_free(&rpc_out); data_blob_free(&client_reply); data_blob_free(&server_response); return nt_status; } /* 8 here is named pipe message mode. */ ret = cli_write(cli->cli, cli->fnum, 0x8, prs_data_p(&rpc_out), 0, (size_t)prs_offset(&rpc_out)); if (ret != (ssize_t)prs_offset(&rpc_out)) { DEBUG(0,("rpc_send_auth_auth3: cli_write failed. Return was %d\n", (int)ret)); prs_mem_free(&rpc_out); data_blob_free(&client_reply); data_blob_free(&server_response); return cli_get_nt_error(cli->cli); } DEBUG(5,("rpc_send_auth_auth3: Remote machine %s pipe %s " "fnum 0x%x sent auth3 response ok.\n", cli->cli->desthost, cli->pipe_name, (unsigned int)cli->fnum)); prs_mem_free(&rpc_out); data_blob_free(&client_reply); data_blob_free(&server_response); return NT_STATUS_OK;}/******************************************************************* Creates a DCE/RPC bind alter context authentication request which may contain a spnego auth blobl ********************************************************************/static NTSTATUS create_rpc_alter_context(uint32 rpc_call_id, RPC_IFACE *abstract, RPC_IFACE *transfer, enum pipe_auth_level auth_level, const DATA_BLOB *pauth_blob, /* spnego auth blob already created. */ prs_struct *rpc_out){ RPC_HDR_AUTH hdr_auth; prs_struct auth_info; NTSTATUS ret = NT_STATUS_OK; ZERO_STRUCT(hdr_auth); prs_init(&auth_info, RPC_HDR_AUTH_LEN, prs_get_mem_context(rpc_out), MARSHALL); /* We may change the pad length before marshalling. */ init_rpc_hdr_auth(&hdr_auth, RPC_SPNEGO_AUTH_TYPE, (int)auth_level, 0, 1); if (pauth_blob->length) { if (!prs_copy_data_in(&auth_info, (const char *)pauth_blob->data, pauth_blob->length)) { prs_mem_free(&auth_info); return NT_STATUS_NO_MEMORY; } } ret = create_bind_or_alt_ctx_internal(RPC_ALTCONT, rpc_out, rpc_call_id, abstract, transfer, &hdr_auth, &auth_info); prs_mem_free(&auth_info); return ret;}/******************************************************************* Third leg of the SPNEGO bind mechanism - sends alter context PDU and gets a response. ********************************************************************/static NTSTATUS rpc_finish_spnego_ntlmssp_bind(struct rpc_pipe_client *cli, RPC_HDR *phdr, prs_struct *rbuf, uint32 rpc_call_id, RPC_IFACE *abstract, RPC_IFACE *transfer, enum pipe_auth_type auth_type, enum pipe_auth_level auth_level){ DATA_BLOB server_spnego_response = data_blob(NULL,0); DATA_BLOB server_ntlm_response = data_blob(NULL,0); DATA_BLOB client_reply = data_blob(NULL,0); DATA_BLOB tmp_blob = data_blob(NULL, 0); RPC_HDR_AUTH hdr_auth; NTSTATUS nt_status; prs_struct rpc_out; if (!phdr->auth_len || (phdr->frag_len < phdr->auth_len + RPC_HDR_AUTH_LEN)) { return NT_STATUS_INVALID_PARAMETER; } /* Process the returned NTLMSSP blob first. */ if (!prs_set_offset(rbuf, phdr->frag_len - phdr->auth_len - RPC_HDR_AUTH_LEN)) { return NT_STATUS_INVALID_PARAMETER; } if(!smb_io_rpc_hdr_auth("hdr_auth", &hdr_auth, rbuf, 0)) { return NT_STATUS_INVALID_PARAMETER; } server_spnego_response = data_blob(NULL, phdr->auth_len); prs_copy_data_out((char *)server_spnego_response.data, rbuf, phdr->auth_len); /* The server might give us back two challenges - tmp_blob is for the second. */ if (!spnego_parse_challenge(server_spnego_response, &server_ntlm_response, &tmp_blob)) { data_blob_free(&server_spnego_response); data_blob_free(&server_ntlm_response); data_blob_free(&tmp_blob); return NT_STATUS_INVALID_PARAMETER; } /* We're finished with the server spnego response and the tmp_blob. */ data_blob_free(&server_spnego_response); data_blob_free(&tmp_blob); nt_status = ntlmssp_update(cli->auth.a_u.ntlmssp_state, server_ntlm_response, &client_reply); /* Finished with the server_ntlm response */ data_blob_free(&server_ntlm_response); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(0,("rpc_finish_spnego_ntlmssp_bind: NTLMSSP update using server blob failed.\n")); data_blob_free(&client_reply); return nt_status; } /* SPNEGO wrap the client reply. */ tmp_blob = spnego_gen_auth(client_reply); data_blob_free(&client_reply); client_reply = tmp_blob; tmp_blob = data_blob(NULL,0); /* Ensure it's safe to free this just in case. */ /* Now prepare the alter context pdu. */ prs_init(&rpc_out, 0, prs_get_mem_context(rbuf), MARSHALL); nt_status = create_rpc_alter_context(rpc_call_id, abstract, transfer, auth_level, &client_reply, &rpc_out); data_blob_free(&client_reply); if (!NT_STATUS_IS_OK(nt_status)) { prs_mem_free(&rpc_out); return nt_status; } /* Initialize the returning data struct. */ prs_mem_free(rbuf); prs_init(rbuf, 0, cli->cli->mem_ctx, UNMARSHALL); nt_status = rpc_api_pipe(cli, &rpc_out, rbuf, RPC_ALTCONTRESP); if (!NT_STATUS_IS_OK(nt_status)) { prs_mem_free(&rpc_out); return nt_status; } prs_mem_free(&rpc_out); /* Get the auth blob from the reply. */ if(!smb_io_rpc_hdr("rpc_hdr ", phdr, rbuf, 0)) { DEBUG(0,("rpc_finish_spnego_ntlmssp_bind: Failed to unmarshall RPC_HDR.\n")); return NT_STATUS_BUFFER_TOO_SMALL; } if (!prs_set_offset(rbuf, phdr->frag_len - phdr->auth_len - RPC_HDR_AUTH_LEN)) { return NT_STATUS_INVALID_PARAMETER; } if(!smb_io_rpc_hdr_auth("hdr_auth", &hdr_auth, rbuf, 0)) { return NT_STATUS_INVALID_PARAMETER; } server_spnego_response = data_blob(NULL, phdr->auth_len); prs_copy_data_out((char *)server_spnego_response.data, rbuf, phdr->auth_len); /* Check we got a valid auth response. */ if (!spnego_parse_auth_response(server_spnego_response, NT_STATUS_OK, &tmp_blob)) { data_blob_free(&server_spnego_response); data_blob_free(&tmp_blob); return NT_STATUS_INVALID_PARAMETER; } data_blob_free(&server_spnego_response); data_blob_free(&tmp_blob); DEBUG(5,("rpc_finish_spnego_ntlmssp_bind: alter context request to " "remote machine %s pipe %s fnum 0x%x.\n", cli->cli->desthost, cli->pipe_name, (unsigned int)cli->fnum)); return NT_STATUS_OK;}/**************************************************************************** Do an rpc bind.****************************************************************************/static NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli, enum pipe_auth_type auth_type, enum pipe_auth_level auth_level){ RPC_HDR hdr; RPC_HDR_BA hdr_ba; RPC_IFACE abstract; RPC_IFACE transfer; prs_struct rpc_out; prs_struct rbuf; uint32 rpc_call_id; NTSTATUS status; DEBUG(5,("Bind RPC Pipe[%x]: %s auth_type %u, auth_level %u\n", (unsigned int)cli->fnum, cli->pipe_name, (unsigned int)auth_type, (unsigned int)auth_level )); if (!valid_pipe_name(cli->pipe_idx, &abstract, &transfer)) { return NT_STATUS_INVALID_PARAMETER; } prs_init(&rpc_out, 0, cli->cli->mem_ctx, MARSHALL); rpc_call_id = get_rpc_call_id(); /* Marshall the outgoing data. */ status = create_rpc_bind_req(cli, &rpc_out, rpc_call_id, &abstract, &transfer, auth_type, auth_level); if (!NT_STATUS_IS_OK(status)) { prs_mem_free(&rpc_out); return status; } /* Initialize the incoming data struct. */ prs_init(&rbuf, 0, cli->cli->mem_ctx, UNMARSHALL); /* send data on \PIPE\. receive a response */ status = rpc_api_pipe(cli, &rpc_out, &rbuf, RPC_BINDACK); if (!NT_STATUS_IS_OK(status)) { prs_mem_free(&rpc_out); return status; } prs_mem_free(&rpc_out); DEBUG(3,("rpc_pipe_bind: Remote machine %s pipe %s " "fnum 0x%x bind request returned ok.\n", cli->cli->desthost, cli->pipe_name, (unsigned int)cli->fnum)); /* Unmarshall the RPC header */ if(!smb_io_rpc_hdr("hdr" , &hdr, &rbuf, 0)) { DEBUG(0,("rpc_pipe_bind: failed to unmarshall RPC_HDR.\n")); prs_mem_free(&rbuf); return NT_STATUS_BUFFER_TOO_SMALL; } if(!smb_io_rpc_hdr_ba("", &hdr_ba, &rbuf, 0)) { DEBUG(0,("rpc_pipe_bind: Failed to unmarshall RPC_HDR_BA.\n")); prs_mem_free(&rbuf); return NT_STATUS_BUFFER_TOO_SMALL; } if(!check_bind_response(&hdr_ba, cli->pipe_idx, &transfer)) { DEBUG(2,("rpc_pipe_bind: check_bind_response failed.\n")); prs_mem_free(&rbuf); return NT_STATUS_BUFFER_TOO_SMALL; } cli->max_xmit_frag = hdr_ba.bba.max_tsize; cli->max_recv_frag = hdr_ba.bba.max_rsize; /* For authenticated binds we may need to do 3 or 4 leg binds. */ switch(auth_type) { case PIPE_AUTH_TYPE_NONE: case PIPE_AUTH_TYPE_SCHANNEL: /* Bind complete. */ break; case PIPE_AUTH_TYPE_NTLMSSP: /* Need to send AUTH3 packet - no reply. */ status = rpc_finish_auth3_bind(cli, &hdr, &rbuf, rpc_call_id, auth_type, auth_level); if (!NT_STATUS_IS_OK(status)) { prs_mem_free(&rbuf); return status; } break; case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP: /* Need to send alter context request and reply. */ status = rpc_finish_spnego_ntlmssp_bind(cli, &hdr, &rbuf, rpc_call_id, &abstract, &transfer, auth_type, auth_level); if
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?