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.
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.
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/>.
15 * Written by Raphaël Gertz <rapsys@rapsys.eu>
18 //Required for mkostemp, O_CLOEXEC, strdup, memmem
21 //Required for SSIZE_MAX, LONG_MAX
24 //Required for pid_t, kill, waitpid
28 //Required for printf, sscanf, sprintf
31 //Required for struct stat, fstat
34 //Required for closedir, DIR, opendir, readdir, struct dirent
37 //Required for close, dup2, execve, fork, read, STDERR_FILENO, STDOUT_FILENO, STDIN_FILENO, write
40 //Required for open, O_CLOEXEC, O_NOATIME, O_NOFOLLOW
43 //Required for atoi, calloc, exit, EXIT_FAILURE, EXIT_SUCCESS, free, getenv, malloc, realloc
46 //Required for memchr, memcpy, memmem, strdup, strlen, strncmp
52 //Required for nanosleep
55 //Default passphrase max size
56 #define DEFAULT_PASSPHRASE_SIZE_MAX 512
58 //Default keyfile max size
59 //XXX: file should be maximum 8192*1024-1 character long
60 #define DEFAULT_KEYFILE_SIZE_MAX (8192 * 1024)
63 #define CRYPTTAB "/etc/crypttab"
66 #define CRYPTSETUP "/sbin/cryptsetup"
69 #define SYSTEMDCRYPTSETUP "/usr/lib/systemd/systemd-cryptsetup"
72 #define IHTTPDPID "/run/ihttpd/ihttpd.pid"
74 //Default systemd ask-password dir
75 #define ASKPASSWORDDIR "/run/systemd/ask-password"
78 #define ASKPASSWORDLOG "/run/ihttpd/log/child.askpassword.log"
79 #define IHTTPDLOG "/run/ihttpd/log/child.ihttpd.log"
82 #define FORMID "5903c738"
83 #define FORMURI "/" FORMID ".html"
85 //Create struct for http error status
86 struct httpStatusStruct
{
91 //Declare http error status array
92 const struct httpStatusStruct httpStatuses
[] = {
95 {405, "Method Not Allowed"},
96 {411, "Length Required"},
97 {500, "Internal Server Error"},
98 {503, "Service Unavailable"}
104 void die(const int, const char*);
105 void header(const int, const char*);
106 void showForm(const char*, const int, const int);
107 void showMaintenance();
108 int extractValue(char**, int*, char*, int);
109 int extractLuksDevice(char**, char**);
110 int extractIHttpdPid(pid_t
*);
111 int extractAskPasswordPid(pid_t
*);
116 void die(const int code
, const char *err
) {
117 //TODO: see if we add a nice text/html template ?
118 //Send content as text
119 header(code
, "text/plain");
120 //Print error line if available
124 if (fflush(NULL
) == -1) {
127 //Exit with failure code
134 void header(const int code
, const char *ctype
) {
156 printf("Status: %d %s\r\n", httpStatuses
[k
].value
, httpStatuses
[k
].description
);
158 printf("Cache-Control: no-cache, no-store, must-revalidate\r\n");
159 printf("Pragma: no-cache\r\n");
160 printf("Expires: 0\r\n");
161 printf("X-Robots-Tag: noindex, nofollow, noarchive, nosnippet, noodp\r\n");
162 printf("Content-type: %s\r\n\r\n", ctype
);
168 void showForm(const char *requestUri
, const int keyfileSizeMax
, const int passphraseSizeMax
) {
169 header(503, "text/html");
170 printf("<!DOCTYPE HTML>\r\n");
171 printf("<html>\r\n");
172 printf("<head>\r\n");
173 printf("<title>Key upload form!</title>\r\n");
174 printf("<style type=\"text/css\">body{color:black;background-color:white;}a:link{color:#00c;}p,address{margin-left:3em;}span{font-size:smaller;}</style>\r\n");
175 printf("</head>\r\n");
176 printf("<body>\r\n");
177 printf("<div id=\"wrapper\">\r\n");
178 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
);
179 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
);
180 printf("</div>\r\n");
181 printf("</body>\r\n");
182 printf("</html>\r\n");
188 void showMaintenance() {
189 header(503, "text/html");
190 printf("<!DOCTYPE HTML>\r\n");
191 printf("<html>\r\n");
192 printf("<head>\r\n");
193 printf("<title>Service unavailable!</title>\r\n");
194 printf("<style type=\"text/css\">body{color:black;background-color:white;}a:link{color:#00c;}p,address{margin-left:3em;}span{font-size:smaller;}</style>\r\n");
195 printf("</head>\r\n");
196 printf("<body>\r\n");
197 printf("<h1>Service unavailable!</h1>\r\n");
198 printf("<p>The server is temporarily unable to service your\r\n");
199 printf("request due to maintenance downtime or capacity\r\n");
200 printf("problems. Please try again later.</p>\r\n");
201 printf("<h2>Error 503</h2>\r\n");
202 printf("<address><a href=\"/\">%s</a><br /><span>%s</span></address>\r\n", getenv("SERVER_NAME"), getenv("SERVER_SOFTWARE"));
203 printf("<!--crc32:%s-->\r\n", FORMID
);
204 printf("</body>\r\n");
205 printf("</html>\r\n");
211 int extractValue(char **value
, int *valueLength
, char *contentType
, int contentLength
) {
212 //Handle application/x-www-form-urlencoded request
213 if (contentType
!= NULL
&& !strncmp(contentType
, "application/x-www-form-urlencoded", 33)) {
216 //Declare key and buf
219 if ((key
= malloc(4*sizeof(char))) == NULL
) {
220 //Unable to allocate key
223 //Allocate buf to maximum possible value size + 1 for trailing \0
224 if ((buf
= calloc(1, (DEFAULT_PASSPHRASE_SIZE_MAX
+1)*sizeof(char))) == NULL
) {
225 //Unable to allocate value
232 //XXX: initialised as & for new key, becomes = when fetching value
234 for (i
= 0, k
= 0, v
= 0; i
< contentLength
; i
++) {
235 //Safeguard against a value greater than DEFAULT_PASSPHRASE_SIZE_MAX
236 //XXX: this should never happen because we should be protected by contentLength already
237 if (v
== DEFAULT_PASSPHRASE_SIZE_MAX
+1) {
243 //Read one character from stdin
244 r
= read(STDIN_FILENO
, &d
, 1);
247 //Error while parsing post data
257 //Handle case where key has an other name
259 //Check key is "key" and we get '=' as new char and assign delim to =
260 if (strncmp(key
, "key", 3) || (delim
= d
) != '=') {
266 //Handle key or value separator in query string
267 } else if (d
== '&' || d
== '=') {
268 //Invalid query string
287 //Unescape and reduce value if not empty
291 //Loop on value and reduce length on the fly
292 for(l
=0,m
=0; m
< v
; l
++,m
++) {
293 //Replace + with space
296 //Skip partial present %XX
299 (buf
[l
] = buf
[m
]) == '%' &&
300 //Check we didn't reach valueStrLength
302 //Check next two digits are valid
303 ((buf
[m
+1] >= 'A' && buf
[m
+1] <= 'F') || (buf
[m
+1] >= 'a' && buf
[m
+1] <= 'f') || (buf
[m
+1] >= '0' && buf
[m
+1] <= '9')) &&
304 ((buf
[m
+2] >= 'A' && buf
[m
+2] <= 'F') || (buf
[m
+2] >= 'a' && buf
[m
+2] <= 'f') || (buf
[m
+2] >= '0' && buf
[m
+2] <= '9'))
306 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');
314 if ((*value
= malloc((*valueLength
)*sizeof(char))) == NULL
) {
315 //Unable to alloc value
321 memcpy(*value
, buf
, *valueLength
);
325 //Handle multipart/form-data request
326 } else if (contentType
!= NULL
&& !strncmp(contentType
, "multipart/form-data", 19)) {
330 int boundaryLength
= strlen(contentType
) - 30 + 1;
331 //Client send LF ending without CR
336 if ((boundary
= calloc(1, boundaryLength
*sizeof(char))) == NULL
) {
337 //Unable to allocate boundary
341 memcpy(boundary
, contentType
+ 30, boundaryLength
- 1);
346 if ((buf
= malloc(contentLength
*sizeof(char))) == NULL
) {
347 //Unable to allocate buffer
355 for (b
= 0, s
= 0; b
< contentLength
; b
++) {
356 //Detect possible boundary
357 //XXX: b is boundaryLength-1 + 2 after s
358 //XXX: d will be a CR(CRLF line ending) or LF(LF line ending) or -(of final --)
359 if (b
== s
+ 2 + boundaryLength
- 1 && !strncmp(boundary
, buf
+ b
- boundaryLength
+ 1, boundaryLength
- 1)) {
360 //Only after first boundary match
363 if (start
[0] == '\r' && start
[1] == '\n') {
366 } else if (start
[0] == '\n') {
372 char *new = start
, *prev
= start
, *name
= NULL
;
373 //Search for a new line
374 while ((new = memchr(new, '\n', b
- (new - buf
)))) {
375 //Jump to first character after new line
378 int lineLength
= new - prev
- 1;
379 //Remove chariage return if necessary
380 if (prev
[lineLength
] == '\r') {
384 //Break loop after headers end
385 if (lineLength
== 1) {
388 //Allocate a name buf of maximum line length
389 //XXX: need to be filled with zero as we don't know what will comes with sscanf call and we rely on strlen
390 if ((name
= calloc(1, lineLength
*sizeof(char))) == NULL
) {
391 //Unable to allocate name
397 if (sscanf(prev
, "Content-Disposition: form-data; name=\"%[^\"]\"", name
)) {
399 if ((name
= realloc(name
, (strlen(name
)+1)*sizeof(char))) == NULL
) {
400 //Unable to reduce name
406 if (!strncmp(name
, "key", 3)) {
415 //Init value if found
418 char *end
= buf
+ b
- boundaryLength
- 3;
419 //Remove CR at end if provided
420 //XXX: only remove CR at end if we encountered one before
425 if (end
- new - 1 >= DEFAULT_KEYFILE_SIZE_MAX
) {
434 *valueLength
= end
- new - 1;
436 if ((*value
= malloc((*valueLength
)*sizeof(char))) == NULL
) {
437 //Unable to allocate value
443 memcpy(*value
, new, *valueLength
);
447 //Set start to matched boundary
450 //Read one character from stdin
451 r
= read(STDIN_FILENO
, &d
, 1);
454 //Error while parsing post data
466 //Store new possible boundary start
485 * Extract luks and device
487 int extractLuksDevice(char **luks
, char **device
) {
488 //Declare file descriptor
490 //Declare buf, device and luks pointer
492 //Declare stat struct
495 if ((fd
= open(CRYPTTAB
, O_RDONLY
|O_NOATIME
|O_NOFOLLOW
|O_CLOEXEC
)) == -1) {
496 //Can't open crypttab file
500 if ((stats
= calloc(1, sizeof(struct stat
))) == NULL
) {
501 //Unable to allocate stats
505 if (fstat(fd
, stats
) == -1) {
506 //Can't stat crypttab
510 if ((bufLength
= stats
->st_size
) > SSIZE_MAX
) {
515 if ((buf
= malloc(bufLength
*sizeof(char))) == NULL
) {
516 //Unable to allocate buf
520 if ((read(fd
, buf
, bufLength
)) < bufLength
) {
521 //Fail to read crypttab file
529 //Search first separator (\s|\t) after luks
530 if ((l
= memchr(buf
, ' ', bufLength
)) == NULL
&& (l
= memchr(buf
, ' ', bufLength
)) == NULL
) {
535 //Search first separator (\s|\t) after device
536 if ((d
= memchr(l
, ' ', bufLength
- (l
- buf
))) == NULL
&& (d
= memchr(l
, ' ', bufLength
- (l
- buf
))) == NULL
&& (d
= memchr(l
, '\n', bufLength
- (l
- buf
))) == NULL
) {
543 if ((*luks
= malloc((l
- buf
- 1)*sizeof(char))) == NULL
) {
547 if ((*device
= malloc((d
- l
- 1)*sizeof(char))) == NULL
) {
548 //Free and reset luks
555 memcpy(*luks
, buf
, l
- buf
- 1);
557 (*luks
)[l
- buf
- 1] = '\0';
560 memcpy(*device
, l
, d
- l
- 1);
562 (*device
)[d
- l
- 1] = '\0';
572 * Extract ask-password pid
574 int extractAskPasswordPid(pid_t
*pid
) {
575 //Declare stuct dirent
576 struct dirent
*entry
;
582 //Allocate dirent struct
583 if ((entry
= calloc(1, sizeof(struct dirent
))) == NULL
) {
584 //Unable to allocate entry
588 //Open systemd ask-password dir
589 if ((askdir
= opendir(ASKPASSWORDDIR
)) == NULL
) {
595 if (chdir(ASKPASSWORDDIR
) == -1) {
596 //Can't change to ask dir
600 //Loop on dir content
601 while((entry
= readdir(askdir
))) {
602 //Handle each ask.XXXXXX file
603 if (!strncmp(entry
->d_name
, "ask.", 4) && strlen(entry
->d_name
) == 10) {
604 //Declare file descriptor
608 //Declare stat struct
611 if ((fd
= open(entry
->d_name
, O_RDONLY
|O_NOATIME
|O_NOFOLLOW
|O_CLOEXEC
)) == -1) {
612 //Can't open ask file
616 if ((stats
= calloc(1, sizeof(struct stat
))) == NULL
) {
617 //Unable to allocate stats
621 if (fstat(fd
, stats
) == -1) {
622 //Can't stat ask file
626 if ((bufLength
= stats
->st_size
) > SSIZE_MAX
) {
631 if ((buf
= malloc(bufLength
*sizeof(char))) == NULL
) {
632 //Unable to allocate buf
636 if ((read(fd
, buf
, bufLength
)) < bufLength
) {
637 //Fail to read ask file
646 char *nl
= buf
, *pl
= buf
, *e
;
650 //Search for a new line
651 while ((nl
= memmem(nl
, bufLength
- (nl
- buf
), "\n", strlen("\n")))) {
655 //Check if we have a = in line but not empty value ("=\n")
656 if ((e
= memmem(pl
, bufLength
- (pl
- buf
), "=", strlen("="))) && e
< nl
- 2) {
660 if (!strncmp(pl
, "PID", 3)) {
663 //Allocate pid string
664 if ((pidStr
= malloc((nl
- e
)*sizeof(char))) == NULL
) {
665 //Unable to allocate pid string
669 memcpy(pidStr
, e
, nl
- e
- 1);
670 //Terminate pid string
671 pidStr
[nl
- e
] = '\0';
673 if ((*pid
= atoi(pidStr
)) <= 1) {
679 //Found a valid process
684 //Jump prev line to new line
693 //Close systemd ask-password dir
694 if (closedir(askdir
) == -1) {
695 //Can't close ask dir
706 //Found more than one pid
707 } else if (found
> 1) {
719 int extractIHttpdPid(pid_t
*pid
) {
720 //Declare file descriptor
722 //Declare buf, device and luks pointer
723 char *buf
, *l
, *pidStr
;
724 //Declare stat struct
727 if ((fd
= open(IHTTPDPID
, O_RDONLY
|O_NOATIME
|O_NOFOLLOW
|O_CLOEXEC
)) == -1) {
728 //Can't open crypttab file
732 if ((stats
= calloc(1, sizeof(struct stat
))) == NULL
) {
733 //Unable to allocate stats
737 if (fstat(fd
, stats
) == -1) {
738 //Can't stat crypttab
742 if ((bufLength
= stats
->st_size
) > SSIZE_MAX
) {
747 if ((buf
= malloc(bufLength
*sizeof(char))) == NULL
) {
748 //Unable to allocate buf
752 if ((read(fd
, buf
, bufLength
)) < bufLength
) {
753 //Fail to read crypttab file
761 //Search first separator (\s|\t|\n) after pid
762 if ((l
= memchr(buf
, ' ', bufLength
)) == NULL
&& (l
= memchr(buf
, ' ', bufLength
)) == NULL
&& (l
= memchr(buf
, '\n', bufLength
)) == NULL
) {
769 if ((pidStr
= malloc((l
- buf
- 1)*sizeof(char))) == NULL
) {
774 memcpy(pidStr
, buf
, l
- buf
- 1);
776 pidStr
[l
- buf
- 1] = '\0';
782 if ((*pid
= atoi(pidStr
)) <= 1) {
797 int main(int argc
, char **argv
) {
799 char *requestMethod
= getenv("REQUEST_METHOD");
801 char *requestUri
= getenv("REQUEST_URI");
803 //Handle unknown requests
804 if (requestMethod
== NULL
|| (strncmp(requestMethod
, "GET", 3) && strncmp(requestMethod
, "HEAD", 4) && strncmp(requestMethod
, "POST", 4))) {
805 //Send method not allowed
806 die(405, "Unsupported request method");
807 //Handle get and head
808 } else if (!strncmp(requestMethod
, "GET", 3) || !strncmp(requestMethod
, "HEAD", 4)) {
809 //Check if we have form uri
810 if (requestUri
!= NULL
&& strlen(requestUri
) == strlen(FORMURI
) && !strncmp(requestUri
, FORMURI
, strlen(FORMURI
))) {
812 showForm(requestUri
, DEFAULT_KEYFILE_SIZE_MAX
, DEFAULT_PASSPHRASE_SIZE_MAX
);
813 //Not form uri requested
815 //Send maintenance page
819 } else /*if (!strncmp(requestMethod, "POST", 4))*/ {
827 //XXX: will contain number of char in value without trailing \0
830 //XXX: will contain value without a tailing \0
835 //Content length string from env
836 char *contentLengthStr
= getenv("CONTENT_LENGTH");
838 char *contentType
= getenv("CONTENT_TYPE");
840 //Declare luks and device
841 char *luks
= NULL
, *device
= NULL
;
846 //Pairs of pipe for stdin, stdout and stderr
847 int inPipe
[2], errPipe
[2];
849 //Handle unknown content type
850 if (contentType
== NULL
|| (strncmp(contentType
, "application/x-www-form-urlencoded", 33) && strncmp(contentType
, "multipart/form-data", 19))) {
851 die(400, "Unknown content type");
854 //Handle invalid multipart/form-data content type
855 //XXX: max boundary length is 70 as per rfc1521 & rfc2046
856 if (!strncmp(contentType
, "multipart/form-data", 19) && (strncmp(contentType
, "multipart/form-data; boundary=", 30) || strlen(contentType
) <= 30 || strlen(contentType
) > 100)) {
857 die(400, "Malformed boundary in multipart/form-data request");
860 //Handle invalid content length
861 //XXX: deny empty contentLength as chrome send a contentLength even for a device
862 if (contentLengthStr
== NULL
|| (contentLength
= atoi(contentLengthStr
)) <= 0) {
863 die(411, "Invalid content length");
866 //Handle application/x-www-form-urlencoded request length
867 //XXX: limit to key=xyz where xyz can be all encoded in %XX
868 if (!strncmp(contentType
, "application/x-www-form-urlencoded", 33) && contentLength
> (DEFAULT_PASSPHRASE_SIZE_MAX
* 3 + 4)) {
869 die(400, "Invalid application/x-www-form-urlencoded request length");
872 //Handle multipart/form-data request length
873 //XXX: limit to arbitrary 3 times the keyfile max size
874 if (!strncmp(contentType
, "multipart/form-data", 19) && contentLength
> (DEFAULT_KEYFILE_SIZE_MAX
* 3)) {
875 die(400, "Invalid multipart/form-data request length");
879 if ((ret
= extractValue(&value
, &valueLength
, contentType
, contentLength
)) < 0) {
880 die(500, "Failed to extract value");
883 //Extract luks and device
884 if ((ret
= extractLuksDevice(&luks
, &device
)) < 0) {
885 die(500, "Failed to extract luks and device");
888 //Declare cargv array
889 char *cargvs
[] = { CRYPTSETUP
, "-d", "-", "luksOpen", device
, luks
, NULL
};
890 //TODO: device cannot be an UUID=xyz, a resolved block device is required for it
891 //char *scargvs[] = { SYSTEMDCRYPTSETUP, "attach", luks, device, "-", NULL };
893 //Check cryptsetup binary
894 if (access(CRYPTSETUP
, F_OK
|X_OK
) == -1) {
895 //Check systemdcryptsetup binary
896 if (access(SYSTEMDCRYPTSETUP
, F_OK
|X_OK
) == -1) {
897 die(500, "No cryptsetup available");
900 //TODO: resolve UUID in real device name
901 //TODO: passing password through the socket is not possible, as it rely on password ending with \0
902 die(500, "systemd-cryptsetupd is not implementable");
910 if (pipe(inPipe
) == -1) {
911 die(500, "Failed to create in pipe");
915 if (pipe(errPipe
) == -1) {
916 die(500, "Failed to create err pipe");
920 if ((pid
= fork()) == -1) {
921 die(500, "Failed to fork");
927 char *carge
[] = { NULL
};
930 //Redirect stdin to pipe
931 if (dup2(inPipe
[0], STDIN_FILENO
) == -1) {
932 die(500, "Failed to redirect in pipe");
937 //Redirect stderr to pipe
938 if (dup2(errPipe
[1], STDERR_FILENO
) == -1) {
939 die(500, "Failed to redirect err pipe");
946 if (execve(cargv
[0], cargv
, carge
) == -1) {
947 die(500, "Failed to call cryptsetup");
956 //Close unused inPipe end
958 //Close unused errPipe end
961 //Send password on stdin anyway
962 //XXX: this fail if device is already unlocked for example
963 write(inPipe
[1], value
, valueLength
);
968 //Close stdin with EOF
972 if (waitpid(pid
, &ret
, 0) == -1) {
973 die(500, "Failed to wait child");
976 //Handle already in use device
978 die(500, "Device already in use");
979 //Handle already unlocked device
980 //} else if (ret == 1280) {
981 // die(200, "Device already unlocked");
982 //Handle invalid luks device
983 //} else if (ret == 256) {
984 // die(500, "Device is now a valid device");
985 //Handle no key available with this passphrase
986 } else if (ret
== 512) {
987 die(500, "No slot for this value");
988 //Handle unexisting device or permission denied
989 } else if (ret
== 1014) {
990 die(500, "Device doesn't exist or access denied");
992 } else if (ret
!= 0) {
993 //Err length and counter
994 int errLength
= 2048, e
= 0;
1000 if ((err
= malloc(errLength
*sizeof(char))) == NULL
) {
1001 die(500, "Couldn't alloc err buffer");
1003 //Advance after ret code
1004 e
= sprintf(err
, "%d:", ret
);
1005 //Fetch stderr and store in err buffer
1006 while(read(errPipe
[0], &c
, 1) > 0) {
1007 //Grow buffer if we reach end
1008 if (e
== errLength
) {
1009 if ((err
= realloc(err
, (errLength
+2048)*sizeof(char))) == NULL
) {
1010 die(500, "Couldn't grow err buffer");
1019 //Terminate err buffer
1021 //Realloc err buffer
1022 if ((err
= realloc(err
, (e
+1)*sizeof(char))) == NULL
) {
1023 die(500, "Couldn't ungrow err buffer");
1025 //Die with luks error
1032 //Removed as it was making fail the process of booting sometimes
1035 if ((pid
= fork()) == -1) {
1036 die(500, "Failed to fork");
1039 //IHttpd killing child process
1044 //Declare ihttpd pid
1048 close(STDIN_FILENO
);
1050 //Disable line buffering on stdout and stderr
1051 setvbuf(stdout
, NULL
, _IONBF
, 0);
1052 setvbuf(stderr
, NULL
, _IONBF
, 0);
1054 //Redirect output to log
1055 if ((fd
= open(IHTTPDLOG
, O_CREAT
| O_TRUNC
| O_WRONLY
, S_IRUSR
| S_IWUSR
)) == -1) {
1056 fprintf(stderr
, "Open ihttpd child log failed\n");
1059 close(STDOUT_FILENO
);
1060 //Redirect stdout on childlog
1061 if (dup2(fd
, STDOUT_FILENO
) == -1) {
1062 fprintf(stderr
, "Redirect stdout to ihttpd child log failed\n");
1065 close(STDERR_FILENO
);
1066 //Redirect stderr on childlog
1067 if (dup2(fd
, STDERR_FILENO
) == -1) {
1068 fprintf(stderr
, "Redirect stderr to ihttpd child log failed\n");
1074 //Extract ihttpd pid
1075 if (extractIHttpdPid(&ihttpdPid
) < 0) {
1076 fprintf(stderr
, "Failed to extract ihttpd pid");
1080 //Close stdout and stderr without childlog
1082 close(STDOUT_FILENO
);
1083 close(STDERR_FILENO
);
1086 //Wait until get rattached to init(getppid()==1)
1087 //XXX: we are really blind here
1088 while(getppid() != 1) {
1089 //Sleep half a second
1090 if (usleep(500000) == -1 && fd
!= -1) {
1091 printf("Usleep failed\n");
1096 if (kill(ihttpdPid
, 0) == 0 && kill(ihttpdPid
, SIGTERM
) == -1 && fd
!= -1) {
1097 printf("Termiate ihttpd failed\n");
1100 //Sleep half a second
1101 if (usleep(500000) == -1 && fd
!= -1) {
1102 printf("Usleep failed\n");
1106 if (kill(ihttpdPid
, 0) == 0 && kill(ihttpdPid
, SIGKILL
) == -1) {
1107 printf("Kill ihttpd failed\n");
1114 //Sleep before killing askpassword process
1115 if (usleep(500000) == -1) {
1116 die(500, "Usleep failed");
1120 if ((pid
= fork()) == -1) {
1121 die(500, "Failed to fork");
1124 //Ask password killing child process
1125 //XXX: we are blind here
1130 //Declare ask password pid
1131 pid_t askPasswordPid
;
1134 close(STDIN_FILENO
);
1136 //Disable line buffering on stdout and stderr
1137 setvbuf(stdout
, NULL
, _IONBF
, 0);
1138 setvbuf(stderr
, NULL
, _IONBF
, 0);
1140 //Redirect output to log
1141 if ((fd
= open(ASKPASSWORDLOG
, O_CREAT
| O_TRUNC
| O_WRONLY
, S_IRUSR
| S_IWUSR
)) == -1) {
1142 fprintf(stderr
, "Open ask password child log failed\n");
1145 close(STDOUT_FILENO
);
1146 //Redirect stdout on childlog
1147 if (dup2(fd
, STDOUT_FILENO
) == -1) {
1148 fprintf(stderr
, "Redirect stdout to ask password child log failed\n");
1151 close(STDERR_FILENO
);
1152 //Redirect stderr on childlog
1153 if (dup2(fd
, STDERR_FILENO
) == -1) {
1154 fprintf(stderr
, "Redirect stderr to ask password child log failed\n");
1160 //Extract ask password pid
1161 if (extractAskPasswordPid(&askPasswordPid
) < 0) {
1162 fprintf(stderr
, "Failed to extract ask password pid");
1166 //Close stdout and stderr without childlog
1168 close(STDOUT_FILENO
);
1169 close(STDERR_FILENO
);
1172 //Wait until get rattached to init(getppid()==1)
1173 //XXX: we are really blind here
1174 while(getppid() != 1) {
1175 //Sleep half a second
1176 if (usleep(500000) == -1 && fd
!= -1) {
1177 printf("Usleep failed\n");
1181 //Termitate ask password
1182 if (kill(askPasswordPid
, 0) == 0 && kill(askPasswordPid
, SIGTERM
) == -1 && fd
!= -1) {
1183 printf("Termiate ask password failed\n");
1187 //Sleep half a second
1188 if (usleep(500000) == -1 && fd
!= -1) {
1189 printf("Usleep failed\n");
1193 if (kill(askPasswordPid
, 0) == 0 && kill(askPasswordPid
, SIGKILL
) == -1) {
1194 printf("Kill ask password failed\n");
1201 header(200, "text/plain");
1202 printf("Sent value, boot should resume now");