httpd.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <auth.h>
  4. #include <mp.h>
  5. #include <libsec.h>
  6. #include "httpd.h"
  7. #include "httpsrv.h"
  8. typedef struct Strings Strings;
  9. struct Strings
  10. {
  11. char *s1;
  12. char *s2;
  13. };
  14. char *netdir;
  15. char *webroot;
  16. char *HTTPLOG = "httpd/log";
  17. static char netdirb[256];
  18. static char *namespace;
  19. static void becomenone(char*);
  20. static char *csquery(char*, char*, char*);
  21. static void dolisten(char*);
  22. static int doreq(HConnect*);
  23. static int send(HConnect*);
  24. static Strings stripmagic(HConnect*, char*);
  25. static char* stripprefix(char*, char*);
  26. static char* sysdom(void);
  27. static int notfound(HConnect *c, char *url);
  28. uchar *certificate;
  29. int certlen;
  30. void
  31. usage(void)
  32. {
  33. fprint(2, "usage: httpd [-a srvaddress] [-d domain] [-n namespace] [-w webroot]\n");
  34. exits("usage");
  35. }
  36. void
  37. main(int argc, char **argv)
  38. {
  39. char *address;
  40. namespace = nil;
  41. address = nil;
  42. hmydomain = nil;
  43. netdir = "/net";
  44. fmtinstall('D', hdatefmt);
  45. fmtinstall('H', httpfmt);
  46. fmtinstall('U', hurlfmt);
  47. ARGBEGIN{
  48. case 'c':
  49. certificate = readcert(ARGF(), &certlen);
  50. if(certificate == nil)
  51. sysfatal("reading certificate: %r");
  52. break;
  53. case 'n':
  54. namespace = ARGF();
  55. break;
  56. case 'a':
  57. address = ARGF();
  58. break;
  59. case 'd':
  60. hmydomain = ARGF();
  61. break;
  62. case 'w':
  63. webroot = ARGF();
  64. break;
  65. default:
  66. usage();
  67. break;
  68. }ARGEND
  69. if(argc)
  70. usage();
  71. if(namespace == nil)
  72. namespace = "/lib/namespace.httpd";
  73. if(address == nil)
  74. address = "*";
  75. if(webroot == nil)
  76. webroot = "/usr/web";
  77. else{
  78. cleanname(webroot);
  79. if(webroot[0] != '/')
  80. webroot = "/usr/web";
  81. }
  82. switch(rfork(RFNOTEG|RFPROC|RFFDG|RFNAMEG)) {
  83. case -1:
  84. sysfatal("fork");
  85. case 0:
  86. break;
  87. default:
  88. exits(nil);
  89. }
  90. /*
  91. * open all files we might need before castrating namespace
  92. */
  93. time(nil);
  94. if(hmydomain == nil)
  95. hmydomain = sysdom();
  96. syslog(0, HTTPLOG, nil);
  97. logall[0] = open("/sys/log/httpd/0", OWRITE);
  98. logall[1] = open("/sys/log/httpd/1", OWRITE);
  99. redirectinit();
  100. contentinit();
  101. urlinit();
  102. statsinit();
  103. becomenone(namespace);
  104. dolisten(netmkaddr(address, "tcp", certificate == nil ? "http" : "https"));
  105. exits(nil);
  106. }
  107. static void
  108. becomenone(char *namespace)
  109. {
  110. int fd;
  111. fd = open("#c/user", OWRITE);
  112. if(fd < 0 || write(fd, "none", strlen("none")) < 0)
  113. sysfatal("can't become none");
  114. close(fd);
  115. if(newns("none", nil) < 0)
  116. sysfatal("can't build normal namespace");
  117. if(addns("none", namespace) < 0)
  118. sysfatal("can't build httpd namespace");
  119. }
  120. static HConnect*
  121. mkconnect(void)
  122. {
  123. HConnect *c;
  124. c = ezalloc(sizeof(HConnect));
  125. c->hpos = c->header;
  126. c->hstop = c->header;
  127. c->replog = writelog;
  128. return c;
  129. }
  130. static HSPriv*
  131. mkhspriv(void)
  132. {
  133. HSPriv *p;
  134. p = ezalloc(sizeof(HSPriv));
  135. return p;
  136. }
  137. static void
  138. dolisten(char *address)
  139. {
  140. HSPriv *hp;
  141. HConnect *c;
  142. NetConnInfo *nci;
  143. char ndir[NETPATHLEN], dir[NETPATHLEN], *p;
  144. int ctl, nctl, data, t, ok, spotchk;
  145. TLSconn conn;
  146. spotchk = 0;
  147. syslog(0, HTTPLOG, "httpd starting");
  148. ctl = announce(address, dir);
  149. if(ctl < 0){
  150. syslog(0, HTTPLOG, "can't announce on %s: %r", address);
  151. fprint(2, "failed: %d\n", getpid());
  152. for(;;)sleep(1000);
  153. return;
  154. }
  155. strcpy(netdirb, dir);
  156. p = nil;
  157. if(netdir[0] == '/'){
  158. p = strchr(netdirb+1, '/');
  159. if(p != nil)
  160. *p = '\0';
  161. }
  162. if(p == nil)
  163. strcpy(netdirb, "/net");
  164. netdir = netdirb;
  165. for(;;){
  166. /*
  167. * wait for a call (or an error)
  168. */
  169. nctl = listen(dir, ndir);
  170. if(nctl < 0){
  171. syslog(0, HTTPLOG, "can't listen on %s: %r", address);
  172. syslog(0, HTTPLOG, "ctls = %d", ctl);
  173. return;
  174. }
  175. /*
  176. * start a process for the service
  177. */
  178. switch(rfork(RFFDG|RFPROC|RFNOWAIT|RFNAMEG)){
  179. case -1:
  180. close(nctl);
  181. continue;
  182. case 0:
  183. /*
  184. * see if we know the service requested
  185. */
  186. data = accept(ctl, ndir);
  187. if(data >= 0 && certificate != nil){
  188. memset(&conn, 0, sizeof(conn));
  189. conn.cert = certificate;
  190. conn.certlen = certlen;
  191. data = tlsServer(data, &conn);
  192. }
  193. if(data < 0){
  194. syslog(0, HTTPLOG, "can't open %s/data: %r", ndir);
  195. exits(nil);
  196. }
  197. dup(data, 0);
  198. dup(data, 1);
  199. dup(data, 2);
  200. close(data);
  201. close(ctl);
  202. close(nctl);
  203. nci = getnetconninfo(ndir, -1);
  204. c = mkconnect();
  205. hp = mkhspriv();
  206. hp->remotesys = nci->rsys;
  207. hp->remoteserv = nci->rserv;
  208. c->private = hp;
  209. hinit(&c->hin, 0, Hread);
  210. hinit(&c->hout, 1, Hwrite);
  211. /*
  212. * serve requests until a magic request.
  213. * later requests have to come quickly.
  214. * only works for http/1.1 or later.
  215. */
  216. for(t = 15*60*1000; ; t = 15*1000){
  217. if(hparsereq(c, t) <= 0)
  218. exits(nil);
  219. ok = doreq(c);
  220. hflush(&c->hout);
  221. if(c->head.closeit || ok < 0)
  222. exits(nil);
  223. hreqcleanup(c);
  224. }
  225. exits(nil);
  226. default:
  227. close(nctl);
  228. break;
  229. }
  230. if(++spotchk > 50){
  231. spotchk = 0;
  232. redirectinit();
  233. contentinit();
  234. urlinit();
  235. statsinit();
  236. }
  237. }
  238. }
  239. static int
  240. doreq(HConnect *c)
  241. {
  242. HSPriv *hp;
  243. Strings ss;
  244. char *magic, *uri, *origuri, *newpath, *hb;
  245. char virtualhost[100], logfd0[10], logfd1[10], vers[16];
  246. int n;
  247. /*
  248. * munge uri for magic
  249. */
  250. uri = c->req.uri;
  251. ss = stripmagic(c, uri);
  252. uri = ss.s1;
  253. magic = ss.s2;
  254. /*
  255. * for magic we exec a new program and serve no more requests
  256. */
  257. if(magic != nil && strcmp(magic, "httpd") != 0){
  258. snprint(c->xferbuf, HBufSize, "/bin/ip/httpd/%s", magic);
  259. snprint(logfd0, sizeof(logfd0), "%d", logall[0]);
  260. snprint(logfd1, sizeof(logfd1), "%d", logall[1]);
  261. snprint(vers, sizeof(vers), "HTTP/%d.%d", c->req.vermaj, c->req.vermin);
  262. hb = hunload(&c->hin);
  263. if(hb == nil){
  264. hfail(c, HInternal);
  265. return -1;
  266. }
  267. hp = c->private;
  268. execl(c->xferbuf, magic, "-d", hmydomain, "-w", webroot, "-r", hp->remotesys, "-N", netdir, "-b", hb,
  269. "-L", logfd0, logfd1, "-R", c->header,
  270. c->req.meth, vers, uri, c->req.search, nil);
  271. logit(c, "no magic %s uri %s", magic, uri);
  272. hfail(c, HNotFound, uri);
  273. return -1;
  274. }
  275. /*
  276. * normal case is just file transfer
  277. */
  278. origuri = uri;
  279. if(hparseheaders(c, 15*60*1000) < 0)
  280. exits("failed");
  281. if(!http11(c) && !c->head.persist)
  282. c->head.closeit = 1;
  283. if(origuri[0]=='/' && origuri[1]=='~'){
  284. n = strlen(origuri) + 4 + UTFmax;
  285. newpath = halloc(c, n);
  286. snprint(newpath, n, "/who/%s", origuri+2);
  287. c->req.uri = newpath;
  288. uri = newpath;
  289. }else if(origuri[0]=='/' && origuri[1]==0){
  290. snprint(virtualhost, sizeof virtualhost, "http://%s/", c->head.host);
  291. uri = redirect(c, virtualhost);
  292. if(uri == nil)
  293. uri = redirect(c, origuri);
  294. }else
  295. uri = redirect(c, origuri);
  296. if(uri != nil)
  297. return hmoved(c, uri);
  298. return send(c);
  299. }
  300. static int
  301. send(HConnect *c)
  302. {
  303. Dir *dir;
  304. char *w, *p, *masque;
  305. int fd, fd1, n, force301, ok;
  306. if(c->req.search)
  307. return hfail(c, HNoSearch, c->req.uri);
  308. if(strcmp(c->req.meth, "GET") != 0 && strcmp(c->req.meth, "HEAD") != 0)
  309. return hunallowed(c, "GET, HEAD");
  310. if(c->head.expectother || c->head.expectcont)
  311. return hfail(c, HExpectFail);
  312. masque = masquerade(c->head.host);
  313. /*
  314. * check for directory/file mismatch with trailing /,
  315. * and send any redirections.
  316. */
  317. n = strlen(webroot) + strlen(masque) + strlen(c->req.uri) +
  318. STRLEN("/index.html") + STRLEN("/.httplogin") + 1;
  319. w = halloc(c, n);
  320. strcpy(w, webroot);
  321. strcat(w, masque);
  322. strcat(w, c->req.uri);
  323. /*
  324. * don't show the contents of .httplogin
  325. */
  326. n = strlen(w);
  327. if(strcmp(w+n-STRLEN(".httplogin"), ".httplogin") == 0)
  328. return notfound(c, c->req.uri);
  329. fd = open(w, OREAD);
  330. if(fd < 0 && strlen(masque)>0 && strncmp(c->req.uri, masque, strlen(masque)) == 0){
  331. // may be a URI from before virtual hosts; try again without masque
  332. strcpy(w, webroot);
  333. strcat(w, c->req.uri);
  334. fd = open(w, OREAD);
  335. }
  336. if(fd < 0)
  337. return notfound(c, c->req.uri);
  338. dir = dirfstat(fd);
  339. if(dir == nil){
  340. close(fd);
  341. return hfail(c, HInternal);
  342. }
  343. p = strchr(w, '\0');
  344. if(dir->mode & DMDIR){
  345. free(dir);
  346. if(p > w && p[-1] == '/'){
  347. strcat(w, "index.html");
  348. force301 = 0;
  349. }else{
  350. strcat(w, "/index.html");
  351. force301 = 1;
  352. }
  353. fd1 = open(w, OREAD);
  354. if(fd1 < 0){
  355. close(fd);
  356. return notfound(c, c->req.uri);
  357. }
  358. c->req.uri = w + strlen(webroot) + strlen(masque);
  359. if(force301 && c->req.vermaj){
  360. close(fd);
  361. close(fd1);
  362. return hmoved(c, c->req.uri);
  363. }
  364. close(fd);
  365. fd = fd1;
  366. dir = dirfstat(fd);
  367. if(dir == nil){
  368. close(fd);
  369. return hfail(c, HInternal);
  370. }
  371. }else if(p > w && p[-1] == '/'){
  372. free(dir);
  373. close(fd);
  374. *strrchr(c->req.uri, '/') = '\0';
  375. return hmoved(c, c->req.uri);
  376. }
  377. ok = authorize(c, w);
  378. if(ok <= 0){
  379. free(dir);
  380. close(fd);
  381. return ok;
  382. }
  383. return sendfd(c, fd, dir, nil, nil);
  384. }
  385. static Strings
  386. stripmagic(HConnect *hc, char *uri)
  387. {
  388. Strings ss;
  389. char *newuri, *prog, *s;
  390. prog = stripprefix("/magic/", uri);
  391. if(prog == nil){
  392. ss.s1 = uri;
  393. ss.s2 = nil;
  394. return ss;
  395. }
  396. s = strchr(prog, '/');
  397. if(s == nil)
  398. newuri = "";
  399. else{
  400. newuri = hstrdup(hc, s);
  401. *s = 0;
  402. s = strrchr(s, '/');
  403. if(s != nil && s[1] == 0)
  404. *s = 0;
  405. }
  406. ss.s1 = newuri;
  407. ss.s2 = prog;
  408. return ss;
  409. }
  410. static char*
  411. stripprefix(char *pre, char *str)
  412. {
  413. while(*pre)
  414. if(*str++ != *pre++)
  415. return nil;
  416. return str;
  417. }
  418. /*
  419. * couldn't open a file
  420. * figure out why and return and error message
  421. */
  422. static int
  423. notfound(HConnect *c, char *url)
  424. {
  425. c->xferbuf[0] = 0;
  426. errstr(c->xferbuf, sizeof c->xferbuf);
  427. if(strstr(c->xferbuf, "file does not exist") != nil)
  428. return hfail(c, HNotFound, url);
  429. if(strstr(c->xferbuf, "permission denied") != nil)
  430. return hfail(c, HUnauth, url);
  431. return hfail(c, HNotFound, url);
  432. }
  433. static char*
  434. sysdom(void)
  435. {
  436. char *dn;
  437. dn = csquery("sys" , sysname(), "dom");
  438. if(dn == nil)
  439. dn = "who cares";
  440. return dn;
  441. }
  442. /*
  443. * query the connection server
  444. */
  445. static char*
  446. csquery(char *attr, char *val, char *rattr)
  447. {
  448. char token[64+4];
  449. char buf[256], *p, *sp;
  450. int fd, n;
  451. if(val == nil || val[0] == 0)
  452. return nil;
  453. snprint(buf, sizeof(buf), "%s/cs", netdir);
  454. fd = open(buf, ORDWR);
  455. if(fd < 0)
  456. return nil;
  457. fprint(fd, "!%s=%s", attr, val);
  458. seek(fd, 0, 0);
  459. snprint(token, sizeof(token), "%s=", rattr);
  460. for(;;){
  461. n = read(fd, buf, sizeof(buf)-1);
  462. if(n <= 0)
  463. break;
  464. buf[n] = 0;
  465. p = strstr(buf, token);
  466. if(p != nil && (p == buf || *(p-1) == 0)){
  467. close(fd);
  468. sp = strchr(p, ' ');
  469. if(sp)
  470. *sp = 0;
  471. p = strchr(p, '=');
  472. if(p == nil)
  473. return nil;
  474. return estrdup(p+1);
  475. }
  476. }
  477. close(fd);
  478. return nil;
  479. }