int cli_errno(struct cli_state *cli) { NTSTATUS status; if (cli_is_nt_error(cli)) { status = cli_nt_error(cli); return map_errno_from_nt_status(status); } if (cli_is_dos_error(cli)) { uint8 eclass; uint32 ecode; cli_dos_error(cli, &eclass, &ecode); status = dos_to_ntstatus(eclass, ecode); return map_errno_from_nt_status(status); } /* * Yuck! A special case for this Vista error. Since its high-order * byte isn't 0xc0, it doesn't match cli_is_nt_error() above. */ status = cli_nt_error(cli); if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_INACCESSIBLE_SYSTEM_SHORTCUT)) { return EACCES; } /* for other cases */ return EINVAL; }
NTSTATUS cli_get_nt_error(struct cli_state *cli) { if (cli_is_nt_error(cli)) { return cli_nt_error(cli); } else if (cli_is_dos_error(cli)) { uint32 ecode; uint8 eclass; cli_dos_error(cli, &eclass, &ecode); return dos_to_ntstatus(eclass, ecode); } else { /* Something went wrong, we don't know what. */ return NT_STATUS_UNSUCCESSFUL; } }
bool cli_receive_nt_trans(struct cli_state *cli, char **param, unsigned int *param_len, char **data, unsigned int *data_len) { unsigned int total_data=0; unsigned int total_param=0; unsigned int this_data,this_param; uint8 eclass; uint32 ecode; bool ret = False; uint16_t mid; *data_len = *param_len = 0; mid = SVAL(cli->outbuf,smb_mid); if (!cli_receive_smb(cli)) { cli_state_seqnum_remove(cli, mid); return False; } show_msg(cli->inbuf); /* sanity check */ if (CVAL(cli->inbuf,smb_com) != SMBnttrans) { DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n", CVAL(cli->inbuf,smb_com))); cli_state_seqnum_remove(cli, mid); return(False); } /* * An NT RPC pipe call can return ERRDOS, ERRmoredata * to a trans call. This is not an error and should not * be treated as such. */ if (cli_is_dos_error(cli)) { cli_dos_error(cli, &eclass, &ecode); if (!(eclass == ERRDOS && ecode == ERRmoredata)) { goto out; } } /* * Likewise for NT_STATUS_BUFFER_TOO_SMALL */ if (cli_is_nt_error(cli)) { if (!NT_STATUS_EQUAL(cli_nt_error(cli), NT_STATUS_BUFFER_TOO_SMALL)) { goto out; } } /* parse out the lengths */ total_data = IVAL(cli->inbuf,smb_ntr_TotalDataCount); total_param = IVAL(cli->inbuf,smb_ntr_TotalParameterCount); /* Only allow 16 megs. */ if (total_param > 16*1024*1024) { DEBUG(0,("cli_receive_nt_trans: param buffer too large %d\n", total_param)); goto out; } if (total_data > 16*1024*1024) { DEBUG(0,("cli_receive_nt_trans: data buffer too large %d\n", total_data)); goto out; } /* allocate it */ if (total_data) { /* We know adding 2 is safe as total_data is less * than 16mb (above). */ *data = (char *)SMB_REALLOC(*data,total_data+2); if (!(*data)) { DEBUG(0,("cli_receive_nt_trans: failed to enlarge data buffer to %d\n",total_data)); goto out; } } if (total_param) { /* We know adding 2 is safe as total_param is less * than 16mb (above). */ *param = (char *)SMB_REALLOC(*param,total_param+2); if (!(*param)) { DEBUG(0,("cli_receive_nt_trans: failed to enlarge param buffer to %d\n", total_param)); goto out; } } while (1) { this_data = SVAL(cli->inbuf,smb_ntr_DataCount); this_param = SVAL(cli->inbuf,smb_ntr_ParameterCount); if (this_data + *data_len > total_data || this_param + *param_len > total_param) { DEBUG(1,("Data overflow in cli_receive_nt_trans\n")); goto out; } if (this_data + *data_len < this_data || this_data + *data_len < *data_len || this_param + *param_len < this_param || this_param + *param_len < *param_len) { DEBUG(1,("Data overflow in cli_receive_nt_trans\n")); goto out; } if (this_data) { unsigned int data_offset_out = SVAL(cli->inbuf,smb_ntr_DataDisplacement); unsigned int data_offset_in = SVAL(cli->inbuf,smb_ntr_DataOffset); if (data_offset_out > total_data || data_offset_out + this_data > total_data || data_offset_out + this_data < data_offset_out || data_offset_out + this_data < this_data) { DEBUG(1,("Data overflow in cli_receive_nt_trans\n")); goto out; } if (data_offset_in > cli->bufsize || data_offset_in + this_data > cli->bufsize || data_offset_in + this_data < data_offset_in || data_offset_in + this_data < this_data) { DEBUG(1,("Data overflow in cli_receive_nt_trans\n")); goto out; } memcpy(*data + data_offset_out, smb_base(cli->inbuf) + data_offset_in, this_data); } if (this_param) { unsigned int param_offset_out = SVAL(cli->inbuf,smb_ntr_ParameterDisplacement); unsigned int param_offset_in = SVAL(cli->inbuf,smb_ntr_ParameterOffset); if (param_offset_out > total_param || param_offset_out + this_param > total_param || param_offset_out + this_param < param_offset_out || param_offset_out + this_param < this_param) { DEBUG(1,("Param overflow in cli_receive_nt_trans\n")); goto out; } if (param_offset_in > cli->bufsize || param_offset_in + this_param > cli->bufsize || param_offset_in + this_param < param_offset_in || param_offset_in + this_param < this_param) { DEBUG(1,("Param overflow in cli_receive_nt_trans\n")); goto out; } memcpy(*param + param_offset_out, smb_base(cli->inbuf) + param_offset_in, this_param); } *data_len += this_data; *param_len += this_param; if (total_data <= *data_len && total_param <= *param_len) { ret = True; break; } if (!cli_receive_smb(cli)) { goto out; } show_msg(cli->inbuf); /* sanity check */ if (CVAL(cli->inbuf,smb_com) != SMBnttrans) { DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n", CVAL(cli->inbuf,smb_com))); goto out; } if (cli_is_dos_error(cli)) { cli_dos_error(cli, &eclass, &ecode); if(!(eclass == ERRDOS && ecode == ERRmoredata)) { goto out; } } /* * Likewise for NT_STATUS_BUFFER_TOO_SMALL */ if (cli_is_nt_error(cli)) { if (!NT_STATUS_EQUAL(cli_nt_error(cli), NT_STATUS_BUFFER_TOO_SMALL)) { goto out; } } /* parse out the total lengths again - they can shrink! */ if (IVAL(cli->inbuf,smb_ntr_TotalDataCount) < total_data) total_data = IVAL(cli->inbuf,smb_ntr_TotalDataCount); if (IVAL(cli->inbuf,smb_ntr_TotalParameterCount) < total_param) total_param = IVAL(cli->inbuf,smb_ntr_TotalParameterCount); if (total_data <= *data_len && total_param <= *param_len) { ret = True; break; } } out: cli_state_seqnum_remove(cli, mid); if (ret) { /* Ensure the last 2 bytes of param and data are 2 null * bytes. These are malloc'ed, but not included in any * length counts. This allows cli_XX string reading functions * to safely null terminate. */ if (total_data) { SSVAL(*data,total_data,0); } if (total_param) { SSVAL(*param,total_param,0); } } return ret; }