smb_share.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. /*****************************************************************************
  2. * __________________ _________ _____ _____ .__ ._.
  3. * \______ \______ \ / _____/ / \ / _ \ |__| ____ | |
  4. * | | _/| | \ \_____ \ / \ / \ / /_\ \| _/ __ \ | |
  5. * | | \| ` \/ / Y \ / | | \ ___/ \|
  6. * |______ /_______ /_______ \____|__ / /\ \____|__ |__|\___ | __
  7. * \/ \/ \/ \/ )/ \/ \/ \/
  8. *
  9. * This file is part of liBDSM. Copyright © 2014-2015 VideoLabs SAS
  10. *
  11. * Author: Julien 'Lta' BALLET <contact@lta.io>
  12. *
  13. * liBDSM is released under LGPLv2.1 (or later) and is also available
  14. * under a commercial license.
  15. *****************************************************************************
  16. * This program is free software; you can redistribute it and/or modify it
  17. * under the terms of the GNU Lesser General Public License as published by
  18. * the Free Software Foundation; either version 2.1 of the License, or
  19. * (at your option) any later version.
  20. *
  21. * This program is distributed in the hope that it will be useful,
  22. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24. * GNU Lesser General Public License for more details.
  25. *
  26. * You should have received a copy of the GNU Lesser General Public License
  27. * along with this program; if not, write to the Free Software Foundation,
  28. * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  29. *****************************************************************************/
  30. #include <assert.h>
  31. #include <stdlib.h>
  32. #include <unistd.h>
  33. #include <string.h>
  34. #include <stdio.h>
  35. #include "bdsm_debug.h"
  36. #include "smb_session_msg.h"
  37. #include "smb_utils.h"
  38. #include "smb_fd.h"
  39. #include "smb_share.h"
  40. #include "smb_file.h"
  41. smb_tid smb_tree_connect(smb_session *s, const char *name)
  42. {
  43. smb_tree_connect_req req;
  44. smb_tree_connect_resp *resp;
  45. smb_message resp_msg;
  46. smb_message *req_msg;
  47. smb_share *share;
  48. size_t path_len, utf_path_len;
  49. char *path, *utf_path;
  50. assert(s != NULL && name != NULL);
  51. // Build \\SERVER\Share path from name
  52. path_len = strlen(name) + strlen(s->srv.name) + 4;
  53. path = alloca(path_len);
  54. snprintf(path, path_len, "\\\\%s\\%s", s->srv.name, name);
  55. utf_path_len = smb_to_utf16(path, strlen(path) + 1, &utf_path);
  56. req_msg = smb_message_new(SMB_CMD_TREE_CONNECT);
  57. if (!req_msg)
  58. return -1;
  59. // Packet headers
  60. req_msg->packet->header.tid = 0xffff; // Behavior of libsmbclient
  61. smb_message_set_andx_members(req_msg);
  62. // Packet payload
  63. SMB_MSG_INIT_PKT_ANDX(req);
  64. req.wct = 4;
  65. req.flags = 0x0c; // (??)
  66. req.passwd_len = 1; // Null byte
  67. req.bct = utf_path_len + 6 + 1;
  68. SMB_MSG_PUT_PKT(req_msg, req);
  69. smb_message_put8(req_msg, 0); // Ze null byte password;
  70. smb_message_append(req_msg, utf_path, utf_path_len);
  71. free(utf_path);
  72. smb_message_append(req_msg, "?????", strlen("?????") + 1);
  73. if (!smb_session_send_msg(s, req_msg))
  74. {
  75. smb_message_destroy(req_msg);
  76. return -1;
  77. }
  78. smb_message_destroy(req_msg);
  79. if (!smb_session_recv_msg(s, &resp_msg))
  80. return -1;
  81. if (resp_msg.packet->header.status != NT_STATUS_SUCCESS)
  82. return -1;
  83. resp = (smb_tree_connect_resp *)resp_msg.packet->payload;
  84. share = calloc(1, sizeof(smb_share));
  85. if (!share)
  86. return -1;
  87. share->tid = resp_msg.packet->header.tid;
  88. share->opts = resp->opt_support;
  89. share->rights = resp->max_rights;
  90. share->guest_rights = resp->guest_rights;
  91. smb_session_share_add(s, share);
  92. return share->tid;
  93. }
  94. int smb_tree_disconnect(smb_session *s, smb_tid tid)
  95. {
  96. smb_tree_disconnect_req req;
  97. smb_tree_disconnect_resp *resp;
  98. smb_message *req_msg;
  99. smb_message resp_msg;
  100. if ((s == NULL) || (tid == -1))
  101. return -1;
  102. req_msg = smb_message_new(SMB_CMD_TREE_DISCONNECT);
  103. if (!req_msg)
  104. return -1;
  105. // Packet headers
  106. req_msg->packet->header.tid = (uint16_t)tid;
  107. // Packet payload
  108. req.wct = 0; // Must be 0
  109. req.bct = 0; // Must be 0
  110. SMB_MSG_PUT_PKT(req_msg, req);
  111. if (!smb_session_send_msg(s, req_msg))
  112. {
  113. smb_message_destroy(req_msg);
  114. return -1;
  115. }
  116. smb_message_destroy(req_msg);
  117. if (!smb_session_recv_msg(s, &resp_msg))
  118. return -1;
  119. if (resp_msg.packet->header.status != NT_STATUS_SUCCESS)
  120. return -1;
  121. resp = (smb_tree_disconnect_resp *)resp_msg.packet->payload;
  122. if ((resp->wct != 0) || (resp->bct != 0))
  123. return -1;
  124. return 0;
  125. }
  126. // Here we parse the NetShareEnumAll response packet payload to extract
  127. // The share list.
  128. static size_t smb_share_parse_enum(smb_message *msg, char ***list)
  129. {
  130. uint32_t share_count, i;
  131. uint8_t *data, *eod;
  132. uint32_t *p_share_count;
  133. assert(msg != NULL && list != NULL);
  134. // Let's skip smb parameters and DCE/RPC stuff until we are at the begginning of
  135. // NetShareCtrl
  136. p_share_count = (uint32_t *)(msg->packet->payload + 60);
  137. share_count = *p_share_count;
  138. data = msg->packet->payload + 72 + share_count * 12;
  139. eod = msg->packet->payload + msg->payload_size;
  140. *list = calloc(share_count + 1, sizeof(char *));
  141. if (!list)
  142. return 0;
  143. assert(*list != NULL);
  144. for (i = 0; i < share_count && data < eod; i++)
  145. {
  146. uint32_t name_len, com_len;
  147. name_len = *((uint32_t *)data); // Read 'Max Count', make it a multiple of 2
  148. data += 3 * sizeof(uint32_t); // Move pointer to beginning of Name.
  149. smb_from_utf16((const char *)data, name_len * 2, (*list) + i);
  150. if (name_len % 2) name_len += 1; // Align next move
  151. data += name_len * 2; // Move the pointer to Comment 'Max count'
  152. com_len = *((uint32_t *)data);
  153. data += 3 * sizeof(uint32_t); // Move pointer to beginning of Comment.
  154. if (com_len % 2) com_len += 1; // Align next move
  155. data += com_len * 2; // Move the pointer to next item
  156. }
  157. return i;
  158. }
  159. size_t smb_share_list_count(smb_share_list list)
  160. {
  161. size_t res;
  162. if (list == NULL)
  163. return 0;
  164. for (res = 0; list[res] != NULL; res++)
  165. ;
  166. return res;
  167. }
  168. const char *smb_share_list_at(smb_share_list list, size_t index)
  169. {
  170. assert(list != NULL);
  171. return list[index];
  172. }
  173. void smb_share_list_destroy(smb_share_list list)
  174. {
  175. assert(list != NULL);
  176. for (size_t i = 0; list[i] != NULL; i++)
  177. free(list[i]);
  178. free(list);
  179. }
  180. // We should normally implement SCERPC and SRVSVC to perform a share list. But
  181. // since these two protocols have no other use for us, we'll do it the trash way
  182. // PS: Worst function _EVER_. I don't understand a bit myself
  183. size_t smb_share_get_list(smb_session *s, char ***list)
  184. {
  185. smb_message *req, resp;
  186. smb_trans_req trans;
  187. smb_tid ipc_tid;
  188. smb_fd srvscv_fd;
  189. uint16_t rpc_len;
  190. ssize_t res, frag_len_cursor;
  191. assert(s != NULL && list != NULL);
  192. *list = NULL;
  193. ipc_tid = smb_tree_connect(s, "IPC$");
  194. if (ipc_tid == -1)
  195. return 0;
  196. srvscv_fd = smb_fopen(s, ipc_tid, "\\srvsvc", SMB_MOD_READ | SMB_MOD_WRITE);
  197. if (!srvscv_fd)
  198. return 0;
  199. //// Phase 1:
  200. // We bind a context or whatever for DCE/RPC
  201. req = smb_message_new(SMD_CMD_TRANS);
  202. if (!req)
  203. return 0;
  204. req->packet->header.tid = (uint16_t)ipc_tid;
  205. rpc_len = 0xffff;
  206. SMB_MSG_INIT_PKT(trans);
  207. trans.wct = 16;
  208. trans.total_data_count = 72;
  209. trans.max_data_count = rpc_len;
  210. trans.param_offset = 84;
  211. trans.data_count = 72;
  212. trans.data_offset = 84;
  213. trans.setup_count = 2;
  214. trans.pipe_function = 0x26;
  215. trans.fid = SMB_FD_FID(srvscv_fd);
  216. trans.bct = 89;
  217. SMB_MSG_PUT_PKT(req, trans);
  218. smb_message_put8(req, 0); // Padding
  219. smb_message_put_utf16(req, "\\PIPE\\", strlen("\\PIPE\\") + 1);
  220. smb_message_put16(req, 0); // Padding to be aligned with wtf boundary :-/
  221. // Now we'll 'build' the DCE/RPC Packet. This basically a copycat
  222. // from wireshark values.
  223. smb_message_put8(req, 5); // version major
  224. smb_message_put8(req, 0); // minor
  225. smb_message_put8(req, 0x0b); // Packet type = 'bind'
  226. smb_message_put8(req, 0x03); // Packet flags = ??
  227. smb_message_put32(req, 0x10); // Representation = little endian/ASCII. Damn
  228. smb_message_put16(req, 72); // Data len again
  229. smb_message_put16(req, 0); // Auth len ?
  230. smb_message_put32(req, 19); // Call ID ?
  231. smb_message_put16(req, rpc_len); // Max Xmit size
  232. smb_message_put16(req, rpc_len); // Max Recv size
  233. smb_message_put32(req, 0); // Assoc group ?
  234. smb_message_put32(req, 1); // Num Ctx Item
  235. // Adding the CtxItem, whatever could that be
  236. smb_message_put16(req, 0); // ContextID
  237. smb_message_put16(req, 1); // Num Trans Item
  238. // SRVSVC UUID
  239. const uint8_t uuid_e[8] = {0x12, 0x78, 0x5a, 0x47, 0xbf, 0x6e, 0xe1, 0x88};
  240. smb_message_put_uuid(req, 0x4b324fc8, 0x1670, 0x01d3, uuid_e);
  241. smb_message_put16(req, 3); // Version
  242. smb_message_put16(req, 0); // Minor
  243. // Another UUID
  244. const uint8_t uuid_e2[8] = {0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60};
  245. smb_message_put_uuid(req, 0x8a885d04, 0x1ceb, 0x11c9, uuid_e2);
  246. smb_message_put32(req, 2); // Another version
  247. // Let's send this ugly pile of shit over the network !
  248. res = smb_session_send_msg(s, req);
  249. smb_message_destroy(req);
  250. if (!res)
  251. return 0;
  252. // Is the server throwing pile of shit back at me ?
  253. res = smb_session_recv_msg(s, &resp);
  254. if (!res || resp.packet->payload[68])
  255. {
  256. BDSM_dbg("Bind call failed: 0x%hhx (reason = 0x%hhx)\n",
  257. resp.packet->payload[68], resp.packet->payload[70]);
  258. return 0;
  259. }
  260. //// Phase 2:
  261. // Now we have the 'bind' done (regarless of what it is), we'll call
  262. // NetShareEnumAll
  263. req = smb_message_new(SMD_CMD_TRANS);
  264. if (!req)
  265. return 0;
  266. req->packet->header.tid = (uint16_t)ipc_tid;
  267. // this struct will be set at the end when we know the data size
  268. SMB_MSG_ADVANCE_PKT(req, smb_trans_req);
  269. smb_message_put8(req, 0); // Padding
  270. smb_message_put_utf16(req, "\\PIPE\\", strlen("\\PIPE\\") + 1);
  271. smb_message_put16(req, 0); // Padding
  272. // Now we'll 'build' the DCE/RPC Packet. This basically a copycat
  273. // from wireshark values.
  274. smb_message_put8(req, 5); // version major
  275. smb_message_put8(req, 0); // minor
  276. smb_message_put8(req, 0); // Packet type = 'request'
  277. smb_message_put8(req, 0x03); // Packet flags = ??
  278. smb_message_put32(req, 0x10); // Representation = little endian/ASCII. Damn
  279. // Let's save the cursor here to update that later
  280. frag_len_cursor = req->cursor;
  281. smb_message_put16(req, 0); // Data len again (frag length)
  282. smb_message_put16(req, 0); // Auth len ?
  283. smb_message_put32(req, 12); // Call ID ?
  284. smb_message_put32(req, 64); // Alloc hint ?
  285. smb_message_put16(req, 0); // Context ID ?
  286. smb_message_put16(req, 15); // OpNum = NetShareEnumAll
  287. // Pointer to server UNC
  288. smb_message_put32(req, 0x00020000); // Referent ID ?
  289. smb_message_put32(req, strlen(s->srv.name) + 1); // Max count
  290. smb_message_put32(req, 0); // Offset
  291. smb_message_put32(req, strlen(s->srv.name) + 1); // Actual count
  292. // The server name, supposed to be downcased
  293. smb_message_put_utf16(req, s->srv.name, strlen(s->srv.name) + 1);
  294. if ((strlen(s->srv.name) % 2) == 0) // It won't be aligned with the terminating byte
  295. smb_message_put16(req, 0);
  296. smb_message_put32(req, 1); // Level 1 ?
  297. smb_message_put32(req, 1); // Ctr ?
  298. smb_message_put32(req, 0x00020004); // Referent ID ?
  299. smb_message_put64(req, 0); // Count/Null Pointer to NetShareInfo1
  300. smb_message_put32(req, 0xffffffff); // Max Buffer (0xffffffff required by smbX)
  301. smb_message_put32(req, 0x00020008); // Referent ID ?
  302. smb_message_put32(req, 0); // Resume ?
  303. // fill trans pkt at the end since we know the size at the end
  304. SMB_MSG_INIT_PKT(trans);
  305. trans.wct = 16;
  306. trans.max_data_count = 4280;
  307. trans.setup_count = 2;
  308. trans.pipe_function = 0x26; // TransactNmPipe;
  309. trans.fid = SMB_FD_FID(srvscv_fd);
  310. trans.bct = req->cursor - sizeof(smb_trans_req);
  311. trans.data_count = trans.bct - 17; // 17 -> padding + \PIPE\ + padding
  312. trans.total_data_count = trans.data_count;
  313. trans.data_offset = 84;
  314. trans.param_offset = 84;
  315. // but insert it at the begining
  316. SMB_MSG_INSERT_PKT(req, 0, trans);
  317. req->packet->payload[frag_len_cursor] = trans.data_count; // (data_count SHOULD stay < 256)
  318. // Let's send this ugly pile of shit over the network !
  319. res = smb_session_send_msg(s, req);
  320. smb_message_destroy(req);
  321. if (!res)
  322. return 0;
  323. // Is the server throwing pile of shit back at me ?
  324. res = smb_session_recv_msg(s, &resp);
  325. if (!res && (uint32_t)resp.packet->payload[resp.payload_size - 4])
  326. {
  327. BDSM_dbg("NetShareEnumAll call failed.\n");
  328. return 0;
  329. }
  330. //// Phase 3
  331. // We parse the list of Share (finally !) and build function response
  332. res = smb_share_parse_enum(&resp, list);
  333. // Close the pipe
  334. smb_fclose(s, srvscv_fd);
  335. return res;
  336. }