CGI Bash Shell Interface
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

subshell.c 8.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. /**
  2. * @PROJECT CGI Bash Shell Interface
  3. * @COPYRIGHT See COPYING in the top level directory
  4. * @FILE subshell.c
  5. * @PURPOSE Subshell execution
  6. * @DEVELOPERS Nathan Angelacos <nangel@users.sourceforge.net>
  7. * Rafal Kupiec <belliash@asiotec.eu.org>
  8. */
  9. #include <stdio.h>
  10. #include <unistd.h>
  11. #include <time.h>
  12. #include <getopt.h>
  13. #include <sys/mman.h>
  14. #include <sys/types.h>
  15. #include <sys/wait.h>
  16. #include <sys/stat.h>
  17. #include <sys/fcntl.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <ctype.h>
  21. #include "common.h"
  22. #include "buffer.h"
  23. #include "error.h"
  24. #include "subshell.h"
  25. #include "cbsi.h"
  26. char open_tag[3] = "<%";
  27. char close_tag[3] = "%>";
  28. const char* g_tag[] = {
  29. "",
  30. "",
  31. ":",
  32. "@",
  33. ""
  34. };
  35. token_t* build_token_list(script_t* scriptbuf, token_t* tokenlist) {
  36. char* start;
  37. char* end;
  38. char* curpos;
  39. char* endpos;
  40. token_t* curtoken;
  41. token_t* firsttoken;
  42. curtoken = tokenlist;
  43. firsttoken = tokenlist;
  44. curpos = scriptbuf->buf + scriptbuf->curpos;
  45. endpos = scriptbuf->buf + scriptbuf->size;
  46. while(curpos < endpos) {
  47. start = strstr(curpos, open_tag);
  48. end = strstr(curpos, close_tag);
  49. if(start && !end) {
  50. die_with_message(scriptbuf, start, g_err_msg[E_NO_END_MARKER], open_tag[1]);
  51. }
  52. if((start > end) || (!start && end)) {
  53. die_with_message(scriptbuf, end, g_err_msg[E_END_BEFORE_BEGIN], open_tag[1], open_tag[1]);
  54. }
  55. if(start && (strstr(start + 1, open_tag) && (strstr (start + 1, open_tag) < end)))
  56. die_with_message(scriptbuf, start, g_err_msg[E_NO_END_MARKER], open_tag[1]);
  57. if(end) {
  58. curtoken = push_token_on_list(curtoken, scriptbuf, curpos, start - curpos);
  59. if(firsttoken == NULL) {
  60. firsttoken = curtoken;
  61. }
  62. curtoken = push_token_on_list(curtoken, scriptbuf, start, end - start);
  63. if(firsttoken == NULL) {
  64. firsttoken = curtoken;
  65. }
  66. curpos = end + 2;
  67. } else {
  68. curtoken = push_token_on_list(curtoken, scriptbuf, curpos, endpos - curpos);
  69. if(firsttoken == NULL) {
  70. firsttoken = curtoken;
  71. }
  72. curpos = endpos;
  73. }
  74. }
  75. return firsttoken;
  76. }
  77. void free_script_list(script_t* script) {
  78. script_t* next;
  79. while(script) {
  80. next = script->next;
  81. if(script->name) {
  82. free(script->name);
  83. }
  84. if(script->buf) {
  85. free(script->buf);
  86. }
  87. free(script);
  88. script = next;
  89. }
  90. }
  91. void free_token_list(token_t* tokenlist) {
  92. token_t* next;
  93. while(tokenlist) {
  94. next = tokenlist->next;
  95. free(tokenlist);
  96. tokenlist = next;
  97. }
  98. }
  99. script_t* load_script(char* filename, script_t* scriptlist) {
  100. script_t* scriptbuf;
  101. int scriptfp;
  102. struct stat filestat;
  103. scriptfp = open(filename, O_NONBLOCK + O_RDONLY);
  104. if(scriptfp == -1) {
  105. die_with_message(NULL, NULL, g_err_msg[E_FILE_OPEN_FAIL], filename);
  106. }
  107. fstat(scriptfp, &filestat);
  108. scriptbuf = (script_t *) xmalloc(sizeof (script_t));
  109. scriptbuf->name = (char *) xmalloc(strlen (filename) + 1);
  110. scriptbuf->buf = (char *) xmalloc(filestat.st_size + 1);
  111. memset(scriptbuf->name, 0, strlen(filename) + 1);
  112. memcpy(scriptbuf->name, filename, strlen(filename));
  113. memset(scriptbuf->buf, 0, filestat.st_size + 1);
  114. read(scriptfp, scriptbuf->buf, filestat.st_size);
  115. scriptbuf->size = filestat.st_size;
  116. scriptbuf->uid = filestat.st_uid;
  117. scriptbuf->gid = filestat.st_gid;
  118. scriptbuf->curpos = 0;
  119. scriptbuf->next = NULL;
  120. if(scriptlist != NULL) {
  121. while(scriptlist->next) {
  122. scriptlist = scriptlist->next;
  123. }
  124. scriptlist->next = scriptbuf;
  125. }
  126. if(memcmp(scriptbuf->buf, "#!", 2) == 0) {
  127. while((scriptbuf->curpos < scriptbuf->size) && ((char) scriptbuf->buf[scriptbuf->curpos] != '\n')) {
  128. (scriptbuf->curpos)++;
  129. }
  130. (scriptbuf->curpos)++;
  131. }
  132. close(scriptfp);
  133. return scriptbuf;
  134. }
  135. void preprocess_token_list(token_t* tokenlist) {
  136. script_t* newscript;
  137. token_t* me;
  138. char* cp;
  139. me = tokenlist;
  140. while(me) {
  141. if(memcmp(me->buf, open_tag, 2)) {
  142. me->tag = HTML;
  143. } else {
  144. me->tag = NOOP;
  145. me->buf[me->len] = '\0';
  146. cp = me->buf + 2;
  147. if(memcmp(cp, g_tag[ECHO], 1) == 0) {
  148. me->tag = ECHO;
  149. me->buf = find_whitespace(me->buf);
  150. me->len = strlen(me->buf);
  151. } else if(memcmp(cp, g_tag[TRANSLATE], 1) == 0) {
  152. me->tag = TRANSLATE;
  153. me->buf = find_whitespace(me->buf);
  154. me->len = strlen(me->buf);
  155. }
  156. if(isspace(*cp)) {
  157. me->tag = RUN;
  158. me->buf = cp;
  159. }
  160. if(me->tag == NOOP) {
  161. die_with_message(me->script, cp, g_err_msg[E_NO_OP]);
  162. }
  163. me->len = strlen(me->buf);
  164. }
  165. me = me->next;
  166. }
  167. }
  168. token_t* process_token_list(buffer_t* buf, token_t* token) {
  169. char *c;
  170. buffer_init(buf);
  171. subshell_exec(buf, "\n");
  172. while(token) {
  173. switch(token->tag) {
  174. case HTML:
  175. c = token->buf;
  176. while((c < (token->buf + token->len)) && (isspace(*c))) {
  177. c++;
  178. }
  179. if(c != token->buf + token->len) {
  180. subshell_echo (buf, token->buf, token->len);
  181. }
  182. break;
  183. case RUN:
  184. subshell_exec(buf, token->buf);
  185. subshell_exec(buf, "\n");
  186. break;
  187. case ECHO:
  188. subshell_eval(buf, token->buf, token->len);
  189. break;
  190. case TRANSLATE:
  191. subshell_translate(buf, token->buf, token->len);
  192. break;
  193. default:
  194. break;
  195. }
  196. token = token->next;
  197. }
  198. return token;
  199. }
  200. token_t* push_token_on_list(token_t* tokenlist, script_t* scriptbuf, char* start, size_t len) {
  201. token_t* me;
  202. token_t* next;
  203. if(len == 0) {
  204. return tokenlist;
  205. }
  206. me = (token_t*) xmalloc(sizeof(token_t));
  207. if(tokenlist == NULL) {
  208. next = NULL;
  209. } else {
  210. next = tokenlist->next;
  211. tokenlist->next = me;
  212. }
  213. me->next = next;
  214. me->script = scriptbuf;
  215. me->buf = start;
  216. me->len = len;
  217. return me;
  218. }
  219. void subshell_destroy(void) {
  220. int status;
  221. waitpid(subshell_pid, &status, 0);
  222. }
  223. void subshell_doscript(buffer_t* script, char* name) {
  224. static char postfix[] = "\nexit\n";
  225. write(subshell_pipe[PARENT_OUT], script->data, script->ptr - script->data);
  226. write(subshell_pipe[PARENT_OUT], postfix, strlen(postfix));
  227. return;
  228. }
  229. void subshell_echo(buffer_t* buf, char* str, size_t len) {
  230. static char echo_start[] = "printf '%s' '";
  231. static char echo_quote[] = "'\\''";
  232. static char echo_end[] = "'\n";
  233. const size_t maxlen = 3096;
  234. size_t pos;
  235. if(len == 0) {
  236. return;
  237. }
  238. pos = 0;
  239. buffer_add(buf, echo_start, strlen(echo_start));
  240. while(pos < len) {
  241. if (str[pos] == '\'') {
  242. buffer_add(buf, echo_quote, strlen(echo_quote));
  243. } else {
  244. buffer_add(buf, str + pos, 1);
  245. }
  246. pos++;
  247. if((pos % maxlen) == 0) {
  248. buffer_add(buf, echo_end, strlen(echo_end));
  249. buffer_add(buf, echo_start, strlen(echo_start));
  250. }
  251. }
  252. buffer_add(buf, echo_end, strlen(echo_end));
  253. }
  254. void subshell_eval(buffer_t* buf, char* str, size_t len) {
  255. static char echo_start[] = "echo -n ";
  256. static char echo_end[] = "\n";
  257. if(len == 0) {
  258. return;
  259. }
  260. str = trim(str);
  261. if(!*str) {
  262. return;
  263. }
  264. buffer_add(buf, echo_start, strlen(echo_start));
  265. buffer_add(buf, str, len);
  266. buffer_add(buf, echo_end, strlen(echo_end));
  267. }
  268. void subshell_exec(buffer_t* buf, char* str) {
  269. buffer_add (buf, str, strlen (str));
  270. return;
  271. }
  272. void subshell_setup (char* shell, list_t* env) {
  273. int retcode = 0;
  274. int count;
  275. argv_t* argv;
  276. char* av[20];
  277. list_t* next;
  278. if(shell == NULL) {
  279. return;
  280. }
  281. retcode = pipe(&subshell_pipe[PARENT_IN]);
  282. if(retcode == 0) {
  283. subshell_pid = fork();
  284. if(subshell_pid == -1) {
  285. die_with_message(NULL, NULL, g_err_msg[E_SUBSHELL_FAIL]);
  286. }
  287. if(subshell_pid == 0) {
  288. dup2(subshell_pipe[PARENT_IN], STDIN_FILENO);
  289. close(subshell_pipe[PARENT_IN]);
  290. close(subshell_pipe[PARENT_OUT]);
  291. count = argc_argv(shell, &argv);
  292. if(count > 19) {
  293. av[19] = "\0";
  294. count = 18;
  295. }
  296. while(count >= 0) {
  297. av[count] = argv[count].string;
  298. count--;
  299. }
  300. while(env) {
  301. next = env->next;
  302. putenv(env->buf);
  303. env = next;
  304. }
  305. execv(argv[0].string, av);
  306. free(argv);
  307. die_with_message(NULL, NULL, g_err_msg[E_SUBSHELL_FAIL]);
  308. } else {
  309. close(subshell_pipe[PARENT_IN]);
  310. }
  311. }
  312. }
  313. void subshell_translate(buffer_t* buf, char* str, size_t len) {
  314. static char echo_start[] = "echo -n \"";
  315. static char echo_end[] = "\"\n";
  316. short hash;
  317. lstr* i;
  318. char* text = NULL;
  319. if(len == 0) {
  320. return;
  321. }
  322. str = trim(str);
  323. if(!*str) {
  324. return;
  325. }
  326. if(language != NULL && translations > 0) {
  327. hash = generateHash(str);
  328. i = ltable[hash];
  329. while(text == NULL && i != NULL) {
  330. if(strcmp(str, i->msgid) == 0) {
  331. text = i->msgstr;
  332. } else {
  333. i = i->next;
  334. }
  335. }
  336. }
  337. if(text == NULL) {
  338. text = str;
  339. }
  340. buffer_add(buf, echo_start, strlen(echo_start));
  341. buffer_add(buf, text, strlen(text));
  342. buffer_add(buf, echo_end, strlen(echo_end));
  343. }