ktpd_session.c 38 KB

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