listen.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  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. static int
  228. ignore(char *srvdir, char *name)
  229. {
  230. int rv;
  231. char *file = smprint("%s/%s", srvdir, name);
  232. Dir *d = dirstat(file);
  233. rv = !d || d->length <= 0; /* ignore unless it's non-empty */
  234. free(d);
  235. free(file);
  236. return rv;
  237. }
  238. void
  239. scandir(char *proto, char *protodir, char *dname)
  240. {
  241. int fd, i, n, nlen;
  242. char *nm;
  243. Dir *db;
  244. fd = open(dname, OREAD);
  245. if(fd < 0)
  246. return;
  247. nlen = strlen(proto);
  248. while((n=dirread(fd, &db)) > 0){
  249. for(i=0; i<n; i++){
  250. nm = db[i].name;
  251. if(db[i].qid.type&QTDIR ||
  252. strncmp(nm, proto, nlen) != 0 ||
  253. ignore(dname, nm))
  254. continue;
  255. addannounce("%s!*!%s", protodir, nm+nlen);
  256. }
  257. free(db);
  258. }
  259. close(fd);
  260. }
  261. void
  262. becomenone(void)
  263. {
  264. int fd;
  265. fd = open("#c/user", OWRITE);
  266. if(fd < 0 || write(fd, "none", strlen("none")) < 0)
  267. error("can't become none");
  268. close(fd);
  269. if(newns("none", namespace) < 0)
  270. error("can't build namespace");
  271. }
  272. void
  273. dolisten(char *proto, char *dir, int ctl, char *srvdir, char *dialstr)
  274. {
  275. Service s;
  276. char ndir[40];
  277. int nctl, data;
  278. procsetname("%s %s", dir, dialstr);
  279. for(;;){
  280. /*
  281. * wait for a call (or an error)
  282. */
  283. nctl = listen(dir, ndir);
  284. if(nctl < 0){
  285. if(!quiet)
  286. syslog(1, listenlog, "listen: %r");
  287. return;
  288. }
  289. /*
  290. * start a subprocess for the connection
  291. */
  292. switch(rfork(RFFDG|RFPROC|RFNOWAIT|RFENVG|RFNAMEG|RFNOTEG)){
  293. case -1:
  294. reject(nctl, ndir, "host overloaded");
  295. close(nctl);
  296. continue;
  297. case 0:
  298. /*
  299. * see if we know the service requested
  300. */
  301. memset(&s, 0, sizeof s);
  302. if(!findserv(proto, ndir, &s, srvdir)){
  303. if(!quiet)
  304. syslog(1, listenlog, "%s: unknown service '%s' from '%s': %r",
  305. proto, s.serv, s.remote);
  306. reject(nctl, ndir, "connection refused");
  307. exits(0);
  308. }
  309. data = accept(nctl, ndir);
  310. if(data < 0){
  311. syslog(1, listenlog, "can't open %s/data: %r", ndir);
  312. exits(0);
  313. }
  314. fprint(nctl, "keepalive");
  315. close(ctl);
  316. close(nctl);
  317. newcall(data, proto, ndir, &s);
  318. exits(0);
  319. default:
  320. close(nctl);
  321. break;
  322. }
  323. }
  324. }
  325. /*
  326. * look in the service directory for the service.
  327. * if the shell script or program is zero-length, ignore it,
  328. * thus providing a way to disable a service with a bind.
  329. */
  330. int
  331. findserv(char *proto, char *dir, Service *s, char *srvdir)
  332. {
  333. int rv;
  334. Dir *d;
  335. if(!getserv(proto, dir, s))
  336. return 0;
  337. snprint(s->prog, sizeof s->prog, "%s/%s", srvdir, s->serv);
  338. d = dirstat(s->prog);
  339. rv = d && d->length > 0; /* ignore unless it's non-empty */
  340. free(d);
  341. return rv;
  342. }
  343. /*
  344. * get the service name out of the local address
  345. */
  346. int
  347. getserv(char *proto, char *dir, Service *s)
  348. {
  349. char addr[128], *serv, *p;
  350. long n;
  351. readstr(dir, "remote", s->remote, sizeof(s->remote)-1);
  352. if(p = utfrune(s->remote, L'\n'))
  353. *p = '\0';
  354. n = readstr(dir, "local", addr, sizeof(addr)-1);
  355. if(n <= 0)
  356. return 0;
  357. if(p = utfrune(addr, L'\n'))
  358. *p = '\0';
  359. serv = utfrune(addr, L'!');
  360. if(!serv)
  361. serv = "login";
  362. else
  363. serv++;
  364. /*
  365. * disallow service names like
  366. * ../../usr/user/bin/rc/su
  367. */
  368. if(strlen(serv) +strlen(proto) >= NAMELEN || utfrune(serv, L'/') || *serv == '.')
  369. return 0;
  370. snprint(s->serv, sizeof s->serv, "%s%s", proto, serv);
  371. return 1;
  372. }
  373. char *
  374. remoteaddr(char *dir)
  375. {
  376. char buf[128], *p;
  377. int n, fd;
  378. snprint(buf, sizeof buf, "%s/remote", dir);
  379. fd = open(buf, OREAD);
  380. if(fd < 0)
  381. return strdup("");
  382. n = read(fd, buf, sizeof(buf));
  383. close(fd);
  384. if(n > 0){
  385. buf[n] = 0;
  386. p = strchr(buf, '!');
  387. if(p)
  388. *p = 0;
  389. return strdup(buf);
  390. }
  391. return strdup("");
  392. }
  393. void
  394. newcall(int fd, char *proto, char *dir, Service *s)
  395. {
  396. char data[4*NAMELEN];
  397. char *p;
  398. if(!quiet){
  399. if(dir != nil){
  400. p = remoteaddr(dir);
  401. syslog(0, listenlog, "%s call for %s on chan %s (%s)", proto, s->serv, dir, p);
  402. free(p);
  403. } else
  404. syslog(0, listenlog, "%s call for %s on chan %s", proto, s->serv, dir);
  405. }
  406. snprint(data, sizeof data, "%s/data", dir);
  407. bind(data, "/dev/cons", MREPL);
  408. dup(fd, 0);
  409. dup(fd, 1);
  410. dup(fd, 2);
  411. close(fd);
  412. /*
  413. * close all the fds
  414. */
  415. for(fd=3; fd<20; fd++)
  416. close(fd);
  417. execl(s->prog, s->prog, s->serv, proto, dir, nil);
  418. error(s->prog);
  419. }
  420. void
  421. error(char *s)
  422. {
  423. syslog(1, listenlog, "%s: %s: %r", proto, s);
  424. exits(0);
  425. }
  426. /*
  427. * read a string from a device
  428. */
  429. int
  430. readstr(char *dir, char *info, char *s, int len)
  431. {
  432. int n, fd;
  433. char buf[3*NAMELEN+4];
  434. snprint(buf, sizeof buf, "%s/%s", dir, info);
  435. fd = open(buf, OREAD);
  436. if(fd<0)
  437. return 0;
  438. n = read(fd, s, len-1);
  439. if(n<=0){
  440. close(fd);
  441. return -1;
  442. }
  443. s[n] = 0;
  444. close(fd);
  445. return n+1;
  446. }