static void smb_tr2_find2_parse_entries(smb_file **files_p, smb_tr2_find2_entry *iter, size_t count, uint8_t *eod) { smb_file *tmp = NULL; size_t i; for (i = 0; i < count && (uint8_t *)iter < eod; i++) { // Create a smb_file and fill it tmp = calloc(1, sizeof(smb_file)); if (!tmp) return; tmp->name_len = smb_from_utf16((const char *)iter->name, iter->name_len, &tmp->name); tmp->name[tmp->name_len] = 0; tmp->created = iter->created; tmp->accessed = iter->accessed; tmp->written = iter->written; tmp->changed = iter->changed; tmp->size = iter->size; tmp->alloc_size = iter->alloc_size; tmp->attr = iter->attr; tmp->is_dir = tmp->attr & SMB_ATTR_DIR; tmp->next = *files_p; *files_p = tmp; iter = (smb_tr2_find2_entry *)(((char *)iter) + iter->next_entry); } return; }
static smb_file *smb_find_parse(smb_message *msg) { smb_trans2_resp *tr2; smb_tr2_find2_params *params; smb_tr2_find2_entry *iter; smb_file *files, *tmp; uint8_t *eod; size_t count, i; assert(msg != NULL); // Let's parse the answer we got from server tr2 = (smb_trans2_resp *)msg->packet->payload; params = (smb_tr2_find2_params *)tr2->payload; iter = (smb_tr2_find2_entry *)(tr2->payload + sizeof(smb_tr2_find2_params)); eod = msg->packet->payload + msg->payload_size; count = params->count; files = NULL; for(i = 0; i < count && (uint8_t *)iter < eod; i++) { // Create a smb_file and fill it tmp = calloc(1, sizeof(smb_file)); assert(tmp != NULL); tmp->name_len = smb_from_utf16((const char *)iter->name, iter->name_len, &tmp->name); tmp->name[tmp->name_len] = 0; tmp->created = iter->created; tmp->accessed = iter->accessed; tmp->written = iter->written; tmp->changed = iter->changed; tmp->size = iter->size; tmp->alloc_size = iter->alloc_size; tmp->attr = iter->attr; tmp->is_dir = tmp->attr & SMB_ATTR_DIR; tmp->next = files; files = tmp; iter = (smb_tr2_find2_entry *)(((char *)iter) + iter->next_entry); } return (files); }
// Here we parse the NetShareEnumAll response packet payload to extract // The share list. static ssize_t smb_share_parse_enum(smb_message *msg, char ***list) { uint32_t share_count, i; uint8_t *data, *eod; uint32_t *p_share_count; assert(msg != NULL && list != NULL); if( msg != NULL && list != NULL ) { // Let's skip smb parameters and DCE/RPC stuff until we are at the begginning of // NetShareCtrl p_share_count = (uint32_t *)(msg->packet->payload + 60); share_count = *p_share_count; data = msg->packet->payload + 72 + share_count * 12; eod = msg->packet->payload + msg->payload_size; *list = calloc(share_count + 1, sizeof(char *)); if (!(*list)) return -1; for (i = 0; i < share_count && data < eod; i++) { uint32_t name_len, com_len; name_len = *((uint32_t *)data); // Read 'Max Count', make it a multiple of 2 data += 3 * sizeof(uint32_t); // Move pointer to beginning of Name. smb_from_utf16((const char *)data, name_len * 2, (*list) + i); if (name_len % 2) name_len += 1; // Align next move data += name_len * 2; // Move the pointer to Comment 'Max count' com_len = *((uint32_t *)data); data += 3 * sizeof(uint32_t); // Move pointer to beginning of Comment. if (com_len % 2) com_len += 1; // Align next move data += com_len * 2; // Move the pointer to next item } return i; } return -1; }
smb_file *smb_fstat(smb_session *s, smb_tid tid, const char *path) { smb_message *msg, reply; smb_trans2_req *tr2; smb_trans2_resp *tr2_resp; smb_tr2_query *query; smb_tr2_path_info *info; smb_file *file; size_t path_len, msg_len; int res; assert(s != NULL && path != NULL && tid); path_len = strlen(path) + 1; msg_len = sizeof(smb_trans2_req) + sizeof(smb_tr2_query); msg_len += path_len * 2 + 3; // +3 for eventual padding msg = smb_message_new(SMB_CMD_TRANS2, msg_len); smb_message_set_default_flags(msg); msg->packet->header.tid = tid; tr2 = (smb_trans2_req *)msg->packet->payload; tr2->wct = 15; tr2->total_param_count = path_len * 2 + sizeof(smb_tr2_query); tr2->max_param_count = 2; // ?? Why not the same or 12 ? tr2->max_data_count = 0xffff; tr2->param_count = tr2->total_param_count; tr2->param_offset = 68; // Offset of find_first_params in packet; tr2->data_count = 0; tr2->data_offset = 96; // Offset of pattern in packet tr2->setup_count = 1; tr2->cmd = SMB_TR2_QUERY_PATH; tr2->bct = sizeof(smb_tr2_query) + path_len * 2 + 3; query = (smb_tr2_query *)tr2->payload; query->interest = 0x0107; // Query File All Info smb_message_advance(msg, sizeof(smb_trans2_req)); smb_message_advance(msg, sizeof(smb_tr2_query)); smb_message_put_utf16(msg, "", path, path_len); // Adds padding at the end if necessary. if (msg->cursor % 4) { int padding = 4 - msg->cursor % 4; tr2->bct += padding; for (int i = 0; i < padding; i++) smb_message_put8(msg, 0); } res = smb_session_send_msg(s, msg); smb_message_destroy(msg); if (!res) { BDSM_dbg("Unable to query pattern: %s\n", path); return (NULL); } if (!smb_session_recv_msg(s, &reply) || reply.packet->header.status != NT_STATUS_SUCCESS) { BDSM_dbg("Unable to recv msg or failure for %s\n", path); return (NULL); } tr2_resp = (smb_trans2_resp *)reply.packet->payload; info = (smb_tr2_path_info *)(tr2_resp->payload + 4); //+4 is padding file = calloc(1, sizeof(smb_file)); assert(file != NULL); file->name_len = smb_from_utf16((const char *)info->name, info->name_len, &file->name); file->name[info->name_len] = 0; file->created = info->created; file->accessed = info->accessed; file->written = info->written; file->changed = info->changed; file->alloc_size = info->alloc_size; file->size = info->size; file->attr = info->attr; file->is_dir = info->is_dir; return (file); }
smb_file *smb_fstat(smb_session *s, smb_tid tid, const char *path) { smb_message *msg, reply; smb_trans2_req tr2; smb_trans2_resp *tr2_resp; smb_tr2_query query; smb_tr2_path_info *info; smb_file *file; size_t utf_path_len, msg_len; char *utf_path; int res, padding = 0; assert(s != NULL && path != NULL); utf_path_len = smb_to_utf16(path, strlen(path) + 1, &utf_path); if (utf_path_len == 0) return 0; msg_len = sizeof(smb_trans2_req) + sizeof(smb_tr2_query); msg_len += utf_path_len; if (msg_len %4) padding = 4 - msg_len % 4; msg = smb_message_new(SMB_CMD_TRANS2); if (!msg) { free(utf_path); return 0; } msg->packet->header.tid = tid; SMB_MSG_INIT_PKT(tr2); tr2.wct = 15; tr2.total_param_count = utf_path_len + sizeof(smb_tr2_query); tr2.param_count = tr2.total_param_count; tr2.max_param_count = 2; // ?? Why not the same or 12 ? tr2.max_data_count = 0xffff; tr2.param_offset = 68; // Offset of find_first_params in packet; tr2.data_count = 0; tr2.data_offset = 96; // Offset of pattern in packet tr2.setup_count = 1; tr2.cmd = SMB_TR2_QUERY_PATH; tr2.bct = sizeof(smb_tr2_query) + utf_path_len + padding; SMB_MSG_PUT_PKT(msg, tr2); SMB_MSG_INIT_PKT(query); query.interest = SMB_FIND2_QUERY_FILE_ALL_INFO; SMB_MSG_PUT_PKT(msg, query); smb_message_append(msg, utf_path, utf_path_len); free(utf_path); // Adds padding at the end if necessary. while (padding--) smb_message_put8(msg, 0); res = smb_session_send_msg(s, msg); smb_message_destroy(msg); if (!res) { BDSM_dbg("Unable to query pattern: %s\n", path); return NULL; } if (!smb_session_recv_msg(s, &reply) || reply.packet->header.status != NT_STATUS_SUCCESS) { BDSM_dbg("Unable to recv msg or failure for %s\n", path); return NULL; } tr2_resp = (smb_trans2_resp *)reply.packet->payload; info = (smb_tr2_path_info *)(tr2_resp->payload + 4); //+4 is padding file = calloc(1, sizeof(smb_file)); if (!file) return NULL; file->name_len = smb_from_utf16((const char *)info->name, info->name_len, &file->name); file->name[info->name_len / 2] = 0; file->created = info->created; file->accessed = info->accessed; file->written = info->written; file->changed = info->changed; file->alloc_size = info->alloc_size; file->size = info->size; file->attr = info->attr; file->is_dir = info->is_dir; return file; }