mirror of the now-defunct rocklinux.org
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.

456 lines
10 KiB

  1. #include <stdint.h>
  2. #include <errno.h>
  3. #include <stdio.h>
  4. #include <unistd.h>
  5. #include <signal.h>
  6. #include <stdlib.h>
  7. #include <netinet/in.h>
  8. #include <arpa/inet.h>
  9. #include <sys/stat.h>
  10. #include <sys/types.h>
  11. #include <sys/socket.h>
  12. #include <sys/time.h>
  13. #include <sys/wait.h>
  14. #include <string.h>
  15. #include <fcntl.h>
  16. #define TCPPORT 28336
  17. #define CMD_EXEC 1
  18. #define CMD_ADDARG 2
  19. #define CMD_ADDENV 3
  20. #define CMD_CHDIR 4
  21. #define CMD_CHROOT 5
  22. #define CMD_EXIT 6
  23. #define CMD_BUILDID 7
  24. #define CMD_WRITE0 1000
  25. #define CMD_CLOSE0 2000
  26. #define CMD_ENABLE0 3000
  27. struct pn_pkg {
  28. uint32_t len;
  29. uint32_t type;
  30. char data[];
  31. };
  32. struct sbuf;
  33. struct sbuf {
  34. struct sbuf *next;
  35. int len, c;
  36. struct pn_pkg *p;
  37. char *d;
  38. };
  39. struct sbuf *recv4p = 0;
  40. struct sbuf *send2p = 0;
  41. int sbuf_c = 0;
  42. void conn_send(int conn, int len, int type, char *data)
  43. {
  44. struct pn_pkg *p = malloc( sizeof(struct pn_pkg) + len );
  45. int i, rc;
  46. p->len = htonl(len);
  47. p->type = htonl(type);
  48. memcpy(p->data, data, len);
  49. len += sizeof(struct pn_pkg);
  50. for (i = 0; i < len; i += rc) {
  51. rc = write(conn, (char*)p + i, len - i);
  52. if ( rc <= 0 ) {
  53. fprintf(stderr, "network write error: %s\n", strerror(errno));
  54. exit(-1);
  55. }
  56. }
  57. free(p);
  58. }
  59. int conn_read(int conn, char *buf, int len, int nonblock)
  60. {
  61. int f = -1;
  62. if ( nonblock ) {
  63. f = fcntl(conn, F_GETFL, 0);
  64. fcntl(conn, F_SETFL, f | O_NONBLOCK);
  65. }
  66. while (len) {
  67. int rc = read(conn, buf, len);
  68. if ( rc < 0 ) {
  69. if ( errno == EAGAIN ) break;
  70. fprintf(stderr, "network read error: %s\n", strerror(errno));
  71. exit(-1);
  72. }
  73. if ( rc == 0 ) {
  74. fprintf(stderr, "connection closed by peer\n");
  75. exit(-1);
  76. }
  77. if ( f != -1 )
  78. fcntl(conn, F_SETFL, f);
  79. len -= rc; buf += rc; f = -1;
  80. }
  81. if ( f != -1 )
  82. fcntl(conn, F_SETFL, f);
  83. return len;
  84. }
  85. struct pn_pkg *conn_recv(int conn, int nonblock)
  86. {
  87. struct pn_pkg *p = malloc( sizeof(struct pn_pkg) );
  88. if ( conn_read(conn, (char*)p, 8, nonblock) ) {
  89. free(p);
  90. return 0;
  91. }
  92. p->len = ntohl(p->len);
  93. p->type = ntohl(p->type);
  94. p = realloc(p, sizeof(struct pn_pkg) + p->len);
  95. conn_read(conn, p->data, p->len, 0);
  96. return p;
  97. }
  98. void do_chroot(char *d, char *b)
  99. {
  100. char buf[1024];
  101. char *e = malloc(strlen(d)+strlen(b)+2);
  102. int i;
  103. sprintf(e, "%s:%s", d, b);
  104. for (i=0; e[i]; i++) if ( e[i] == '/' ) e[i] = '_';
  105. snprintf(buf, 1024, "%s/pseudonative_handler", e);
  106. if ( access(buf, F_OK) ) {
  107. mkdir(e, 0700);
  108. snprintf(buf, 1024, "mount -t nfs -o noac %s/build/%s %s", d, b, e);
  109. system(buf);
  110. snprintf(buf, 1024, "mount -t nfs -o noac %s %s/ROCK/loop", d, e);
  111. system(buf);
  112. snprintf(buf, 1024, "mount -t nfs -o noac %s/config %s/ROCK/config", d, e);
  113. system(buf);
  114. snprintf(buf, 1024, "mount -t nfs -o noac %s/download %s/ROCK/download", d, e);
  115. system(buf);
  116. snprintf(buf, 1024, "mount -t proc none %s/proc", e);
  117. system(buf);
  118. }
  119. chdir(e);
  120. chroot(".");
  121. free(e);
  122. }
  123. void do_session(int conn)
  124. {
  125. char *argv[1024], *bid="", *exe = "/bin/true";
  126. int f0[2], f1[2], f2[2], m, f, argc = 0;
  127. int open_0 = 1, open_1 = 1, open_2 = 1;
  128. int schedule_close_0 = 0, enable_0 = 0;
  129. unsigned char retval;
  130. struct timeval tv;
  131. fd_set rfds, wfds;
  132. struct pn_pkg *p;
  133. clearenv();
  134. signal(SIGCHLD, SIG_DFL);
  135. signal(SIGPIPE, SIG_IGN);
  136. while (1) {
  137. if ( (p = conn_recv(conn, 0)) == 0 ) {
  138. fprintf(stderr, "\nnetwork read error: EOF\n");
  139. exit(-1);
  140. }
  141. switch (p->type) {
  142. case CMD_EXEC:
  143. printf("\nEXE: %s", p->data);
  144. exe = strdup(p->data);
  145. break;
  146. case CMD_ADDARG:
  147. printf(m == p->type ? " %s" : "\nARG: %s", p->data);
  148. argv[argc++] = strdup(p->data);
  149. break;
  150. case CMD_ADDENV:
  151. printf(m == p->type ? "." : "\nENV: .");
  152. putenv(strdup(p->data));
  153. break;
  154. case CMD_CHDIR:
  155. printf("\nCHD: %s", p->data);
  156. chdir(p->data);
  157. break;
  158. case CMD_BUILDID:
  159. bid = strdup(p->data);
  160. break;
  161. case CMD_CHROOT:
  162. printf("\nMNT: %s %s", p->data, bid);
  163. do_chroot(p->data, bid);
  164. break;
  165. }
  166. if ((m=p->type) == CMD_EXEC) {
  167. free(p);
  168. break;
  169. }
  170. free(p);
  171. }
  172. pipe(f0);
  173. pipe(f1);
  174. pipe(f2);
  175. printf("\n");
  176. fflush(stderr);
  177. fflush(stdout);
  178. if (!fork()) {
  179. dup2(f0[0], 0); close(f0[0]); close(f0[1]);
  180. dup2(f1[1], 1); close(f1[0]); close(f1[1]);
  181. dup2(f2[1], 2); close(f2[0]); close(f2[1]);
  182. signal(SIGPIPE, SIG_DFL);
  183. argv[argc] = 0;
  184. execv(exe, argv);
  185. fprintf(stderr, "Can't execute %s: %s\n", exe, strerror(errno));
  186. exit(-1);
  187. }
  188. close(f0[0]);
  189. close(f1[1]);
  190. close(f2[1]);
  191. /* This is usefull for reading strace dumps, etc. */
  192. #if 0
  193. printf("FDS: fd0=%d, fd1=%d, fd2=%d, conn=%d\n",
  194. f0[1], f1[0], f2[0], conn);
  195. #endif
  196. f = fcntl(f0[1], F_GETFL, 0);
  197. fcntl(f0[1], F_SETFL, f | O_NONBLOCK);
  198. f = fcntl(f1[0], F_GETFL, 0);
  199. fcntl(f1[0], F_SETFL, f | O_NONBLOCK);
  200. f = fcntl(f2[0], F_GETFL, 0);
  201. fcntl(f2[0], F_SETFL, f | O_NONBLOCK);
  202. while (open_1 || open_2)
  203. {
  204. char buf[512];
  205. int rc;
  206. FD_ZERO(&rfds);
  207. FD_ZERO(&wfds);
  208. m = f0[1];
  209. if ( conn > m ) m = conn; FD_SET(conn, &rfds);
  210. if ( open_1 ) { if ( f1[0] > m ) m = f1[0]; FD_SET(f1[0], &rfds); }
  211. if ( open_2 ) { if ( f2[0] > m ) m = f2[0]; FD_SET(f2[0], &rfds); }
  212. write(1, "?", 1);
  213. tv.tv_sec = 1;
  214. tv.tv_usec = 0;
  215. if ( schedule_close_0 < 2 && (send2p || !enable_0) ){
  216. FD_SET(f0[1], &wfds);
  217. rc = select(m+1, &rfds, &wfds, 0, &tv);
  218. } else
  219. rc = select(m+1, &rfds, 0, 0, &tv);
  220. if ( rc < 0 && errno != EINTR ) {
  221. fprintf(stderr, "select error: %s\n", strerror(errno));
  222. exit(-1);
  223. }
  224. /* FIXME: This should only be triggered if the proc is actually
  225. * sleeping (read(), poll(), select(), etc) on input */
  226. if ( !enable_0 && FD_ISSET(f0[1], &wfds) ) {
  227. write(1, "E", 1);
  228. conn_send(conn, 0, CMD_ENABLE0, 0);
  229. enable_0 = 1;
  230. }
  231. nextread:
  232. if ( schedule_close_0 == 2 )
  233. goto skip_send2p;
  234. while ( send2p )
  235. {
  236. struct sbuf *t;
  237. while ( send2p->len > 0 ) {
  238. rc = write(f0[1], send2p->d, send2p->len);
  239. if ( rc <= 0 ) {
  240. if ( errno == EAGAIN ) goto skip_send2p;
  241. if ( errno == EPIPE ) {
  242. write(1, "[P]", 3);
  243. conn_send(conn, 0, CMD_CLOSE0, 0);
  244. schedule_close_0 = 2;
  245. goto skip_send2p;
  246. }
  247. fprintf(stderr, "write error (%d): %s\n", f0[1], strerror(errno));
  248. exit(-1);
  249. }
  250. send2p->len -= rc;
  251. send2p->d += rc;
  252. fflush(stdout);
  253. }
  254. write(1, "X", 1);
  255. send2p = (t = send2p)->next;
  256. free(t->p); free(t);
  257. }
  258. if ( !send2p ) {
  259. recv4p = 0;
  260. if ( schedule_close_0 ) {
  261. schedule_close_0 = 2;
  262. write(1, "[X]", 3);
  263. close(f0[1]);
  264. }
  265. }
  266. skip_send2p:;
  267. if ( (p = conn_recv(conn, 1)) ) {
  268. if ( p->type == CMD_WRITE0 && open_0 ) {
  269. struct sbuf *t = malloc(sizeof(struct sbuf));
  270. t->next = 0;
  271. t->p = p;
  272. t->len = p->len;
  273. t->d = p->data;
  274. t->c = sbuf_c++;
  275. if ( recv4p )
  276. recv4p->next = t;
  277. else
  278. send2p = t;
  279. recv4p = t;
  280. write(1, "0", 1);
  281. goto nextread;
  282. }
  283. if ( p->type == CMD_CLOSE0 ) {
  284. write(1, "[0]", 3);
  285. if ( !schedule_close_0 )
  286. schedule_close_0 = 1;
  287. open_0 = 0;
  288. }
  289. if ( p->type == CMD_CLOSE0+1 ) {
  290. write(1, "[P1]", 4);
  291. close(f1[0]);
  292. open_1 = 0;
  293. }
  294. if ( p->type == CMD_CLOSE0+2 ) {
  295. write(1, "[P2]", 4);
  296. close(f2[0]);
  297. open_2 = 0;
  298. }
  299. free(p);
  300. goto nextread;
  301. }
  302. if( open_1 )
  303. {
  304. rc = read(f1[0], buf, 512);
  305. if ( rc > 0 ) {
  306. write(1, "1", 1);
  307. conn_send(conn, rc, CMD_WRITE0+1, buf);
  308. goto nextread;
  309. } else if (rc == 0) {
  310. write(1, "[1]", 3);
  311. conn_send(conn, 0, CMD_CLOSE0+1, 0);
  312. open_1 = 0;
  313. } else if ( errno != EAGAIN ) {
  314. perror("Error on read from f1:");
  315. }
  316. }
  317. if( open_2 )
  318. {
  319. rc = read(f2[0], buf, 512);
  320. if ( rc > 0 ) {
  321. write(1, "2", 1);
  322. conn_send(conn, rc, CMD_WRITE0+2, buf);
  323. goto nextread;
  324. } else if (rc == 0) {
  325. write(1, "[2]", 3);
  326. conn_send(conn, 0, CMD_CLOSE0+2, 0);
  327. open_2 = 0;
  328. } else if ( errno != EAGAIN ) {
  329. perror("Error on read from f2:");
  330. }
  331. }
  332. }
  333. write(1, "\n", 1);
  334. wait(&m);
  335. retval = WEXITSTATUS(m);
  336. conn_send(conn, 1, CMD_EXIT, &retval);
  337. printf("RET: %d\n", retval);
  338. }
  339. int main(int argc, char **argv)
  340. {
  341. struct sockaddr_in addr;
  342. int listenfd, fd;
  343. printf("\n");
  344. printf("**********************************************************************\n");
  345. printf("* *\n");
  346. printf("* ROCK Linux Pseudo-Native Daemon by Clifford Wolf *\n");
  347. printf("* *\n");
  348. printf("* This daemon will create subdirectories in the current working *\n");
  349. printf("* directory and mount NFS shares there. There is no authentication *\n");
  350. printf("* implemented - so everyone who can reach the TCP port can also *\n");
  351. printf("* execute commands. So secure the port using iptables! *\n");
  352. printf("* *\n");
  353. printf("**********************************************************************\n");
  354. printf("\n");
  355. signal(SIGCHLD, SIG_IGN);
  356. if ( (listenfd=socket(AF_INET, SOCK_STREAM, 0)) == -1 ) {
  357. fprintf(stderr, "socket: %s\n", strerror(errno));
  358. return 1;
  359. }
  360. bzero(&addr,sizeof(addr));
  361. addr.sin_family=AF_INET;
  362. addr.sin_addr.s_addr = htonl(INADDR_ANY);
  363. addr.sin_port = htons(TCPPORT);
  364. if ( bind(listenfd, (struct sockaddr *)&addr, sizeof(addr)) == -1 ) {
  365. fprintf(stderr, "bind: %s\n", strerror(errno));
  366. return 1;
  367. }
  368. if ( listen(listenfd, 5) == -1 ) {
  369. fprintf(stderr, "listen: %s\n", strerror(errno));
  370. return 1;
  371. }
  372. printf("Listening on TCP port %d ...\n", TCPPORT);
  373. while (1) {
  374. if ( (fd=accept(listenfd, NULL, NULL)) == -1 ) {
  375. fprintf(stderr, "accept: %s\n", strerror(errno));
  376. return 1;
  377. }
  378. if ( !fork() ) {
  379. fprintf(stderr, "\nconnection %d opened.", (int)getpid());
  380. do_session(fd);
  381. return 0;
  382. } else close(fd);
  383. }
  384. return 0;
  385. }