]> Raphaël G. Git Repositories - ihttpd/blob - SOURCES/index.bin.c
Initial import
[ihttpd] / SOURCES / index.bin.c
1 /**
2 * This program is free software: you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation, either version 3 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 *
15 * Written by Raphaël Gertz <rapsys@rapsys.eu>
16 */
17
18 //Required for mkostemp, O_CLOEXEC, strdup, memmem
19 #define _GNU_SOURCE
20
21 //Required for SSIZE_MAX, LONG_MAX
22 #include <limits.h>
23
24 //Required for pid_t, kill, waitpid
25 #include <sys/wait.h>
26 #include <signal.h>
27
28 //Required for printf, sscanf, sprintf
29 #include <stdio.h>
30
31 //Required for struct stat, fstat
32 #include <sys/stat.h>
33
34 //Required for closedir, DIR, opendir, readdir, struct dirent
35 #include <dirent.h>
36
37 //Required for close, dup2, execve, fork, read, STDERR_FILENO, STDOUT_FILENO, STDIN_FILENO, write
38 #include <unistd.h>
39
40 //Required for open, O_CLOEXEC, O_NOATIME, O_NOFOLLOW
41 #include <fcntl.h>
42
43 //Required for atoi, calloc, exit, EXIT_FAILURE, EXIT_SUCCESS, free, getenv, malloc, realloc
44 #include <stdlib.h>
45
46 //Required for memchr, memcpy, memmem, strdup, strlen, strncmp
47 #include <string.h>
48
49 //Required for bool
50 #include <stdbool.h>
51
52 //Required for nanosleep
53 #include <time.h>
54
55 //Default passphrase max size
56 #define DEFAULT_PASSPHRASE_SIZE_MAX 512
57
58 //Default keyfile max size
59 //XXX: file should be maximum 8192*1024-1 character long
60 #define DEFAULT_KEYFILE_SIZE_MAX (8192 * 1024)
61
62 //Default crypttab
63 #define CRYPTTAB "/etc/crypttab"
64
65 //Default cryptsetup
66 #define CRYPTSETUP "/sbin/cryptsetup"
67
68 //Default pid file
69 #define IHTTPDPID "/run/ihttpd/ihttpd.pid"
70
71 //Default systemd ask-password dir
72 #define ASKPASSWORDDIR "/run/systemd/ask-password"
73
74 //Define child log
75 #define ASKPASSWORDLOG "/run/ihttpd/log/child.askpassword.log"
76 #define IHTTPDLOG "/run/ihttpd/log/child.ihttpd.log"
77
78 //Create struct for http error status
79 struct httpStatusStruct {
80 int value;
81 char *description;
82 };
83
84 //Declare http error status array
85 const struct httpStatusStruct httpStatuses[] = {
86 {200, "OK"},
87 {400, "Bad Request"},
88 {405, "Method Not Allowed"},
89 {411, "Length Required"},
90 {500, "Internal Server Error"}
91 };
92
93 /**
94 * Prototype
95 */
96 void die(const int, const char*);
97 void header(const int, const char*);
98 void showForm(const char*, const int, const int);
99 int extractValue(char**, int*, char*, int);
100 int extractLuksDevice(char**, char**);
101 int extractIHttpdPid(pid_t *);
102 int extractAskPasswordPid(pid_t *);
103
104 /**
105 * Die with error
106 */
107 void die(const int code, const char *err) {
108 //TODO: see if we add a nice text/html template ?
109 //Send content as text
110 header(code, "text/plain");
111 //Print error line if available
112 if (err != NULL)
113 printf("%s", err);
114 //Flush all
115 if (fflush(NULL) == -1) {
116 perror("fflush");
117 }
118 //Exit with failure code
119 exit(EXIT_FAILURE);
120 }
121
122 /**
123 * Send header
124 */
125 void header(const int code, const char *ctype) {
126 int k;
127 switch(code) {
128 case 400:
129 k = 1;
130 break;
131 case 405:
132 k = 2;
133 break;
134 case 411:
135 k = 3;
136 break;
137 case 500:
138 k = 4;
139 break;
140 default:
141 k = 0;
142 }
143 //Send http status
144 printf("Status: %d %s\r\n", httpStatuses[k].value, httpStatuses[k].description);
145 //Make sure no cache
146 printf("Cache-Control: no-cache, no-store, must-revalidate\r\n");
147 printf("Pragma: no-cache\r\n");
148 printf("Expires: 0\r\n");
149 printf("X-Robots-Tag: noindex, nofollow, noarchive, nosnippet, noodp\r\n");
150 printf("Content-type: %s\r\n\r\n", ctype);
151 }
152
153 /**
154 * Show form
155 */
156 void showForm(const char *requestUri, const int keyfileSizeMax, const int passphraseSizeMax) {
157 header(200, "text/html");
158 printf("<!DOCTYPE HTML>\r\n");
159 printf("<html>\r\n");
160 printf("<head><title>Key upload form</title></head>\r\n");
161 printf("<body>\r\n");
162 printf("<div id=\"wrapper\">\r\n");
163 printf("<form enctype=\"multipart/form-data\" action=\"%s\" method=\"post\"><fieldset><legend>Upload key</legend><label for=\"file\"></label><input type=\"hidden\" name=\"MAX_FILE_SIZE\" value=\"%d\" /><input id=\"file\" type=\"file\" name=\"key\" /><input type=\"submit\" value=\"Send\" /></fieldset></form>\r\n", requestUri, keyfileSizeMax);
164 printf("<form action=\"%s\" method=\"post\"><fieldset><legend>Type key</legend><label for=\"password\"></label><input id=\"password\" type=\"password\" name=\"key\" maxlength=\"%d\" /><input type=\"submit\" value=\"Send\" /></fieldset></form>\r\n", requestUri, passphraseSizeMax);
165 printf("</div>\r\n");
166 printf("</body>\r\n");
167 printf("</html>\r\n");
168 }
169
170 /**
171 * Extract value
172 */
173 int extractValue(char **value, int *valueLength, char *contentType, int contentLength) {
174 //Handle application/x-www-form-urlencoded request
175 if (contentType != NULL && !strncmp(contentType, "application/x-www-form-urlencoded", 33)) {
176 //Indexes and return
177 int i, k, v, r;
178 //Declare key and buf
179 char *key, *buf;
180 //Allocate key
181 if ((key = malloc(4*sizeof(char))) == NULL) {
182 //Unable to allocate key
183 return -1;
184 }
185 //Allocate buf to maximum possible value size + 1 for trailing \0
186 if ((buf = calloc(1, (DEFAULT_PASSPHRASE_SIZE_MAX+1)*sizeof(char))) == NULL) {
187 //Unable to allocate value
188 free(key);
189 return -2;
190 }
191 //Char buffer
192 char d = '\0';
193 //Char delimiter
194 //XXX: initialised as & for new key, becomes = when fetching value
195 char delim = '&';
196 for (i = 0, k = 0, v = 0; i < contentLength; i++) {
197 //Safeguard against a value greater than DEFAULT_PASSPHRASE_SIZE_MAX
198 //XXX: this should never happen because we should be protected by contentLength already
199 if (v == DEFAULT_PASSPHRASE_SIZE_MAX+1) {
200 //Invalid value
201 free(key);
202 free(buf);
203 return -3;
204 }
205 //Read one character from stdin
206 r = read(STDIN_FILENO, &d, 1);
207 //Handle errors
208 if (r < 0) {
209 //Error while parsing post data
210 free(key);
211 free(buf);
212 return -4;
213 } else if (r == 0) {
214 //Partial receive
215 free(key);
216 free(buf);
217 return -5;
218 }
219 //Handle case where key has an other name
220 if (i == 3) {
221 //Check key is "key" and we get '=' as new char and assign delim to =
222 if (strncmp(key, "key", 3) || (delim = d) != '=') {
223 //Invalid key
224 free(key);
225 free(buf);
226 return -6;
227 }
228 //Handle key or value separator in query string
229 } else if (d == '&' || d == '=') {
230 //Invalid query string
231 free(key);
232 free(buf);
233 return -7;
234 //Handle a value
235 } else {
236 //Save key char
237 if (delim == '&') {
238 key[k] = d;
239 k++;
240 //Save buf char
241 } else {
242 buf[v] = d;
243 v++;
244 }
245 }
246 }
247 //Free key
248 free(key);
249 //Unescape and reduce value if not empty
250 if (v > 0) {
251 //Declare iterators
252 int l,m, s = v;
253 //Loop on value and reduce length on the fly
254 for(l=0,m=0; m < v; l++,m++) {
255 //Replace + with space
256 if (buf[m] == '+') {
257 buf[l] = ' ';
258 //Skip partial present %XX
259 } else if (
260 //Assign char
261 (buf[l] = buf[m]) == '%' &&
262 //Check we didn't reach valueStrLength
263 (m+2 < v) &&
264 //Check next two digits are valid
265 ((buf[m+1] >= 'A' && buf[m+1] <= 'F') || (buf[m+1] >= 'a' && buf[m+1] <= 'f') || (buf[m+1] >= '0' && buf[m+1] <= '9')) &&
266 ((buf[m+2] >= 'A' && buf[m+2] <= 'F') || (buf[m+2] >= 'a' && buf[m+2] <= 'f') || (buf[m+2] >= '0' && buf[m+2] <= '9'))
267 ) {
268 buf[l] = (buf[m+1] >= 'A' ? (buf[m+1] & 0xdf) - 'A' + 10 : buf[m+1] - '0') * 16 + (buf[m+2] >= 'A' ? (buf[m+2] & 0xdf) - 'A' + 10 : buf[m+2] - '0');
269 m += 2;
270 s -= 2;
271 }
272 }
273 //Set value length
274 *valueLength = s;
275 //Alloc value
276 if ((*value = malloc((*valueLength)*sizeof(char))) == NULL) {
277 //Unable to alloc value
278 free(key);
279 free(buf);
280 return -8;
281 }
282 //Copy value
283 memcpy(*value, buf, *valueLength);
284 }
285 //Free buf
286 free(buf);
287 //Handle multipart/form-data request
288 } else if (contentType != NULL && !strncmp(contentType, "multipart/form-data", 19)) {
289 //Indexes and return
290 int b, s, r;
291 //Boundary length
292 int boundaryLength = strlen(contentType) - 30 + 1;
293 //Client send LF ending without CR
294 int lfstyle = 0;
295 //Declare boundary
296 char *boundary;
297 //Allocate boundary
298 if ((boundary = calloc(1, boundaryLength*sizeof(char))) == NULL) {
299 //Unable to allocate boundary
300 return -9;
301 }
302 //Extract boundary
303 memcpy(boundary, contentType + 30, boundaryLength - 1);
304
305 //Declare buffers
306 char *start, *buf;
307 //Allocate buffer
308 if ((buf = malloc(contentLength*sizeof(char))) == NULL) {
309 //Unable to allocate buffer
310 free(boundary);
311 return -10;
312 }
313 //Char buffer
314 char d = '\0';
315
316 //Loop
317 for (b = 0, s = 0; b < contentLength; b++) {
318 //Detect possible boundary
319 //XXX: b is boundaryLength-1 + 2 after s
320 //XXX: d will be a CR(CRLF line ending) or LF(LF line ending) or -(of final --)
321 if (b == s + 2 + boundaryLength - 1 && !strncmp(boundary, buf + b - boundaryLength + 1, boundaryLength - 1)) {
322 //Only after first boundary match
323 if (s > 0) {
324 //Trim line jump
325 if (start[0] == '\r' && start[1] == '\n') {
326 start += 2;
327 lfstyle = 1;
328 } else if (start[0] == '\n') {
329 start++;
330 }
331 //Found flag
332 bool found = false;
333 //Allocate pointers
334 char *new = start, *prev = start, *name = NULL;
335 //Search for a new line
336 while ((new = memchr(new, '\n', b - (new - buf)))) {
337 //Jump to first character after new line
338 new++;
339 //Init line length
340 int lineLength = new - prev - 1;
341 //Remove chariage return if necessary
342 if (prev[lineLength] == '\r') {
343 lineLength--;
344 lfstyle = 1;
345 }
346 //Break loop after headers end
347 if (lineLength == 1) {
348 break;
349 }
350 //Allocate a name buf of maximum line length
351 //XXX: need to be filled with zero as we don't know what will comes with sscanf call and we rely on strlen
352 if ((name = calloc(1, lineLength*sizeof(char))) == NULL) {
353 //Unable to allocate name
354 free(boundary);
355 free(buf);
356 return -11;
357 }
358 //Search for name
359 if (sscanf(prev, "Content-Disposition: form-data; name=\"%[^\"]\"", name)) {
360 //Realloc name
361 if ((name = realloc(name, (strlen(name)+1)*sizeof(char))) == NULL) {
362 //Unable to reduce name
363 free(boundary);
364 free(buf);
365 free(name);
366 return -12;
367 }
368 if (!strncmp(name, "key", 3)) {
369 found = true;
370 }
371 }
372 //Free name
373 free(name);
374 //Jump to next one
375 prev = new;
376 }
377 //Init value if found
378 if (found) {
379 //Declare end
380 char *end = buf + b - boundaryLength - 3;
381 //Remove CR at end if provided
382 //XXX: only remove CR at end if we encountered one before
383 if (lfstyle) {
384 end++;
385 }
386 //On too big keyfile
387 if (end - new - 1 >= DEFAULT_KEYFILE_SIZE_MAX) {
388 //Keyfile too large
389 free(boundary);
390 free(buf);
391 return -13;
392 }
393 //On non empty value
394 if (end - new > 1) {
395 //Set value length
396 *valueLength = end - new - 1;
397 //Allocate value
398 if ((*value = malloc((*valueLength)*sizeof(char))) == NULL) {
399 //Unable to allocate value
400 free(boundary);
401 free(buf);
402 return -14;
403 }
404 //Copy value
405 memcpy(*value, new, *valueLength);
406 }
407 }
408 }
409 //Set start to matched boundary
410 start = buf + b;
411 }
412 //Read one character from stdin
413 r = read(STDIN_FILENO, &d, 1);
414 //Handle errors
415 if (r < 0) {
416 //Error while parsing post data
417 free(boundary);
418 free(buf);
419 return -15;
420 } else if (r == 0) {
421 //Partial receive
422 free(boundary);
423 free(buf);
424 return -16;
425 }
426 //New line case
427 if (d == '\n') {
428 //Store new possible boundary start
429 s = b + 1;
430 }
431 buf[b] = d;
432 }
433
434 //Free buffers
435 free(boundary);
436 free(buf);
437 //Unhandled request
438 } else {
439 return -17;
440 }
441
442 //Send value
443 return 0;
444 }
445
446 /**
447 * Extract luks and device
448 */
449 int extractLuksDevice(char **luks, char **device) {
450 //Declare file descriptor
451 int fd, bufLength;
452 //Declare buf, device and luks pointer
453 char *buf, *d, *l;
454 //Declare stat struct
455 struct stat *stats;
456 //Open file
457 if ((fd = open(CRYPTTAB, O_RDONLY|O_NOATIME|O_NOFOLLOW|O_CLOEXEC)) == -1) {
458 //Can't open crypttab file
459 return -1;
460 }
461 //Allocate stats
462 if ((stats = calloc(1, sizeof(struct stat))) == NULL) {
463 //Unable to allocate stats
464 return -2;
465 }
466 //Stat file
467 if (fstat(fd, stats) == -1) {
468 //Can't stat crypttab
469 return -3;
470 }
471 //Check file size
472 if ((bufLength = stats->st_size) > SSIZE_MAX) {
473 //Crypttab too big
474 return -4;
475 }
476 //Allocate buf
477 if ((buf = malloc(bufLength*sizeof(char))) == NULL) {
478 //Unable to allocate buf
479 return -5;
480 }
481 //Read file
482 if ((read(fd, buf, bufLength)) < bufLength) {
483 //Fail to read crypttab file
484 return -6;
485 }
486 //Close file
487 close(fd);
488 //Free stats buffer
489 free(stats);
490
491 //Search first separator (\s|\t) after luks
492 if ((l = memchr(buf, ' ', bufLength)) == NULL && (l = memchr(buf, ' ', bufLength)) == NULL) {
493 return -7;
494 }
495 //Jump to next char
496 l++;
497 //Search first separator (\s|\t) after device
498 if ((d = memchr(l, ' ', bufLength - (l - buf))) == NULL && (d = memchr(l, ' ', bufLength - (l - buf))) == NULL && (d = memchr(l, '\n', bufLength - (l - buf))) == NULL) {
499 return -8;
500 }
501 //Jump to next char
502 d++;
503
504 //Alloc luks
505 if ((*luks = malloc((l - buf - 1)*sizeof(char))) == NULL) {
506 return -9;
507 }
508 //Allocate device
509 if ((*device = malloc((d - l - 1)*sizeof(char))) == NULL) {
510 //Free and reset luks
511 free(luks);
512 luks=NULL;
513 return -10;
514 }
515
516 //Copy luks
517 memcpy(*luks, buf, l - buf - 1);
518 //Terminate luks
519 (*luks)[l - buf - 1] = '\0';
520
521 //Copy device
522 memcpy(*device, l, d - l - 1);
523 //Terminate device
524 (*device)[d - l - 1] = '\0';
525
526 //Free buffer
527 free(buf);
528
529 //Success
530 return 0;
531 }
532
533 /**
534 * Extract ask-password pid
535 */
536 int extractAskPasswordPid(pid_t *pid) {
537 //Declare stuct dirent
538 struct dirent *entry;
539 //Declare askdir
540 DIR *askdir;
541 //Declare found
542 int found = 0;
543
544 //Allocate dirent struct
545 if ((entry = calloc(1, sizeof(struct dirent))) == NULL) {
546 //Unable to allocate entry
547 return -1;
548 }
549
550 //Open systemd ask-password dir
551 if ((askdir = opendir(ASKPASSWORDDIR)) == NULL) {
552 //Can't open ask dir
553 return -2;
554 }
555
556 //Change dir
557 if (chdir(ASKPASSWORDDIR) == -1) {
558 //Can't change to ask dir
559 return -3;
560 }
561
562 //Loop on dir content
563 while((entry = readdir(askdir))) {
564 //Handle each ask.XXXXXX file
565 if (!strncmp(entry->d_name, "ask.", 4) && strlen(entry->d_name) == 10) {
566 //Declare file descriptor
567 int fd, bufLength;
568 //Declare buf
569 char *buf;
570 //Declare stat struct
571 struct stat *stats;
572 //Open file
573 if ((fd = open(entry->d_name, O_RDONLY|O_NOATIME|O_NOFOLLOW|O_CLOEXEC)) == -1) {
574 //Can't open ask file
575 return -4;
576 }
577 //Allocate stats
578 if ((stats = calloc(1, sizeof(struct stat))) == NULL) {
579 //Unable to allocate stats
580 return -5;
581 }
582 //Stat file
583 if (fstat(fd, stats) == -1) {
584 //Can't stat ask file
585 return -6;
586 }
587 //Check file size
588 if ((bufLength = stats->st_size) > SSIZE_MAX) {
589 //Ask file too big
590 return -7;
591 }
592 //Allocate buf
593 if ((buf = malloc(bufLength*sizeof(char))) == NULL) {
594 //Unable to allocate buf
595 return -8;
596 }
597 //Read file
598 if ((read(fd, buf, bufLength)) < bufLength) {
599 //Fail to read ask file
600 return -9;
601 }
602 //Close file
603 close(fd);
604 //Free stats buffer
605 free(stats);
606
607 //Allocate pointers
608 char *nl = buf, *pl = buf, *e;
609 //Allocate pid
610 *pid = 0;
611
612 //Search for a new line
613 while ((nl = memmem(nl, bufLength - (nl - buf), "\n", strlen("\n")))) {
614 //Jump to next char
615 nl++;
616
617 //Check if we have a = in line but not empty value ("=\n")
618 if ((e = memmem(pl, bufLength - (pl - buf), "=", strlen("="))) && e < nl - 2) {
619 //Jump to next char
620 e++;
621 //Look for PID
622 if (!strncmp(pl, "PID", 3)) {
623 //Declade pid string
624 char *pidStr;
625 //Allocate pid string
626 if ((pidStr = malloc((nl - e)*sizeof(char))) == NULL) {
627 //Unable to allocate pid string
628 return -10;
629 }
630 //Copy pid
631 memcpy(pidStr, e, nl - e - 1);
632 //Terminate pid string
633 pidStr[nl - e] = '\0';
634 //Check pid value
635 if ((*pid = atoi(pidStr)) <= 1) {
636 //Invalid pid
637 return -11;
638 }
639 //Free pid string
640 free(pidStr);
641 //Found a valid process
642 found++;
643 }
644 }
645
646 //Jump prev line to new line
647 pl = nl;
648 }
649
650 //Free buffers
651 free(buf);
652 }
653 }
654
655 //Close systemd ask-password dir
656 if (closedir(askdir) == -1) {
657 //Can't close ask dir
658 return -13;
659 }
660
661 //Free entry
662 free(entry);
663
664 //Found no valid pid
665 if (found == 0) {
666 //No pid found
667 return -14;
668 //Found more than one pid
669 } else if (found > 1) {
670 //No pid found
671 return -15;
672 }
673
674 //Success
675 return 0;
676 }
677
678 /**
679 * Extract ihttpd pid
680 */
681 int extractIHttpdPid(pid_t *pid) {
682 //Declare file descriptor
683 int fd, bufLength;
684 //Declare buf, device and luks pointer
685 char *buf, *l, *pidStr;
686 //Declare stat struct
687 struct stat *stats;
688 //Open file
689 if ((fd = open(IHTTPDPID, O_RDONLY|O_NOATIME|O_NOFOLLOW|O_CLOEXEC)) == -1) {
690 //Can't open crypttab file
691 return -1;
692 }
693 //Allocate stats
694 if ((stats = calloc(1, sizeof(struct stat))) == NULL) {
695 //Unable to allocate stats
696 return -2;
697 }
698 //Stat file
699 if (fstat(fd, stats) == -1) {
700 //Can't stat crypttab
701 return -3;
702 }
703 //Check file size
704 if ((bufLength = stats->st_size) > SSIZE_MAX) {
705 //Crypttab too big
706 return -4;
707 }
708 //Allocate buf
709 if ((buf = malloc(bufLength*sizeof(char))) == NULL) {
710 //Unable to allocate buf
711 return -5;
712 }
713 //Read file
714 if ((read(fd, buf, bufLength)) < bufLength) {
715 //Fail to read crypttab file
716 return -6;
717 }
718 //Close file
719 close(fd);
720 //Free stats buffer
721 free(stats);
722
723 //Search first separator (\s|\t|\n) after pid
724 if ((l = memchr(buf, ' ', bufLength)) == NULL && (l = memchr(buf, ' ', bufLength)) == NULL && (l = memchr(buf, '\n', bufLength)) == NULL) {
725 return -7;
726 }
727 //Jump to next char
728 l++;
729
730 //Alloc pid string
731 if ((pidStr = malloc((l - buf - 1)*sizeof(char))) == NULL) {
732 return -9;
733 }
734
735 //Copy luks
736 memcpy(pidStr, buf, l - buf - 1);
737 //Terminate luks
738 pidStr[l - buf - 1] = '\0';
739
740 //Free buffer
741 free(buf);
742
743 //Store pid
744 if ((*pid = atoi(pidStr)) <= 1) {
745 //Invalid pid
746 return -10;
747 }
748
749 //Free pid string
750 free(pidStr);
751
752 //Success
753 return 0;
754 }
755
756 /**
757 * Main function
758 */
759 int main(int argc, char **argv) {
760
761 //Get request method
762 char *requestMethod = getenv("REQUEST_METHOD");
763
764 //Handle unknown requests
765 if (requestMethod == NULL || (strncmp(requestMethod, "GET", 3) && strncmp(requestMethod, "HEAD", 4) && strncmp(requestMethod, "POST", 4))) {
766 //Send method not allowed
767 die(405, "Unsupported request method");
768 //Handle get and head
769 } else if (!strncmp(requestMethod, "GET", 3) || !strncmp(requestMethod, "HEAD", 4)) {
770 //Send form
771 showForm(getenv("REQUEST_URI")?getenv("REQUEST_URI"):"/", DEFAULT_KEYFILE_SIZE_MAX, DEFAULT_PASSPHRASE_SIZE_MAX);
772 //Handle post
773 } else /*if (!strncmp(requestMethod, "POST", 4))*/ {
774 //Return value
775 int ret;
776
777 //Child pid
778 pid_t pid;
779
780 //Value length
781 //XXX: will contain number of char in value without trailing \0
782 int valueLength;
783 //Value string
784 //XXX: will contain value without a tailing \0
785 char *value = NULL;
786
787 //Content length
788 int contentLength;
789 //Content length string from env
790 char *contentLengthStr = getenv("CONTENT_LENGTH");
791 //Content type
792 char *contentType = getenv("CONTENT_TYPE");
793
794 //Declare luks and device
795 char *luks = NULL, *device = NULL;
796
797 //Pairs of pipe for stdin, stdout and stderr
798 int inPipe[2], errPipe[2];
799
800 //Handle unknown content type
801 if (contentType == NULL || (strncmp(contentType, "application/x-www-form-urlencoded", 33) && strncmp(contentType, "multipart/form-data", 19))) {
802 die(400, "Unknown content type");
803 }
804
805 //Handle invalid multipart/form-data content type
806 //XXX: max boundary length is 70 as per rfc1521 & rfc2046
807 if (!strncmp(contentType, "multipart/form-data", 19) && (strncmp(contentType, "multipart/form-data; boundary=", 30) || strlen(contentType) <= 30 || strlen(contentType) > 100)) {
808 die(400, "Malformed boundary in multipart/form-data request");
809 }
810
811 //Handle invalid content length
812 //XXX: deny empty contentLength as chrome send a contentLength even for a device
813 if (contentLengthStr == NULL || (contentLength = atoi(contentLengthStr)) <= 0) {
814 die(411, "Invalid content length");
815 }
816
817 //Handle application/x-www-form-urlencoded request length
818 //XXX: limit to key=xyz where xyz can be all encoded in %XX
819 if (!strncmp(contentType, "application/x-www-form-urlencoded", 33) && contentLength > (DEFAULT_PASSPHRASE_SIZE_MAX * 3 + 4)) {
820 die(400, "Invalid application/x-www-form-urlencoded request length");
821 }
822
823 //Handle multipart/form-data request length
824 //XXX: limit to arbitrary 3 times the keyfile max size
825 if (!strncmp(contentType, "multipart/form-data", 19) && contentLength > (DEFAULT_KEYFILE_SIZE_MAX * 3)) {
826 die(400, "Invalid multipart/form-data request length");
827 }
828
829 //Extract value
830 if ((ret = extractValue(&value, &valueLength, contentType, contentLength)) < 0) {
831 die(500, "Failed to extract value");
832 }
833
834
835 //Extract luks and device
836 if ((ret = extractLuksDevice(&luks, &device)) < 0) {
837 die(500, "Failed to extract luks and device");
838 }
839
840 //Create stdin pipe
841 if (pipe(inPipe) == -1) {
842 die(500, "Failed to create in pipe");
843 }
844
845 //Create stderr pipe
846 if (pipe(errPipe) == -1) {
847 die(500, "Failed to create err pipe");
848 }
849
850 //Fork process
851 if ((pid = fork()) == -1) {
852 die(500, "Failed to fork");
853 }
854
855 //Child process
856 if (pid == 0) {
857 //Child argv
858 char *cargv[] = { CRYPTSETUP, "-d", "-", "luksOpen", device, luks, NULL };
859 char *carge[] = { NULL };
860 //Free value
861 free(value);
862 //Redirect stdin to pipe
863 if (dup2(inPipe[0], STDIN_FILENO) == -1) {
864 die(500, "Failed to redirect in pipe");
865 }
866 //Close inPipe
867 close(inPipe[0]);
868 close(inPipe[1]);
869 //Redirect stderr to pipe
870 if (dup2(errPipe[1], STDERR_FILENO) == -1) {
871 die(500, "Failed to redirect err pipe");
872 }
873 //Close errPipe
874 close(errPipe[0]);
875 close(errPipe[1]);
876 //Call cryptsetup
877 if (execve(CRYPTSETUP, cargv, carge) == -1) {
878 die(500, "Failed to call cryptsetup");
879 }
880 //Parent process
881 } else {
882 //Free luks
883 free(luks);
884 //Free device
885 free(device);
886
887 //Close unused inPipe end
888 close(inPipe[0]);
889 //Close unused errPipe end
890 close(errPipe[1]);
891
892 //Send password on stdin anyway
893 //XXX: this fail if device is already unlocked for example
894 write(inPipe[1], value, valueLength);
895
896 //Free value
897 free(value);
898
899 //Close stdin with EOF
900 close(inPipe[1]);
901
902 //Wait child
903 if (waitpid(pid, &ret, 0) == -1) {
904 die(500, "Failed to wait child");
905 }
906
907 //Handle already unlocked device
908 if (ret == 1280) {
909 die(200, "Device already unlocked");
910 //Handle already in use device
911 } else if (ret == 5) {
912 die(500, "Device already in use");
913 //Handle invalid luks device
914 } else if (ret == 256) {
915 die(500, "Device is now a valid device");
916 //Handle no key available with this passphrase
917 } else if (ret == 512) {
918 die(500, "No slot for this value");
919 //Handle unexisting device or permission denied
920 } else if (ret == 1014) {
921 die(500, "Device doesn't exist or access denied");
922 //Unknown error
923 } else if (ret != 0) {
924 //Err length and counter
925 int errLength = 2048, e = 0;
926 //Declare err buffer
927 char *err;
928 //Buffer char
929 char c;
930 //Alloc err buffer
931 if ((err = malloc(errLength*sizeof(char))) == NULL) {
932 die(500, "Couldn't alloc err buffer");
933 }
934 //Advance after ret code
935 e = sprintf(err, "%d:", ret);
936 //Fetch stderr and store in err buffer
937 while(read(errPipe[0], &c, 1) > 0) {
938 //Grow buffer if we reach end
939 if (e == errLength) {
940 if ((err = realloc(err, (errLength+2048)*sizeof(char))) == NULL) {
941 die(500, "Couldn't grow err buffer");
942 }
943 errLength += 2048;
944 }
945 //Store character
946 err[e] = c;
947 //Pass to next
948 e++;
949 }
950 //Terminate err buffer
951 err[e] = '\0';
952 //Realloc err buffer
953 if ((err = realloc(err, (e+1)*sizeof(char))) == NULL) {
954 die(500, "Couldn't ungrow err buffer");
955 }
956 //Die with luks error
957 die(500, err);
958 }
959 //Close errPipe
960 close(errPipe[0]);
961 }
962
963 //Fork process
964 if ((pid = fork()) == -1) {
965 die(500, "Failed to fork");
966 }
967
968 //IHttpd killing child process
969 if (pid == 0) {
970 //File descriptor
971 int fd;
972
973 //Declare ihttpd pid
974 pid_t ihttpdPid;
975
976 //Close stdin
977 close(STDIN_FILENO);
978
979 //Disable line buffering on stdout and stderr
980 setvbuf(stdout, NULL, _IONBF, 0);
981 setvbuf(stderr, NULL, _IONBF, 0);
982
983 //Redirect output to log
984 if ((fd = open(IHTTPDLOG, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR)) == -1) {
985 fprintf(stderr, "Open ihttpd child log failed\n");
986 } else {
987 //Close stdout
988 close(STDOUT_FILENO);
989 //Redirect stdout on childlog
990 if (dup2(fd, STDOUT_FILENO) == -1) {
991 fprintf(stderr, "Redirect stdout to ihttpd child log failed\n");
992 }
993 //Close stderr
994 close(STDERR_FILENO);
995 //Redirect stderr on childlog
996 if (dup2(fd, STDERR_FILENO) == -1) {
997 fprintf(stderr, "Redirect stderr to ihttpd child log failed\n");
998 }
999 //Close childlog fd
1000 close(fd);
1001 }
1002
1003 //Extract ihttpd pid
1004 if (extractIHttpdPid(&ihttpdPid) < 0) {
1005 fprintf(stderr, "Failed to extract ihttpd pid");
1006 exit(EXIT_FAILURE);
1007 }
1008
1009 //Close stdout and stderr without childlog
1010 if (fd == -1) {
1011 close(STDOUT_FILENO);
1012 close(STDERR_FILENO);
1013 }
1014
1015 //Wait until get rattached to init(getppid()==1)
1016 //XXX: we are really blind here
1017 while(getppid() != 1) {
1018 //Sleep half a second
1019 if (usleep(500000) == -1 && fd != -1) {
1020 printf("Usleep failed\n");
1021 }
1022 }
1023
1024 //Termiate ihttpd
1025 if (kill(ihttpdPid, 0) == 0 && kill(ihttpdPid, SIGTERM) == -1 && fd != -1) {
1026 printf("Termiate ihttpd failed\n");
1027 }
1028
1029 //Sleep half a second
1030 if (usleep(500000) == -1 && fd != -1) {
1031 printf("Usleep failed\n");
1032 }
1033
1034 //Kill ihttpd
1035 if (kill(ihttpdPid, 0) == 0 && kill(ihttpdPid, SIGKILL) == -1) {
1036 printf("Kill ihttpd failed\n");
1037 }
1038
1039 //Parent process
1040 } else {
1041
1042 //Fork process
1043 if ((pid = fork()) == -1) {
1044 die(500, "Failed to fork");
1045 }
1046
1047 //Ask password killing child process
1048 //XXX: we are blind here
1049 if (pid == 0) {
1050 //File descriptor
1051 int fd;
1052
1053 //Declare ask password pid
1054 pid_t askPasswordPid;
1055
1056 //Close stdin
1057 close(STDIN_FILENO);
1058
1059 //Disable line buffering on stdout and stderr
1060 setvbuf(stdout, NULL, _IONBF, 0);
1061 setvbuf(stderr, NULL, _IONBF, 0);
1062
1063 //Redirect output to log
1064 if ((fd = open(ASKPASSWORDLOG, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR)) == -1) {
1065 fprintf(stderr, "Open ask password child log failed\n");
1066 } else {
1067 //Close stdout
1068 close(STDOUT_FILENO);
1069 //Redirect stdout on childlog
1070 if (dup2(fd, STDOUT_FILENO) == -1) {
1071 fprintf(stderr, "Redirect stdout to ask password child log failed\n");
1072 }
1073 //Close stderr
1074 close(STDERR_FILENO);
1075 //Redirect stderr on childlog
1076 if (dup2(fd, STDERR_FILENO) == -1) {
1077 fprintf(stderr, "Redirect stderr to ask password child log failed\n");
1078 }
1079 //Close childlog fd
1080 close(fd);
1081 }
1082
1083 //Extract ask password pid
1084 if (extractAskPasswordPid(&askPasswordPid) < 0) {
1085 fprintf(stderr, "Failed to extract ask password pid");
1086 exit(EXIT_FAILURE);
1087 }
1088
1089 //Close stdout and stderr without childlog
1090 if (fd == -1) {
1091 close(STDOUT_FILENO);
1092 close(STDERR_FILENO);
1093 }
1094
1095 //Wait until get rattached to init(getppid()==1)
1096 //XXX: we are really blind here
1097 while(getppid() != 1) {
1098 //Sleep half a second
1099 if (usleep(500000) == -1 && fd != -1) {
1100 printf("Usleep failed\n");
1101 }
1102 }
1103
1104 //Termitate ask password
1105 if (kill(askPasswordPid, 0) == 0 && kill(askPasswordPid, SIGTERM) == -1 && fd != -1) {
1106 printf("Termiate ask password failed\n");
1107 }
1108
1109
1110 //Sleep half a second
1111 if (usleep(500000) == -1 && fd != -1) {
1112 printf("Usleep failed\n");
1113 }
1114
1115 //Kill ask password
1116 if (kill(askPasswordPid, 0) == 0 && kill(askPasswordPid, SIGKILL) == -1) {
1117 printf("Kill ask password failed\n");
1118 }
1119
1120 //Parent process
1121 } else {
1122
1123 //Process success
1124 header(200, "text/plain");
1125 printf("Sent value, boot should resume now");
1126 fflush(NULL);
1127
1128 }
1129
1130 }
1131
1132 }
1133
1134 exit(EXIT_SUCCESS);
1135 }