ktpd_session.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <assert.h>
  5. #include <unistd.h>
  6. #include <errno.h>
  7. #include <sys/types.h>
  8. #include <sys/stat.h>
  9. #include <fcntl.h>
  10. #include <sys/socket.h>
  11. #include <sys/un.h>
  12. #include <syslog.h>
  13. #include <faux/str.h>
  14. #include <faux/async.h>
  15. #include <faux/msg.h>
  16. #include <klish/ksession.h>
  17. #include <klish/ktp.h>
  18. #include <klish/ktp_session.h>
  19. typedef enum {
  20. KTPD_SESSION_STATE_DISCONNECTED = 'd',
  21. KTPD_SESSION_STATE_NOT_AUTHORIZED = 'a',
  22. KTPD_SESSION_STATE_IDLE = 'i',
  23. KTPD_SESSION_STATE_WAIT_FOR_PROCESS = 'p',
  24. } ktpd_session_state_e;
  25. struct ktpd_session_s {
  26. ksession_t *ksession;
  27. ktpd_session_state_e state;
  28. uid_t uid;
  29. gid_t gid;
  30. char *user;
  31. faux_async_t *async;
  32. ktpd_session_stall_cb_fn stall_cb; // Stall callback
  33. void *stall_udata;
  34. faux_hdr_t *hdr; // Engine will receive header and then msg
  35. };
  36. static bool_t check_ktp_header(faux_hdr_t *hdr)
  37. {
  38. assert(hdr);
  39. if (!hdr)
  40. return BOOL_FALSE;
  41. if (faux_hdr_magic(hdr) != KTP_MAGIC)
  42. return BOOL_FALSE;
  43. if (faux_hdr_major(hdr) != KTP_MAJOR)
  44. return BOOL_FALSE;
  45. if (faux_hdr_minor(hdr) != KTP_MINOR)
  46. return BOOL_FALSE;
  47. if (faux_hdr_len(hdr) < (int)sizeof(*hdr))
  48. return BOOL_FALSE;
  49. return BOOL_TRUE;
  50. }
  51. static bool_t ktpd_session_send_error(ktpd_session_t *session,
  52. ktp_cmd_e cmd, const char *error)
  53. {
  54. faux_msg_t *msg = NULL;
  55. assert(session);
  56. if (!session)
  57. return BOOL_FALSE;
  58. msg = ktp_msg_preform(cmd, KTP_STATUS_ERROR);
  59. if (error)
  60. faux_msg_add_param(msg, KTP_PARAM_ERROR, error, strlen(error));
  61. faux_msg_send_async(msg, session->async);
  62. faux_msg_free(msg);
  63. return BOOL_TRUE;
  64. }
  65. static bool_t ktpd_session_process_cmd(ktpd_session_t *session, faux_msg_t *msg)
  66. {
  67. char *line = NULL;
  68. faux_msg_t *ack = NULL;
  69. // kpargv_t *pargv = NULL;
  70. ktp_cmd_e cmd = KTP_CMD_ACK;
  71. kexec_t *exec = NULL;
  72. faux_error_t *error = NULL;
  73. assert(session);
  74. assert(msg);
  75. // Get line from message
  76. if (!(line = faux_msg_get_str_param_by_type(msg, KTP_PARAM_LINE))) {
  77. ktpd_session_send_error(session, cmd,
  78. "The line is not specified");
  79. return BOOL_FALSE;
  80. }
  81. // Parsing
  82. error = faux_error_new();
  83. exec = ksession_parse_for_exec(session->ksession, line, error);
  84. faux_str_free(line);
  85. if (exec) {
  86. kexec_contexts_node_t *iter = kexec_contexts_iter(exec);
  87. kcontext_t *context = NULL;
  88. while ((context = kexec_contexts_each(&iter))) {
  89. kpargv_debug(kcontext_pargv(context));
  90. }
  91. } else {
  92. faux_error_show(error);
  93. }
  94. // ktpd_session_exec(session, exec);
  95. // kpargv_debug(pargv);
  96. // if (kpargv_status(pargv) != KPARSE_OK) {
  97. // char *error = NULL;
  98. // error = faux_str_sprintf("Can't parse line: %s",
  99. // kpargv_status_str(pargv));
  100. // kpargv_free(pargv);
  101. // ktpd_session_send_error(session, cmd, error);
  102. // return BOOL_FALSE;
  103. // }
  104. //
  105. // kpargv_free(pargv);
  106. kexec_free(exec);
  107. faux_error_free(error);
  108. // Send ACK message
  109. ack = ktp_msg_preform(cmd, KTP_STATUS_NONE);
  110. faux_msg_send_async(ack, session->async);
  111. faux_msg_free(ack);
  112. return BOOL_TRUE;
  113. }
  114. static bool_t ktpd_session_process_completion(ktpd_session_t *session, faux_msg_t *msg)
  115. {
  116. char *line = NULL;
  117. faux_msg_t *ack = NULL;
  118. kpargv_t *pargv = NULL;
  119. ktp_cmd_e cmd = KTP_COMPLETION_ACK;
  120. assert(session);
  121. assert(msg);
  122. // Get line from message
  123. if (!(line = faux_msg_get_str_param_by_type(msg, KTP_PARAM_LINE))) {
  124. ktpd_session_send_error(session, cmd, NULL);
  125. return BOOL_FALSE;
  126. }
  127. // Parsing
  128. pargv = ksession_parse_for_completion(session->ksession, line);
  129. faux_str_free(line);
  130. if (!pargv) {
  131. ktpd_session_send_error(session, cmd, NULL);
  132. return BOOL_FALSE;
  133. }
  134. kpargv_debug(pargv);
  135. kpargv_free(pargv);
  136. // Send ACK message
  137. ack = ktp_msg_preform(cmd, KTP_STATUS_NONE);
  138. faux_msg_send_async(ack, session->async);
  139. faux_msg_free(ack);
  140. return BOOL_TRUE;
  141. }
  142. static bool_t ktpd_session_process_help(ktpd_session_t *session, faux_msg_t *msg)
  143. {
  144. char *line = NULL;
  145. faux_msg_t *ack = NULL;
  146. // kpargv_t *pargv = NULL;
  147. ktp_cmd_e cmd = KTP_HELP_ACK;
  148. assert(session);
  149. assert(msg);
  150. // Get line from message
  151. if (!(line = faux_msg_get_str_param_by_type(msg, KTP_PARAM_LINE))) {
  152. ktpd_session_send_error(session, cmd, NULL);
  153. return BOOL_FALSE;
  154. }
  155. /* // Parsing
  156. pargv = ksession_parse_line(session->ksession, line, KPURPOSE_HELP);
  157. faux_str_free(line);
  158. kpargv_free(pargv);
  159. */
  160. // Send ACK message
  161. ack = ktp_msg_preform(cmd, KTP_STATUS_NONE);
  162. faux_msg_send_async(ack, session->async);
  163. faux_msg_free(ack);
  164. return BOOL_TRUE;
  165. }
  166. static bool_t ktpd_session_dispatch(ktpd_session_t *session, faux_msg_t *msg)
  167. {
  168. uint16_t cmd = 0;
  169. assert(session);
  170. if (!session)
  171. return BOOL_FALSE;
  172. assert(msg);
  173. if (!msg)
  174. return BOOL_FALSE;
  175. cmd = faux_msg_get_cmd(msg);
  176. switch (cmd) {
  177. case KTP_CMD:
  178. ktpd_session_process_cmd(session, msg);
  179. break;
  180. case KTP_COMPLETION:
  181. ktpd_session_process_completion(session, msg);
  182. break;
  183. case KTP_HELP:
  184. ktpd_session_process_help(session, msg);
  185. break;
  186. default:
  187. syslog(LOG_WARNING, "Unsupported command: 0x%04u\n", cmd);
  188. break;
  189. }
  190. return BOOL_TRUE;
  191. }
  192. /** @brief Low-level function to receive KTP message.
  193. *
  194. * Firstly function gets the header of message. Then it checks and parses
  195. * header and find out the length of whole message. Then it receives the rest
  196. * of message.
  197. */
  198. static bool_t ktpd_session_read_cb(faux_async_t *async,
  199. void *data, size_t len, void *user_data)
  200. {
  201. ktpd_session_t *session = (ktpd_session_t *)user_data;
  202. faux_msg_t *completed_msg = NULL;
  203. assert(async);
  204. assert(data);
  205. assert(session);
  206. // Receive header
  207. if (!session->hdr) {
  208. size_t whole_len = 0;
  209. size_t msg_wo_hdr = 0;
  210. session->hdr = (faux_hdr_t *)data;
  211. // Check for broken header
  212. if (!check_ktp_header(session->hdr)) {
  213. faux_free(session->hdr);
  214. session->hdr = NULL;
  215. return BOOL_FALSE;
  216. }
  217. whole_len = faux_hdr_len(session->hdr);
  218. // msg_wo_hdr >= 0 because check_ktp_header() validates whole_len
  219. msg_wo_hdr = whole_len - sizeof(faux_hdr_t);
  220. // Plan to receive message body
  221. if (msg_wo_hdr > 0) {
  222. faux_async_set_read_limits(async,
  223. msg_wo_hdr, msg_wo_hdr);
  224. return BOOL_TRUE;
  225. }
  226. // Here message is completed (msg body has zero length)
  227. completed_msg = faux_msg_deserialize_parts(session->hdr, NULL, 0);
  228. // Receive message body
  229. } else {
  230. completed_msg = faux_msg_deserialize_parts(session->hdr, data, len);
  231. faux_free(data);
  232. }
  233. // Plan to receive msg header
  234. faux_async_set_read_limits(session->async,
  235. sizeof(faux_hdr_t), sizeof(faux_hdr_t));
  236. faux_free(session->hdr);
  237. session->hdr = NULL; // Ready to recv new header
  238. // Here message is completed
  239. ktpd_session_dispatch(session, completed_msg);
  240. faux_msg_free(completed_msg);
  241. return BOOL_TRUE;
  242. }
  243. static bool_t ktpd_session_stall_cb(faux_async_t *async,
  244. size_t len, void *user_data)
  245. {
  246. ktpd_session_t *session = (ktpd_session_t *)user_data;
  247. assert(async);
  248. assert(session);
  249. if (!session->stall_cb)
  250. return BOOL_TRUE;
  251. session->stall_cb(session, session->stall_udata);
  252. async = async; // Happy compiler
  253. len = len; // Happy compiler
  254. return BOOL_TRUE;
  255. }
  256. ktpd_session_t *ktpd_session_new(int sock, const kscheme_t *scheme,
  257. const char *start_entry)
  258. {
  259. ktpd_session_t *session = NULL;
  260. if (sock < 0)
  261. return NULL;
  262. session = faux_zmalloc(sizeof(*session));
  263. assert(session);
  264. if (!session)
  265. return NULL;
  266. // Init
  267. session->state = KTPD_SESSION_STATE_NOT_AUTHORIZED;
  268. session->ksession = ksession_new(scheme, start_entry);
  269. assert(session->ksession);
  270. session->async = faux_async_new(sock);
  271. assert(session->async);
  272. // Receive message header first
  273. faux_async_set_read_limits(session->async,
  274. sizeof(faux_hdr_t), sizeof(faux_hdr_t));
  275. faux_async_set_read_cb(session->async, ktpd_session_read_cb, session);
  276. session->hdr = NULL;
  277. return session;
  278. }
  279. void ktpd_session_free(ktpd_session_t *session)
  280. {
  281. if (!session)
  282. return;
  283. ksession_free(session->ksession);
  284. faux_free(session->hdr);
  285. close(ktpd_session_fd(session));
  286. faux_async_free(session->async);
  287. faux_free(session);
  288. }
  289. bool_t ktpd_session_connected(ktpd_session_t *session)
  290. {
  291. assert(session);
  292. if (!session)
  293. return BOOL_FALSE;
  294. if (KTPD_SESSION_STATE_DISCONNECTED == session->state)
  295. return BOOL_FALSE;
  296. return BOOL_TRUE;
  297. }
  298. int ktpd_session_fd(const ktpd_session_t *session)
  299. {
  300. assert(session);
  301. if (!session)
  302. return BOOL_FALSE;
  303. return faux_async_fd(session->async);
  304. }
  305. bool_t ktpd_session_async_in(ktpd_session_t *session)
  306. {
  307. assert(session);
  308. if (!session)
  309. return BOOL_FALSE;
  310. if (!ktpd_session_connected(session))
  311. return BOOL_FALSE;
  312. if (faux_async_in(session->async) < 0)
  313. return BOOL_FALSE;
  314. return BOOL_TRUE;
  315. }
  316. bool_t ktpd_session_async_out(ktpd_session_t *session)
  317. {
  318. assert(session);
  319. if (!session)
  320. return BOOL_FALSE;
  321. if (!ktpd_session_connected(session))
  322. return BOOL_FALSE;
  323. if (faux_async_out(session->async) < 0)
  324. return BOOL_FALSE;
  325. return BOOL_TRUE;
  326. }
  327. void ktpd_session_set_stall_cb(ktpd_session_t *session,
  328. ktpd_session_stall_cb_fn stall_cb, void *user_data)
  329. {
  330. assert(session);
  331. if (!session)
  332. return;
  333. session->stall_cb = stall_cb;
  334. session->stall_udata = user_data;
  335. faux_async_set_stall_cb(session->async, ktpd_session_stall_cb, session);
  336. }
  337. #if 0
  338. static void ktpd_session_bad_socket(ktpd_session_t *session)
  339. {
  340. assert(session);
  341. if (!session)
  342. return;
  343. session->state = KTPD_SESSION_STATE_DISCONNECTED;
  344. }
  345. #endif