BOOL rpc_api_pipe_req(struct cli_state *cli, uint8 op_num, prs_struct *data, prs_struct *rdata) { uint32 auth_len, real_auth_len, auth_hdr_len, max_data, data_left, data_sent; NTSTATUS nt_status; BOOL ret = False; uint32 callid = 0; fstring dump_name; auth_len = 0; real_auth_len = 0; auth_hdr_len = 0; if (cli->pipe_auth_flags & AUTH_PIPE_SIGN) { if (cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP) { auth_len = RPC_AUTH_NTLMSSP_CHK_LEN; } if (cli->pipe_auth_flags & AUTH_PIPE_NETSEC) { auth_len = RPC_AUTH_NETSEC_CHK_LEN; } auth_hdr_len = RPC_HDR_AUTH_LEN; } /* * calc how much actual data we can send in a PDU fragment */ max_data = cli->max_xmit_frag - RPC_HEADER_LEN - RPC_HDR_REQ_LEN - auth_hdr_len - auth_len - 8; for (data_left = prs_offset(data), data_sent = 0; data_left > 0;) { prs_struct outgoing_packet; prs_struct sec_blob; uint32 data_len, send_size; uint8 flags = 0; uint32 auth_padding = 0; DATA_BLOB sign_blob; /* * how much will we send this time */ send_size = MIN(data_left, max_data); if (!prs_init(&sec_blob, send_size, /* will need at least this much */ cli->mem_ctx, MARSHALL)) { DEBUG(0,("Could not malloc %u bytes", send_size+auth_padding)); return False; } if(!prs_append_some_prs_data(&sec_blob, data, data_sent, send_size)) { DEBUG(0,("Failed to append data to netsec blob\n")); prs_mem_free(&sec_blob); return False; } /* * NT expects the data that is sealed to be 8-byte * aligned. The padding must be encrypted as well and * taken into account when generating the * authentication verifier. The amount of padding must * be stored in the auth header. */ if (cli->pipe_auth_flags) { size_t data_and_padding_size; int auth_type; int auth_level; prs_align_uint64(&sec_blob); get_auth_type_level(cli->pipe_auth_flags, &auth_type, &auth_level); data_and_padding_size = prs_offset(&sec_blob); auth_padding = data_and_padding_size - send_size; /* insert the auth header */ if(!create_auth_hdr(&sec_blob, auth_type, auth_level, auth_padding)) { prs_mem_free(&sec_blob); return False; } /* create an NTLMSSP signature */ if (cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP) { /* * Seal the outgoing data if requested. */ if (cli->pipe_auth_flags & AUTH_PIPE_SEAL) { nt_status = ntlmssp_seal_packet(cli->ntlmssp_pipe_state, (unsigned char*)prs_data_p(&sec_blob), data_and_padding_size, &sign_blob); if (!NT_STATUS_IS_OK(nt_status)) { prs_mem_free(&sec_blob); return False; } } else if (cli->pipe_auth_flags & AUTH_PIPE_SIGN) { nt_status = ntlmssp_sign_packet(cli->ntlmssp_pipe_state, (unsigned char*)prs_data_p(&sec_blob), data_and_padding_size, &sign_blob); if (!NT_STATUS_IS_OK(nt_status)) { prs_mem_free(&sec_blob); return False; } } /* write auth footer onto the packet */ real_auth_len = sign_blob.length; prs_copy_data_in(&sec_blob, (char *)sign_blob.data, sign_blob.length); data_blob_free(&sign_blob); } else if (cli->pipe_auth_flags & AUTH_PIPE_NETSEC) { size_t parse_offset_marker; RPC_AUTH_NETSEC_CHK verf; DEBUG(10,("SCHANNEL seq_num=%d\n", cli->auth_info.seq_num)); netsec_encode(&cli->auth_info, cli->pipe_auth_flags, SENDER_IS_INITIATOR, &verf, prs_data_p(&sec_blob), data_and_padding_size); cli->auth_info.seq_num++; /* write auth footer onto the packet */ parse_offset_marker = prs_offset(&sec_blob); if (!smb_io_rpc_auth_netsec_chk("", &verf, &sec_blob, 0)) { prs_mem_free(&sec_blob); return False; } real_auth_len = prs_offset(&sec_blob) - parse_offset_marker; } } data_len = RPC_HEADER_LEN + RPC_HDR_REQ_LEN + prs_offset(&sec_blob); /* * Malloc parse struct to hold it (and enough for alignments). */ if(!prs_init(&outgoing_packet, data_len + 8, cli->mem_ctx, MARSHALL)) { DEBUG(0,("rpc_api_pipe_req: Failed to malloc %u bytes.\n", (unsigned int)data_len )); return False; } if (data_left == prs_offset(data)) flags |= RPC_FLG_FIRST; if (data_left <= max_data) flags |= RPC_FLG_LAST; /* * Write out the RPC header and the request header. */ if(!(callid = create_rpc_request(&outgoing_packet, op_num, data_len, real_auth_len, flags, callid, data_left))) { DEBUG(0,("rpc_api_pipe_req: Failed to create RPC request.\n")); prs_mem_free(&outgoing_packet); prs_mem_free(&sec_blob); return False; } prs_append_prs_data(&outgoing_packet, &sec_blob); prs_mem_free(&sec_blob); DEBUG(100,("data_len: %x data_calc_len: %x\n", data_len, prs_offset(&outgoing_packet))); if (flags & RPC_FLG_LAST) ret = rpc_api_pipe(cli, &outgoing_packet, rdata, RPC_RESPONSE); else { cli_write(cli, cli->nt_pipe_fnum, 0x0008, prs_data_p(&outgoing_packet), data_sent, data_len); } prs_mem_free(&outgoing_packet); data_sent += send_size; data_left -= send_size; } /* Also capture received data */ slprintf(dump_name, sizeof(dump_name) - 1, "reply_%s", cli_pipe_get_name(cli)); prs_dump(dump_name, op_num, rdata); return ret; }
/**************************************************************************** do a LSA Request Challenge ****************************************************************************/ BOOL do_lsa_req_chal(uint16 fnum, uint32 call_id, char *desthost, char *myhostname, DOM_CHAL *clnt_chal, DOM_CHAL *srv_chal) { char *rparam = NULL; char *rdata = NULL; char *p; int rdrcnt,rprcnt; pstring data; /* only 1024 bytes */ uint16 setup[2]; /* only need 2 uint16 setup parameters */ LSA_Q_REQ_CHAL q_c; BOOL valid_chal = False; if (srv_chal == NULL || clnt_chal == NULL) return False; /* create and send a MSRPC command with api LSA_REQCHAL */ DEBUG(4,("LSA Request Challenge from %s to %s: %s\n", desthost, myhostname, credstr(clnt_chal->data))); /* store the parameters */ make_q_req_chal(&q_c, desthost, myhostname, clnt_chal); /* turn parameters into data stream */ p = lsa_io_q_req_chal(False, &q_c, data + 0x18, data, 4, 0); /* create the request RPC_HDR_RR _after_ the main data: length is now known */ create_rpc_request(call_id, LSA_REQCHAL, data, PTR_DIFF(p, data)); /* create setup parameters. */ setup[0] = 0x0026; /* 0x26 indicates "transact named pipe" */ setup[1] = fnum; /* file handle, from the SMBcreateX pipe, earlier */ /* send the data on \PIPE\ */ if (cli_call_api("\\PIPE\\", 0, 0, PTR_DIFF(p, data), 2, 1024, BUFFER_SIZE, &rprcnt,&rdrcnt, NULL, data, setup, &rparam,&rdata)) { LSA_R_REQ_CHAL r_c; RPC_HDR_RR hdr; int hdr_len; int pkt_len; DEBUG(5, ("cli_call_api: return OK\n")); p = rdata; if (p) p = smb_io_rpc_hdr_rr (True, &hdr, p, rdata, 4, 0); if (p) p = align_offset(p, rdata, 4); /* oh, what a surprise */ hdr_len = PTR_DIFF(p, rdata); if (p && hdr_len != hdr.hdr.frag_len - hdr.alloc_hint) { /* header length not same as calculated header length */ DEBUG(2,("do_lsa_req_chal: hdr_len %x != frag_len-alloc_hint %x\n", hdr_len, hdr.hdr.frag_len - hdr.alloc_hint)); p = NULL; } if (p) p = lsa_io_r_req_chal(True, &r_c, p, rdata, 4, 0); pkt_len = PTR_DIFF(p, rdata); if (p && pkt_len != hdr.hdr.frag_len) { /* packet data size not same as reported fragment length */ DEBUG(2,("do_lsa_req_chal: pkt_len %x != frag_len \n", pkt_len, hdr.hdr.frag_len)); p = NULL; } if (p && r_c.status != 0) { /* report error code */ DEBUG(0,("LSA_REQ_CHAL: nt_status error %lx\n", r_c.status)); p = NULL; } if (p) { /* ok, at last: we're happy. return the challenge */ memcpy(srv_chal, r_c.srv_chal.data, sizeof(srv_chal->data)); valid_chal = True; } } if (rparam) free(rparam); if (rdata) free(rdata); return valid_chal; }
/*************************************************************************** do a LSA SAM Logoff ****************************************************************************/ BOOL do_lsa_sam_logoff(uint16 fnum, uint32 call_id, uchar sess_key[8], DOM_CRED *sto_clnt_cred, char *logon_srv, char *comp_name, DOM_CRED *clnt_cred, DOM_CRED *rtn_cred, uint16 logon_level, uint16 switch_value, DOM_ID_INFO_1 *id1, DOM_CRED *srv_cred) { char *rparam = NULL; char *rdata = NULL; char *p; int rdrcnt,rprcnt; pstring data; /* only 1024 bytes */ uint16 setup[2]; /* only need 2 uint16 setup parameters */ LSA_Q_SAM_LOGOFF q_s; BOOL valid_cred = False; if (srv_cred == NULL || clnt_cred == NULL || rtn_cred == NULL) return False; /* create and send a MSRPC command with api LSA_SAMLOGON */ DEBUG(4,("LSA SAM Logoff: srv:%s mc:%s clnt %s %lx rtn: %s %lx ll: %d\n", logon_srv, comp_name, credstr(clnt_cred->challenge.data), clnt_cred->timestamp.time, credstr(rtn_cred->challenge.data), rtn_cred ->timestamp.time, logon_level)); /* store the parameters */ make_sam_info(&(q_s.sam_id), logon_srv, comp_name, clnt_cred, rtn_cred, logon_level, switch_value, id1); /* turn parameters into data stream */ p = lsa_io_q_sam_logoff(False, &q_s, data + 0x18, data, 4, 0); /* create the request RPC_HDR_RR _after_ the main data: length is now known */ create_rpc_request(call_id, LSA_SAMLOGOFF, data, PTR_DIFF(p, data)); /* create setup parameters. */ setup[0] = 0x0026; /* 0x26 indicates "transact named pipe" */ setup[1] = fnum; /* file handle, from the SMBcreateX pipe, earlier */ /* send the data on \PIPE\ */ if (cli_call_api("\\PIPE\\", 0, 0, PTR_DIFF(p, data), 2, 1024, BUFFER_SIZE, &rprcnt,&rdrcnt, NULL, data, setup, &rparam,&rdata)) { LSA_R_SAM_LOGOFF r_s; RPC_HDR_RR hdr; int hdr_len; int pkt_len; DEBUG(5, ("cli_call_api: return OK\n")); p = rdata; if (p) p = smb_io_rpc_hdr_rr (True, &hdr, p, rdata, 4, 0); if (p) p = align_offset(p, rdata, 4); /* oh, what a surprise */ hdr_len = PTR_DIFF(p, rdata); if (p && hdr_len != hdr.hdr.frag_len - hdr.alloc_hint) { /* header length not same as calculated header length */ DEBUG(2,("do_lsa_sam_logoff: hdr_len %x != frag_len-alloc_hint %x\n", hdr_len, hdr.hdr.frag_len - hdr.alloc_hint)); p = NULL; } if (p) p = lsa_io_r_sam_logoff(True, &r_s, p, rdata, 4, 0); pkt_len = PTR_DIFF(p, rdata); if (p && pkt_len != hdr.hdr.frag_len) { /* packet data size not same as reported fragment length */ DEBUG(2,("do_lsa_sam_logoff: pkt_len %x != frag_len \n", pkt_len, hdr.hdr.frag_len)); p = NULL; } if (p && r_s.status != 0) { /* report error code */ DEBUG(0,("LSA_SAMLOGOFF: nt_status error %lx\n", r_s.status)); p = NULL; } if (p) { if (clnt_deal_with_creds(sess_key, sto_clnt_cred, &(r_s.srv_creds))) { DEBUG(5, ("do_lsa_sam_logoff: server credential check OK\n")); /* ok, at last: we're happy. return the challenge */ memcpy(srv_cred, &(r_s.srv_creds), sizeof(r_s.srv_creds)); valid_cred = True; } else { DEBUG(5, ("do_lsa_sam_logoff: server credential check failed\n")); } } } if (rparam) free(rparam); if (rdata) free(rdata); return valid_cred; }
/**************************************************************************** do a LSA Authenticate 2 ****************************************************************************/ BOOL do_lsa_auth2(uint16 fnum, uint32 call_id, char *logon_srv, char *acct_name, uint16 sec_chan, char *comp_name, DOM_CHAL *clnt_chal, uint32 neg_flags, DOM_CHAL *srv_chal) { char *rparam = NULL; char *rdata = NULL; char *p; int rdrcnt,rprcnt; pstring data; /* only 1024 bytes */ uint16 setup[2]; /* only need 2 uint16 setup parameters */ LSA_Q_AUTH_2 q_a; BOOL valid_chal = False; if (srv_chal == NULL || clnt_chal == NULL) return False; /* create and send a MSRPC command with api LSA_AUTH2 */ DEBUG(4,("LSA Authenticate 2: srv:%s acct:%s sc:%x mc: %s chal %s neg: %lx\n", logon_srv, acct_name, sec_chan, comp_name, credstr(clnt_chal->data), neg_flags)); /* store the parameters */ make_q_auth_2(&q_a, logon_srv, acct_name, sec_chan, comp_name, clnt_chal, neg_flags); /* turn parameters into data stream */ p = lsa_io_q_auth_2(False, &q_a, data + 0x18, data, 4, 0); /* create the request RPC_HDR_RR _after_ the main data: length is now known */ create_rpc_request(call_id, LSA_AUTH2, data, PTR_DIFF(p, data)); /* create setup parameters. */ setup[0] = 0x0026; /* 0x26 indicates "transact named pipe" */ setup[1] = fnum; /* file handle, from the SMBcreateX pipe, earlier */ /* send the data on \PIPE\ */ if (cli_call_api("\\PIPE\\", 0, 0, PTR_DIFF(p, data), 2, 1024, BUFFER_SIZE, &rprcnt,&rdrcnt, NULL, data, setup, &rparam,&rdata)) { LSA_R_AUTH_2 r_a; RPC_HDR_RR hdr; int hdr_len; int pkt_len; DEBUG(5, ("cli_call_api: return OK\n")); p = rdata; if (p) p = smb_io_rpc_hdr_rr (True, &hdr, p, rdata, 4, 0); if (p) p = align_offset(p, rdata, 4); /* oh, what a surprise */ hdr_len = PTR_DIFF(p, rdata); if (p && hdr_len != hdr.hdr.frag_len - hdr.alloc_hint) { /* header length not same as calculated header length */ DEBUG(2,("do_lsa_auth2: hdr_len %x != frag_len-alloc_hint %x\n", hdr_len, hdr.hdr.frag_len - hdr.alloc_hint)); p = NULL; } if (p) p = lsa_io_r_auth_2(True, &r_a, p, rdata, 4, 0); pkt_len = PTR_DIFF(p, rdata); if (p && pkt_len != hdr.hdr.frag_len) { /* packet data size not same as reported fragment length */ DEBUG(2,("do_lsa_auth2: pkt_len %x != frag_len \n", pkt_len, hdr.hdr.frag_len)); p = NULL; } if (p && r_a.status != 0) { /* report error code */ DEBUG(0,("LSA_AUTH2: nt_status error %lx\n", r_a.status)); p = NULL; } if (p && r_a.srv_flgs.neg_flags != q_a.clnt_flgs.neg_flags) { /* report different neg_flags */ DEBUG(0,("LSA_AUTH2: error neg_flags (q,r) differ - (%lx,%lx)\n", q_a.clnt_flgs.neg_flags, r_a.srv_flgs.neg_flags)); p = NULL; } if (p) { /* ok, at last: we're happy. return the challenge */ memcpy(srv_chal, r_a.srv_chal.data, sizeof(srv_chal->data)); valid_chal = True; } } if (rparam) free(rparam); if (rdata) free(rdata); return valid_chal; }