PageRenderTime 31ms CodeModel.GetById 36ms RepoModel.GetById 1ms app.codeStats 0ms

/source4/kdc/proxy.c

https://github.com/lauria/Samba4
C | 585 lines | 448 code | 83 blank | 54 comment | 52 complexity | d99b74475249e8f2967108f2e0f014f8 MD5 | raw file
  1. /*
  2. Unix SMB/CIFS implementation.
  3. KDC Server request proxying
  4. Copyright (C) Andrew Tridgell 2010
  5. Copyright (C) Andrew Bartlett 2010
  6. Copyright (C) Stefan Metzmacher 2011
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 3 of the License, or
  10. (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "includes.h"
  19. #include "smbd/process_model.h"
  20. #include "lib/tsocket/tsocket.h"
  21. #include "libcli/util/tstream.h"
  22. #include "lib/util/tevent_ntstatus.h"
  23. #include "lib/stream/packet.h"
  24. #include "kdc/kdc-glue.h"
  25. #include "dsdb/samdb/samdb.h"
  26. #include "libcli/composite/composite.h"
  27. #include "libcli/resolve/resolve.h"
  28. /*
  29. get a list of our replication partners from repsFrom, returning it in *proxy_list
  30. */
  31. static WERROR kdc_proxy_get_writeable_dcs(struct kdc_server *kdc, TALLOC_CTX *mem_ctx, char ***proxy_list)
  32. {
  33. WERROR werr;
  34. uint32_t count, i;
  35. struct repsFromToBlob *reps;
  36. werr = dsdb_loadreps(kdc->samdb, mem_ctx, ldb_get_default_basedn(kdc->samdb), "repsFrom", &reps, &count);
  37. W_ERROR_NOT_OK_RETURN(werr);
  38. if (count == 0) {
  39. /* we don't have any DCs to replicate with. Very
  40. strange for a RODC */
  41. DEBUG(1,(__location__ ": No replication sources for RODC in KDC proxy\n"));
  42. talloc_free(reps);
  43. return WERR_DS_DRA_NO_REPLICA;
  44. }
  45. (*proxy_list) = talloc_array(mem_ctx, char *, count+1);
  46. W_ERROR_HAVE_NO_MEMORY_AND_FREE(*proxy_list, reps);
  47. talloc_steal(*proxy_list, reps);
  48. for (i=0; i<count; i++) {
  49. const char *dns_name = NULL;
  50. if (reps->version == 1) {
  51. dns_name = reps->ctr.ctr1.other_info->dns_name;
  52. } else if (reps->version == 2) {
  53. dns_name = reps->ctr.ctr2.other_info->dns_name1;
  54. }
  55. (*proxy_list)[i] = talloc_strdup(*proxy_list, dns_name);
  56. W_ERROR_HAVE_NO_MEMORY_AND_FREE((*proxy_list)[i], *proxy_list);
  57. }
  58. (*proxy_list)[i] = NULL;
  59. talloc_free(reps);
  60. return WERR_OK;
  61. }
  62. struct kdc_udp_proxy_state {
  63. struct tevent_context *ev;
  64. struct kdc_server *kdc;
  65. uint16_t port;
  66. DATA_BLOB in;
  67. DATA_BLOB out;
  68. char **proxy_list;
  69. uint32_t next_proxy;
  70. struct {
  71. struct nbt_name name;
  72. const char *ip;
  73. struct tdgram_context *dgram;
  74. } proxy;
  75. };
  76. static void kdc_udp_next_proxy(struct tevent_req *req);
  77. struct tevent_req *kdc_udp_proxy_send(TALLOC_CTX *mem_ctx,
  78. struct tevent_context *ev,
  79. struct kdc_server *kdc,
  80. uint16_t port,
  81. DATA_BLOB in)
  82. {
  83. struct tevent_req *req;
  84. struct kdc_udp_proxy_state *state;
  85. WERROR werr;
  86. req = tevent_req_create(mem_ctx, &state,
  87. struct kdc_udp_proxy_state);
  88. if (req == NULL) {
  89. return NULL;
  90. }
  91. state->ev = ev;
  92. state->kdc = kdc;
  93. state->port = port;
  94. state->in = in;
  95. werr = kdc_proxy_get_writeable_dcs(kdc, state, &state->proxy_list);
  96. if (!W_ERROR_IS_OK(werr)) {
  97. NTSTATUS status = werror_to_ntstatus(werr);
  98. tevent_req_nterror(req, status);
  99. return tevent_req_post(req, ev);
  100. }
  101. kdc_udp_next_proxy(req);
  102. if (!tevent_req_is_in_progress(req)) {
  103. return tevent_req_post(req, ev);
  104. }
  105. return req;
  106. }
  107. static void kdc_udp_proxy_resolve_done(struct composite_context *csubreq);
  108. /*
  109. try the next proxy in the list
  110. */
  111. static void kdc_udp_next_proxy(struct tevent_req *req)
  112. {
  113. struct kdc_udp_proxy_state *state =
  114. tevent_req_data(req,
  115. struct kdc_udp_proxy_state);
  116. const char *proxy_dnsname = state->proxy_list[state->next_proxy];
  117. struct composite_context *csubreq;
  118. if (proxy_dnsname == NULL) {
  119. tevent_req_nterror(req, NT_STATUS_NO_LOGON_SERVERS);
  120. return;
  121. }
  122. state->next_proxy++;
  123. /* make sure we close the socket of the last try */
  124. TALLOC_FREE(state->proxy.dgram);
  125. ZERO_STRUCT(state->proxy);
  126. make_nbt_name(&state->proxy.name, proxy_dnsname, 0);
  127. csubreq = resolve_name_ex_send(lpcfg_resolve_context(state->kdc->task->lp_ctx),
  128. state,
  129. RESOLVE_NAME_FLAG_FORCE_DNS,
  130. 0,
  131. &state->proxy.name,
  132. state->ev);
  133. if (tevent_req_nomem(csubreq, req)) {
  134. return;
  135. }
  136. csubreq->async.fn = kdc_udp_proxy_resolve_done;
  137. csubreq->async.private_data = req;
  138. }
  139. static void kdc_udp_proxy_sendto_done(struct tevent_req *subreq);
  140. static void kdc_udp_proxy_recvfrom_done(struct tevent_req *subreq);
  141. static void kdc_udp_proxy_resolve_done(struct composite_context *csubreq)
  142. {
  143. struct tevent_req *req =
  144. talloc_get_type_abort(csubreq->async.private_data,
  145. struct tevent_req);
  146. struct kdc_udp_proxy_state *state =
  147. tevent_req_data(req,
  148. struct kdc_udp_proxy_state);
  149. NTSTATUS status;
  150. struct tevent_req *subreq;
  151. struct tsocket_address *local_addr, *proxy_addr;
  152. int ret;
  153. status = resolve_name_recv(csubreq, state, &state->proxy.ip);
  154. if (!NT_STATUS_IS_OK(status)) {
  155. DEBUG(0,("Unable to resolve proxy[%s] - %s\n",
  156. state->proxy.name.name, nt_errstr(status)));
  157. kdc_udp_next_proxy(req);
  158. return;
  159. }
  160. /* get an address for us to use locally */
  161. ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0, &local_addr);
  162. if (ret != 0) {
  163. kdc_udp_next_proxy(req);
  164. return;
  165. }
  166. ret = tsocket_address_inet_from_strings(state, "ip",
  167. state->proxy.ip,
  168. state->port,
  169. &proxy_addr);
  170. if (ret != 0) {
  171. kdc_udp_next_proxy(req);
  172. return;
  173. }
  174. /* create a socket for us to work on */
  175. ret = tdgram_inet_udp_socket(local_addr, proxy_addr,
  176. state, &state->proxy.dgram);
  177. if (ret != 0) {
  178. kdc_udp_next_proxy(req);
  179. return;
  180. }
  181. subreq = tdgram_sendto_send(state,
  182. state->ev,
  183. state->proxy.dgram,
  184. state->in.data,
  185. state->in.length,
  186. NULL);
  187. if (tevent_req_nomem(subreq, req)) {
  188. return;
  189. }
  190. tevent_req_set_callback(subreq, kdc_udp_proxy_sendto_done, req);
  191. /* setup to receive the reply from the proxy */
  192. subreq = tdgram_recvfrom_send(state, state->ev, state->proxy.dgram);
  193. if (tevent_req_nomem(subreq, req)) {
  194. return;
  195. }
  196. tevent_req_set_callback(subreq, kdc_udp_proxy_recvfrom_done, req);
  197. tevent_req_set_endtime(subreq, state->ev,
  198. timeval_current_ofs(state->kdc->proxy_timeout, 0));
  199. DEBUG(4,("kdc_udp_proxy: proxying request to %s[%s]\n",
  200. state->proxy.name.name, state->proxy.ip));
  201. }
  202. /*
  203. called when the send of the call to the proxy is complete
  204. this is used to get an errors from the sendto()
  205. */
  206. static void kdc_udp_proxy_sendto_done(struct tevent_req *subreq)
  207. {
  208. struct tevent_req *req =
  209. tevent_req_callback_data(subreq,
  210. struct tevent_req);
  211. struct kdc_udp_proxy_state *state =
  212. tevent_req_data(req,
  213. struct kdc_udp_proxy_state);
  214. ssize_t ret;
  215. int sys_errno;
  216. ret = tdgram_sendto_recv(subreq, &sys_errno);
  217. TALLOC_FREE(subreq);
  218. if (ret == -1) {
  219. DEBUG(4,("kdc_udp_proxy: sendto for %s[%s] gave %d : %s\n",
  220. state->proxy.name.name, state->proxy.ip,
  221. sys_errno, strerror(sys_errno)));
  222. kdc_udp_next_proxy(req);
  223. }
  224. }
  225. /*
  226. called when the proxy replies
  227. */
  228. static void kdc_udp_proxy_recvfrom_done(struct tevent_req *subreq)
  229. {
  230. struct tevent_req *req =
  231. tevent_req_callback_data(subreq,
  232. struct tevent_req);
  233. struct kdc_udp_proxy_state *state =
  234. tevent_req_data(req,
  235. struct kdc_udp_proxy_state);
  236. int sys_errno;
  237. uint8_t *buf;
  238. ssize_t len;
  239. len = tdgram_recvfrom_recv(subreq, &sys_errno,
  240. state, &buf, NULL);
  241. TALLOC_FREE(subreq);
  242. if (len == -1) {
  243. DEBUG(4,("kdc_udp_proxy: reply from %s[%s] gave %d : %s\n",
  244. state->proxy.name.name, state->proxy.ip,
  245. sys_errno, strerror(sys_errno)));
  246. kdc_udp_next_proxy(req);
  247. return;
  248. }
  249. /*
  250. * Check the reply came from the right IP?
  251. * As we use connected udp sockets, that should not be needed...
  252. */
  253. state->out.length = len;
  254. state->out.data = buf;
  255. tevent_req_done(req);
  256. }
  257. NTSTATUS kdc_udp_proxy_recv(struct tevent_req *req,
  258. TALLOC_CTX *mem_ctx,
  259. DATA_BLOB *out)
  260. {
  261. struct kdc_udp_proxy_state *state =
  262. tevent_req_data(req,
  263. struct kdc_udp_proxy_state);
  264. NTSTATUS status;
  265. if (tevent_req_is_nterror(req, &status)) {
  266. tevent_req_received(req);
  267. return status;
  268. }
  269. out->data = talloc_move(mem_ctx, &state->out.data);
  270. out->length = state->out.length;
  271. tevent_req_received(req);
  272. return NT_STATUS_OK;
  273. }
  274. struct kdc_tcp_proxy_state {
  275. struct tevent_context *ev;
  276. struct kdc_server *kdc;
  277. uint16_t port;
  278. DATA_BLOB in;
  279. uint8_t in_hdr[4];
  280. struct iovec in_iov[2];
  281. DATA_BLOB out;
  282. char **proxy_list;
  283. uint32_t next_proxy;
  284. struct {
  285. struct nbt_name name;
  286. const char *ip;
  287. struct tstream_context *stream;
  288. } proxy;
  289. };
  290. static void kdc_tcp_next_proxy(struct tevent_req *req);
  291. struct tevent_req *kdc_tcp_proxy_send(TALLOC_CTX *mem_ctx,
  292. struct tevent_context *ev,
  293. struct kdc_server *kdc,
  294. uint16_t port,
  295. DATA_BLOB in)
  296. {
  297. struct tevent_req *req;
  298. struct kdc_tcp_proxy_state *state;
  299. WERROR werr;
  300. req = tevent_req_create(mem_ctx, &state,
  301. struct kdc_tcp_proxy_state);
  302. if (req == NULL) {
  303. return NULL;
  304. }
  305. state->ev = ev;
  306. state->kdc = kdc;
  307. state->port = port;
  308. state->in = in;
  309. werr = kdc_proxy_get_writeable_dcs(kdc, state, &state->proxy_list);
  310. if (!W_ERROR_IS_OK(werr)) {
  311. NTSTATUS status = werror_to_ntstatus(werr);
  312. tevent_req_nterror(req, status);
  313. return tevent_req_post(req, ev);
  314. }
  315. RSIVAL(state->in_hdr, 0, state->in.length);
  316. state->in_iov[0].iov_base = (char *)state->in_hdr;
  317. state->in_iov[0].iov_len = 4;
  318. state->in_iov[1].iov_base = (char *)state->in.data;
  319. state->in_iov[1].iov_len = state->in.length;
  320. kdc_tcp_next_proxy(req);
  321. if (!tevent_req_is_in_progress(req)) {
  322. return tevent_req_post(req, ev);
  323. }
  324. return req;
  325. }
  326. static void kdc_tcp_proxy_resolve_done(struct composite_context *csubreq);
  327. /*
  328. try the next proxy in the list
  329. */
  330. static void kdc_tcp_next_proxy(struct tevent_req *req)
  331. {
  332. struct kdc_tcp_proxy_state *state =
  333. tevent_req_data(req,
  334. struct kdc_tcp_proxy_state);
  335. const char *proxy_dnsname = state->proxy_list[state->next_proxy];
  336. struct composite_context *csubreq;
  337. if (proxy_dnsname == NULL) {
  338. tevent_req_nterror(req, NT_STATUS_NO_LOGON_SERVERS);
  339. return;
  340. }
  341. state->next_proxy++;
  342. /* make sure we close the socket of the last try */
  343. TALLOC_FREE(state->proxy.stream);
  344. ZERO_STRUCT(state->proxy);
  345. make_nbt_name(&state->proxy.name, proxy_dnsname, 0);
  346. csubreq = resolve_name_ex_send(lpcfg_resolve_context(state->kdc->task->lp_ctx),
  347. state,
  348. RESOLVE_NAME_FLAG_FORCE_DNS,
  349. 0,
  350. &state->proxy.name,
  351. state->ev);
  352. if (tevent_req_nomem(csubreq, req)) {
  353. return;
  354. }
  355. csubreq->async.fn = kdc_tcp_proxy_resolve_done;
  356. csubreq->async.private_data = req;
  357. }
  358. static void kdc_tcp_proxy_connect_done(struct tevent_req *subreq);
  359. static void kdc_tcp_proxy_resolve_done(struct composite_context *csubreq)
  360. {
  361. struct tevent_req *req =
  362. talloc_get_type_abort(csubreq->async.private_data,
  363. struct tevent_req);
  364. struct kdc_tcp_proxy_state *state =
  365. tevent_req_data(req,
  366. struct kdc_tcp_proxy_state);
  367. NTSTATUS status;
  368. struct tevent_req *subreq;
  369. struct tsocket_address *local_addr, *proxy_addr;
  370. int ret;
  371. status = resolve_name_recv(csubreq, state, &state->proxy.ip);
  372. if (!NT_STATUS_IS_OK(status)) {
  373. DEBUG(0,("Unable to resolve proxy[%s] - %s\n",
  374. state->proxy.name.name, nt_errstr(status)));
  375. kdc_tcp_next_proxy(req);
  376. return;
  377. }
  378. /* get an address for us to use locally */
  379. ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0, &local_addr);
  380. if (ret != 0) {
  381. kdc_tcp_next_proxy(req);
  382. return;
  383. }
  384. ret = tsocket_address_inet_from_strings(state, "ip",
  385. state->proxy.ip,
  386. state->port,
  387. &proxy_addr);
  388. if (ret != 0) {
  389. kdc_tcp_next_proxy(req);
  390. return;
  391. }
  392. subreq = tstream_inet_tcp_connect_send(state, state->ev,
  393. local_addr, proxy_addr);
  394. if (tevent_req_nomem(subreq, req)) {
  395. return;
  396. }
  397. tevent_req_set_callback(subreq, kdc_tcp_proxy_connect_done, req);
  398. tevent_req_set_endtime(subreq, state->ev,
  399. timeval_current_ofs(state->kdc->proxy_timeout, 0));
  400. }
  401. static void kdc_tcp_proxy_writev_done(struct tevent_req *subreq);
  402. static void kdc_tcp_proxy_read_pdu_done(struct tevent_req *subreq);
  403. static void kdc_tcp_proxy_connect_done(struct tevent_req *subreq)
  404. {
  405. struct tevent_req *req =
  406. tevent_req_callback_data(subreq,
  407. struct tevent_req);
  408. struct kdc_tcp_proxy_state *state =
  409. tevent_req_data(req,
  410. struct kdc_tcp_proxy_state);
  411. int ret, sys_errno;
  412. ret = tstream_inet_tcp_connect_recv(subreq, &sys_errno,
  413. state, &state->proxy.stream, NULL);
  414. TALLOC_FREE(subreq);
  415. if (ret != 0) {
  416. kdc_tcp_next_proxy(req);
  417. return;
  418. }
  419. subreq = tstream_writev_send(state,
  420. state->ev,
  421. state->proxy.stream,
  422. state->in_iov, 2);
  423. if (tevent_req_nomem(subreq, req)) {
  424. return;
  425. }
  426. tevent_req_set_callback(subreq, kdc_tcp_proxy_writev_done, req);
  427. subreq = tstream_read_pdu_blob_send(state,
  428. state->ev,
  429. state->proxy.stream,
  430. 4, /* initial_read_size */
  431. packet_full_request_u32,
  432. req);
  433. if (tevent_req_nomem(subreq, req)) {
  434. return;
  435. }
  436. tevent_req_set_callback(subreq, kdc_tcp_proxy_read_pdu_done, req);
  437. tevent_req_set_endtime(subreq, state->kdc->task->event_ctx,
  438. timeval_current_ofs(state->kdc->proxy_timeout, 0));
  439. DEBUG(4,("kdc_tcp_proxy: proxying request to %s[%s]\n",
  440. state->proxy.name.name, state->proxy.ip));
  441. }
  442. static void kdc_tcp_proxy_writev_done(struct tevent_req *subreq)
  443. {
  444. struct tevent_req *req =
  445. tevent_req_callback_data(subreq,
  446. struct tevent_req);
  447. int ret, sys_errno;
  448. ret = tstream_writev_recv(subreq, &sys_errno);
  449. TALLOC_FREE(subreq);
  450. if (ret == -1) {
  451. kdc_tcp_next_proxy(req);
  452. }
  453. }
  454. static void kdc_tcp_proxy_read_pdu_done(struct tevent_req *subreq)
  455. {
  456. struct tevent_req *req =
  457. tevent_req_callback_data(subreq,
  458. struct tevent_req);
  459. struct kdc_tcp_proxy_state *state =
  460. tevent_req_data(req,
  461. struct kdc_tcp_proxy_state);
  462. NTSTATUS status;
  463. DATA_BLOB raw;
  464. status = tstream_read_pdu_blob_recv(subreq, state, &raw);
  465. TALLOC_FREE(subreq);
  466. if (!NT_STATUS_IS_OK(status)) {
  467. kdc_tcp_next_proxy(req);
  468. return;
  469. }
  470. /*
  471. * raw blob has the length in the first 4 bytes,
  472. * which we do not need here.
  473. */
  474. state->out = data_blob_talloc(state, raw.data + 4, raw.length - 4);
  475. if (state->out.length != raw.length - 4) {
  476. tevent_req_oom(req);
  477. return;
  478. }
  479. tevent_req_done(req);
  480. }
  481. NTSTATUS kdc_tcp_proxy_recv(struct tevent_req *req,
  482. TALLOC_CTX *mem_ctx,
  483. DATA_BLOB *out)
  484. {
  485. struct kdc_tcp_proxy_state *state =
  486. tevent_req_data(req,
  487. struct kdc_tcp_proxy_state);
  488. NTSTATUS status;
  489. if (tevent_req_is_nterror(req, &status)) {
  490. tevent_req_received(req);
  491. return status;
  492. }
  493. out->data = talloc_move(mem_ctx, &state->out.data);
  494. out->length = state->out.length;
  495. tevent_req_received(req);
  496. return NT_STATUS_OK;
  497. }