listen.c 10 KB

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