uhttpd.c 24 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136
  1. /*
  2. * uhttpd - Tiny single-threaded httpd - Main component
  3. *
  4. * Copyright (C) 2010 Jo-Philipp Wich <[email protected]>
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. #define _XOPEN_SOURCE 500 /* crypt() */
  19. #include "uhttpd.h"
  20. #include "uhttpd-utils.h"
  21. #include "uhttpd-file.h"
  22. #ifdef HAVE_CGI
  23. #include "uhttpd-cgi.h"
  24. #endif
  25. #ifdef HAVE_LUA
  26. #include "uhttpd-lua.h"
  27. #endif
  28. #ifdef HAVE_TLS
  29. #include "uhttpd-tls.h"
  30. #endif
  31. static int run = 1;
  32. static void uh_sigterm(int sig)
  33. {
  34. run = 0;
  35. }
  36. static void uh_sigchld(int sig)
  37. {
  38. while( waitpid(-1, NULL, WNOHANG) > 0 ) { }
  39. }
  40. static void uh_config_parse(struct config *conf)
  41. {
  42. FILE *c;
  43. char line[512];
  44. char *col1 = NULL;
  45. char *col2 = NULL;
  46. char *eol = NULL;
  47. const char *path = conf->file ? conf->file : "/etc/httpd.conf";
  48. if( (c = fopen(path, "r")) != NULL )
  49. {
  50. memset(line, 0, sizeof(line));
  51. while( fgets(line, sizeof(line) - 1, c) )
  52. {
  53. if( (line[0] == '/') && (strchr(line, ':') != NULL) )
  54. {
  55. if( !(col1 = strchr(line, ':')) || (*col1++ = 0) ||
  56. !(col2 = strchr(col1, ':')) || (*col2++ = 0) ||
  57. !(eol = strchr(col2, '\n')) || (*eol++ = 0) )
  58. continue;
  59. if( !uh_auth_add(line, col1, col2) )
  60. {
  61. fprintf(stderr,
  62. "Notice: No password set for user %s, ignoring "
  63. "authentication on %s\n", col1, line
  64. );
  65. }
  66. }
  67. else if( !strncmp(line, "I:", 2) )
  68. {
  69. if( !(col1 = strchr(line, ':')) || (*col1++ = 0) ||
  70. !(eol = strchr(col1, '\n')) || (*eol++ = 0) )
  71. continue;
  72. conf->index_file = strdup(col1);
  73. }
  74. else if( !strncmp(line, "E404:", 5) )
  75. {
  76. if( !(col1 = strchr(line, ':')) || (*col1++ = 0) ||
  77. !(eol = strchr(col1, '\n')) || (*eol++ = 0) )
  78. continue;
  79. conf->error_handler = strdup(col1);
  80. }
  81. #ifdef HAVE_CGI
  82. else if( (line[0] == '*') && (strchr(line, ':') != NULL) )
  83. {
  84. if( !(col1 = strchr(line, '*')) || (*col1++ = 0) ||
  85. !(col2 = strchr(col1, ':')) || (*col2++ = 0) ||
  86. !(eol = strchr(col2, '\n')) || (*eol++ = 0) )
  87. continue;
  88. if( !uh_interpreter_add(col1, col2) )
  89. {
  90. fprintf(stderr,
  91. "Unable to add interpreter %s for extension %s: "
  92. "Out of memory\n", col2, col1
  93. );
  94. }
  95. }
  96. #endif
  97. }
  98. fclose(c);
  99. }
  100. }
  101. static int uh_socket_bind(
  102. fd_set *serv_fds, int *max_fd, const char *host, const char *port,
  103. struct addrinfo *hints, int do_tls, struct config *conf
  104. ) {
  105. int sock = -1;
  106. int yes = 1;
  107. int status;
  108. int bound = 0;
  109. int tcp_ka_idl, tcp_ka_int, tcp_ka_cnt;
  110. struct listener *l = NULL;
  111. struct addrinfo *addrs = NULL, *p = NULL;
  112. if( (status = getaddrinfo(host, port, hints, &addrs)) != 0 )
  113. {
  114. fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(status));
  115. }
  116. /* try to bind a new socket to each found address */
  117. for( p = addrs; p; p = p->ai_next )
  118. {
  119. /* get the socket */
  120. if( (sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1 )
  121. {
  122. perror("socket()");
  123. goto error;
  124. }
  125. /* "address already in use" */
  126. if( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) )
  127. {
  128. perror("setsockopt()");
  129. goto error;
  130. }
  131. /* TCP keep-alive */
  132. if( conf->tcp_keepalive > 0 )
  133. {
  134. tcp_ka_idl = 1;
  135. tcp_ka_cnt = 3;
  136. tcp_ka_int = conf->tcp_keepalive;
  137. if( setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes)) ||
  138. setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, &tcp_ka_idl, sizeof(tcp_ka_idl)) ||
  139. setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, &tcp_ka_int, sizeof(tcp_ka_int)) ||
  140. setsockopt(sock, SOL_TCP, TCP_KEEPCNT, &tcp_ka_cnt, sizeof(tcp_ka_cnt)) )
  141. {
  142. fprintf(stderr, "Notice: Unable to enable TCP keep-alive: %s\n",
  143. strerror(errno));
  144. }
  145. }
  146. /* required to get parallel v4 + v6 working */
  147. if( p->ai_family == AF_INET6 )
  148. {
  149. if( setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)) == -1 )
  150. {
  151. perror("setsockopt()");
  152. goto error;
  153. }
  154. }
  155. /* bind */
  156. if( bind(sock, p->ai_addr, p->ai_addrlen) == -1 )
  157. {
  158. perror("bind()");
  159. goto error;
  160. }
  161. /* listen */
  162. if( listen(sock, UH_LIMIT_CLIENTS) == -1 )
  163. {
  164. perror("listen()");
  165. goto error;
  166. }
  167. /* add listener to global list */
  168. if( ! (l = uh_listener_add(sock, conf)) )
  169. {
  170. fprintf(stderr, "uh_listener_add(): Failed to allocate memory\n");
  171. goto error;
  172. }
  173. #ifdef HAVE_TLS
  174. /* init TLS */
  175. l->tls = do_tls ? conf->tls : NULL;
  176. #endif
  177. /* add socket to server fd set */
  178. FD_SET(sock, serv_fds);
  179. fd_cloexec(sock);
  180. *max_fd = max(*max_fd, sock);
  181. bound++;
  182. continue;
  183. error:
  184. if( sock > 0 )
  185. close(sock);
  186. }
  187. freeaddrinfo(addrs);
  188. return bound;
  189. }
  190. static struct http_request * uh_http_header_parse(struct client *cl, char *buffer, int buflen)
  191. {
  192. char *method = &buffer[0];
  193. char *path = NULL;
  194. char *version = NULL;
  195. char *headers = NULL;
  196. char *hdrname = NULL;
  197. char *hdrdata = NULL;
  198. int i;
  199. int hdrcount = 0;
  200. static struct http_request req;
  201. memset(&req, 0, sizeof(req));
  202. /* terminate initial header line */
  203. if( (headers = strfind(buffer, buflen, "\r\n", 2)) != NULL )
  204. {
  205. buffer[buflen-1] = 0;
  206. *headers++ = 0;
  207. *headers++ = 0;
  208. /* find request path */
  209. if( (path = strchr(buffer, ' ')) != NULL )
  210. *path++ = 0;
  211. /* find http version */
  212. if( (path != NULL) && ((version = strchr(path, ' ')) != NULL) )
  213. *version++ = 0;
  214. /* check method */
  215. if( strcmp(method, "GET") && strcmp(method, "HEAD") && strcmp(method, "POST") )
  216. {
  217. /* invalid method */
  218. uh_http_response(cl, 405, "Method Not Allowed");
  219. return NULL;
  220. }
  221. else
  222. {
  223. switch(method[0])
  224. {
  225. case 'G':
  226. req.method = UH_HTTP_MSG_GET;
  227. break;
  228. case 'H':
  229. req.method = UH_HTTP_MSG_HEAD;
  230. break;
  231. case 'P':
  232. req.method = UH_HTTP_MSG_POST;
  233. break;
  234. }
  235. }
  236. /* check path */
  237. if( !path || !strlen(path) )
  238. {
  239. /* malformed request */
  240. uh_http_response(cl, 400, "Bad Request");
  241. return NULL;
  242. }
  243. else
  244. {
  245. req.url = path;
  246. }
  247. /* check version */
  248. if( (version == NULL) || (strcmp(version, "HTTP/0.9") &&
  249. strcmp(version, "HTTP/1.0") && strcmp(version, "HTTP/1.1")) )
  250. {
  251. /* unsupported version */
  252. uh_http_response(cl, 400, "Bad Request");
  253. return NULL;
  254. }
  255. else
  256. {
  257. req.version = strtof(&version[5], NULL);
  258. }
  259. /* process header fields */
  260. for( i = (int)(headers - buffer); i < buflen; i++ )
  261. {
  262. /* found eol and have name + value, push out header tuple */
  263. if( hdrname && hdrdata && (buffer[i] == '\r' || buffer[i] == '\n') )
  264. {
  265. buffer[i] = 0;
  266. /* store */
  267. if( (hdrcount + 1) < array_size(req.headers) )
  268. {
  269. req.headers[hdrcount++] = hdrname;
  270. req.headers[hdrcount++] = hdrdata;
  271. hdrname = hdrdata = NULL;
  272. }
  273. /* too large */
  274. else
  275. {
  276. uh_http_response(cl, 413, "Request Entity Too Large");
  277. return NULL;
  278. }
  279. }
  280. /* have name but no value and found a colon, start of value */
  281. else if( hdrname && !hdrdata &&
  282. ((i+1) < buflen) && (buffer[i] == ':')
  283. ) {
  284. buffer[i] = 0;
  285. hdrdata = &buffer[i+1];
  286. while ((hdrdata + 1) < (buffer + buflen) && *hdrdata == ' ')
  287. hdrdata++;
  288. }
  289. /* have no name and found [A-Za-z], start of name */
  290. else if( !hdrname && isalpha(buffer[i]) )
  291. {
  292. hdrname = &buffer[i];
  293. }
  294. }
  295. /* valid enough */
  296. req.redirect_status = 200;
  297. return &req;
  298. }
  299. /* Malformed request */
  300. uh_http_response(cl, 400, "Bad Request");
  301. return NULL;
  302. }
  303. static struct http_request * uh_http_header_recv(struct client *cl)
  304. {
  305. static char buffer[UH_LIMIT_MSGHEAD];
  306. char *bufptr = &buffer[0];
  307. char *idxptr = NULL;
  308. struct timeval timeout;
  309. fd_set reader;
  310. ssize_t blen = sizeof(buffer)-1;
  311. ssize_t rlen = 0;
  312. memset(buffer, 0, sizeof(buffer));
  313. while( blen > 0 )
  314. {
  315. FD_ZERO(&reader);
  316. FD_SET(cl->socket, &reader);
  317. /* fail after 0.1s */
  318. timeout.tv_sec = 0;
  319. timeout.tv_usec = 100000;
  320. /* check whether fd is readable */
  321. if( select(cl->socket + 1, &reader, NULL, NULL, &timeout) > 0 )
  322. {
  323. /* receive data */
  324. ensure_out(rlen = uh_tcp_peek(cl, bufptr, blen));
  325. if( (idxptr = strfind(buffer, sizeof(buffer), "\r\n\r\n", 4)) )
  326. {
  327. ensure_out(rlen = uh_tcp_recv(cl, bufptr,
  328. (int)(idxptr - bufptr) + 4));
  329. /* header read complete ... */
  330. blen -= rlen;
  331. return uh_http_header_parse(cl, buffer,
  332. sizeof(buffer) - blen - 1);
  333. }
  334. else
  335. {
  336. ensure_out(rlen = uh_tcp_recv(cl, bufptr, rlen));
  337. /* unexpected eof - #7904 */
  338. if( rlen == 0 )
  339. return NULL;
  340. blen -= rlen;
  341. bufptr += rlen;
  342. }
  343. }
  344. else
  345. {
  346. /* invalid request (unexpected eof/timeout) */
  347. return NULL;
  348. }
  349. }
  350. /* request entity too large */
  351. uh_http_response(cl, 413, "Request Entity Too Large");
  352. out:
  353. return NULL;
  354. }
  355. #if defined(HAVE_LUA) || defined(HAVE_CGI)
  356. static int uh_path_match(const char *prefix, const char *url)
  357. {
  358. if( (strstr(url, prefix) == url) &&
  359. ((prefix[strlen(prefix)-1] == '/') ||
  360. (strlen(url) == strlen(prefix)) ||
  361. (url[strlen(prefix)] == '/'))
  362. ) {
  363. return 1;
  364. }
  365. return 0;
  366. }
  367. #endif
  368. static void uh_dispatch_request(
  369. struct client *cl, struct http_request *req, struct path_info *pin
  370. ) {
  371. #ifdef HAVE_CGI
  372. struct interpreter *ipr = NULL;
  373. if( uh_path_match(cl->server->conf->cgi_prefix, pin->name) ||
  374. (ipr = uh_interpreter_lookup(pin->phys)) )
  375. {
  376. uh_cgi_request(cl, req, pin, ipr);
  377. }
  378. else
  379. #endif
  380. {
  381. uh_file_request(cl, req, pin);
  382. }
  383. }
  384. static void uh_mainloop(struct config *conf, fd_set serv_fds, int max_fd)
  385. {
  386. /* master file descriptor list */
  387. fd_set used_fds, read_fds;
  388. /* working structs */
  389. struct http_request *req;
  390. struct path_info *pin;
  391. struct client *cl;
  392. /* maximum file descriptor number */
  393. int new_fd, cur_fd = 0;
  394. /* clear the master and temp sets */
  395. FD_ZERO(&used_fds);
  396. FD_ZERO(&read_fds);
  397. /* backup server descriptor set */
  398. used_fds = serv_fds;
  399. /* loop */
  400. while(run)
  401. {
  402. /* create a working copy of the used fd set */
  403. read_fds = used_fds;
  404. /* sleep until socket activity */
  405. if( select(max_fd + 1, &read_fds, NULL, NULL, NULL) == -1 )
  406. {
  407. perror("select()");
  408. exit(1);
  409. }
  410. /* run through the existing connections looking for data to be read */
  411. for( cur_fd = 0; cur_fd <= max_fd; cur_fd++ )
  412. {
  413. /* is a socket managed by us */
  414. if( FD_ISSET(cur_fd, &read_fds) )
  415. {
  416. /* is one of our listen sockets */
  417. if( FD_ISSET(cur_fd, &serv_fds) )
  418. {
  419. /* handle new connections */
  420. if( (new_fd = accept(cur_fd, NULL, 0)) != -1 )
  421. {
  422. /* add to global client list */
  423. if( (cl = uh_client_add(new_fd, uh_listener_lookup(cur_fd))) != NULL )
  424. {
  425. #ifdef HAVE_TLS
  426. /* setup client tls context */
  427. if( conf->tls )
  428. {
  429. if( conf->tls_accept(cl) < 1 )
  430. {
  431. fprintf(stderr,
  432. "tls_accept failed, "
  433. "connection dropped\n");
  434. /* close client socket */
  435. close(new_fd);
  436. /* remove from global client list */
  437. uh_client_remove(new_fd);
  438. continue;
  439. }
  440. }
  441. #endif
  442. /* add client socket to global fdset */
  443. FD_SET(new_fd, &used_fds);
  444. fd_cloexec(new_fd);
  445. max_fd = max(max_fd, new_fd);
  446. }
  447. /* insufficient resources */
  448. else
  449. {
  450. fprintf(stderr,
  451. "uh_client_add(): Cannot allocate memory\n");
  452. close(new_fd);
  453. }
  454. }
  455. }
  456. /* is a client socket */
  457. else
  458. {
  459. if( ! (cl = uh_client_lookup(cur_fd)) )
  460. {
  461. /* this should not happen! */
  462. fprintf(stderr,
  463. "uh_client_lookup(): No entry for fd %i!\n",
  464. cur_fd);
  465. goto cleanup;
  466. }
  467. /* parse message header */
  468. if( (req = uh_http_header_recv(cl)) != NULL )
  469. {
  470. /* RFC1918 filtering required? */
  471. if( conf->rfc1918_filter &&
  472. sa_rfc1918(&cl->peeraddr) &&
  473. !sa_rfc1918(&cl->servaddr) )
  474. {
  475. uh_http_sendhf(cl, 403, "Forbidden",
  476. "Rejected request from RFC1918 IP "
  477. "to public server address");
  478. }
  479. else
  480. #ifdef HAVE_LUA
  481. /* Lua request? */
  482. if( conf->lua_state &&
  483. uh_path_match(conf->lua_prefix, req->url) )
  484. {
  485. conf->lua_request(cl, req, conf->lua_state);
  486. }
  487. else
  488. #endif
  489. /* dispatch request */
  490. if( (pin = uh_path_lookup(cl, req->url)) != NULL )
  491. {
  492. /* auth ok? */
  493. if( !pin->redirected && uh_auth_check(cl, req, pin) )
  494. uh_dispatch_request(cl, req, pin);
  495. }
  496. /* 404 */
  497. else
  498. {
  499. /* Try to invoke an error handler */
  500. pin = uh_path_lookup(cl, conf->error_handler);
  501. if( pin && uh_auth_check(cl, req, pin) )
  502. {
  503. req->redirect_status = 404;
  504. uh_dispatch_request(cl, req, pin);
  505. }
  506. else
  507. {
  508. uh_http_sendhf(cl, 404, "Not Found",
  509. "No such file or directory");
  510. }
  511. }
  512. }
  513. #ifdef HAVE_TLS
  514. /* free client tls context */
  515. if( conf->tls )
  516. conf->tls_close(cl);
  517. #endif
  518. cleanup:
  519. /* close client socket */
  520. close(cur_fd);
  521. FD_CLR(cur_fd, &used_fds);
  522. /* remove from global client list */
  523. uh_client_remove(cur_fd);
  524. }
  525. }
  526. }
  527. }
  528. #ifdef HAVE_LUA
  529. /* destroy the Lua state */
  530. if( conf->lua_state != NULL )
  531. conf->lua_close(conf->lua_state);
  532. #endif
  533. }
  534. #ifdef HAVE_TLS
  535. static inline int uh_inittls(struct config *conf)
  536. {
  537. /* library handle */
  538. void *lib;
  539. /* already loaded */
  540. if( conf->tls != NULL )
  541. return 0;
  542. /* load TLS plugin */
  543. if( ! (lib = dlopen("uhttpd_tls.so", RTLD_LAZY | RTLD_GLOBAL)) )
  544. {
  545. fprintf(stderr,
  546. "Notice: Unable to load TLS plugin - disabling SSL support! "
  547. "(Reason: %s)\n", dlerror()
  548. );
  549. return 1;
  550. }
  551. else
  552. {
  553. /* resolve functions */
  554. if( !(conf->tls_init = dlsym(lib, "uh_tls_ctx_init")) ||
  555. !(conf->tls_cert = dlsym(lib, "uh_tls_ctx_cert")) ||
  556. !(conf->tls_key = dlsym(lib, "uh_tls_ctx_key")) ||
  557. !(conf->tls_free = dlsym(lib, "uh_tls_ctx_free")) ||
  558. !(conf->tls_accept = dlsym(lib, "uh_tls_client_accept")) ||
  559. !(conf->tls_close = dlsym(lib, "uh_tls_client_close")) ||
  560. !(conf->tls_recv = dlsym(lib, "uh_tls_client_recv")) ||
  561. !(conf->tls_send = dlsym(lib, "uh_tls_client_send"))
  562. ) {
  563. fprintf(stderr,
  564. "Error: Failed to lookup required symbols "
  565. "in TLS plugin: %s\n", dlerror()
  566. );
  567. exit(1);
  568. }
  569. /* init SSL context */
  570. if( ! (conf->tls = conf->tls_init()) )
  571. {
  572. fprintf(stderr, "Error: Failed to initalize SSL context\n");
  573. exit(1);
  574. }
  575. }
  576. return 0;
  577. }
  578. #endif
  579. int main (int argc, char **argv)
  580. {
  581. /* master file descriptor list */
  582. fd_set serv_fds;
  583. /* working structs */
  584. struct addrinfo hints;
  585. struct sigaction sa;
  586. struct config conf;
  587. /* signal mask */
  588. sigset_t ss;
  589. /* maximum file descriptor number */
  590. int cur_fd, max_fd = 0;
  591. #ifdef HAVE_TLS
  592. int tls = 0;
  593. int keys = 0;
  594. #endif
  595. int bound = 0;
  596. int nofork = 0;
  597. /* args */
  598. int opt;
  599. char bind[128];
  600. char *port = NULL;
  601. #ifdef HAVE_LUA
  602. /* library handle */
  603. void *lib;
  604. #endif
  605. FD_ZERO(&serv_fds);
  606. /* handle SIGPIPE, SIGINT, SIGTERM, SIGCHLD */
  607. sa.sa_flags = 0;
  608. sigemptyset(&sa.sa_mask);
  609. sa.sa_handler = SIG_IGN;
  610. sigaction(SIGPIPE, &sa, NULL);
  611. sa.sa_handler = uh_sigchld;
  612. sigaction(SIGCHLD, &sa, NULL);
  613. sa.sa_handler = uh_sigterm;
  614. sigaction(SIGINT, &sa, NULL);
  615. sigaction(SIGTERM, &sa, NULL);
  616. /* defer SIGCHLD */
  617. sigemptyset(&ss);
  618. sigaddset(&ss, SIGCHLD);
  619. sigprocmask(SIG_BLOCK, &ss, NULL);
  620. /* prepare addrinfo hints */
  621. memset(&hints, 0, sizeof(hints));
  622. hints.ai_family = AF_UNSPEC;
  623. hints.ai_socktype = SOCK_STREAM;
  624. hints.ai_flags = AI_PASSIVE;
  625. /* parse args */
  626. memset(&conf, 0, sizeof(conf));
  627. memset(bind, 0, sizeof(bind));
  628. while( (opt = getopt(argc, argv,
  629. "fSDRC:K:E:I:p:s:h:c:l:L:d:r:m:x:i:t:T:A:")) > 0
  630. ) {
  631. switch(opt)
  632. {
  633. /* [addr:]port */
  634. case 'p':
  635. case 's':
  636. if( (port = strrchr(optarg, ':')) != NULL )
  637. {
  638. if( (optarg[0] == '[') && (port > optarg) && (port[-1] == ']') )
  639. memcpy(bind, optarg + 1,
  640. min(sizeof(bind), (int)(port - optarg) - 2));
  641. else
  642. memcpy(bind, optarg,
  643. min(sizeof(bind), (int)(port - optarg)));
  644. port++;
  645. }
  646. else
  647. {
  648. port = optarg;
  649. }
  650. #ifdef HAVE_TLS
  651. if( opt == 's' )
  652. {
  653. if( uh_inittls(&conf) )
  654. {
  655. fprintf(stderr,
  656. "Notice: TLS support is disabled, "
  657. "ignoring '-s %s'\n", optarg
  658. );
  659. continue;
  660. }
  661. tls = 1;
  662. }
  663. #endif
  664. /* bind sockets */
  665. bound += uh_socket_bind(
  666. &serv_fds, &max_fd, bind[0] ? bind : NULL, port,
  667. &hints, (opt == 's'), &conf
  668. );
  669. memset(bind, 0, sizeof(bind));
  670. break;
  671. #ifdef HAVE_TLS
  672. /* certificate */
  673. case 'C':
  674. if( !uh_inittls(&conf) )
  675. {
  676. if( conf.tls_cert(conf.tls, optarg) < 1 )
  677. {
  678. fprintf(stderr,
  679. "Error: Invalid certificate file given\n");
  680. exit(1);
  681. }
  682. keys++;
  683. }
  684. break;
  685. /* key */
  686. case 'K':
  687. if( !uh_inittls(&conf) )
  688. {
  689. if( conf.tls_key(conf.tls, optarg) < 1 )
  690. {
  691. fprintf(stderr,
  692. "Error: Invalid private key file given\n");
  693. exit(1);
  694. }
  695. keys++;
  696. }
  697. break;
  698. #endif
  699. /* docroot */
  700. case 'h':
  701. if( ! realpath(optarg, conf.docroot) )
  702. {
  703. fprintf(stderr, "Error: Invalid directory %s: %s\n",
  704. optarg, strerror(errno));
  705. exit(1);
  706. }
  707. break;
  708. /* error handler */
  709. case 'E':
  710. if( (strlen(optarg) == 0) || (optarg[0] != '/') )
  711. {
  712. fprintf(stderr, "Error: Invalid error handler: %s\n",
  713. optarg);
  714. exit(1);
  715. }
  716. conf.error_handler = optarg;
  717. break;
  718. /* index file */
  719. case 'I':
  720. if( (strlen(optarg) == 0) || (optarg[0] == '/') )
  721. {
  722. fprintf(stderr, "Error: Invalid index page: %s\n",
  723. optarg);
  724. exit(1);
  725. }
  726. conf.index_file = optarg;
  727. break;
  728. /* don't follow symlinks */
  729. case 'S':
  730. conf.no_symlinks = 1;
  731. break;
  732. /* don't list directories */
  733. case 'D':
  734. conf.no_dirlists = 1;
  735. break;
  736. case 'R':
  737. conf.rfc1918_filter = 1;
  738. break;
  739. #ifdef HAVE_CGI
  740. /* cgi prefix */
  741. case 'x':
  742. conf.cgi_prefix = optarg;
  743. break;
  744. /* interpreter */
  745. case 'i':
  746. if( (optarg[0] == '.') && (port = strchr(optarg, '=')) )
  747. {
  748. *port++ = 0;
  749. uh_interpreter_add(optarg, port);
  750. }
  751. else
  752. {
  753. fprintf(stderr, "Error: Invalid interpreter: %s\n",
  754. optarg);
  755. exit(1);
  756. }
  757. break;
  758. #endif
  759. #ifdef HAVE_LUA
  760. /* lua prefix */
  761. case 'l':
  762. conf.lua_prefix = optarg;
  763. break;
  764. /* lua handler */
  765. case 'L':
  766. conf.lua_handler = optarg;
  767. break;
  768. #endif
  769. #if defined(HAVE_CGI) || defined(HAVE_LUA)
  770. /* script timeout */
  771. case 't':
  772. conf.script_timeout = atoi(optarg);
  773. break;
  774. #endif
  775. /* network timeout */
  776. case 'T':
  777. conf.network_timeout = atoi(optarg);
  778. break;
  779. /* tcp keep-alive */
  780. case 'A':
  781. conf.tcp_keepalive = atoi(optarg);
  782. break;
  783. /* no fork */
  784. case 'f':
  785. nofork = 1;
  786. break;
  787. /* urldecode */
  788. case 'd':
  789. if( (port = malloc(strlen(optarg)+1)) != NULL )
  790. {
  791. /* "decode" plus to space to retain compat */
  792. for (opt = 0; optarg[opt]; opt++)
  793. if (optarg[opt] == '+')
  794. optarg[opt] = ' ';
  795. memset(port, 0, strlen(optarg)+1);
  796. uh_urldecode(port, strlen(optarg), optarg, strlen(optarg));
  797. printf("%s", port);
  798. free(port);
  799. exit(0);
  800. }
  801. break;
  802. /* basic auth realm */
  803. case 'r':
  804. conf.realm = optarg;
  805. break;
  806. /* md5 crypt */
  807. case 'm':
  808. printf("%s\n", crypt(optarg, "$1$"));
  809. exit(0);
  810. break;
  811. /* config file */
  812. case 'c':
  813. conf.file = optarg;
  814. break;
  815. default:
  816. fprintf(stderr,
  817. "Usage: %s -p [addr:]port [-h docroot]\n"
  818. " -f Do not fork to background\n"
  819. " -c file Configuration file, default is '/etc/httpd.conf'\n"
  820. " -p [addr:]port Bind to specified address and port, multiple allowed\n"
  821. #ifdef HAVE_TLS
  822. " -s [addr:]port Like -p but provide HTTPS on this port\n"
  823. " -C file ASN.1 server certificate file\n"
  824. " -K file ASN.1 server private key file\n"
  825. #endif
  826. " -h directory Specify the document root, default is '.'\n"
  827. " -E string Use given virtual URL as 404 error handler\n"
  828. " -I string Use given filename as index page for directories\n"
  829. " -S Do not follow symbolic links outside of the docroot\n"
  830. " -D Do not allow directory listings, send 403 instead\n"
  831. " -R Enable RFC1918 filter\n"
  832. #ifdef HAVE_LUA
  833. " -l string URL prefix for Lua handler, default is '/lua'\n"
  834. " -L file Lua handler script, omit to disable Lua\n"
  835. #endif
  836. #ifdef HAVE_CGI
  837. " -x string URL prefix for CGI handler, default is '/cgi-bin'\n"
  838. " -i .ext=path Use interpreter at path for files with the given extension\n"
  839. #endif
  840. #if defined(HAVE_CGI) || defined(HAVE_LUA)
  841. " -t seconds CGI and Lua script timeout in seconds, default is 60\n"
  842. #endif
  843. " -T seconds Network timeout in seconds, default is 30\n"
  844. " -d string URL decode given string\n"
  845. " -r string Specify basic auth realm\n"
  846. " -m string MD5 crypt given string\n"
  847. "\n", argv[0]
  848. );
  849. exit(1);
  850. }
  851. }
  852. #ifdef HAVE_TLS
  853. if( (tls == 1) && (keys < 2) )
  854. {
  855. fprintf(stderr, "Error: Missing private key or certificate file\n");
  856. exit(1);
  857. }
  858. #endif
  859. if( bound < 1 )
  860. {
  861. fprintf(stderr, "Error: No sockets bound, unable to continue\n");
  862. exit(1);
  863. }
  864. /* default docroot */
  865. if( !conf.docroot[0] && !realpath(".", conf.docroot) )
  866. {
  867. fprintf(stderr, "Error: Can not determine default document root: %s\n",
  868. strerror(errno));
  869. exit(1);
  870. }
  871. /* default realm */
  872. if( ! conf.realm )
  873. conf.realm = "Protected Area";
  874. /* config file */
  875. uh_config_parse(&conf);
  876. /* default network timeout */
  877. if( conf.network_timeout <= 0 )
  878. conf.network_timeout = 30;
  879. #if defined(HAVE_CGI) || defined(HAVE_LUA)
  880. /* default script timeout */
  881. if( conf.script_timeout <= 0 )
  882. conf.script_timeout = 60;
  883. #endif
  884. #ifdef HAVE_CGI
  885. /* default cgi prefix */
  886. if( ! conf.cgi_prefix )
  887. conf.cgi_prefix = "/cgi-bin";
  888. #endif
  889. #ifdef HAVE_LUA
  890. /* load Lua plugin */
  891. if( ! (lib = dlopen("uhttpd_lua.so", RTLD_LAZY | RTLD_GLOBAL)) )
  892. {
  893. fprintf(stderr,
  894. "Notice: Unable to load Lua plugin - disabling Lua support! "
  895. "(Reason: %s)\n", dlerror()
  896. );
  897. }
  898. else
  899. {
  900. /* resolve functions */
  901. if( !(conf.lua_init = dlsym(lib, "uh_lua_init")) ||
  902. !(conf.lua_close = dlsym(lib, "uh_lua_close")) ||
  903. !(conf.lua_request = dlsym(lib, "uh_lua_request"))
  904. ) {
  905. fprintf(stderr,
  906. "Error: Failed to lookup required symbols "
  907. "in Lua plugin: %s\n", dlerror()
  908. );
  909. exit(1);
  910. }
  911. /* init Lua runtime if handler is specified */
  912. if( conf.lua_handler )
  913. {
  914. /* default lua prefix */
  915. if( ! conf.lua_prefix )
  916. conf.lua_prefix = "/lua";
  917. conf.lua_state = conf.lua_init(conf.lua_handler);
  918. }
  919. }
  920. #endif
  921. /* fork (if not disabled) */
  922. if( ! nofork )
  923. {
  924. switch( fork() )
  925. {
  926. case -1:
  927. perror("fork()");
  928. exit(1);
  929. case 0:
  930. /* daemon setup */
  931. if( chdir("/") )
  932. perror("chdir()");
  933. if( (cur_fd = open("/dev/null", O_WRONLY)) > -1 )
  934. dup2(cur_fd, 0);
  935. if( (cur_fd = open("/dev/null", O_RDONLY)) > -1 )
  936. dup2(cur_fd, 1);
  937. if( (cur_fd = open("/dev/null", O_RDONLY)) > -1 )
  938. dup2(cur_fd, 2);
  939. break;
  940. default:
  941. exit(0);
  942. }
  943. }
  944. /* server main loop */
  945. uh_mainloop(&conf, serv_fds, max_fd);
  946. #ifdef HAVE_LUA
  947. /* destroy the Lua state */
  948. if( conf.lua_state != NULL )
  949. conf.lua_close(conf.lua_state);
  950. #endif
  951. return 0;
  952. }