listen.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <auth.h>
  4. #define NAMELEN 64 /* reasonable upper limit for name elements */
  5. typedef struct Service Service;
  6. struct Service
  7. {
  8. char serv[NAMELEN]; /* name of the service */
  9. char remote[3*NAMELEN]; /* address of remote system */
  10. char prog[5*NAMELEN+1]; /* program to execute */
  11. };
  12. typedef struct Announce Announce;
  13. struct Announce
  14. {
  15. Announce *next;
  16. char *a;
  17. int announced;
  18. };
  19. int readstr(char*, char*, char*, int);
  20. void dolisten(char*, char*, int, char*, char*);
  21. void newcall(int, char*, char*, Service*);
  22. int findserv(char*, char*, Service*, char*);
  23. int getserv(char*, char*, Service*);
  24. void error(char*);
  25. void scandir(char*, char*, char*);
  26. void becomenone(void);
  27. void listendir(char*, char*, int);
  28. char listenlog[] = "listen";
  29. int quiet;
  30. char *cpu;
  31. char *proto;
  32. Announce *announcements;
  33. #define SEC 1000
  34. char *namespace;
  35. void
  36. usage(void)
  37. {
  38. error("usage: aux/listen [-q] [-n namespace] [-d servdir] [-t trustdir] [proto]");
  39. }
  40. /*
  41. * based on libthread's threadsetname, but drags in less library code.
  42. * actually just sets the arguments displayed.
  43. */
  44. static void
  45. procsetname(char *fmt, ...)
  46. {
  47. int fd;
  48. char *cmdname;
  49. char buf[128];
  50. va_list arg;
  51. va_start(arg, fmt);
  52. cmdname = vsmprint(fmt, arg);
  53. va_end(arg);
  54. if (cmdname == nil)
  55. return;
  56. snprint(buf, sizeof buf, "#p/%d/args", getpid());
  57. if((fd = open(buf, OWRITE)) >= 0){
  58. write(fd, cmdname, strlen(cmdname)+1);
  59. close(fd);
  60. }
  61. free(cmdname);
  62. }
  63. void
  64. main(int argc, char *argv[])
  65. {
  66. Service *s;
  67. char *protodir;
  68. char *trustdir;
  69. char *servdir;
  70. servdir = 0;
  71. trustdir = 0;
  72. proto = "il";
  73. quiet = 0;
  74. argv0 = argv[0];
  75. cpu = getenv("cputype");
  76. if(cpu == 0)
  77. error("can't get cputype");
  78. ARGBEGIN{
  79. case 'd':
  80. servdir = EARGF(usage());
  81. break;
  82. case 'q':
  83. quiet = 1;
  84. break;
  85. case 't':
  86. trustdir = EARGF(usage());
  87. break;
  88. case 'n':
  89. namespace = EARGF(usage());
  90. break;
  91. default:
  92. usage();
  93. }ARGEND;
  94. if(!servdir && !trustdir)
  95. servdir = "/bin/service";
  96. if(servdir && strlen(servdir) + NAMELEN >= sizeof(s->prog))
  97. error("service directory too long");
  98. if(trustdir && strlen(trustdir) + NAMELEN >= sizeof(s->prog))
  99. error("trusted service directory too long");
  100. switch(argc){
  101. case 1:
  102. proto = argv[0];
  103. break;
  104. case 0:
  105. break;
  106. default:
  107. usage();
  108. }
  109. syslog(0, listenlog, "started on %s", proto);
  110. protodir = proto;
  111. proto = strrchr(proto, '/');
  112. if(proto == 0)
  113. proto = protodir;
  114. else
  115. proto++;
  116. listendir(protodir, servdir, 0);
  117. listendir(protodir, trustdir, 1);
  118. /* command returns */
  119. exits(0);
  120. }
  121. static void
  122. dingdong(void*, char *msg)
  123. {
  124. if(strstr(msg, "alarm") != nil)
  125. noted(NCONT);
  126. noted(NDFLT);
  127. }
  128. void
  129. listendir(char *protodir, char *srvdir, int trusted)
  130. {
  131. int ctl, pid, start;
  132. Announce *a;
  133. char dir[40];
  134. if (srvdir == 0)
  135. return;
  136. /*
  137. * insulate ourselves from later
  138. * changing of console environment variables
  139. * erase privileged crypt state
  140. */
  141. switch(rfork(RFNOTEG|RFPROC|RFFDG|RFNOWAIT|RFENVG|RFNAMEG)) {
  142. case -1:
  143. error("fork");
  144. case 0:
  145. break;
  146. default:
  147. return;
  148. }
  149. procsetname("%s %s %s", protodir, srvdir, namespace);
  150. if (!trusted)
  151. becomenone();
  152. notify(dingdong);
  153. pid = getpid();
  154. for(;;){
  155. /*
  156. * loop through announcements and process trusted services in
  157. * invoker's ns and untrusted in none's.
  158. */
  159. scandir(proto, protodir, srvdir);
  160. for(a = announcements; a; a = a->next){
  161. if(a->announced > 0)
  162. continue;
  163. sleep((pid*10)%200);
  164. /* a process per service */
  165. switch(pid = rfork(RFFDG|RFPROC)){
  166. case -1:
  167. syslog(1, listenlog, "couldn't fork for %s", a->a);
  168. break;
  169. case 0:
  170. for(;;){
  171. ctl = announce(a->a, dir);
  172. if(ctl < 0) {
  173. syslog(1, listenlog,
  174. "giving up on %s: %r", a->a);
  175. exits("ctl");
  176. }
  177. dolisten(proto, dir, ctl, srvdir, a->a);
  178. close(ctl);
  179. }
  180. default:
  181. a->announced = pid;
  182. break;
  183. }
  184. }
  185. /* pick up any children that gave up and sleep for at least 60 seconds */
  186. start = time(0);
  187. alarm(60*1000);
  188. while((pid = waitpid()) > 0)
  189. for(a = announcements; a; a = a->next)
  190. if(a->announced == pid)
  191. a->announced = 0;
  192. alarm(0);
  193. start = 60 - (time(0)-start);
  194. if(start > 0)
  195. sleep(start*1000);
  196. }
  197. /* not reached */
  198. }
  199. /*
  200. * make a list of all services to announce for
  201. */
  202. void
  203. addannounce(char *fmt, ...)
  204. {
  205. Announce *a, **l;
  206. char str[128];
  207. va_list arg;
  208. va_start(arg, fmt);
  209. vseprint(str, str+sizeof(str), fmt, arg);
  210. va_end(arg);
  211. /* look for duplicate */
  212. l = &announcements;
  213. for(a = announcements; a; a = a->next){
  214. if(strcmp(str, a->a) == 0)
  215. return;
  216. l = &a->next;
  217. }
  218. /* accept it */
  219. a = mallocz(sizeof(*a) + strlen(str) + 1, 1);
  220. if(a == 0)
  221. return;
  222. a->a = ((char*)a)+sizeof(*a);
  223. strcpy(a->a, str);
  224. a->announced = 0;
  225. *l = a;
  226. }
  227. void
  228. scandir(char *proto, char *protodir, char *dname)
  229. {
  230. int fd, i, n, nlen;
  231. Dir *db;
  232. fd = open(dname, OREAD);
  233. if(fd < 0)
  234. return;
  235. nlen = strlen(proto);
  236. while((n=dirread(fd, &db)) > 0){
  237. for(i=0; i<n; i++){
  238. if(db[i].qid.type&QTDIR)
  239. continue;
  240. if(strncmp(db[i].name, proto, nlen) != 0)
  241. continue;
  242. addannounce("%s!*!%s", protodir, db[i].name+nlen);
  243. }
  244. free(db);
  245. }
  246. close(fd);
  247. }
  248. void
  249. becomenone(void)
  250. {
  251. int fd;
  252. fd = open("#c/user", OWRITE);
  253. if(fd < 0 || write(fd, "none", strlen("none")) < 0)
  254. error("can't become none");
  255. close(fd);
  256. if(newns("none", namespace) < 0)
  257. error("can't build namespace");
  258. }
  259. void
  260. dolisten(char *proto, char *dir, int ctl, char *srvdir, char *dialstr)
  261. {
  262. Service s;
  263. char ndir[40];
  264. int nctl, data;
  265. procsetname("%s %s", dir, dialstr);
  266. for(;;){
  267. /*
  268. * wait for a call (or an error)
  269. */
  270. nctl = listen(dir, ndir);
  271. if(nctl < 0){
  272. if(!quiet)
  273. syslog(1, listenlog, "listen: %r");
  274. return;
  275. }
  276. /*
  277. * start a subprocess for the connection
  278. */
  279. switch(rfork(RFFDG|RFPROC|RFNOWAIT|RFENVG|RFNAMEG|RFNOTEG)){
  280. case -1:
  281. reject(nctl, ndir, "host overloaded");
  282. close(nctl);
  283. continue;
  284. case 0:
  285. /*
  286. * see if we know the service requested
  287. */
  288. memset(&s, 0, sizeof s);
  289. if(!findserv(proto, ndir, &s, srvdir)){
  290. if(!quiet)
  291. syslog(1, listenlog, "%s: unknown service '%s' from '%s': %r",
  292. proto, s.serv, s.remote);
  293. reject(nctl, ndir, "connection refused");
  294. exits(0);
  295. }
  296. data = accept(nctl, ndir);
  297. if(data < 0){
  298. syslog(1, listenlog, "can't open %s/data: %r", ndir);
  299. exits(0);
  300. }
  301. fprint(nctl, "keepalive");
  302. close(ctl);
  303. close(nctl);
  304. newcall(data, proto, ndir, &s);
  305. exits(0);
  306. default:
  307. close(nctl);
  308. break;
  309. }
  310. }
  311. }
  312. /*
  313. * look in the service directory for the service.
  314. * if the shell script or program is zero-length, ignore it,
  315. * thus providing a way to disable a service with a bind.
  316. */
  317. int
  318. findserv(char *proto, char *dir, Service *s, char *srvdir)
  319. {
  320. int rv;
  321. Dir *d;
  322. if(!getserv(proto, dir, s))
  323. return 0;
  324. snprint(s->prog, sizeof s->prog, "%s/%s", srvdir, s->serv);
  325. d = dirstat(s->prog);
  326. rv = d && d->length > 0;
  327. free(d);
  328. return rv;
  329. }
  330. /*
  331. * get the service name out of the local address
  332. */
  333. int
  334. getserv(char *proto, char *dir, Service *s)
  335. {
  336. char addr[128], *serv, *p;
  337. long n;
  338. readstr(dir, "remote", s->remote, sizeof(s->remote)-1);
  339. if(p = utfrune(s->remote, L'\n'))
  340. *p = '\0';
  341. n = readstr(dir, "local", addr, sizeof(addr)-1);
  342. if(n <= 0)
  343. return 0;
  344. if(p = utfrune(addr, L'\n'))
  345. *p = '\0';
  346. serv = utfrune(addr, L'!');
  347. if(!serv)
  348. serv = "login";
  349. else
  350. serv++;
  351. /*
  352. * disallow service names like
  353. * ../../usr/user/bin/rc/su
  354. */
  355. if(strlen(serv) +strlen(proto) >= NAMELEN || utfrune(serv, L'/') || *serv == '.')
  356. return 0;
  357. snprint(s->serv, sizeof s->serv, "%s%s", proto, serv);
  358. return 1;
  359. }
  360. char *
  361. remoteaddr(char *dir)
  362. {
  363. char buf[128], *p;
  364. int n, fd;
  365. snprint(buf, sizeof buf, "%s/remote", dir);
  366. fd = open(buf, OREAD);
  367. if(fd < 0)
  368. return strdup("");
  369. n = read(fd, buf, sizeof(buf));
  370. close(fd);
  371. if(n > 0){
  372. buf[n] = 0;
  373. p = strchr(buf, '!');
  374. if(p)
  375. *p = 0;
  376. return strdup(buf);
  377. }
  378. return strdup("");
  379. }
  380. void
  381. newcall(int fd, char *proto, char *dir, Service *s)
  382. {
  383. char data[4*NAMELEN];
  384. char *p;
  385. if(!quiet){
  386. if(dir != nil){
  387. p = remoteaddr(dir);
  388. syslog(0, listenlog, "%s call for %s on chan %s (%s)", proto, s->serv, dir, p);
  389. free(p);
  390. } else
  391. syslog(0, listenlog, "%s call for %s on chan %s", proto, s->serv, dir);
  392. }
  393. snprint(data, sizeof data, "%s/data", dir);
  394. bind(data, "/dev/cons", MREPL);
  395. dup(fd, 0);
  396. dup(fd, 1);
  397. dup(fd, 2);
  398. close(fd);
  399. /*
  400. * close all the fds
  401. */
  402. for(fd=3; fd<20; fd++)
  403. close(fd);
  404. execl(s->prog, s->prog, s->serv, proto, dir, nil);
  405. error(s->prog);
  406. }
  407. void
  408. error(char *s)
  409. {
  410. syslog(1, listenlog, "%s: %s: %r", proto, s);
  411. exits(0);
  412. }
  413. /*
  414. * read a string from a device
  415. */
  416. int
  417. readstr(char *dir, char *info, char *s, int len)
  418. {
  419. int n, fd;
  420. char buf[3*NAMELEN+4];
  421. snprint(buf, sizeof buf, "%s/%s", dir, info);
  422. fd = open(buf, OREAD);
  423. if(fd<0)
  424. return 0;
  425. n = read(fd, s, len-1);
  426. if(n<=0){
  427. close(fd);
  428. return -1;
  429. }
  430. s[n] = 0;
  431. close(fd);
  432. return n+1;
  433. }