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 IHTTPDPID "/run/ihttpd/ihttpd.pid"
71 //Default systemd ask-password dir
72 #define ASKPASSWORDDIR "/run/systemd/ask-password"
75 #define ASKPASSWORDLOG "/run/ihttpd/log/child.askpassword.log"
76 #define IHTTPDLOG "/run/ihttpd/log/child.ihttpd.log"
78 //Create struct for http error status
79 struct httpStatusStruct
{
84 //Declare http error status array
85 const struct httpStatusStruct httpStatuses
[] = {
88 {405, "Method Not Allowed"},
89 {411, "Length Required"},
90 {500, "Internal Server Error"}
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
*);
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
115 if (fflush(NULL
) == -1) {
118 //Exit with failure code
125 void header(const int code
, const char *ctype
) {
144 printf("Status: %d %s\r\n", httpStatuses
[k
].value
, httpStatuses
[k
].description
);
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
);
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");
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)) {
178 //Declare key and buf
181 if ((key
= malloc(4*sizeof(char))) == NULL
) {
182 //Unable to allocate key
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
194 //XXX: initialised as & for new key, becomes = when fetching value
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) {
205 //Read one character from stdin
206 r
= read(STDIN_FILENO
, &d
, 1);
209 //Error while parsing post data
219 //Handle case where key has an other name
221 //Check key is "key" and we get '=' as new char and assign delim to =
222 if (strncmp(key
, "key", 3) || (delim
= d
) != '=') {
228 //Handle key or value separator in query string
229 } else if (d
== '&' || d
== '=') {
230 //Invalid query string
249 //Unescape and reduce value if not empty
253 //Loop on value and reduce length on the fly
254 for(l
=0,m
=0; m
< v
; l
++,m
++) {
255 //Replace + with space
258 //Skip partial present %XX
261 (buf
[l
] = buf
[m
]) == '%' &&
262 //Check we didn't reach valueStrLength
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'))
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');
276 if ((*value
= malloc((*valueLength
)*sizeof(char))) == NULL
) {
277 //Unable to alloc value
283 memcpy(*value
, buf
, *valueLength
);
287 //Handle multipart/form-data request
288 } else if (contentType
!= NULL
&& !strncmp(contentType
, "multipart/form-data", 19)) {
292 int boundaryLength
= strlen(contentType
) - 30 + 1;
293 //Client send LF ending without CR
298 if ((boundary
= calloc(1, boundaryLength
*sizeof(char))) == NULL
) {
299 //Unable to allocate boundary
303 memcpy(boundary
, contentType
+ 30, boundaryLength
- 1);
308 if ((buf
= malloc(contentLength
*sizeof(char))) == NULL
) {
309 //Unable to allocate buffer
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
325 if (start
[0] == '\r' && start
[1] == '\n') {
328 } else if (start
[0] == '\n') {
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
340 int lineLength
= new - prev
- 1;
341 //Remove chariage return if necessary
342 if (prev
[lineLength
] == '\r') {
346 //Break loop after headers end
347 if (lineLength
== 1) {
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
359 if (sscanf(prev
, "Content-Disposition: form-data; name=\"%[^\"]\"", name
)) {
361 if ((name
= realloc(name
, (strlen(name
)+1)*sizeof(char))) == NULL
) {
362 //Unable to reduce name
368 if (!strncmp(name
, "key", 3)) {
377 //Init value if found
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
387 if (end
- new - 1 >= DEFAULT_KEYFILE_SIZE_MAX
) {
396 *valueLength
= end
- new - 1;
398 if ((*value
= malloc((*valueLength
)*sizeof(char))) == NULL
) {
399 //Unable to allocate value
405 memcpy(*value
, new, *valueLength
);
409 //Set start to matched boundary
412 //Read one character from stdin
413 r
= read(STDIN_FILENO
, &d
, 1);
416 //Error while parsing post data
428 //Store new possible boundary start
447 * Extract luks and device
449 int extractLuksDevice(char **luks
, char **device
) {
450 //Declare file descriptor
452 //Declare buf, device and luks pointer
454 //Declare stat struct
457 if ((fd
= open(CRYPTTAB
, O_RDONLY
|O_NOATIME
|O_NOFOLLOW
|O_CLOEXEC
)) == -1) {
458 //Can't open crypttab file
462 if ((stats
= calloc(1, sizeof(struct stat
))) == NULL
) {
463 //Unable to allocate stats
467 if (fstat(fd
, stats
) == -1) {
468 //Can't stat crypttab
472 if ((bufLength
= stats
->st_size
) > SSIZE_MAX
) {
477 if ((buf
= malloc(bufLength
*sizeof(char))) == NULL
) {
478 //Unable to allocate buf
482 if ((read(fd
, buf
, bufLength
)) < bufLength
) {
483 //Fail to read crypttab file
491 //Search first separator (\s|\t) after luks
492 if ((l
= memchr(buf
, ' ', bufLength
)) == NULL
&& (l
= memchr(buf
, ' ', bufLength
)) == NULL
) {
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
) {
505 if ((*luks
= malloc((l
- buf
- 1)*sizeof(char))) == NULL
) {
509 if ((*device
= malloc((d
- l
- 1)*sizeof(char))) == NULL
) {
510 //Free and reset luks
517 memcpy(*luks
, buf
, l
- buf
- 1);
519 (*luks
)[l
- buf
- 1] = '\0';
522 memcpy(*device
, l
, d
- l
- 1);
524 (*device
)[d
- l
- 1] = '\0';
534 * Extract ask-password pid
536 int extractAskPasswordPid(pid_t
*pid
) {
537 //Declare stuct dirent
538 struct dirent
*entry
;
544 //Allocate dirent struct
545 if ((entry
= calloc(1, sizeof(struct dirent
))) == NULL
) {
546 //Unable to allocate entry
550 //Open systemd ask-password dir
551 if ((askdir
= opendir(ASKPASSWORDDIR
)) == NULL
) {
557 if (chdir(ASKPASSWORDDIR
) == -1) {
558 //Can't change to ask dir
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
570 //Declare stat struct
573 if ((fd
= open(entry
->d_name
, O_RDONLY
|O_NOATIME
|O_NOFOLLOW
|O_CLOEXEC
)) == -1) {
574 //Can't open ask file
578 if ((stats
= calloc(1, sizeof(struct stat
))) == NULL
) {
579 //Unable to allocate stats
583 if (fstat(fd
, stats
) == -1) {
584 //Can't stat ask file
588 if ((bufLength
= stats
->st_size
) > SSIZE_MAX
) {
593 if ((buf
= malloc(bufLength
*sizeof(char))) == NULL
) {
594 //Unable to allocate buf
598 if ((read(fd
, buf
, bufLength
)) < bufLength
) {
599 //Fail to read ask file
608 char *nl
= buf
, *pl
= buf
, *e
;
612 //Search for a new line
613 while ((nl
= memmem(nl
, bufLength
- (nl
- buf
), "\n", strlen("\n")))) {
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) {
622 if (!strncmp(pl
, "PID", 3)) {
625 //Allocate pid string
626 if ((pidStr
= malloc((nl
- e
)*sizeof(char))) == NULL
) {
627 //Unable to allocate pid string
631 memcpy(pidStr
, e
, nl
- e
- 1);
632 //Terminate pid string
633 pidStr
[nl
- e
] = '\0';
635 if ((*pid
= atoi(pidStr
)) <= 1) {
641 //Found a valid process
646 //Jump prev line to new line
655 //Close systemd ask-password dir
656 if (closedir(askdir
) == -1) {
657 //Can't close ask dir
668 //Found more than one pid
669 } else if (found
> 1) {
681 int extractIHttpdPid(pid_t
*pid
) {
682 //Declare file descriptor
684 //Declare buf, device and luks pointer
685 char *buf
, *l
, *pidStr
;
686 //Declare stat struct
689 if ((fd
= open(IHTTPDPID
, O_RDONLY
|O_NOATIME
|O_NOFOLLOW
|O_CLOEXEC
)) == -1) {
690 //Can't open crypttab file
694 if ((stats
= calloc(1, sizeof(struct stat
))) == NULL
) {
695 //Unable to allocate stats
699 if (fstat(fd
, stats
) == -1) {
700 //Can't stat crypttab
704 if ((bufLength
= stats
->st_size
) > SSIZE_MAX
) {
709 if ((buf
= malloc(bufLength
*sizeof(char))) == NULL
) {
710 //Unable to allocate buf
714 if ((read(fd
, buf
, bufLength
)) < bufLength
) {
715 //Fail to read crypttab file
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
) {
731 if ((pidStr
= malloc((l
- buf
- 1)*sizeof(char))) == NULL
) {
736 memcpy(pidStr
, buf
, l
- buf
- 1);
738 pidStr
[l
- buf
- 1] = '\0';
744 if ((*pid
= atoi(pidStr
)) <= 1) {
759 int main(int argc
, char **argv
) {
762 char *requestMethod
= getenv("REQUEST_METHOD");
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)) {
771 showForm(getenv("REQUEST_URI")?getenv("REQUEST_URI"):"/", DEFAULT_KEYFILE_SIZE_MAX
, DEFAULT_PASSPHRASE_SIZE_MAX
);
773 } else /*if (!strncmp(requestMethod, "POST", 4))*/ {
781 //XXX: will contain number of char in value without trailing \0
784 //XXX: will contain value without a tailing \0
789 //Content length string from env
790 char *contentLengthStr
= getenv("CONTENT_LENGTH");
792 char *contentType
= getenv("CONTENT_TYPE");
794 //Declare luks and device
795 char *luks
= NULL
, *device
= NULL
;
797 //Pairs of pipe for stdin, stdout and stderr
798 int inPipe
[2], errPipe
[2];
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");
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");
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");
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");
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");
830 if ((ret
= extractValue(&value
, &valueLength
, contentType
, contentLength
)) < 0) {
831 die(500, "Failed to extract value");
835 //Extract luks and device
836 if ((ret
= extractLuksDevice(&luks
, &device
)) < 0) {
837 die(500, "Failed to extract luks and device");
841 if (pipe(inPipe
) == -1) {
842 die(500, "Failed to create in pipe");
846 if (pipe(errPipe
) == -1) {
847 die(500, "Failed to create err pipe");
851 if ((pid
= fork()) == -1) {
852 die(500, "Failed to fork");
858 char *cargv
[] = { CRYPTSETUP
, "-d", "-", "luksOpen", device
, luks
, NULL
};
859 char *carge
[] = { NULL
};
862 //Redirect stdin to pipe
863 if (dup2(inPipe
[0], STDIN_FILENO
) == -1) {
864 die(500, "Failed to redirect in pipe");
869 //Redirect stderr to pipe
870 if (dup2(errPipe
[1], STDERR_FILENO
) == -1) {
871 die(500, "Failed to redirect err pipe");
877 if (execve(CRYPTSETUP
, cargv
, carge
) == -1) {
878 die(500, "Failed to call cryptsetup");
887 //Close unused inPipe end
889 //Close unused errPipe end
892 //Send password on stdin anyway
893 //XXX: this fail if device is already unlocked for example
894 write(inPipe
[1], value
, valueLength
);
899 //Close stdin with EOF
903 if (waitpid(pid
, &ret
, 0) == -1) {
904 die(500, "Failed to wait child");
907 //Handle already unlocked device
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");
923 } else if (ret
!= 0) {
924 //Err length and counter
925 int errLength
= 2048, e
= 0;
931 if ((err
= malloc(errLength
*sizeof(char))) == NULL
) {
932 die(500, "Couldn't alloc err buffer");
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");
950 //Terminate err buffer
953 if ((err
= realloc(err
, (e
+1)*sizeof(char))) == NULL
) {
954 die(500, "Couldn't ungrow err buffer");
956 //Die with luks error
964 if ((pid
= fork()) == -1) {
965 die(500, "Failed to fork");
968 //IHttpd killing child process
979 //Disable line buffering on stdout and stderr
980 setvbuf(stdout
, NULL
, _IONBF
, 0);
981 setvbuf(stderr
, NULL
, _IONBF
, 0);
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");
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");
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");
1003 //Extract ihttpd pid
1004 if (extractIHttpdPid(&ihttpdPid
) < 0) {
1005 fprintf(stderr
, "Failed to extract ihttpd pid");
1009 //Close stdout and stderr without childlog
1011 close(STDOUT_FILENO
);
1012 close(STDERR_FILENO
);
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");
1025 if (kill(ihttpdPid
, 0) == 0 && kill(ihttpdPid
, SIGTERM
) == -1 && fd
!= -1) {
1026 printf("Termiate ihttpd failed\n");
1029 //Sleep half a second
1030 if (usleep(500000) == -1 && fd
!= -1) {
1031 printf("Usleep failed\n");
1035 if (kill(ihttpdPid
, 0) == 0 && kill(ihttpdPid
, SIGKILL
) == -1) {
1036 printf("Kill ihttpd failed\n");
1043 if ((pid
= fork()) == -1) {
1044 die(500, "Failed to fork");
1047 //Ask password killing child process
1048 //XXX: we are blind here
1053 //Declare ask password pid
1054 pid_t askPasswordPid
;
1057 close(STDIN_FILENO
);
1059 //Disable line buffering on stdout and stderr
1060 setvbuf(stdout
, NULL
, _IONBF
, 0);
1061 setvbuf(stderr
, NULL
, _IONBF
, 0);
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");
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");
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");
1083 //Extract ask password pid
1084 if (extractAskPasswordPid(&askPasswordPid
) < 0) {
1085 fprintf(stderr
, "Failed to extract ask password pid");
1089 //Close stdout and stderr without childlog
1091 close(STDOUT_FILENO
);
1092 close(STDERR_FILENO
);
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");
1104 //Termitate ask password
1105 if (kill(askPasswordPid
, 0) == 0 && kill(askPasswordPid
, SIGTERM
) == -1 && fd
!= -1) {
1106 printf("Termiate ask password failed\n");
1110 //Sleep half a second
1111 if (usleep(500000) == -1 && fd
!= -1) {
1112 printf("Usleep failed\n");
1116 if (kill(askPasswordPid
, 0) == 0 && kill(askPasswordPid
, SIGKILL
) == -1) {
1117 printf("Kill ask password failed\n");
1124 header(200, "text/plain");
1125 printf("Sent value, boot should resume now");