ktpd_session.c 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467
  1. #define _GNU_SOURCE
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <assert.h>
  6. #include <unistd.h>
  7. #include <errno.h>
  8. #include <sys/types.h>
  9. #include <sys/stat.h>
  10. #include <fcntl.h>
  11. #include <sys/socket.h>
  12. #include <sys/un.h>
  13. #include <syslog.h>
  14. #include <poll.h>
  15. #include <sys/wait.h>
  16. #include <faux/str.h>
  17. #include <faux/conv.h>
  18. #include <faux/async.h>
  19. #include <faux/msg.h>
  20. #include <faux/eloop.h>
  21. #include <faux/sysdb.h>
  22. #include <klish/ksession.h>
  23. #include <klish/ksession_parse.h>
  24. #include <klish/ktp.h>
  25. #include <klish/ktp_session.h>
  26. typedef enum {
  27. KTPD_SESSION_STATE_DISCONNECTED = 'd',
  28. KTPD_SESSION_STATE_UNAUTHORIZED = 'a',
  29. KTPD_SESSION_STATE_IDLE = 'i',
  30. KTPD_SESSION_STATE_WAIT_FOR_PROCESS = 'p',
  31. } ktpd_session_state_e;
  32. struct ktpd_session_s {
  33. ksession_t *session;
  34. ktpd_session_state_e state;
  35. faux_async_t *async; // Object for data exchange with client (KTP)
  36. faux_hdr_t *hdr; // Engine will receive header and then msg
  37. faux_eloop_t *eloop; // External link, dont's free()
  38. kexec_t *exec;
  39. bool_t exit;
  40. bool_t stdin_must_be_closed;
  41. };
  42. // Static declarations
  43. static bool_t ktpd_session_read_cb(faux_async_t *async,
  44. faux_buf_t *buf, size_t len, void *user_data);
  45. static bool_t wait_for_actions_ev(faux_eloop_t *eloop, faux_eloop_type_e type,
  46. void *associated_data, void *user_data);
  47. bool_t client_ev(faux_eloop_t *eloop, faux_eloop_type_e type,
  48. void *associated_data, void *user_data);
  49. static bool_t ktpd_session_exec(ktpd_session_t *ktpd, const char *line,
  50. int *retcode, faux_error_t *error,
  51. bool_t dry_run, bool_t *view_was_changed);
  52. static bool_t action_stdout_ev(faux_eloop_t *eloop, faux_eloop_type_e type,
  53. void *associated_data, void *user_data);
  54. static bool_t action_stderr_ev(faux_eloop_t *eloop, faux_eloop_type_e type,
  55. void *associated_data, void *user_data);
  56. static bool_t get_stream(ktpd_session_t *ktpd, int fd, bool_t is_stderr);
  57. ktpd_session_t *ktpd_session_new(int sock, kscheme_t *scheme,
  58. const char *start_entry, faux_eloop_t *eloop)
  59. {
  60. ktpd_session_t *ktpd = NULL;
  61. if (sock < 0)
  62. return NULL;
  63. if (!eloop)
  64. return NULL;
  65. ktpd = faux_zmalloc(sizeof(*ktpd));
  66. assert(ktpd);
  67. if (!ktpd)
  68. return NULL;
  69. // Init
  70. ktpd->state = KTPD_SESSION_STATE_UNAUTHORIZED;
  71. ktpd->eloop = eloop;
  72. ktpd->session = ksession_new(scheme, start_entry);
  73. if (!ktpd->session) {
  74. faux_free(ktpd);
  75. return NULL;
  76. }
  77. ktpd->exec = NULL;
  78. // Client can send command to close stdin but it can't be done
  79. // immediately because stdin buffer can still contain data. So really
  80. // close stdin after all data is written.
  81. ktpd->stdin_must_be_closed = BOOL_FALSE;
  82. // Exit flag. It differs from ksession done flag because KTPD session
  83. // can't exit immediately. It must finish current command processing
  84. // before really stop the event loop. Note: User defined plugin
  85. // function must use ksession done flag. This exit flag is internal
  86. // feature of KTPD session.
  87. ktpd->exit = BOOL_FALSE;
  88. // Async object
  89. ktpd->async = faux_async_new(sock);
  90. assert(ktpd->async);
  91. // Receive message header first
  92. faux_async_set_read_limits(ktpd->async,
  93. sizeof(faux_hdr_t), sizeof(faux_hdr_t));
  94. faux_async_set_read_cb(ktpd->async, ktpd_session_read_cb, ktpd);
  95. ktpd->hdr = NULL;
  96. faux_async_set_stall_cb(ktpd->async, ktp_stall_cb, ktpd->eloop);
  97. // Eloop callbacks
  98. faux_eloop_add_fd(ktpd->eloop, ktpd_session_fd(ktpd), POLLIN,
  99. client_ev, ktpd);
  100. faux_eloop_add_signal(ktpd->eloop, SIGCHLD, wait_for_actions_ev, ktpd);
  101. return ktpd;
  102. }
  103. void ktpd_session_free(ktpd_session_t *ktpd)
  104. {
  105. kcontext_t *context = NULL;
  106. kscheme_t *scheme = NULL;
  107. if (!ktpd)
  108. return;
  109. // fini session for plugins
  110. if (ktpd->state != KTPD_SESSION_STATE_UNAUTHORIZED) {
  111. scheme = ksession_scheme(ktpd->session);
  112. context = kcontext_new(KCONTEXT_TYPE_PLUGIN_FINI);
  113. kcontext_set_session(context, ktpd->session);
  114. kcontext_set_scheme(context, scheme);
  115. kscheme_fini_session_plugins(scheme, context, NULL);
  116. kcontext_free(context);
  117. }
  118. kexec_free(ktpd->exec);
  119. ksession_free(ktpd->session);
  120. faux_free(ktpd->hdr);
  121. close(ktpd_session_fd(ktpd));
  122. faux_async_free(ktpd->async);
  123. faux_free(ktpd);
  124. }
  125. static char *generate_prompt(ktpd_session_t *ktpd)
  126. {
  127. kpath_levels_node_t *iter = NULL;
  128. klevel_t *level = NULL;
  129. char *prompt = NULL;
  130. iter = kpath_iterr(ksession_path(ktpd->session));
  131. while ((level = kpath_eachr(&iter))) {
  132. const kentry_t *view = klevel_entry(level);
  133. kentry_t *prompt_entry = kentry_nested_by_purpose(view,
  134. KENTRY_PURPOSE_PROMPT);
  135. if (!prompt_entry)
  136. continue;
  137. if (kentry_actions_len(prompt_entry) > 0) {
  138. int rc = -1;
  139. bool_t res = BOOL_FALSE;
  140. res = ksession_exec_locally(ktpd->session,
  141. prompt_entry, NULL, &rc, &prompt);
  142. if (!res || (rc < 0) || !prompt) {
  143. if (prompt)
  144. faux_str_free(prompt);
  145. prompt = NULL;
  146. }
  147. }
  148. if (!prompt) {
  149. if (kentry_value(prompt_entry))
  150. prompt = faux_str_dup(kentry_value(prompt_entry));
  151. }
  152. if (prompt)
  153. break;
  154. }
  155. return prompt;
  156. }
  157. // Format: <key>'\0'<cmd>
  158. static bool_t add_hotkey(faux_msg_t *msg, khotkey_t *hotkey)
  159. {
  160. const char *key = NULL;
  161. const char *cmd = NULL;
  162. char *whole_str = NULL;
  163. size_t key_s = 0;
  164. size_t cmd_s = 0;
  165. key = khotkey_key(hotkey);
  166. key_s = strlen(key);
  167. cmd = khotkey_cmd(hotkey);
  168. cmd_s = strlen(cmd);
  169. whole_str = faux_zmalloc(key_s + 1 + cmd_s);
  170. memcpy(whole_str, key, key_s);
  171. memcpy(whole_str + key_s + 1, cmd, cmd_s);
  172. faux_msg_add_param(msg, KTP_PARAM_HOTKEY, whole_str, key_s + 1 + cmd_s);
  173. faux_free(whole_str);
  174. return BOOL_TRUE;
  175. }
  176. static bool_t add_hotkeys_to_msg(ktpd_session_t *ktpd, faux_msg_t *msg)
  177. {
  178. faux_list_t *list = NULL;
  179. kpath_t *path = NULL;
  180. kentry_hotkeys_node_t *l_iter = NULL;
  181. khotkey_t *hotkey = NULL;
  182. assert(ktpd);
  183. assert(msg);
  184. path = ksession_path(ktpd->session);
  185. assert(path);
  186. if (kpath_len(path) == 1) {
  187. // We don't need additional list because there is only one
  188. // VIEW in the path so hotkey's list is only one too. Get it.
  189. list = kentry_hotkeys(klevel_entry(
  190. (klevel_t *)faux_list_data(kpath_iter(path))));
  191. } else {
  192. faux_list_node_t *iterr = NULL;
  193. klevel_t *level = NULL;
  194. // Create temp hotkeys list to add hotkeys from all VIEWs in
  195. // the path and exclude duplications. Don't free elements
  196. // because they are just a references.
  197. list = faux_list_new(FAUX_LIST_UNSORTED, FAUX_LIST_UNIQUE,
  198. kentry_hotkey_compare, NULL, NULL);
  199. // Begin with the end. Because hotkeys from nested VIEWs has
  200. // higher priority.
  201. iterr = kpath_iterr(path);
  202. while ((level = kpath_eachr(&iterr))) {
  203. const kentry_t *entry = klevel_entry(level);
  204. kentry_hotkeys_node_t *hk_iter = kentry_hotkeys_iter(entry);
  205. while ((hotkey = kentry_hotkeys_each(&hk_iter)))
  206. faux_list_add(list, hotkey);
  207. }
  208. }
  209. // Add found hotkeys to msg
  210. l_iter = faux_list_head(list);
  211. while ((hotkey = (khotkey_t *)faux_list_each(&l_iter)))
  212. add_hotkey(msg, hotkey);
  213. if (kpath_len(path) != 1)
  214. faux_list_free(list);
  215. return BOOL_TRUE;
  216. }
  217. // Now it's not really an auth function. Just a hand-shake with client and
  218. // passing prompt to client.
  219. static bool_t ktpd_session_process_auth(ktpd_session_t *ktpd, faux_msg_t *msg)
  220. {
  221. ktp_cmd_e cmd = KTP_AUTH_ACK;
  222. uint32_t status = KTP_STATUS_NONE;
  223. faux_msg_t *ack = NULL;
  224. char *prompt = NULL;
  225. uint8_t retcode8bit = 0;
  226. struct ucred ucred = {};
  227. socklen_t len = sizeof(ucred);
  228. int sock = -1;
  229. char *user = NULL;
  230. kcontext_t *context = NULL;
  231. kscheme_t *scheme = NULL;
  232. uint32_t client_status = KTP_STATUS_NONE;
  233. assert(ktpd);
  234. assert(msg);
  235. // Get UNIX socket peer information
  236. sock = faux_async_fd(ktpd->async);
  237. if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &ucred, &len) < 0) {
  238. const char *err = "Can't get peer credentials";
  239. syslog(LOG_ERR, "%s for connection %d", err, sock);
  240. ack = ktp_msg_preform(cmd, KTP_STATUS_ERROR | KTP_STATUS_EXIT);
  241. faux_msg_add_param(ack, KTP_PARAM_ERROR, err, strlen(err));
  242. faux_msg_send_async(ack, ktpd->async);
  243. faux_msg_free(ack);
  244. ktpd->exit = BOOL_TRUE;
  245. return BOOL_FALSE;
  246. }
  247. ksession_set_pid(ktpd->session, ucred.pid);
  248. ksession_set_uid(ktpd->session, ucred.uid);
  249. user = faux_sysdb_name_by_uid(ucred.uid);
  250. ksession_set_user(ktpd->session, user);
  251. faux_str_free(user);
  252. // Get tty information from auth message status
  253. client_status = faux_msg_get_status(msg);
  254. ksession_set_isatty_stdin(ktpd->session,
  255. KTP_STATUS_IS_TTY_STDIN(client_status));
  256. ksession_set_isatty_stdout(ktpd->session,
  257. KTP_STATUS_IS_TTY_STDOUT(client_status));
  258. ksession_set_isatty_stderr(ktpd->session,
  259. KTP_STATUS_IS_TTY_STDERR(client_status));
  260. // init session for plugins
  261. scheme = ksession_scheme(ktpd->session);
  262. context = kcontext_new(KCONTEXT_TYPE_PLUGIN_INIT);
  263. kcontext_set_session(context, ktpd->session);
  264. kcontext_set_scheme(context, scheme);
  265. kscheme_init_session_plugins(scheme, context, NULL);
  266. kcontext_free(context);
  267. // Prepare ACK message
  268. ack = ktp_msg_preform(cmd, status);
  269. faux_msg_add_param(ack, KTP_PARAM_RETCODE, &retcode8bit, 1);
  270. // Generate prompt
  271. prompt = generate_prompt(ktpd);
  272. if (prompt) {
  273. faux_msg_add_param(ack, KTP_PARAM_PROMPT, prompt, strlen(prompt));
  274. faux_str_free(prompt);
  275. }
  276. add_hotkeys_to_msg(ktpd, ack);
  277. faux_msg_send_async(ack, ktpd->async);
  278. faux_msg_free(ack);
  279. ktpd->state = KTPD_SESSION_STATE_IDLE;
  280. return BOOL_TRUE;
  281. }
  282. static bool_t ktpd_session_process_cmd(ktpd_session_t *ktpd, faux_msg_t *msg)
  283. {
  284. char *line = NULL;
  285. int retcode = -1;
  286. ktp_cmd_e cmd = KTP_CMD_ACK;
  287. faux_error_t *error = NULL;
  288. bool_t rc = BOOL_FALSE;
  289. bool_t dry_run = BOOL_FALSE;
  290. uint32_t status = KTP_STATUS_NONE;
  291. bool_t ret = BOOL_TRUE;
  292. char *prompt = NULL;
  293. bool_t view_was_changed = BOOL_FALSE;
  294. assert(ktpd);
  295. assert(msg);
  296. // Get line from message
  297. if (!(line = faux_msg_get_str_param_by_type(msg, KTP_PARAM_LINE))) {
  298. ktp_send_error(ktpd->async, cmd, "The line is not specified");
  299. return BOOL_FALSE;
  300. }
  301. // Get dry-run flag from message
  302. if (KTP_STATUS_IS_DRY_RUN(faux_msg_get_status(msg)))
  303. dry_run = BOOL_TRUE;
  304. error = faux_error_new();
  305. ktpd->exec = NULL;
  306. rc = ktpd_session_exec(ktpd, line, &retcode, error,
  307. dry_run, &view_was_changed);
  308. faux_str_free(line);
  309. // Command is scheduled. Eloop will wait for ACTION completion.
  310. // So inform client about it and about command features like
  311. // interactive/non-interactive.
  312. if (ktpd->exec) {
  313. faux_msg_t *ack = NULL;
  314. ktp_status_e status = KTP_STATUS_INCOMPLETED;
  315. if (kexec_interactive(ktpd->exec))
  316. status |= KTP_STATUS_INTERACTIVE;
  317. if (kexec_need_stdin(ktpd->exec))
  318. status |= KTP_STATUS_NEED_STDIN;
  319. ack = ktp_msg_preform(cmd, status);
  320. faux_msg_send_async(ack, ktpd->async);
  321. faux_msg_free(ack);
  322. faux_error_free(error);
  323. return BOOL_TRUE; // Continue and wait for ACTION
  324. }
  325. // Here we don't need to wait for the action. We have retcode already.
  326. if (ksession_done(ktpd->session)) {
  327. ktpd->exit = BOOL_TRUE;
  328. status |= KTP_STATUS_EXIT;
  329. }
  330. // Prepare ACK message
  331. faux_msg_t *ack = ktp_msg_preform(cmd, status);
  332. if (rc) {
  333. uint8_t retcode8bit = 0;
  334. retcode8bit = (uint8_t)(retcode & 0xff);
  335. faux_msg_add_param(ack, KTP_PARAM_RETCODE, &retcode8bit, 1);
  336. } else {
  337. faux_msg_set_status(ack, KTP_STATUS_ERROR);
  338. char *err = faux_error_cstr(error);
  339. faux_msg_add_param(ack, KTP_PARAM_ERROR, err, strlen(err));
  340. faux_str_free(err);
  341. ret = BOOL_FALSE;
  342. }
  343. // Generate prompt
  344. prompt = generate_prompt(ktpd);
  345. if (prompt) {
  346. faux_msg_add_param(ack, KTP_PARAM_PROMPT, prompt, strlen(prompt));
  347. faux_str_free(prompt);
  348. }
  349. // Add hotkeys
  350. if (view_was_changed)
  351. add_hotkeys_to_msg(ktpd, ack);
  352. faux_msg_send_async(ack, ktpd->async);
  353. faux_msg_free(ack);
  354. faux_error_free(error);
  355. return ret;
  356. }
  357. static bool_t ktpd_session_exec(ktpd_session_t *ktpd, const char *line,
  358. int *retcode, faux_error_t *error,
  359. bool_t dry_run, bool_t *view_was_changed_p)
  360. {
  361. kexec_t *exec = NULL;
  362. assert(ktpd);
  363. if (!ktpd)
  364. return BOOL_FALSE;
  365. // Parsing
  366. exec = ksession_parse_for_exec(ktpd->session, line, error);
  367. if (!exec)
  368. return BOOL_FALSE;
  369. // Set dry-run flag
  370. kexec_set_dry_run(exec, dry_run);
  371. // Session status can be changed while parsing
  372. // NOTE: kexec_t is atomic now
  373. // if (ksession_done(ktpd->session)) {
  374. // kexec_free(exec);
  375. // return BOOL_FALSE; // Because action is not completed
  376. // }
  377. // Execute kexec and then wait for completion using global Eloop
  378. if (!kexec_exec(exec)) {
  379. kexec_free(exec);
  380. return BOOL_FALSE; // Something went wrong
  381. }
  382. // If kexec contains only non-exec (for example dry-run) ACTIONs then
  383. // we don't need event loop and can return here.
  384. if (kexec_retcode(exec, retcode)) {
  385. if (view_was_changed_p)
  386. *view_was_changed_p = !kpath_is_equal(
  387. ksession_path(ktpd->session),
  388. kexec_saved_path(exec));
  389. kexec_free(exec);
  390. return BOOL_TRUE;
  391. }
  392. // Save kexec pointer to use later
  393. ktpd->state = KTPD_SESSION_STATE_WAIT_FOR_PROCESS;
  394. ktpd->exec = exec;
  395. faux_eloop_add_fd(ktpd->eloop, kexec_stdout(exec), POLLIN,
  396. action_stdout_ev, ktpd);
  397. faux_eloop_add_fd(ktpd->eloop, kexec_stderr(exec), POLLIN,
  398. action_stderr_ev, ktpd);
  399. return BOOL_TRUE;
  400. }
  401. static bool_t wait_for_actions_ev(faux_eloop_t *eloop, faux_eloop_type_e type,
  402. void *associated_data, void *user_data)
  403. {
  404. int wstatus = 0;
  405. pid_t child_pid = -1;
  406. ktpd_session_t *ktpd = (ktpd_session_t *)user_data;
  407. int retcode = -1;
  408. uint8_t retcode8bit = 0;
  409. faux_msg_t *ack = NULL;
  410. ktp_cmd_e cmd = KTP_CMD_ACK;
  411. uint32_t status = KTP_STATUS_NONE;
  412. char *prompt = NULL;
  413. bool_t view_was_changed = BOOL_FALSE;
  414. if (!ktpd)
  415. return BOOL_FALSE;
  416. // Wait for any child process. Doesn't block.
  417. while ((child_pid = waitpid(-1, &wstatus, WNOHANG)) > 0) {
  418. if (ktpd->exec)
  419. kexec_continue_command_execution(ktpd->exec, child_pid,
  420. wstatus);
  421. }
  422. if (!ktpd->exec)
  423. return BOOL_TRUE;
  424. // Check if kexec is done now
  425. if (!kexec_retcode(ktpd->exec, &retcode))
  426. return BOOL_TRUE; // Continue
  427. // Sometimes SIGCHILD signal can appear before all data were really read
  428. // from process stdout buffer. So read the least data before closing
  429. // file descriptors and send it to client.
  430. get_stream(ktpd, kexec_stdout(ktpd->exec), BOOL_FALSE);
  431. get_stream(ktpd, kexec_stderr(ktpd->exec), BOOL_TRUE);
  432. faux_eloop_del_fd(eloop, kexec_stdout(ktpd->exec));
  433. faux_eloop_del_fd(eloop, kexec_stderr(ktpd->exec));
  434. view_was_changed = !kpath_is_equal(
  435. ksession_path(ktpd->session), kexec_saved_path(ktpd->exec));
  436. kexec_free(ktpd->exec);
  437. ktpd->exec = NULL;
  438. ktpd->state = KTPD_SESSION_STATE_IDLE;
  439. // All kexec_t actions are done so can break the loop if needed.
  440. if (ksession_done(ktpd->session)) {
  441. ktpd->exit = BOOL_TRUE;
  442. status |= KTP_STATUS_EXIT; // Notify client about exiting
  443. }
  444. // Send ACK message
  445. ack = ktp_msg_preform(cmd, status);
  446. retcode8bit = (uint8_t)(retcode & 0xff);
  447. faux_msg_add_param(ack, KTP_PARAM_RETCODE, &retcode8bit, 1);
  448. // Generate prompt
  449. prompt = generate_prompt(ktpd);
  450. if (prompt) {
  451. faux_msg_add_param(ack, KTP_PARAM_PROMPT, prompt, strlen(prompt));
  452. faux_str_free(prompt);
  453. }
  454. // Add hotkeys
  455. if (view_was_changed)
  456. add_hotkeys_to_msg(ktpd, ack);
  457. faux_msg_send_async(ack, ktpd->async);
  458. faux_msg_free(ack);
  459. type = type; // Happy compiler
  460. associated_data = associated_data; // Happy compiler
  461. if (ktpd->exit)
  462. return BOOL_FALSE;
  463. return BOOL_TRUE;
  464. }
  465. static int compl_compare(const void *first, const void *second)
  466. {
  467. const char *f = (const char *)first;
  468. const char *s = (const char *)second;
  469. return strcmp(f, s);
  470. }
  471. static int compl_kcompare(const void *key, const void *list_item)
  472. {
  473. const char *f = (const char *)key;
  474. const char *s = (const char *)list_item;
  475. return strcmp(f, s);
  476. }
  477. static bool_t ktpd_session_process_completion(ktpd_session_t *ktpd, faux_msg_t *msg)
  478. {
  479. char *line = NULL;
  480. faux_msg_t *ack = NULL;
  481. kpargv_t *pargv = NULL;
  482. ktp_cmd_e cmd = KTP_COMPLETION_ACK;
  483. uint32_t status = KTP_STATUS_NONE;
  484. const char *prefix = NULL;
  485. size_t prefix_len = 0;
  486. assert(ktpd);
  487. assert(msg);
  488. // Get line from message
  489. if (!(line = faux_msg_get_str_param_by_type(msg, KTP_PARAM_LINE))) {
  490. ktp_send_error(ktpd->async, cmd, NULL);
  491. return BOOL_FALSE;
  492. }
  493. // Parsing
  494. pargv = ksession_parse_for_completion(ktpd->session, line);
  495. faux_str_free(line);
  496. if (!pargv) {
  497. ktp_send_error(ktpd->async, cmd, NULL);
  498. return BOOL_FALSE;
  499. }
  500. kpargv_debug(pargv);
  501. if (ksession_done(ktpd->session)) {
  502. ktpd->exit = BOOL_TRUE;
  503. status |= KTP_STATUS_EXIT; // Notify client about exiting
  504. }
  505. // Prepare ACK message
  506. ack = ktp_msg_preform(cmd, status);
  507. // Last unfinished word. Common prefix for all completions
  508. prefix = kpargv_last_arg(pargv);
  509. if (!faux_str_is_empty(prefix)) {
  510. prefix_len = strlen(prefix);
  511. faux_msg_add_param(ack, KTP_PARAM_PREFIX, prefix, prefix_len);
  512. }
  513. // Fill msg with possible completions
  514. if (!kpargv_completions_is_empty(pargv)) {
  515. const kentry_t *candidate = NULL;
  516. kpargv_completions_node_t *citer = kpargv_completions_iter(pargv);
  517. faux_list_node_t *compl_iter = NULL;
  518. faux_list_t *completions = NULL;
  519. char *compl_str = NULL;
  520. completions = faux_list_new(FAUX_LIST_SORTED, FAUX_LIST_UNIQUE,
  521. compl_compare, compl_kcompare,
  522. (void (*)(void *))faux_str_free);
  523. while ((candidate = kpargv_completions_each(&citer))) {
  524. const kentry_t *completion = NULL;
  525. kparg_t *parg = NULL;
  526. int rc = -1;
  527. char *out = NULL;
  528. bool_t res = BOOL_FALSE;
  529. char *l = NULL; // One line of completion
  530. const char *str = NULL;
  531. // Get completion entry from candidate entry
  532. completion = kentry_nested_by_purpose(candidate,
  533. KENTRY_PURPOSE_COMPLETION);
  534. // If candidate entry doesn't contain completion then try
  535. // to get completion from entry's PTYPE
  536. if (!completion) {
  537. const kentry_t *ptype = NULL;
  538. ptype = kentry_nested_by_purpose(candidate,
  539. KENTRY_PURPOSE_PTYPE);
  540. if (!ptype)
  541. continue;
  542. completion = kentry_nested_by_purpose(ptype,
  543. KENTRY_PURPOSE_COMPLETION);
  544. }
  545. if (!completion)
  546. continue;
  547. parg = kparg_new(candidate, prefix);
  548. kpargv_set_candidate_parg(pargv, parg);
  549. res = ksession_exec_locally(ktpd->session, completion,
  550. pargv, &rc, &out);
  551. kparg_free(parg);
  552. if (!res || (rc < 0) || !out) {
  553. if (out)
  554. faux_str_free(out);
  555. continue;
  556. }
  557. // Get all completions one by one
  558. str = out;
  559. while ((l = faux_str_getline(str, &str))) {
  560. // Compare prefix
  561. if ((prefix_len > 0) &&
  562. (faux_str_cmpn(prefix, l, prefix_len) != 0)) {
  563. faux_str_free(l);
  564. continue;
  565. }
  566. compl_str = l + prefix_len;
  567. faux_list_add(completions, faux_str_dup(compl_str));
  568. faux_str_free(l);
  569. }
  570. faux_str_free(out);
  571. }
  572. // Put completion list to message
  573. compl_iter = faux_list_head(completions);
  574. while ((compl_str = faux_list_each(&compl_iter))) {
  575. faux_msg_add_param(ack, KTP_PARAM_LINE,
  576. compl_str, strlen(compl_str));
  577. }
  578. faux_list_free(completions);
  579. }
  580. faux_msg_send_async(ack, ktpd->async);
  581. faux_msg_free(ack);
  582. kpargv_free(pargv);
  583. return BOOL_TRUE;
  584. }
  585. // The most priority source of help is candidate's help ACTION output. Next
  586. // source is candidate's PTYPE help ACTION output.
  587. // Function generates two lines for one resulting help line. The first
  588. // component is a 'prefix' and the second component is 'text'.
  589. // The 'prefix' can be something like 'ip', 'filter' i.e.
  590. // subcommand or '3..89', '<STRING>' i.e. description of type. The 'text'
  591. // field is description of current parameter. For example 'Interface IP
  592. // address'. So the full help can be:
  593. // AAA.BBB.CCC.DDD Interface IP address
  594. // [ first field ] [ second field ]
  595. //
  596. // If not candidate parameter nor PTYPE contains the help functions the engine
  597. // tries to construct help itself.
  598. //
  599. // It uses the following sources for 'prefix':
  600. // * 'help' field of PTYPE
  601. // * 'value' field of PTYPE
  602. // * 'name' field of PTYPE
  603. // * 'value' field of parameter
  604. // * 'name' field of parameter
  605. //
  606. // Engine uses the following sources for 'text':
  607. // * 'help' field of parameter
  608. // * 'value' field of parameter
  609. // * 'name' field of parameter
  610. static bool_t ktpd_session_process_help(ktpd_session_t *ktpd, faux_msg_t *msg)
  611. {
  612. char *line = NULL;
  613. faux_msg_t *ack = NULL;
  614. kpargv_t *pargv = NULL;
  615. ktp_cmd_e cmd = KTP_HELP_ACK;
  616. uint32_t status = KTP_STATUS_NONE;
  617. const char *prefix = NULL;
  618. assert(ktpd);
  619. assert(msg);
  620. // Get line from message
  621. if (!(line = faux_msg_get_str_param_by_type(msg, KTP_PARAM_LINE))) {
  622. ktp_send_error(ktpd->async, cmd, NULL);
  623. return BOOL_FALSE;
  624. }
  625. // Parsing
  626. pargv = ksession_parse_for_completion(ktpd->session, line);
  627. faux_str_free(line);
  628. if (!pargv) {
  629. ktp_send_error(ktpd->async, cmd, NULL);
  630. return BOOL_FALSE;
  631. }
  632. if (ksession_done(ktpd->session)) {
  633. ktpd->exit = BOOL_TRUE;
  634. status |= KTP_STATUS_EXIT; // Notify client about exiting
  635. }
  636. // Prepare ACK message
  637. ack = ktp_msg_preform(cmd, status);
  638. // Last unfinished word. Common prefix for all entries
  639. prefix = kpargv_last_arg(pargv);
  640. // Fill msg with possible help messages
  641. if (!kpargv_completions_is_empty(pargv)) {
  642. const kentry_t *candidate = NULL;
  643. kpargv_completions_node_t *citer = kpargv_completions_iter(pargv);
  644. faux_list_node_t *help_iter = NULL;
  645. faux_list_t *help_list = NULL;
  646. help_t *help_struct = NULL;
  647. help_list = faux_list_new(FAUX_LIST_SORTED, FAUX_LIST_UNIQUE,
  648. help_compare, NULL, help_free);
  649. while ((candidate = kpargv_completions_each(&citer))) {
  650. const kentry_t *help = NULL;
  651. const kentry_t *ptype = NULL;
  652. // Get PTYPE of parameter
  653. ptype = kentry_nested_by_purpose(candidate,
  654. KENTRY_PURPOSE_PTYPE);
  655. // Try to get help fn from parameter itself
  656. help = kentry_nested_by_purpose(candidate,
  657. KENTRY_PURPOSE_HELP);
  658. if (!help && ptype)
  659. help = kentry_nested_by_purpose(ptype,
  660. KENTRY_PURPOSE_HELP);
  661. // Generate help with found ACTION
  662. if (help) {
  663. char *out = NULL;
  664. kparg_t *parg = NULL;
  665. int rc = -1;
  666. parg = kparg_new(candidate, prefix);
  667. kpargv_set_candidate_parg(pargv, parg);
  668. ksession_exec_locally(ktpd->session,
  669. help, pargv, &rc, &out);
  670. kparg_free(parg);
  671. if (out) {
  672. const char *str = out;
  673. char *prefix_str = NULL;
  674. char *line_str = NULL;
  675. do {
  676. prefix_str = faux_str_getline(str, &str);
  677. if (!prefix_str)
  678. break;
  679. line_str = faux_str_getline(str, &str);
  680. if (!line_str) {
  681. faux_str_free(prefix_str);
  682. break;
  683. }
  684. help_struct = help_new(prefix_str, line_str);
  685. if (!faux_list_add(help_list, help_struct))
  686. help_free(help_struct);
  687. } while (line_str);
  688. faux_str_free(out);
  689. }
  690. // Generate help with available information
  691. } else {
  692. const char *prefix_str = NULL;
  693. const char *line_str = NULL;
  694. // Prefix_str
  695. if (ptype) {
  696. prefix_str = kentry_help(ptype);
  697. if (!prefix_str)
  698. prefix_str = kentry_value(ptype);
  699. if (!prefix_str)
  700. prefix_str = kentry_name(ptype);
  701. } else {
  702. prefix_str = kentry_value(candidate);
  703. if (!prefix_str)
  704. prefix_str = kentry_name(candidate);
  705. }
  706. assert(prefix_str);
  707. // Line_str
  708. line_str = kentry_help(candidate);
  709. if (!line_str)
  710. line_str = kentry_value(candidate);
  711. if (!line_str)
  712. line_str = kentry_name(candidate);
  713. assert(line_str);
  714. help_struct = help_new(
  715. faux_str_dup(prefix_str),
  716. faux_str_dup(line_str));
  717. if (!faux_list_add(help_list, help_struct))
  718. help_free(help_struct);
  719. }
  720. }
  721. // Put help list to message
  722. help_iter = faux_list_head(help_list);
  723. while ((help_struct = (help_t *)faux_list_each(&help_iter))) {
  724. faux_msg_add_param(ack, KTP_PARAM_PREFIX,
  725. help_struct->prefix, strlen(help_struct->prefix));
  726. faux_msg_add_param(ack, KTP_PARAM_LINE,
  727. help_struct->line, strlen(help_struct->line));
  728. }
  729. faux_list_free(help_list);
  730. }
  731. faux_msg_send_async(ack, ktpd->async);
  732. faux_msg_free(ack);
  733. kpargv_free(pargv);
  734. return BOOL_TRUE;
  735. }
  736. static ssize_t stdin_out(int fd, faux_buf_t *buf)
  737. {
  738. ssize_t total_written = 0;
  739. assert(buf);
  740. if (!buf)
  741. return -1;
  742. assert(fd >= 0);
  743. while (faux_buf_len(buf) > 0) {
  744. ssize_t data_to_write = 0;
  745. ssize_t bytes_written = 0;
  746. void *data = NULL;
  747. data_to_write = faux_buf_dread_lock_easy(buf, &data);
  748. if (data_to_write <= 0)
  749. return -1;
  750. bytes_written = write(fd, data, data_to_write);
  751. if (bytes_written > 0) {
  752. total_written += bytes_written;
  753. faux_buf_dread_unlock_easy(buf, bytes_written);
  754. } else {
  755. faux_buf_dread_unlock_easy(buf, 0);
  756. }
  757. if (bytes_written < 0) {
  758. if ( // Something went wrong
  759. (errno != EINTR) &&
  760. (errno != EAGAIN) &&
  761. (errno != EWOULDBLOCK)
  762. )
  763. return -1;
  764. // Not whole data block was written
  765. } else if (bytes_written != data_to_write) {
  766. break;
  767. }
  768. }
  769. return total_written;
  770. }
  771. static bool_t push_stdin(ktpd_session_t *ktpd)
  772. {
  773. faux_buf_t *bufin = NULL;
  774. int fd = -1;
  775. if (!ktpd)
  776. return BOOL_TRUE;
  777. if (!ktpd->exec)
  778. return BOOL_TRUE;
  779. fd = kexec_stdin(ktpd->exec);
  780. if (fd < 0) // May be fd is already closed
  781. return BOOL_FALSE;
  782. bufin = kexec_bufin(ktpd->exec);
  783. assert(bufin);
  784. stdin_out(fd, bufin); // Non-blocking write
  785. if (faux_buf_len(bufin) != 0) // Try later
  786. return BOOL_TRUE;
  787. // All data is written
  788. faux_eloop_exclude_fd_event(ktpd->eloop, fd, POLLOUT);
  789. if (ktpd->stdin_must_be_closed) {
  790. close(fd);
  791. kexec_set_stdin(ktpd->exec, -1);
  792. }
  793. return BOOL_TRUE;
  794. }
  795. static bool_t ktpd_session_process_stdin(ktpd_session_t *ktpd, faux_msg_t *msg)
  796. {
  797. char *line = NULL;
  798. unsigned int len = 0;
  799. faux_buf_t *bufin = NULL;
  800. int fd = -1;
  801. bool_t interrupt = BOOL_FALSE;
  802. const kaction_t *action = NULL;
  803. assert(ktpd);
  804. assert(msg);
  805. if (!ktpd->exec)
  806. return BOOL_FALSE;
  807. fd = kexec_stdin(ktpd->exec);
  808. if (fd < 0)
  809. return BOOL_FALSE;
  810. if (!faux_msg_get_param_by_type(msg, KTP_PARAM_LINE, (void **)&line, &len))
  811. return BOOL_TRUE; // It's strange but not a bug
  812. if (len == 0)
  813. return BOOL_TRUE;
  814. bufin = kexec_bufin(ktpd->exec);
  815. assert(bufin);
  816. action = kexec_current_action(ktpd->exec);
  817. if (action)
  818. interrupt = kaction_interrupt(action);
  819. // If current action is non-interruptible and action's stdin is terminal
  820. // then remove ^C (0x03) symbol from stdin stream to don't deliver
  821. // SIGINT to process
  822. if (isatty(fd) && !interrupt) {
  823. // 0x03 is a ^C
  824. const char chars_to_search[] = {0x03, 0};
  825. const char *start = line;
  826. const char *pos = NULL;
  827. size_t cur_len = len;
  828. while ((pos = faux_str_charsn(start, chars_to_search, cur_len))) {
  829. size_t written = pos - start;
  830. faux_buf_write(bufin, start, written);
  831. start = pos + 1;
  832. cur_len = cur_len - written - 1;
  833. }
  834. if (cur_len > 0)
  835. faux_buf_write(bufin, start, cur_len);
  836. } else {
  837. faux_buf_write(bufin, line, len);
  838. }
  839. stdin_out(fd, bufin); // Non-blocking write
  840. if (faux_buf_len(bufin) == 0)
  841. return BOOL_TRUE;
  842. // Non-blocking write can't write all data so plan to write later
  843. faux_eloop_include_fd_event(ktpd->eloop, fd, POLLOUT);
  844. return BOOL_TRUE;
  845. }
  846. static bool_t ktpd_session_process_winch(ktpd_session_t *ktpd, faux_msg_t *msg)
  847. {
  848. char *line = NULL;
  849. char *p = NULL;
  850. unsigned short width = 0;
  851. unsigned short height = 0;
  852. assert(ktpd);
  853. assert(msg);
  854. if (!(line = faux_msg_get_str_param_by_type(msg, KTP_PARAM_WINCH)))
  855. return BOOL_TRUE;
  856. p = strchr(line, ' ');
  857. if (!p || (p == line)) {
  858. faux_str_free(line);
  859. return BOOL_FALSE;
  860. }
  861. if (!faux_conv_atous(line, &width, 0)) {
  862. faux_str_free(line);
  863. return BOOL_FALSE;
  864. }
  865. if (!faux_conv_atous(p + 1, &height, 0)) {
  866. faux_str_free(line);
  867. return BOOL_FALSE;
  868. }
  869. ksession_set_term_width(ktpd->session, width);
  870. ksession_set_term_height(ktpd->session, height);
  871. faux_str_free(line);
  872. if (!ktpd->exec)
  873. return BOOL_TRUE;
  874. // Set pseudo terminal window size
  875. kexec_set_winsize(ktpd->exec);
  876. return BOOL_TRUE;
  877. }
  878. static bool_t ktpd_session_process_notification(ktpd_session_t *ktpd, faux_msg_t *msg)
  879. {
  880. assert(ktpd);
  881. assert(msg);
  882. ktpd_session_process_winch(ktpd, msg);
  883. return BOOL_TRUE;
  884. }
  885. static bool_t ktpd_session_process_stdin_close(ktpd_session_t *ktpd,
  886. faux_msg_t *msg)
  887. {
  888. int fd = -1;
  889. assert(ktpd);
  890. assert(msg);
  891. if (!ktpd->exec)
  892. return BOOL_FALSE;
  893. fd = kexec_stdin(ktpd->exec);
  894. if (fd < 0)
  895. return BOOL_FALSE;
  896. // Schedule to close stdin
  897. ktpd->stdin_must_be_closed = BOOL_TRUE;
  898. push_stdin(ktpd);
  899. return BOOL_TRUE;
  900. }
  901. static bool_t ktpd_session_process_stdout_close(ktpd_session_t *ktpd,
  902. faux_msg_t *msg)
  903. {
  904. int fd = -1;
  905. assert(ktpd);
  906. assert(msg);
  907. if (!ktpd->exec)
  908. return BOOL_FALSE;
  909. fd = kexec_stdout(ktpd->exec);
  910. if (fd < 0)
  911. return BOOL_FALSE;
  912. close(fd);
  913. // Remove already generated data from out buffer. This data is not
  914. // needed now
  915. faux_buf_empty(kexec_bufout(ktpd->exec));
  916. return BOOL_TRUE;
  917. }
  918. static bool_t ktpd_session_process_stderr_close(ktpd_session_t *ktpd,
  919. faux_msg_t *msg)
  920. {
  921. int fd = -1;
  922. assert(ktpd);
  923. assert(msg);
  924. if (!ktpd->exec)
  925. return BOOL_FALSE;
  926. fd = kexec_stderr(ktpd->exec);
  927. if (fd < 0)
  928. return BOOL_FALSE;
  929. close(fd);
  930. // Remove already generated data from err buffer. This data is not
  931. // needed any more
  932. faux_buf_empty(kexec_buferr(ktpd->exec));
  933. return BOOL_TRUE;
  934. }
  935. static bool_t ktpd_session_dispatch(ktpd_session_t *ktpd, faux_msg_t *msg)
  936. {
  937. uint16_t cmd = 0;
  938. const char *err = NULL;
  939. ktp_cmd_e ecmd = KTP_NOTIFICATION; // Answer command if error
  940. assert(ktpd);
  941. if (!ktpd)
  942. return BOOL_FALSE;
  943. assert(msg);
  944. if (!msg)
  945. return BOOL_FALSE;
  946. cmd = faux_msg_get_cmd(msg);
  947. switch (cmd) {
  948. case KTP_AUTH:
  949. if ((ktpd->state != KTPD_SESSION_STATE_UNAUTHORIZED) &&
  950. (ktpd->state != KTPD_SESSION_STATE_IDLE)) {
  951. ecmd = KTP_AUTH_ACK;
  952. err = "Server illegal state for authorization";
  953. break;
  954. }
  955. ktpd_session_process_auth(ktpd, msg);
  956. break;
  957. case KTP_CMD:
  958. if (ktpd->state != KTPD_SESSION_STATE_IDLE) {
  959. ecmd = KTP_CMD_ACK;
  960. err = "Server illegal state for command execution";
  961. break;
  962. }
  963. ktpd_session_process_cmd(ktpd, msg);
  964. break;
  965. case KTP_COMPLETION:
  966. if (ktpd->state != KTPD_SESSION_STATE_IDLE) {
  967. ecmd = KTP_COMPLETION_ACK;
  968. err = "Server illegal state for completion";
  969. break;
  970. }
  971. ktpd_session_process_completion(ktpd, msg);
  972. break;
  973. case KTP_HELP:
  974. if (ktpd->state != KTPD_SESSION_STATE_IDLE) {
  975. ecmd = KTP_HELP_ACK;
  976. err = "Server illegal state for help";
  977. break;
  978. }
  979. ktpd_session_process_help(ktpd, msg);
  980. break;
  981. case KTP_STDIN:
  982. if (ktpd->state != KTPD_SESSION_STATE_WAIT_FOR_PROCESS) {
  983. err = "Nobody is waiting for stdin";
  984. break;
  985. }
  986. ktpd_session_process_stdin(ktpd, msg);
  987. break;
  988. case KTP_NOTIFICATION:
  989. ktpd_session_process_notification(ktpd, msg);
  990. break;
  991. case KTP_STDIN_CLOSE:
  992. if (ktpd->state != KTPD_SESSION_STATE_WAIT_FOR_PROCESS) {
  993. err = "No active command is running";
  994. break;
  995. }
  996. ktpd_session_process_stdin_close(ktpd, msg);
  997. break;
  998. case KTP_STDOUT_CLOSE:
  999. if (ktpd->state != KTPD_SESSION_STATE_WAIT_FOR_PROCESS) {
  1000. err = "No active command is running";
  1001. break;
  1002. }
  1003. ktpd_session_process_stdout_close(ktpd, msg);
  1004. break;
  1005. case KTP_STDERR_CLOSE:
  1006. if (ktpd->state != KTPD_SESSION_STATE_WAIT_FOR_PROCESS) {
  1007. err = "No active command is running";
  1008. break;
  1009. }
  1010. ktpd_session_process_stderr_close(ktpd, msg);
  1011. break;
  1012. default:
  1013. syslog(LOG_WARNING, "Unsupported command: 0x%04u", cmd);
  1014. err = "Unsupported command";
  1015. break;
  1016. }
  1017. // On error
  1018. if (err)
  1019. ktp_send_error(ktpd->async, ecmd, err);
  1020. return BOOL_TRUE;
  1021. }
  1022. /** @brief Low-level function to receive KTP message.
  1023. *
  1024. * Firstly function gets the header of message. Then it checks and parses
  1025. * header and find out the length of whole message. Then it receives the rest
  1026. * of message.
  1027. */
  1028. static bool_t ktpd_session_read_cb(faux_async_t *async,
  1029. faux_buf_t *buf, size_t len, void *user_data)
  1030. {
  1031. ktpd_session_t *ktpd = (ktpd_session_t *)user_data;
  1032. faux_msg_t *completed_msg = NULL;
  1033. char *data = NULL;
  1034. assert(async);
  1035. assert(buf);
  1036. assert(ktpd);
  1037. // Linearize buffer
  1038. data = malloc(len);
  1039. faux_buf_read(buf, data, len);
  1040. // Receive header
  1041. if (!ktpd->hdr) {
  1042. size_t whole_len = 0;
  1043. size_t msg_wo_hdr = 0;
  1044. ktpd->hdr = (faux_hdr_t *)data;
  1045. // Check for broken header
  1046. if (!ktp_check_header(ktpd->hdr)) {
  1047. faux_free(ktpd->hdr);
  1048. ktpd->hdr = NULL;
  1049. return BOOL_FALSE;
  1050. }
  1051. whole_len = faux_hdr_len(ktpd->hdr);
  1052. // msg_wo_hdr >= 0 because ktp_check_header() validates whole_len
  1053. msg_wo_hdr = whole_len - sizeof(faux_hdr_t);
  1054. // Plan to receive message body
  1055. if (msg_wo_hdr > 0) {
  1056. faux_async_set_read_limits(async,
  1057. msg_wo_hdr, msg_wo_hdr);
  1058. return BOOL_TRUE;
  1059. }
  1060. // Here message is completed (msg body has zero length)
  1061. completed_msg = faux_msg_deserialize_parts(ktpd->hdr, NULL, 0);
  1062. // Receive message body
  1063. } else {
  1064. completed_msg = faux_msg_deserialize_parts(ktpd->hdr, data, len);
  1065. faux_free(data);
  1066. }
  1067. // Plan to receive msg header
  1068. faux_async_set_read_limits(ktpd->async,
  1069. sizeof(faux_hdr_t), sizeof(faux_hdr_t));
  1070. faux_free(ktpd->hdr);
  1071. ktpd->hdr = NULL; // Ready to recv new header
  1072. // Here message is completed
  1073. ktpd_session_dispatch(ktpd, completed_msg);
  1074. faux_msg_free(completed_msg);
  1075. return BOOL_TRUE;
  1076. }
  1077. bool_t ktpd_session_connected(ktpd_session_t *ktpd)
  1078. {
  1079. assert(ktpd);
  1080. if (!ktpd)
  1081. return BOOL_FALSE;
  1082. if (KTPD_SESSION_STATE_DISCONNECTED == ktpd->state)
  1083. return BOOL_FALSE;
  1084. return BOOL_TRUE;
  1085. }
  1086. int ktpd_session_fd(const ktpd_session_t *ktpd)
  1087. {
  1088. assert(ktpd);
  1089. if (!ktpd)
  1090. return BOOL_FALSE;
  1091. return faux_async_fd(ktpd->async);
  1092. }
  1093. static bool_t get_stream(ktpd_session_t *ktpd, int fd, bool_t is_stderr)
  1094. {
  1095. ssize_t r = -1;
  1096. faux_buf_t *faux_buf = NULL;
  1097. char *buf = NULL;
  1098. ssize_t len = 0;
  1099. faux_msg_t *ack = NULL;
  1100. if (!ktpd)
  1101. return BOOL_TRUE;
  1102. if (!ktpd->exec)
  1103. return BOOL_TRUE;
  1104. if (is_stderr)
  1105. faux_buf = kexec_buferr(ktpd->exec);
  1106. else
  1107. faux_buf = kexec_bufout(ktpd->exec);
  1108. assert(faux_buf);
  1109. do {
  1110. void *linear_buf = NULL;
  1111. ssize_t really_readed = 0;
  1112. ssize_t linear_len =
  1113. faux_buf_dwrite_lock_easy(faux_buf, &linear_buf);
  1114. // Non-blocked read. The fd became non-blocked while
  1115. // kexec_prepare().
  1116. r = read(fd, linear_buf, linear_len);
  1117. if (r > 0)
  1118. really_readed = r;
  1119. faux_buf_dwrite_unlock_easy(faux_buf, really_readed);
  1120. } while (r > 0);
  1121. len = faux_buf_len(faux_buf);
  1122. if (0 == len)
  1123. return BOOL_TRUE;
  1124. buf = malloc(len);
  1125. faux_buf_read(faux_buf, buf, len);
  1126. // Create KTP_STDOUT/KTP_STDERR message to send to client
  1127. ack = ktp_msg_preform(is_stderr ? KTP_STDERR : KTP_STDOUT, KTP_STATUS_NONE);
  1128. faux_msg_add_param(ack, KTP_PARAM_LINE, buf, len);
  1129. faux_msg_send_async(ack, ktpd->async);
  1130. faux_msg_free(ack);
  1131. free(buf);
  1132. return BOOL_TRUE;
  1133. }
  1134. static bool_t action_stdout_ev(faux_eloop_t *eloop, faux_eloop_type_e type,
  1135. void *associated_data, void *user_data)
  1136. {
  1137. faux_eloop_info_fd_t *info = (faux_eloop_info_fd_t *)associated_data;
  1138. ktpd_session_t *ktpd = (ktpd_session_t *)user_data;
  1139. // Interactive command use these function as callback not only for
  1140. // getting stdout but for writing stdin too. Because pseudo-terminal
  1141. // uses the same fd for in and out.
  1142. if (info->revents & POLLOUT)
  1143. push_stdin(ktpd);
  1144. if (info->revents & POLLIN)
  1145. get_stream(ktpd, info->fd, BOOL_FALSE);
  1146. // Some errors or fd is closed so remove it from polling
  1147. // EOF || POLERR || POLLNVAL
  1148. if (info->revents & (POLLHUP | POLLERR | POLLNVAL))
  1149. faux_eloop_del_fd(eloop, info->fd);
  1150. type = type; // Happy compiler
  1151. return BOOL_TRUE;
  1152. }
  1153. static bool_t action_stderr_ev(faux_eloop_t *eloop, faux_eloop_type_e type,
  1154. void *associated_data, void *user_data)
  1155. {
  1156. faux_eloop_info_fd_t *info = (faux_eloop_info_fd_t *)associated_data;
  1157. ktpd_session_t *ktpd = (ktpd_session_t *)user_data;
  1158. if (info->revents & POLLIN)
  1159. get_stream(ktpd, info->fd, BOOL_TRUE);
  1160. // Some errors or fd is closed so remove it from polling
  1161. // EOF || POLERR || POLLNVAL
  1162. if (info->revents & (POLLHUP | POLLERR | POLLNVAL))
  1163. faux_eloop_del_fd(eloop, info->fd);
  1164. type = type; // Happy compiler
  1165. return BOOL_TRUE;
  1166. }
  1167. bool_t client_ev(faux_eloop_t *eloop, faux_eloop_type_e type,
  1168. void *associated_data, void *user_data)
  1169. {
  1170. faux_eloop_info_fd_t *info = (faux_eloop_info_fd_t *)associated_data;
  1171. ktpd_session_t *ktpd = (ktpd_session_t *)user_data;
  1172. faux_async_t *async = ktpd->async;
  1173. assert(async);
  1174. // Write data
  1175. if (info->revents & POLLOUT) {
  1176. faux_eloop_exclude_fd_event(eloop, info->fd, POLLOUT);
  1177. if (faux_async_out(async) < 0) {
  1178. // Someting went wrong
  1179. faux_eloop_del_fd(eloop, info->fd);
  1180. syslog(LOG_ERR, "Can't send data to client");
  1181. return BOOL_FALSE; // Stop event loop
  1182. }
  1183. }
  1184. // Read data
  1185. if (info->revents & POLLIN) {
  1186. if (faux_async_in(async) < 0) {
  1187. // Someting went wrong
  1188. faux_eloop_del_fd(eloop, info->fd);
  1189. syslog(LOG_ERR, "Can't get data from client");
  1190. return BOOL_FALSE; // Stop event loop
  1191. }
  1192. }
  1193. // EOF
  1194. if (info->revents & POLLHUP) {
  1195. faux_eloop_del_fd(eloop, info->fd);
  1196. syslog(LOG_DEBUG, "Connection %d is closed by client", info->fd);
  1197. return BOOL_FALSE; // Stop event loop
  1198. }
  1199. // POLLERR
  1200. if (info->revents & POLLERR) {
  1201. faux_eloop_del_fd(eloop, info->fd);
  1202. syslog(LOG_DEBUG, "POLLERR received %d", info->fd);
  1203. return BOOL_FALSE; // Stop event loop
  1204. }
  1205. // POLLNVAL
  1206. if (info->revents & POLLNVAL) {
  1207. faux_eloop_del_fd(eloop, info->fd);
  1208. syslog(LOG_DEBUG, "POLLNVAL received %d", info->fd);
  1209. return BOOL_FALSE; // Stop event loop
  1210. }
  1211. type = type; // Happy compiler
  1212. // Session can be really finished here. Note KTPD session can't be
  1213. // stopped immediately so it's only two places within code to really
  1214. // break the loop. This one and within wait_for_action_ev().
  1215. if (ktpd->exit)
  1216. return BOOL_FALSE;
  1217. return BOOL_TRUE;
  1218. }
  1219. #if 0
  1220. static void ktpd_session_bad_socket(ktpd_session_t *ktpd)
  1221. {
  1222. assert(ktpd);
  1223. if (!ktpd)
  1224. return;
  1225. ktpd->state = KTPD_SESSION_STATE_DISCONNECTED;
  1226. }
  1227. #endif