smb_session.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  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 "config.h"
  31. #include "compat.h"
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #include <stdio.h>
  35. #include <assert.h>
  36. #include "bdsm_debug.h"
  37. #include "smb_session.h"
  38. #include "smb_session_msg.h"
  39. #include "smb_fd.h"
  40. #include "smb_ntlm.h"
  41. #include "smb_spnego.h"
  42. #include "smb_transport.h"
  43. static int smb_negotiate(smb_session *s);
  44. smb_session *smb_session_new()
  45. {
  46. smb_session *s;
  47. s = calloc(1, sizeof(smb_session));
  48. if (!s)
  49. return NULL;
  50. s->guest = false;
  51. // Explicitly sets pointer to NULL, insted of 0
  52. s->spnego_asn1 = NULL;
  53. s->transport.session = NULL;
  54. s->shares = NULL;
  55. s->creds.domain = NULL;
  56. s->creds.login = NULL;
  57. s->creds.password = NULL;
  58. smb_buffer_init(&s->xsec_target, NULL, 0);
  59. // Until we know more, assume server supports everything.
  60. // s->c
  61. return s;
  62. }
  63. void smb_session_destroy(smb_session *s)
  64. {
  65. assert(s != NULL);
  66. smb_session_share_clear(s);
  67. // FIXME Free smb_share and smb_file
  68. if (s->transport.session != NULL)
  69. {
  70. s->transport.destroy(s->transport.session);
  71. s->transport.session = NULL;
  72. }
  73. if (s->spnego_asn1 != NULL)
  74. asn1_delete_structure(&s->spnego_asn1);
  75. smb_buffer_free(&s->xsec_target);
  76. // Free stored credentials.
  77. free(s->creds.domain);
  78. free(s->creds.login);
  79. free(s->creds.password);
  80. free(s);
  81. }
  82. void smb_session_set_creds(smb_session *s, const char *domain,
  83. const char *login, const char *password)
  84. {
  85. assert(s != NULL);
  86. if (domain != NULL)
  87. {
  88. if (s->creds.domain != NULL)
  89. free(s->creds.domain);
  90. s->creds.domain = strndup(domain, SMB_CREDS_MAXLEN);
  91. }
  92. if (login != NULL)
  93. {
  94. if (s->creds.login != NULL)
  95. free(s->creds.login);
  96. s->creds.login = strndup(login, SMB_CREDS_MAXLEN);
  97. }
  98. if (password != NULL)
  99. {
  100. if (s->creds.password != NULL)
  101. free(s->creds.password);
  102. s->creds.password = strndup(password, SMB_CREDS_MAXLEN);
  103. }
  104. }
  105. int smb_session_connect(smb_session *s, const char *name,
  106. uint32_t ip, int transport)
  107. {
  108. assert(s != NULL && name != NULL);
  109. if (s->transport.session != NULL)
  110. s->transport.destroy(s->transport.session);
  111. switch (transport)
  112. {
  113. case SMB_TRANSPORT_TCP:
  114. smb_transport_tcp(&s->transport);
  115. break;
  116. case SMB_TRANSPORT_NBT:
  117. smb_transport_nbt(&s->transport);
  118. break;
  119. default:
  120. return DSM_ERROR_GENERIC;
  121. }
  122. if ((s->transport.session = s->transport.new(SMB_DEFAULT_BUFSIZE)) == NULL)
  123. return DSM_ERROR_GENERIC;
  124. if (!s->transport.connect(ip, s->transport.session, name))
  125. return DSM_ERROR_NETWORK;
  126. memcpy(s->srv.name, name, strlen(name) + 1);
  127. return smb_negotiate(s);
  128. }
  129. static int smb_negotiate(smb_session *s)
  130. {
  131. const char *dialects[] = SMB_DIALECTS;
  132. smb_message *msg = NULL;
  133. smb_message answer;
  134. smb_nego_resp *nego;
  135. uint16_t *p_payload_size;
  136. assert(s != NULL);
  137. msg = smb_message_new(SMB_CMD_NEGOTIATE);
  138. if (!msg)
  139. return DSM_ERROR_GENERIC;
  140. smb_message_put8(msg, 0); // wct
  141. smb_message_put16(msg, 0); // bct, will be updated later
  142. for (unsigned i = 0; dialects[i] != NULL; i++)
  143. smb_message_append(msg, dialects[i], strlen(dialects[i]) + 1);
  144. p_payload_size = (uint16_t *)(msg->packet->payload + 1);
  145. *p_payload_size = msg->cursor - 3;
  146. if (!smb_session_send_msg(s, msg))
  147. {
  148. smb_message_destroy(msg);
  149. return DSM_ERROR_NETWORK;
  150. }
  151. smb_message_destroy(msg);
  152. if (!smb_session_recv_msg(s, &answer))
  153. return DSM_ERROR_NETWORK;
  154. nego = (smb_nego_resp *)answer.packet->payload;
  155. if (!smb_session_check_nt_status(s, &answer))
  156. return DSM_ERROR_NT;
  157. if (nego->wct != 0x11)
  158. return DSM_ERROR_NETWORK;
  159. s->srv.dialect = nego->dialect_index;
  160. s->srv.security_mode = nego->security_mode;
  161. s->srv.caps = nego->caps;
  162. s->srv.ts = nego->ts;
  163. s->srv.session_key = nego->session_key;
  164. // Copy SPNEGO supported mechanisms token for later usage (login_gss())
  165. if (smb_session_supports(s, SMB_SESSION_XSEC))
  166. BDSM_dbg("Server is supporting extended security\n");
  167. else
  168. s->srv.challenge = nego->challenge;
  169. return DSM_SUCCESS;
  170. }
  171. static int smb_session_login_ntlm(smb_session *s, const char *domain,
  172. const char *user, const char *password)
  173. {
  174. smb_message answer;
  175. smb_message *msg = NULL;
  176. smb_session_req req;
  177. uint8_t *ntlm2 = NULL;
  178. smb_ntlmh hash_v2;
  179. uint64_t user_challenge;
  180. assert(s != NULL);
  181. msg = smb_message_new(SMB_CMD_SETUP);
  182. if (!msg)
  183. return DSM_ERROR_GENERIC;
  184. // this struct will be set at the end when we know the payload size
  185. SMB_MSG_ADVANCE_PKT(msg, smb_session_req);
  186. user_challenge = smb_ntlm_generate_challenge();
  187. // LM2 Response
  188. smb_ntlm2_hash(user, password, domain, hash_v2);
  189. ntlm2 = smb_lm2_response(hash_v2, s->srv.challenge, user_challenge);
  190. smb_message_append(msg, ntlm2, 16 + 8);
  191. free(ntlm2);
  192. if (msg->cursor / 2) // Padding !
  193. smb_message_put8(msg, 0);
  194. smb_message_put_utf16(msg, user, strlen(user));
  195. smb_message_put16(msg, 0);
  196. smb_message_put_utf16(msg, domain, strlen(domain));
  197. smb_message_put16(msg, 0);
  198. smb_message_put_utf16(msg, SMB_OS, strlen(SMB_OS));
  199. smb_message_put16(msg, 0);
  200. smb_message_put_utf16(msg, SMB_LANMAN, strlen(SMB_LANMAN));
  201. smb_message_put16(msg, 0);
  202. SMB_MSG_INIT_PKT_ANDX(req);
  203. req.wct = 13;
  204. req.max_buffer = SMB_SESSION_MAX_BUFFER;
  205. req.mpx_count = 16; // XXX ?
  206. req.vc_count = 1;
  207. //req.session_key = s->srv.session_key; // XXX Useless on the wire?
  208. req.caps = s->srv.caps; // XXX caps & our_caps_mask
  209. req.oem_pass_len = 16 + SMB_LM2_BLOB_SIZE;
  210. req.uni_pass_len = 0; //16 + blob_size; //SMB_NTLM2_BLOB_SIZE;
  211. req.payload_size = msg->cursor - sizeof(smb_session_req);
  212. SMB_MSG_INSERT_PKT(msg, 0, req);
  213. if (!smb_session_send_msg(s, msg))
  214. {
  215. smb_message_destroy(msg);
  216. BDSM_dbg("Unable to send Session Setup AndX message\n");
  217. return DSM_ERROR_NETWORK;
  218. }
  219. smb_message_destroy(msg);
  220. if (smb_session_recv_msg(s, &answer) == 0)
  221. {
  222. BDSM_dbg("Unable to get Session Setup AndX reply\n");
  223. return DSM_ERROR_NETWORK;
  224. }
  225. smb_session_resp *r = (smb_session_resp *)answer.packet->payload;
  226. if (!smb_session_check_nt_status(s, &answer))
  227. {
  228. BDSM_dbg("Session Setup AndX : failure.\n");
  229. return DSM_ERROR_NT;
  230. }
  231. if (r->action & 0x0001)
  232. s->guest = true;
  233. s->srv.uid = answer.packet->header.uid;
  234. s->logged = true;
  235. return DSM_SUCCESS;
  236. }
  237. int smb_session_login(smb_session *s)
  238. {
  239. assert(s != NULL);
  240. if (s->creds.domain == NULL
  241. || s->creds.login == NULL
  242. || s->creds.password == NULL)
  243. return DSM_ERROR_GENERIC;
  244. if (smb_session_supports(s, SMB_SESSION_XSEC))
  245. return (smb_session_login_spnego(s, s->creds.domain, s->creds.login,
  246. s->creds.password));
  247. else
  248. return (smb_session_login_ntlm(s, s->creds.domain, s->creds.login,
  249. s->creds.password));
  250. }
  251. int smb_session_is_guest(smb_session *s)
  252. {
  253. assert(s != NULL);
  254. // We're not logged in yet.
  255. if (s->logged != true)
  256. return -1;
  257. // We're logged in as guest
  258. if (s->guest)
  259. return 1;
  260. // We're logged in as regular user
  261. return 0;
  262. }
  263. const char *smb_session_server_name(smb_session *s)
  264. {
  265. assert(s != NULL);
  266. return s->srv.name;
  267. }
  268. int smb_session_supports(smb_session *s, int what)
  269. {
  270. assert(s != NULL);
  271. switch (what)
  272. {
  273. case SMB_SESSION_XSEC:
  274. return s->srv.caps & SMB_CAPS_XSEC;
  275. default:
  276. return 0;
  277. }
  278. }
  279. uint32_t smb_session_get_nt_status(smb_session *s)
  280. {
  281. assert(s != NULL);
  282. return s->nt_status;
  283. }
  284. bool smb_session_check_nt_status(smb_session *s, smb_message *msg)
  285. {
  286. assert(s != NULL && msg != NULL);
  287. if (msg->packet->header.status != NT_STATUS_SUCCESS)
  288. {
  289. s->nt_status = msg->packet->header.status;
  290. return false;
  291. }
  292. return true;
  293. }