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");