listen.c 11 KB

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